]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Optimise access to PGresult data
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 26 Dec 2020 20:55:32 +0000 (21:55 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 27 Dec 2020 16:14:47 +0000 (17:14 +0100)
Access the underlying data structure instead of using the libpq
functions.

We shouldn't, but the speed increase is noticeable.

psycopg3_c/psycopg3_c/transform.pyx

index e0b4b7d38040ee445b8add97fce53b0c590b484e..4d2127bacea1479c37d71402f8e9a448a54141ee 100644 (file)
@@ -21,6 +21,22 @@ from psycopg3 import errors as e
 from psycopg3.pq import Format
 
 
+# internal structure: you are not supposed to know this. But it's worth some
+# 10% of the innermost loop, so I'm willing to ask for forgiveness later...
+
+ctypedef struct PGresAttValue:
+    int     len
+    char    *value
+
+ctypedef struct pg_result_int:
+    # NOTE: it would be advised that we don't know this structure's content
+    int ntups
+    int numAttributes
+    libpq.PGresAttDesc *attDescs
+    PGresAttValue **tuples
+    # ...more members, which we ignore
+
+
 cdef class RowLoader:
     cdef object pyloader
     cdef CLoader cloader
@@ -160,20 +176,25 @@ cdef class Transformer:
         cdef int col
         cdef int length
         cdef const char *val
+
+        # cheeky access to the internal PGresult structure
+        cdef pg_result_int *ires = <pg_result_int*>res
+        cdef PGresAttValue *attval
+
         rv = PyTuple_New(self._nfields)
         for col in range(self._nfields):
-            length = libpq.PQgetlength(res, crow, col)
-            if length == 0:
-                if libpq.PQgetisnull(res, crow, col):
-                    Py_INCREF(None)
-                    PyTuple_SET_ITEM(rv, col, None)
-                    continue
-
-            val = libpq.PQgetvalue(res, crow, col)
+            attval = &(ires.tuples[crow][col])
+            length = attval.len
+            if length == -1:  # NULL_LEN
+                Py_INCREF(None)
+                PyTuple_SET_ITEM(rv, col, None)
+                continue
+
             # TODO: the is some visible python churn around this lookup.
             # replace with a C array of borrowed references pointing to
             # the cloader.cload function pointer
             loader = self._row_loaders[col]
+            val = attval.value
             if loader.cloader is not None:
                 pyval = loader.cloader.cload(val, length)
             else: