From: Daniele Varrazzo Date: Sun, 10 Jan 2021 18:27:22 +0000 (+0100) Subject: Add a reference on the ViewBuffer to the object owning the memory X-Git-Tag: 3.0.dev0~177 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a822428e3601f4cbff7219f20422ee52cb67cf7;p=thirdparty%2Fpsycopg.git Add a reference on the ViewBuffer to the object owning the memory --- diff --git a/psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx b/psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx index daf434b96..8dd40cad0 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx @@ -152,11 +152,11 @@ cdef class CLoader: cdef object cload(self, const char *data, size_t length): raise NotImplementedError() - def load(self, data: bytes) -> Any: - cdef char *buffer + def load(self, object data) -> Any: + cdef char *ptr cdef Py_ssize_t length - PyBytes_AsStringAndSize(data, &buffer, &length) - return self.cload(data, length) + _buffer_as_string_and_size(data, &ptr, &length) + return self.cload(ptr, length) @classmethod def register( diff --git a/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx b/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx index 50e595bfe..c85affe42 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx @@ -191,7 +191,7 @@ def parse_row_binary(data, tx: Transformer) -> Tuple[Any, ...]: if ptr + length > bufend: raise e.DataError("bad copy data: length exceeding data") field = PyMemoryView_FromObject( - ViewBuffer._from_buffer(ptr, length)) + ViewBuffer._from_buffer(data, ptr, length)) ptr += length Py_INCREF(field) @@ -244,7 +244,7 @@ def parse_row_text(data, tx: Transformer) -> Tuple[Any, ...]: elif num_bs == 0: # Nothing to unescape: we don't need a copy field = PyMemoryView_FromObject( - ViewBuffer._from_buffer(fstart, fend - fstart)) + ViewBuffer._from_buffer(data, fstart, fend - fstart)) # This is a field containing backslashes else: diff --git a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx index 8b3355269..c40c0e6f2 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx @@ -24,8 +24,8 @@ from psycopg3 import errors as e # 10% of the innermost loop, so I'm willing to ask for forgiveness later... ctypedef struct PGresAttValue: - int len - char *value + int len + char *value ctypedef struct pg_result_int: # NOTE: it would be advised that we don't know this structure's content @@ -235,7 +235,6 @@ cdef class Transformer: cdef int row cdef int col cdef PGresAttValue *attval - cdef const char *val cdef object record # not 'tuple' as it would check on assignment cdef object records = PyList_New(row1 - row0) @@ -255,12 +254,11 @@ cdef class Transformer: brecord = PyList_GET_ITEM(records, row - row0) attval = &(ires.tuples[row][col]) if attval.len == -1: # NULL_LEN - Py_INCREF(None) - PyTuple_SET_ITEM(brecord, col, None) - continue + pyval = None + else: + pyval = (loader).cloader.cload( + attval.value, attval.len) - pyval = (loader).cloader.cload( - attval.value, attval.len) Py_INCREF(pyval) PyTuple_SET_ITEM(brecord, col, pyval) @@ -269,14 +267,13 @@ cdef class Transformer: brecord = PyList_GET_ITEM(records, row - row0) attval = &(ires.tuples[row][col]) if attval.len == -1: # NULL_LEN - Py_INCREF(None) - PyTuple_SET_ITEM(brecord, col, None) - continue + pyval = None + else: + # TODO: no copy + b = attval.value[:attval.len] + pyval = PyObject_CallFunctionObjArgs( + (loader).pyloader, b, NULL) - # TODO: no copy - b = attval.value[:attval.len] - pyval = PyObject_CallFunctionObjArgs( - (loader).pyloader, b, NULL) Py_INCREF(pyval) PyTuple_SET_ITEM(brecord, col, pyval) @@ -296,7 +293,6 @@ cdef class Transformer: cdef PyObject *loader # borrowed RowLoader cdef int col cdef PGresAttValue *attval - cdef const char *val cdef object record # not 'tuple' as it would check on assignment record = PyTuple_New(self._nfields) @@ -305,19 +301,17 @@ cdef class Transformer: for col in range(self._nfields): attval = &(ires.tuples[row][col]) if attval.len == -1: # NULL_LEN - Py_INCREF(None) - PyTuple_SET_ITEM(record, col, None) - continue - - val = attval.value - loader = PyList_GET_ITEM(row_loaders, col) - if (loader).cloader is not None: - pyval = (loader).cloader.cload(val, attval.len) + pyval = None else: - # TODO: no copy - b = val[:attval.len] - pyval = PyObject_CallFunctionObjArgs( - (loader).pyloader, b, NULL) + loader = PyList_GET_ITEM(row_loaders, col) + if (loader).cloader is not None: + pyval = (loader).cloader.cload( + attval.value, attval.len) + else: + # TODO: no copy + b = attval.value[:attval.len] + pyval = PyObject_CallFunctionObjArgs( + (loader).pyloader, b, NULL) Py_INCREF(pyval) PyTuple_SET_ITEM(record, col, pyval) diff --git a/psycopg3_c/psycopg3_c/pq.pxd b/psycopg3_c/psycopg3_c/pq.pxd index b19350f57..dbd26755d 100644 --- a/psycopg3_c/psycopg3_c/pq.pxd +++ b/psycopg3_c/psycopg3_c/pq.pxd @@ -17,6 +17,7 @@ cdef class PGconn: cpdef object notifies(self) + cdef class PGresult: cdef libpq.PGresult* pgresult_ptr @@ -40,15 +41,17 @@ cdef class PQBuffer: cdef Py_ssize_t len @staticmethod - cdef PQBuffer _from_buffer(unsigned char *buf, Py_ssize_t len) + cdef PQBuffer _from_buffer(unsigned char *buf, Py_ssize_t length) cdef class ViewBuffer: cdef unsigned char *buf cdef Py_ssize_t len + cdef object obj @staticmethod - cdef ViewBuffer _from_buffer(unsigned char *buf, Py_ssize_t len) + cdef ViewBuffer _from_buffer( + object obj, unsigned char *buf, Py_ssize_t length) cdef int _buffer_as_string_and_size( diff --git a/psycopg3_c/psycopg3_c/pq/pqbuffer.pyx b/psycopg3_c/psycopg3_c/pq/pqbuffer.pyx index ad3f9a5e6..eb5d64822 100644 --- a/psycopg3_c/psycopg3_c/pq/pqbuffer.pyx +++ b/psycopg3_c/psycopg3_c/pq/pqbuffer.pyx @@ -4,20 +4,22 @@ PQbuffer object implementation. # Copyright (C) 2020 The Psycopg Team +cimport cython from cpython.bytes cimport PyBytes_AsStringAndSize from cpython.buffer cimport PyObject_CheckBuffer, PyBUF_SIMPLE from cpython.buffer cimport PyObject_GetBuffer, PyBuffer_Release +@cython.freelist(32) cdef class PQBuffer: """ Wrap a chunk of memory allocated by the libpq and expose it as memoryview. """ @staticmethod - cdef PQBuffer _from_buffer(unsigned char *buf, Py_ssize_t len): + cdef PQBuffer _from_buffer(unsigned char *buf, Py_ssize_t length): cdef PQBuffer rv = PQBuffer.__new__(PQBuffer) rv.buf = buf - rv.len = len + rv.len = length return rv def __cinit__(self): @@ -51,15 +53,19 @@ cdef class PQBuffer: pass +@cython.freelist(32) cdef class ViewBuffer: """ - Wrap a chunk of memory for view only. + Wrap a chunk of memory owned by a different object. """ @staticmethod - cdef ViewBuffer _from_buffer(unsigned char *buf, Py_ssize_t len): + cdef ViewBuffer _from_buffer( + object obj, unsigned char *buf, Py_ssize_t length + ): cdef ViewBuffer rv = ViewBuffer.__new__(ViewBuffer) + rv.obj = obj rv.buf = buf - rv.len = len + rv.len = length return rv def __cinit__(self):