return b"".join(data)
-class BaseArrayLoader(RecursiveLoader):
- base_oid: int
-
-
-class ArrayLoader(BaseArrayLoader):
+class ArrayLoader(RecursiveLoader):
delimiter = b","
+ base_oid: int
def load(self, data: Buffer) -> List[Any]:
loader = self._tx.get_loader(self.base_oid, self.format)
- return load_text(data, loader, self.delimiter)
+ return _load_text(data, loader, self.delimiter)
-class ArrayBinaryLoader(BaseArrayLoader):
+class ArrayBinaryLoader(RecursiveLoader):
format = pq.Format.BINARY
def load(self, data: Buffer) -> List[Any]:
- return load_binary(data, self._tx)
+ return _load_binary(data, self._tx)
def register_array(info: TypeInfo, context: Optional[AdaptContext] = None) -> None:
if not info.array_oid:
raise ValueError(f"the type info {info} doesn't describe an array")
+ base: Type[Any]
adapters = context.adapters if context else postgres.adapters
- base: Type[Any] = ArrayLoader
+ base = getattr(_psycopg, "ArrayLoader", ArrayLoader)
name = f"{info.name.title()}{base.__name__}"
attribs = {
"base_oid": info.oid,
loader = type(name, (base,), attribs)
adapters.register_loader(info.array_oid, loader)
- base = ArrayBinaryLoader
- name = f"{info.name.title()}{base.__name__}"
- attribs = {"base_oid": info.oid}
- loader = type(name, (base,), attribs)
+ loader = getattr(_psycopg, "ArrayBinaryLoader", ArrayBinaryLoader)
adapters.register_loader(info.array_oid, loader)
base = ListDumper
out = [out[i : i + dim] for i in range(0, len(out), dim)]
return out
-
-
-# Override functions with fast versions if available
-if _psycopg:
- load_text = _psycopg.array_load_text
- load_binary = _psycopg.array_load_binary
-
-else:
- load_text = _load_text
- load_binary = _load_binary
const int MAXDIM
-def array_load_text(
- data: Buffer, loader: Loader, delimiter: bytes = b","
-) -> List[Any]:
- cdef char cdelim = delimiter[0]
+cdef class ArrayLoader(_CRecursiveLoader):
- cdef char *buf = NULL
- cdef Py_ssize_t length = 0
- _buffer_as_string_and_size(data, &buf, &length)
+ format = PQ_TEXT
+ base_oid = 0
+ delimiter = b","
- cdef CLoader cloader = None
- cdef object pyload = None
+ cdef object cload(self, const char *data, size_t length):
+ cdef PyObject *row_loader = self._tx._c_get_loader(
+ <PyObject *>self.base_oid, <PyObject *>PQ_TEXT)
- if isinstance(loader, CLoader):
- cloader = <CLoader>loader
- else:
- pyload = loader.load
+ cdef char cdelim = self.delimiter[0]
+ return _array_load_text(data, length, row_loader, cdelim)
+
+
+@cython.final
+cdef class ArrayBinaryLoader(_CRecursiveLoader):
+
+ format = PQ_BINARY
+
+ cdef object cload(self, const char *data, size_t length):
+ return _array_load_binary(data, length, self._tx)
+
+cdef object _array_load_text(
+ const char *buf, size_t length, PyObject *row_loader, char cdelim
+):
if length == 0:
raise e.DataError("malformed array: empty data")
- cdef char *end = buf + length
+ cdef const char *end = buf + length
# Keep and grow a buffer instead of malloc'ing at each element
cdef char *scratch = NULL
rv = a
cdef PyObject *tmp
+ cdef CLoader cloader = None
+ cdef object pyload = None
+ if (<RowLoader>row_loader).cloader is not None:
+ cloader = (<RowLoader>row_loader).cloader
+ else:
+ pyload = (<RowLoader>row_loader).loadfunc
+
try:
while buf < end:
if buf[0] == b'{':
cdef object _parse_token(
- char **bufptr, char *bufend, char cdelim,
+ const char **bufptr, const char *bufend, char cdelim,
char **scratch, size_t *sclen, CLoader cloader, object load
):
- cdef char *start = bufptr[0]
+ cdef const char *start = bufptr[0]
cdef int has_quotes = start[0] == b'"'
cdef int quoted = has_quotes
cdef int num_escapes = 0
if has_quotes:
start += 1
- cdef char *end = start
+ cdef const char *end = start
while end < bufend:
if (end[0] == cdelim or end[0] == b'}') and not quoted:
and start[2] == b'L' and start[3] == b'L':
return None
- cdef char *src
+ cdef const char *src
cdef char *tgt
cdef size_t unesclen
@cython.cdivision(True)
-def array_load_binary(data: Buffer, Transformer tx) -> List[Any]:
- cdef char *buf = NULL
- cdef Py_ssize_t length = 0
- _buffer_as_string_and_size(data, &buf, &length)
-
+cdef object _array_load_binary(const char *buf, size_t length, Transformer tx):
# head is ndims, hasnull, elem oid
cdef uint32_t *buf32 = <uint32_t *>buf
cdef int ndims = endian.be32toh(buf32[0])
)
cdef object oid = <Oid>endian.be32toh(buf32[2])
- cdef PyObject *row_loader = tx._c_get_loader(<PyObject *>oid, <PyObject *>PQ_BINARY)
+ cdef PyObject *row_loader = tx._c_get_loader(
+ <PyObject *>oid, <PyObject *>PQ_BINARY)
cdef Py_ssize_t[MAXDIM] dims
cdef int i
cdef object _array_load_binary_rec(
- Py_ssize_t ndims, Py_ssize_t *dims, char **bufptr, PyObject *row_loader
+ Py_ssize_t ndims, Py_ssize_t *dims, const char **bufptr, PyObject *row_loader
):
- cdef char *buf
+ cdef const char *buf
cdef int i
cdef int32_t size
cdef object val