]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
More tweaks to the Transformer C code
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 29 Dec 2020 04:16:44 +0000 (05:16 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 29 Dec 2020 17:13:18 +0000 (18:13 +0100)
psycopg3_c/psycopg3_c/_psycopg3/transform.pyx

index d13f1829c881ffacfab51b5ff25f1fc3061e30da..50b3d47d38e9baca48f93f91e621de4d14e769c4 100644 (file)
@@ -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 = <object>PyList_GET_ITEM(types, i)
+            fmt = <object>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 = <object>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 = <object>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 <object>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 = <object>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 = <object>ptr
+        loader = loader_cls(oid, self)
+        PyDict_SetItem(cache, oid, loader)
         return loader