From: Daniele Varrazzo Date: Thu, 14 May 2020 17:57:02 +0000 (+1200) Subject: RowLoader moved from adapt to transform module X-Git-Tag: 3.0.dev0~526 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3ddf9b8e453fdc868923761a03137d1226485b22;p=thirdparty%2Fpsycopg.git RowLoader moved from adapt to transform module It's only used by the Transformer and it doesn't need to be exposed. --- diff --git a/psycopg3/adapt.pxd b/psycopg3/adapt.pxd index 4d372a336..3c8a8772a 100644 --- a/psycopg3/adapt.pxd +++ b/psycopg3/adapt.pxd @@ -1,10 +1,14 @@ +""" +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) diff --git a/psycopg3/adapt.pyx b/psycopg3/adapt.pyx index d16881b78..0cd43da68 100644 --- a/psycopg3/adapt.pyx +++ b/psycopg3/adapt.pyx @@ -1,5 +1,19 @@ -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") @@ -31,21 +45,14 @@ cdef void register_c_loader( cloaders[pyloader] = cl -cdef void fill_row_loader(RowLoader *loader, object pyloader): - loader.pyloader = 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 diff --git a/psycopg3/transform.pyx b/psycopg3/transform.pyx index 36fc99031..c5dc3368e 100644 --- a/psycopg3/transform.pyx +++ b/psycopg3/transform.pyx @@ -1,3 +1,13 @@ +""" +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 @@ -9,7 +19,6 @@ from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple 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 @@ -18,6 +27,12 @@ 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. @@ -154,10 +169,24 @@ cdef class Transformer: 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 = 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]