It's only used by the Transformer and it doesn't need to be exposed.
+"""
+C definitions of the adaptation system.
+"""
+
+# Copyright (C) 2020 The Psycopg Team
+
from cpython.object cimport PyObject
+# The type of a function reading a result from the database and returning
+# a Python object.
ctypedef object (*cloader_func)(const char *data, size_t length, void *context)
-ctypedef void * (*get_context_func)(object conn)
-
-cdef struct RowLoader:
- PyObject *pyloader # borrowed
- cloader_func cloader
- void *context
+# Take in input a Loader instance and return a context for a `cloader_func`.
+ctypedef void * (*get_context_func)(object conn)
-from psycopg3.adapt cimport cloader_func, get_context_func, RowLoader
+"""
+C implementation of the adaptation system.
+This module maps each Python adaptation function to a C adaptation function.
+Notice that C adaptation functions have a different signature because they can
+avoid making a memory copy, however this makes impossible to expose them to
+Python.
+
+This module exposes facilities to map the builtin adapters in python to
+equivalent C implementations.
+
+"""
+
+# Copyright (C) 2020 The Psycopg Team
+
+from psycopg3.adapt cimport cloader_func, get_context_func
import logging
logger = logging.getLogger("psycopg3.adapt")
cloaders[pyloader] = cl
-cdef void fill_row_loader(RowLoader *loader, object pyloader):
- loader.pyloader = <PyObject *>pyloader
-
- cdef CLoader cloader
- cloader = cloaders.get(pyloader)
- if cloader is not None:
- loader.cloader = cloader.cloader
- else:
- cloader = cloaders.get(getattr(pyloader, '__func__', None))
- if cloader is not None and cloader.get_context is not NULL:
- loader.cloader = cloader.cloader
- loader.context = cloader.get_context(pyloader.__self__)
+def register_builtin_c_loaders():
+ """
+ Register all the builtin optimized methods.
+ This function is supposed to be called only once, after the Python loaders
+ are registered.
-def register_builtin_c_loaders():
+ """
if cloaders:
logger.warning("c loaders already registered")
return
+"""
+Helper object to transform values between Python and PostgreSQL
+
+Cython implementation: can access to lower level C features without creating
+too many temporary Python objects and performing less memory copying.
+
+"""
+
+# Copyright (C) 2020 The Psycopg Team
+
from libc.string cimport memset
from cpython.object cimport PyObject
from cpython.ref cimport Py_INCREF
from psycopg3.pq cimport libpq
from psycopg3.pq.pq_cython cimport PGresult
-from psycopg3.adapt cimport RowLoader
from psycopg3 import errors as e
from psycopg3.pq.enums import Format
TEXT_OID = 25
+cdef struct RowLoader:
+ PyObject *pyloader # borrowed
+ cloader_func cloader
+ void *context
+
+
cdef class Transformer:
"""
An object that can adapt efficiently between Python and PostgreSQL.
loader = self._set_loader(i, oid, fmt)
cdef void _set_loader(self, int col, libpq.Oid oid, int fmt):
+ pyloader = self._pyloaders[col] = self.get_load_function(oid, fmt)
+
cdef RowLoader *loader = self._row_loaders + col
+ loader.pyloader = <PyObject *>pyloader
- pyloader = self._pyloaders[col] = self.get_load_function(oid, fmt)
- fill_row_loader(loader, pyloader)
+ cdef CLoader cloader = cloaders.get(pyloader)
+
+ if cloader is not None:
+ # The cloader is a normal Python function
+ loader.cloader = cloader.cloader
+ return
+
+ cloader = cloaders.get(getattr(pyloader, '__func__', None))
+ if cloader is not None and cloader.get_context is not NULL:
+ # The cloader is the load() method of a Loader class
+ # Extract the context from the Loader instance
+ loader.cloader = cloader.cloader
+ loader.context = cloader.get_context(pyloader.__self__)
def dump_sequence(
self, objs: Iterable[Any], formats: Iterable[Format]