From: Daniele Varrazzo Date: Tue, 29 Dec 2020 04:16:44 +0000 (+0100) Subject: More tweaks to the Transformer C code X-Git-Tag: 3.0.dev0~228^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3590d1e756396cb29d30600c943d16d64e8e1cd;p=thirdparty%2Fpsycopg.git More tweaks to the Transformer C code --- diff --git a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx index d13f1829c..50b3d47d3 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx @@ -9,7 +9,7 @@ too many temporary Python objects and performing less memory copying. # Copyright (C) 2020 The Psycopg Team from cpython.ref cimport Py_INCREF -from cpython.dict cimport PyDict_GetItem +from cpython.dict cimport PyDict_GetItem, PyDict_SetItem from cpython.list cimport PyList_New, PyList_GET_ITEM, PyList_SET_ITEM from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM from cpython.object cimport PyObject, PyObject_CallFunctionObjArgs @@ -52,6 +52,9 @@ cdef class Transformer: cdef readonly object connection cdef readonly object adapters + # TODO: the dumpers should have the same tweaking of the loaders + cdef dict _adapters_loaders + cdef dict _adapters_dumpers cdef dict _dumpers_cache cdef dict _text_loaders cdef dict _binary_loaders @@ -68,6 +71,9 @@ cdef class Transformer: self.adapters = global_adapters self.connection = None + self._adapters_loaders = self.adapters._loaders + self._adapters_dumpers = self.adapters._dumpers + # mapping class, fmt -> Dumper instance self._dumpers_cache: Dict[Tuple[type, Format], "Dumper"] = {} @@ -107,39 +113,46 @@ cdef class Transformer: Py_INCREF(tmp) PyList_SET_ITEM(formats, i, tmp) - self._c_set_row_types(types, formats) + self._c_set_row_types(self._nfields, types, formats) - def set_row_types(self, types: Sequence[int], formats: Sequence[Format]) -> None: - self._c_set_row_types(types, formats) + def set_row_types(self, + types: Sequence[int], formats: Sequence[Format]) -> None: + self._c_set_row_types(len(types), types, formats) - cdef void _c_set_row_types(self, list types, list formats): + cdef void _c_set_row_types(self, int ntypes, list types, list formats): + cdef list loaders = PyList_New(ntypes) + cdef object loader cdef dict text_loaders = {} cdef dict binary_loaders = {} - cdef list loaders = PyList_New(len(types)) - cdef object loader - cdef libpq.Oid oid - cdef int fmt - cdef int i - for i in range(len(types)): - oid = types[i] - fmt = formats[i] + + # these are used more as Python object than C + cdef object oid + cdef object fmt + cdef PyObject *ptr + for i in range(ntypes): + oid = PyList_GET_ITEM(types, i) + fmt = PyList_GET_ITEM(formats, i) if fmt == 0: - if oid in text_loaders: - loader = text_loaders[oid] + ptr = PyDict_GetItem(text_loaders, oid) + if ptr != NULL: + loader = ptr else: - loader = text_loaders[oid] = self._get_row_loader(oid, fmt) + loader = self._get_row_loader(oid, fmt) + PyDict_SetItem(text_loaders, oid, loader) else: - if oid in binary_loaders: - loader = binary_loaders[oid] + ptr = PyDict_GetItem(binary_loaders, oid) + if ptr != NULL: + loader = ptr else: - loader = binary_loaders[oid] = self._get_row_loader(oid, fmt) + loader = self._get_row_loader(oid, fmt) + PyDict_SetItem(binary_loaders, oid, loader) Py_INCREF(loader) PyList_SET_ITEM(loaders, i, loader) self._row_loaders = loaders - cdef RowLoader _get_row_loader(self, libpq.Oid oid, int fmt): + cdef RowLoader _get_row_loader(self, object oid, object fmt): cdef RowLoader row_loader = RowLoader() loader = self._c_get_loader(oid, fmt) row_loader.pyloader = loader.load @@ -321,21 +334,29 @@ cdef class Transformer: def get_loader(self, oid: int, format: Format) -> "Loader": return self._c_get_loader(oid, format) - cdef object _c_get_loader(self, libpq.Oid oid, int format): + cdef object _c_get_loader(self, object oid, object format): cdef dict cache - cdef object pyoid = oid + cdef PyObject *ptr if format == 0: cache = self._text_loaders else: cache = self._binary_loaders - cdef PyObject *ptr = PyDict_GetItem(cache, pyoid) + ptr = PyDict_GetItem(cache, oid) if ptr != NULL: return ptr - loader_cls = self.adapters._loaders.get((pyoid, format)) - if loader_cls is None: - loader_cls = self.adapters._loaders[oids.INVALID_OID, format] - loader = cache[pyoid] = loader_cls(pyoid, self) + key = (oid, format) + ptr = PyDict_GetItem(self._adapters_loaders, (oid, format)) + if ptr != NULL: + loader_cls = ptr + else: + ptr = PyDict_GetItem( + self.adapters._loaders, (oids.INVALID_OID, format)) + if ptr == NULL: + raise e.InterfaceError(f"unknown oid loader not found") + loader_cls = ptr + loader = loader_cls(oid, self) + PyDict_SetItem(cache, oid, loader) return loader