From: Daniele Varrazzo Date: Mon, 21 Dec 2020 00:21:19 +0000 (+0100) Subject: Further PGconn code moving and stricter declarations X-Git-Tag: 3.0.dev0~252^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68bf5504fba572e96e72f7ab6a347f00bd4ea6fc;p=thirdparty%2Fpsycopg.git Further PGconn code moving and stricter declarations --- diff --git a/psycopg3_c/psycopg3_c/pq/pgconn.pyx b/psycopg3_c/psycopg3_c/pq/pgconn.pyx index b737f0e30..c3bca6238 100644 --- a/psycopg3_c/psycopg3_c/pq/pgconn.pyx +++ b/psycopg3_c/psycopg3_c/pq/pgconn.pyx @@ -25,12 +25,20 @@ cdef class PGconn: self.finish() @classmethod - def connect(cls, conninfo: bytes) -> PGconn: - return _connect(conninfo) + def connect(cls, const char *conninfo) -> PGconn: + cdef impl.PGconn* pgconn = impl.PQconnectdb(conninfo) + if not pgconn: + raise MemoryError("couldn't allocate PGconn") + + return PGconn._from_ptr(pgconn) @classmethod - def connect_start(cls, conninfo: bytes) -> PGconn: - return _connect_start(conninfo) + def connect_start(cls, const char *conninfo) -> PGconn: + cdef impl.PGconn* pgconn = impl.PQconnectStart(conninfo) + if not pgconn: + raise MemoryError("couldn't allocate PGconn") + + return PGconn._from_ptr(pgconn) def connect_poll(self) -> PollingStatus: cdef int rv = self._call_int(impl.PQconnectPoll) @@ -71,7 +79,7 @@ cdef class PGconn: return PollingStatus(rv) @classmethod - def ping(self, conninfo: bytes) -> Ping: + def ping(self, const char *conninfo) -> Ping: cdef int rv = impl.PQping(conninfo) return Ping(rv) @@ -453,17 +461,110 @@ cdef class PGconn: return func(self.pgconn_ptr) -cdef PGconn _connect(const char *conninfo): - cdef impl.PGconn* pgconn = impl.PQconnectdb(conninfo) - if not pgconn: - raise MemoryError("couldn't allocate PGconn") - - return PGconn._from_ptr(pgconn) - +cdef void notice_receiver(void *arg, const impl.PGresult *res_ptr) with gil: + cdef PGconn pgconn = arg + if pgconn.notice_handler is None: + return + + cdef PGresult res = PGresult._from_ptr(res_ptr) + try: + pgconn.notice_handler(res) + except Exception as e: + logger.exception("error in notice receiver: %s", e) + + res.pgresult_ptr = NULL # avoid destroying the pgresult_ptr + + +cdef (int, Oid *, char * const*, int *, int *) _query_params_args( + list param_values: Optional[Sequence[Optional[bytes]]], + param_types: Optional[Sequence[int]], + list param_formats: Optional[Sequence[Format]], +) except *: + cdef int i + + # the PostgresQuery convers the param_types to tuple, so this operation + # is most often no-op + cdef tuple tparam_types + if param_types is not None and not isinstance(param_types, tuple): + tparam_types = tuple(param_types) + else: + tparam_types = param_types + + cdef int nparams = len(param_values) if param_values else 0 + if tparam_types is not None and len(tparam_types) != nparams: + raise ValueError( + "got %d param_values but %d param_types" + % (nparams, len(tparam_types)) + ) + if param_formats is not None and len(param_formats) != nparams: + raise ValueError( + "got %d param_values but %d param_formats" + % (nparams, len(param_formats)) + ) -cdef PGconn _connect_start(const char *conninfo): - cdef impl.PGconn* pgconn = impl.PQconnectStart(conninfo) - if not pgconn: - raise MemoryError("couldn't allocate PGconn") + cdef char **aparams = NULL + cdef int *alenghts = NULL + cdef char *ptr + cdef Py_ssize_t length + + if nparams: + aparams = PyMem_Malloc(nparams * sizeof(char *)) + alenghts = PyMem_Malloc(nparams * sizeof(int)) + for i in range(nparams): + obj = param_values[i] + if obj is None: + aparams[i] = NULL + alenghts[i] = 0 + else: + # TODO: it is a leak if this fails (but it should only fail + # on internal error, e.g. if obj is not a buffer) + _buffer_as_string_and_size(obj, &ptr, &length) + aparams[i] = ptr + alenghts[i] = length + + cdef Oid *atypes = NULL + if tparam_types: + atypes = PyMem_Malloc(nparams * sizeof(Oid)) + for i in range(nparams): + atypes[i] = tparam_types[i] + + cdef int *aformats = NULL + if param_formats is not None: + aformats = PyMem_Malloc(nparams * sizeof(int *)) + for i in range(nparams): + aformats[i] = param_formats[i] + + return (nparams, atypes, aparams, alenghts, aformats) + + +cdef void _clear_query_params( + Oid *ctypes, char *const *cvalues, int *clenghts, int *cformats +): + PyMem_Free(ctypes) + PyMem_Free(cvalues) + PyMem_Free(clenghts) + PyMem_Free(cformats) + + +cdef _options_from_array(impl.PQconninfoOption *opts): + rv = [] + cdef int i = 0 + cdef impl.PQconninfoOption* opt + while 1: + opt = opts + i + if opt.keyword is NULL: + break + rv.append( + ConninfoOption( + keyword=opt.keyword, + envvar=opt.envvar if opt.envvar is not NULL else None, + compiled=opt.compiled if opt.compiled is not NULL else None, + val=opt.val if opt.val is not NULL else None, + label=opt.label if opt.label is not NULL else None, + dispchar=opt.dispchar if opt.dispchar is not NULL else None, + dispsize=opt.dispsize, + ) + ) + i += 1 - return PGconn._from_ptr(pgconn) + return rv diff --git a/psycopg3_c/psycopg3_c/pq_cython.pyx b/psycopg3_c/psycopg3_c/pq_cython.pyx index 26abe2c29..4252cd873 100644 --- a/psycopg3_c/psycopg3_c/pq_cython.pyx +++ b/psycopg3_c/psycopg3_c/pq_cython.pyx @@ -41,118 +41,9 @@ def version(): return impl.PQlibVersion() -cdef void notice_receiver(void *arg, const impl.PGresult *res_ptr) with gil: - cdef PGconn pgconn = arg - if pgconn.notice_handler is None: - return - - cdef PGresult res = PGresult._from_ptr(res_ptr) - try: - pgconn.notice_handler(res) - except Exception as e: - logger.exception("error in notice receiver: %s", e) - - res.pgresult_ptr = NULL # avoid destroying the pgresult_ptr - - include "pq/pgconn.pyx" -cdef (int, Oid *, char * const*, int *, int *) _query_params_args( - list param_values: Optional[Sequence[Optional[bytes]]], - param_types: Optional[Sequence[int]], - list param_formats: Optional[Sequence[Format]], -) except *: - cdef int i - - # the PostgresQuery convers the param_types to tuple, so this operation - # is most often no-op - cdef tuple tparam_types - if param_types is not None and not isinstance(param_types, tuple): - tparam_types = tuple(param_types) - else: - tparam_types = param_types - - cdef int nparams = len(param_values) if param_values else 0 - if tparam_types is not None and len(tparam_types) != nparams: - raise ValueError( - "got %d param_values but %d param_types" - % (nparams, len(tparam_types)) - ) - if param_formats is not None and len(param_formats) != nparams: - raise ValueError( - "got %d param_values but %d param_formats" - % (nparams, len(param_formats)) - ) - - cdef char **aparams = NULL - cdef int *alenghts = NULL - cdef char *ptr - cdef Py_ssize_t length - - if nparams: - aparams = PyMem_Malloc(nparams * sizeof(char *)) - alenghts = PyMem_Malloc(nparams * sizeof(int)) - for i in range(nparams): - obj = param_values[i] - if obj is None: - aparams[i] = NULL - alenghts[i] = 0 - else: - # TODO: it is a leak if this fails (but it should only fail - # on internal error, e.g. if obj is not a buffer) - _buffer_as_string_and_size(obj, &ptr, &length) - aparams[i] = ptr - alenghts[i] = length - - cdef Oid *atypes = NULL - if tparam_types: - atypes = PyMem_Malloc(nparams * sizeof(Oid)) - for i in range(nparams): - atypes[i] = tparam_types[i] - - cdef int *aformats = NULL - if param_formats is not None: - aformats = PyMem_Malloc(nparams * sizeof(int *)) - for i in range(nparams): - aformats[i] = param_formats[i] - - return (nparams, atypes, aparams, alenghts, aformats) - - -cdef void _clear_query_params( - Oid *ctypes, char *const *cvalues, int *clenghts, int *cformats -): - PyMem_Free(ctypes) - PyMem_Free(cvalues) - PyMem_Free(clenghts) - PyMem_Free(cformats) - - -cdef _options_from_array(impl.PQconninfoOption *opts): - rv = [] - cdef int i = 0 - cdef impl.PQconninfoOption* opt - while 1: - opt = opts + i - if opt.keyword is NULL: - break - rv.append( - ConninfoOption( - keyword=opt.keyword, - envvar=opt.envvar if opt.envvar is not NULL else None, - compiled=opt.compiled if opt.compiled is not NULL else None, - val=opt.val if opt.val is not NULL else None, - label=opt.label if opt.label is not NULL else None, - dispchar=opt.dispchar if opt.dispchar is not NULL else None, - dispsize=opt.dispsize, - ) - ) - i += 1 - - return rv - - cdef class PGresult: def __cinit__(self): self.pgresult_ptr = NULL