]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Don't deal with the python-level connection in C adapters
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 7 Jan 2021 23:07:56 +0000 (00:07 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Fri, 8 Jan 2021 01:32:29 +0000 (02:32 +0100)
Use the libpq-level connection to shed some overhead.

psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx
psycopg3_c/psycopg3_c/_psycopg3/transform.pyx
psycopg3_c/psycopg3_c/types/text.pyx

index afa44ad3192411f74e07f6148f18dc17b8ec12c5..daf434b96ca2d476a8a713900463719aeae23d3d 100644 (file)
@@ -34,15 +34,12 @@ logger = logging.getLogger("psycopg3.adapt")
 cdef class CDumper:
     cdef object cls
     cdef public libpq.Oid oid
-    cdef readonly object connection
     cdef pq.PGconn _pgconn
 
     def __init__(self, cls: type, context: Optional[AdaptContext] = None):
         self.cls = cls
-        self.connection = context.connection if context is not None else None
-        self._pgconn = (
-            self.connection.pgconn if self.connection is not None else None
-        )
+        conn = context.connection if context is not None else None
+        self._pgconn = conn.pgconn if conn is not None else None
 
         # default oid is implicitly set to 0, subclasses may override it
         # PG 9.6 goes a bit bonker sending unknown oids, so use text instead
@@ -145,11 +142,12 @@ cdef class CDumper:
 @cython.freelist(8)
 cdef class CLoader:
     cdef public libpq.Oid oid
-    cdef readonly connection
+    cdef pq.PGconn _pgconn
 
     def __init__(self, int oid, context: Optional[AdaptContext] = None):
         self.oid = oid
-        self.connection = context.connection if context is not None else None
+        conn = context.connection if context is not None else None
+        self._pgconn = conn.pgconn if conn is not None else None
 
     cdef object cload(self, const char *data, size_t length):
         raise NotImplementedError()
index e24b2f917850bc0adbd37f5e9c3f77edae60c47e..57e8dc4a6a60108ee207af716a3543884edbbf8d 100644 (file)
@@ -85,6 +85,9 @@ cdef class Transformer:
 
     @pgresult.setter
     def pgresult(self, result: Optional[PGresult]) -> None:
+        self.set_pgresult(result)
+
+    cdef void set_pgresult(self, pq.PGresult result):
         self._pgresult = result
 
         if result is None:
index bb7d83f9d1c2bab8544c7ae548e0dd6c81a4180d..5070f5aae89ac745ca08dafa52b520e27135ae74 100644 (file)
@@ -17,6 +17,7 @@ from cpython.unicode cimport (
 )
 
 from psycopg3_c.pq cimport libpq, Escaping, _buffer_as_string_and_size
+from psycopg3.encodings import pg2py
 
 cdef extern from "Python.h":
     const char *PyUnicode_AsUTF8AndSize(unicode obj, Py_ssize_t *size)
@@ -32,16 +33,18 @@ cdef class _StringDumper(CDumper):
 
         self.is_utf8 = 0
         self.encoding = "utf-8"
+        cdef const char *pgenc
 
-        conn = self.connection
-        if conn is not None:
-            self._bytes_encoding = conn.client_encoding.encode("utf-8")
-            self.encoding = PyBytes_AsString(self._bytes_encoding)
-            if (
-                self._bytes_encoding == b"utf-8"
-                or self._bytes_encoding == b"ascii"
-            ):
+        if self._pgconn is not None:
+            pgenc = libpq.PQparameterStatus(self._pgconn.pgconn_ptr, b"client_encoding")
+            if pgenc == NULL or pgenc == b"UTF8":
+                self._bytes_encoding = b"utf-8"
                 self.is_utf8 = 1
+            else:
+                self._bytes_encoding = pg2py(pgenc).encode("utf-8")
+                if self._bytes_encoding == b"ascii":
+                    self.is_utf8 = 1
+            self.encoding = PyBytes_AsString(self._bytes_encoding)
 
     cdef Py_ssize_t cdump(self, obj, bytearray rv, Py_ssize_t offset) except -1:
         # the server will raise DataError subclass if the string contains 0x00
@@ -105,15 +108,20 @@ cdef class _TextLoader(CLoader):
 
         self.is_utf8 = 0
         self.encoding = "utf-8"
+        cdef const char *pgenc
 
-        conn = self.connection
-        if conn is not None:
-            self._bytes_encoding = conn.client_encoding.encode("utf-8")
-            self.encoding = PyBytes_AsString(self._bytes_encoding)
-            if self._bytes_encoding == b"utf-8":
+        if self._pgconn is not None:
+            pgenc = libpq.PQparameterStatus(self._pgconn.pgconn_ptr, b"client_encoding")
+            if pgenc == NULL or pgenc == b"UTF8":
+                self._bytes_encoding = b"utf-8"
                 self.is_utf8 = 1
-            elif self._bytes_encoding == b"ascii":
+            else:
+                self._bytes_encoding = pg2py(pgenc).encode("utf-8")
+
+            if pgenc == b"SQL_ASCII":
                 self.encoding = NULL
+            else:
+                self.encoding = PyBytes_AsString(self._bytes_encoding)
 
     cdef object cload(self, const char *data, size_t length):
         if self.is_utf8: