From: Daniele Varrazzo Date: Sat, 26 Dec 2020 20:55:32 +0000 (+0100) Subject: Optimise access to PGresult data X-Git-Tag: 3.0.dev0~238 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=21599eb98fb21b8dd782e7631c0d433efc0a9fa5;p=thirdparty%2Fpsycopg.git Optimise access to PGresult data Access the underlying data structure instead of using the libpq functions. We shouldn't, but the speed increase is noticeable. --- diff --git a/psycopg3_c/psycopg3_c/transform.pyx b/psycopg3_c/psycopg3_c/transform.pyx index e0b4b7d38..4d2127bac 100644 --- a/psycopg3_c/psycopg3_c/transform.pyx +++ b/psycopg3_c/psycopg3_c/transform.pyx @@ -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 = 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: