From: Daniele Varrazzo Date: Thu, 14 May 2020 19:47:49 +0000 (+1200) Subject: Utf8 decoding optimized X-Git-Tag: 3.0.dev0~523 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2163eb8aeff09608fe677b046861713805a37311;p=thirdparty%2Fpsycopg.git Utf8 decoding optimized --- diff --git a/psycopg3/transform.pyx b/psycopg3/transform.pyx index c5dc3368e..45f177db6 100644 --- a/psycopg3/transform.pyx +++ b/psycopg3/transform.pyx @@ -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 = PyMem_Malloc(ntypes * sizeof(RowLoader)) memset(self._row_loaders, 0, ntypes * sizeof(RowLoader)) self._pyloaders = [None] * ntypes diff --git a/psycopg3/types/text.pyx b/psycopg3/types/text.pyx index 179088dc7..faeb2e86d 100644 --- a/psycopg3/types/text.pyx +++ b/psycopg3/types/text.pyx @@ -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 = context + if tcontext.cdecoder: + return tcontext.cdecoder(data, length, NULL) + b = PyBytes_FromStringAndSize(data, length) - if context is not NULL: - codec = context - # TODO: check if the refcount is right (but a DECREF here segfaults) - return codec(b)[0] + decoder = (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 loader.decode - else: - return NULL + cdef TextContext *rv = PyMem_Malloc(sizeof(TextContext)) + rv.pydecoder = loader.decode + rv.cdecoder = NULL + + if loader.connection is None or loader.connection.encoding == "UTF8": + rv.cdecoder = PyUnicode_DecodeUTF8 + + return rv cdef object load_bytea_text(const char *data, size_t length, void *context):