]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Add a reference on the ViewBuffer to the object owning the memory
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 10 Jan 2021 18:27:22 +0000 (19:27 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 12 Jan 2021 15:16:34 +0000 (16:16 +0100)
psycopg3_c/psycopg3_c/_psycopg3/adapt.pyx
psycopg3_c/psycopg3_c/_psycopg3/copy.pyx
psycopg3_c/psycopg3_c/_psycopg3/transform.pyx
psycopg3_c/psycopg3_c/pq.pxd
psycopg3_c/psycopg3_c/pq/pqbuffer.pyx

index daf434b96ca2d476a8a713900463719aeae23d3d..8dd40cad08eadeffb98a427c1d5343488e817ac5 100644 (file)
@@ -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(
index 50e595bfef1b6e1868d69ab0e89d93101cb7b5b5..c85affe420d87595729b43e2dc052d55193187bb 100644 (file)
@@ -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:
index 8b33552696fdc1868f8d9bd2b6fae74a0022027f..c40c0e6f256123dc3d836db1eaf455b2355441a7 100644 (file)
@@ -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(<object>brecord, col, None)
-                        continue
+                        pyval = None
+                    else:
+                        pyval = (<RowLoader>loader).cloader.cload(
+                            attval.value, attval.len)
 
-                    pyval = (<RowLoader>loader).cloader.cload(
-                        attval.value, attval.len)
                     Py_INCREF(pyval)
                     PyTuple_SET_ITEM(<object>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(<object>brecord, col, None)
-                        continue
+                        pyval = None
+                    else:
+                        # TODO: no copy
+                        b = attval.value[:attval.len]
+                        pyval = PyObject_CallFunctionObjArgs(
+                            (<RowLoader>loader).pyloader, <PyObject *>b, NULL)
 
-                    # TODO: no copy
-                    b = attval.value[:attval.len]
-                    pyval = PyObject_CallFunctionObjArgs(
-                        (<RowLoader>loader).pyloader, <PyObject *>b, NULL)
                     Py_INCREF(pyval)
                     PyTuple_SET_ITEM(<object>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 (<RowLoader>loader).cloader is not None:
-                pyval = (<RowLoader>loader).cloader.cload(val, attval.len)
+                pyval = None
             else:
-                # TODO: no copy
-                b = val[:attval.len]
-                pyval = PyObject_CallFunctionObjArgs(
-                    (<RowLoader>loader).pyloader, <PyObject *>b, NULL)
+                loader = PyList_GET_ITEM(row_loaders, col)
+                if (<RowLoader>loader).cloader is not None:
+                    pyval = (<RowLoader>loader).cloader.cload(
+                        attval.value, attval.len)
+                else:
+                    # TODO: no copy
+                    b = attval.value[:attval.len]
+                    pyval = PyObject_CallFunctionObjArgs(
+                        (<RowLoader>loader).pyloader, <PyObject *>b, NULL)
 
             Py_INCREF(pyval)
             PyTuple_SET_ITEM(record, col, pyval)
index b19350f575aa14280251d605dc36138979d66cdc..dbd26755d21b93031e0b57a11ac67fb218a4376e 100644 (file)
@@ -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(
index ad3f9a5e636d57bda6c7325c693e4cce6679131a..eb5d64822ad8c96d9e20e9252e38ae40e5c3a8e0 100644 (file)
@@ -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):