]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Utf8 decoding optimized
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 14 May 2020 19:47:49 +0000 (07:47 +1200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 17 May 2020 09:29:34 +0000 (21:29 +1200)
psycopg3/transform.pyx
psycopg3/types/text.pyx

index c5dc3368e7a83b4f2dd7279af3bed4591cccacbb..45f177db6e23009ea1ee187300097f6f2110aae3 100644 (file)
@@ -47,6 +47,8 @@ cdef class Transformer:
     cdef object _connection, _codec
     cdef PGresult _pgresult
     cdef int _nfields, _ntuples
+
+    cdef int _nloaders
     cdef RowLoader *_row_loaders
     cdef object _pyloaders  # only used to keep a reference
 
@@ -61,12 +63,19 @@ cdef class Transformer:
         # mapping oid, fmt -> load function
         self._load_funcs: Dict[Tuple[int, Format], "LoadFunc"] = {}
 
+        self._nloaders = 0
         self._row_loaders = NULL
         self._pyloaders = []
 
         self.pgresult = None
 
     def __dealloc__(self):
+        self._clear_row_loaders()
+
+    def _clear_row_loaders(self):
+        cdef int i
+        for i in range(self._nloaders):
+            PyMem_Free(self._row_loaders[i].context)
         PyMem_Free(self._row_loaders)
 
     def _setup_context(self, context: "AdaptContext") -> None:
@@ -159,7 +168,7 @@ cdef class Transformer:
 
     def set_row_types(self, types: Sequence[Tuple[int, Format]]) -> None:
         cdef int ntypes = len(types)
-        PyMem_Free(self._row_loaders)
+        self._clear_row_loaders()
         self._row_loaders = <RowLoader *>PyMem_Malloc(ntypes * sizeof(RowLoader))
         memset(self._row_loaders, 0, ntypes * sizeof(RowLoader))
         self._pyloaders = [None] * ntypes
index 179088dc713aae388c161aabb62103c1de4f17e4..faeb2e86db99ecd8416179c2cb4d4abeb96a6a18 100644 (file)
@@ -5,26 +5,41 @@ Cython adapters for textual types.
 # Copyright (C) 2020 The Psycopg Team
 
 from cpython.bytes cimport PyBytes_FromStringAndSize
+from cpython.mem cimport PyMem_Malloc
+from cpython.object cimport PyObject
 from cpython.unicode cimport PyUnicode_DecodeUTF8
 from psycopg3.pq cimport libpq
 
+ctypedef unicode (*decodefunc)(char *s, Py_ssize_t size, char *errors)
+
+cdef struct TextContext:
+    PyObject *pydecoder
+    decodefunc cdecoder
+
 
 cdef object load_text(const char *data, size_t length, void *context):
-    # TODO: optimize
+    cdef TextContext *tcontext = <TextContext *>context
+    if tcontext.cdecoder:
+        return tcontext.cdecoder(<char *>data, length, NULL)
+
     b = PyBytes_FromStringAndSize(data, length)
-    if context is not NULL:
-        codec = <object>context
-        # TODO: check if the refcount is right (but a DECREF here segfaults)
-        return codec(b)[0]
+    decoder = <object>(tcontext.pydecoder)
+    if decoder is not None:
+        # TODO: check if the refcount is right
+        return decoder(b)[0]
     else:
         return b
 
 
 cdef void *get_context_text(object loader):
-    if loader.decode is not None:
-        return <void *>loader.decode
-    else:
-        return NULL
+    cdef TextContext *rv = <TextContext *>PyMem_Malloc(sizeof(TextContext))
+    rv.pydecoder = <PyObject *>loader.decode
+    rv.cdecoder = NULL
+
+    if loader.connection is None or loader.connection.encoding == "UTF8":
+        rv.cdecoder = <decodefunc>PyUnicode_DecodeUTF8
+
+    return rv
 
 
 cdef object load_bytea_text(const char *data, size_t length, void *context):