diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index d54037f2..7b623fa0 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -36,6 +36,7 @@ #include "psycopg/config.h" #include "psycopg/python.h" +#include "psycopg/utils.h" #ifdef __cplusplus extern "C" { @@ -115,35 +116,6 @@ typedef struct { char *pyenc; } encodingPair; -/* the Decimal type, used by the DECIMAL typecaster */ -HIDDEN PyObject *psyco_GetDecimalType(void); - -/* forward declarations */ -typedef struct cursorObject cursorObject; -typedef struct connectionObject connectionObject; -typedef struct replicationMessageObject replicationMessageObject; - -/* some utility functions */ -RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg); - -HIDDEN char *psycopg_escape_string(connectionObject *conn, - const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); -HIDDEN char *psycopg_escape_identifier(connectionObject *conn, - const char *str, Py_ssize_t len); -HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len); -HIDDEN int psycopg_is_text_file(PyObject *f); -HIDDEN PyObject *psycopg_text_from_chars_safe( - const char *str, Py_ssize_t len, PyObject *decoder); - -STEALS(1) HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj); - -STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj); - -HIDDEN PyObject *psycopg_dict_from_conninfo_options(PQconninfoOption *options, - int include_password); - -HIDDEN PyObject *psycopg_make_dsn(PyObject *dsn, PyObject *kwargs); - /* Exceptions docstrings */ #define Error_doc \ "Base class for error exceptions." diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index abff26da..04b6b6c5 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -39,7 +39,6 @@ #include "psycopg/typecast.h" #include "psycopg/microprotocols.h" #include "psycopg/microprotocols_proto.h" -#include "psycopg/error.h" #include "psycopg/conninfo.h" #include "psycopg/diagnostics.h" @@ -722,116 +721,6 @@ psyco_errors_set(PyObject *type) } } -/* psyco_set_error - - Create a new error of the given type with extra attributes. */ - -/* TODO: may have been changed to BORROWED */ -RAISES PyObject * -psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg) -{ - PyObject *pymsg; - PyObject *err = NULL; - connectionObject *conn = NULL; - - if (curs) { - conn = ((cursorObject *)curs)->conn; - } - - if ((pymsg = conn_text_from_chars(conn, msg))) { - err = PyObject_CallFunctionObjArgs(exc, pymsg, NULL); - Py_DECREF(pymsg); - } - else { - /* what's better than an error in an error handler in the morning? - * Anyway, some error was set, refcount is ok... get outta here. */ - return NULL; - } - - if (err && PyObject_TypeCheck(err, &errorType)) { - errorObject *perr = (errorObject *)err; - if (curs) { - Py_CLEAR(perr->cursor); - Py_INCREF(curs); - perr->cursor = curs; - } - } - - if (err) { - PyErr_SetObject(exc, err); - Py_DECREF(err); - } - - return err; -} - - -/* Return nonzero if the current one is the main interpreter */ -static int -psyco_is_main_interp(void) -{ - static PyInterpreterState *main_interp = NULL; /* Cached reference */ - PyInterpreterState *interp; - - if (main_interp) { - return (main_interp == PyThreadState_Get()->interp); - } - - /* No cached value: cache the proper value and try again. */ - interp = PyInterpreterState_Head(); - while (interp->next) - interp = interp->next; - - main_interp = interp; - assert (main_interp); - return psyco_is_main_interp(); -} - - -/* psyco_GetDecimalType - - Return a new reference to the adapter for decimal type. - - If decimals should be used but the module import fails, fall back on - the float type. - - If decimals are not to be used, return NULL. -*/ - -PyObject * -psyco_GetDecimalType(void) -{ - static PyObject *cachedType = NULL; - PyObject *decimalType = NULL; - PyObject *decimal; - - /* Use the cached object if running from the main interpreter. */ - int can_cache = psyco_is_main_interp(); - if (can_cache && cachedType) { - Py_INCREF(cachedType); - return cachedType; - } - - /* Get a new reference to the Decimal type. */ - decimal = PyImport_ImportModule("decimal"); - if (decimal) { - decimalType = PyObject_GetAttrString(decimal, "Decimal"); - Py_DECREF(decimal); - } - else { - PyErr_Clear(); - decimalType = NULL; - } - - /* Store the object from future uses. */ - if (can_cache && !cachedType && decimalType) { - Py_INCREF(decimalType); - cachedType = decimalType; - } - - return decimalType; -} - /** method table and module initialization **/ diff --git a/psycopg/utils.c b/psycopg/utils.c index 4908addb..7febf3c5 100644 --- a/psycopg/utils.c +++ b/psycopg/utils.c @@ -27,7 +27,9 @@ #include "psycopg/psycopg.h" #include "psycopg/connection.h" +#include "psycopg/cursor.h" #include "psycopg/pgtypes.h" +#include "psycopg/error.h" #include #include @@ -356,3 +358,114 @@ exit: #endif } + + +/* psyco_set_error + * + * Create a new error of the given type with extra attributes. + */ + +/* TODO: may have been changed to BORROWED */ +RAISES PyObject * +psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg) +{ + PyObject *pymsg; + PyObject *err = NULL; + connectionObject *conn = NULL; + + if (curs) { + conn = ((cursorObject *)curs)->conn; + } + + if ((pymsg = conn_text_from_chars(conn, msg))) { + err = PyObject_CallFunctionObjArgs(exc, pymsg, NULL); + Py_DECREF(pymsg); + } + else { + /* what's better than an error in an error handler in the morning? + * Anyway, some error was set, refcount is ok... get outta here. */ + return NULL; + } + + if (err && PyObject_TypeCheck(err, &errorType)) { + errorObject *perr = (errorObject *)err; + if (curs) { + Py_CLEAR(perr->cursor); + Py_INCREF(curs); + perr->cursor = curs; + } + } + + if (err) { + PyErr_SetObject(exc, err); + Py_DECREF(err); + } + + return err; +} + + +/* Return nonzero if the current one is the main interpreter */ +static int +psyco_is_main_interp(void) +{ + static PyInterpreterState *main_interp = NULL; /* Cached reference */ + PyInterpreterState *interp; + + if (main_interp) { + return (main_interp == PyThreadState_Get()->interp); + } + + /* No cached value: cache the proper value and try again. */ + interp = PyInterpreterState_Head(); + while (interp->next) + interp = interp->next; + + main_interp = interp; + assert (main_interp); + return psyco_is_main_interp(); +} + +/* psyco_GetDecimalType + + Return a new reference to the adapter for decimal type. + + If decimals should be used but the module import fails, fall back on + the float type. + + If decimals are not to be used, return NULL. +*/ + +PyObject * +psyco_GetDecimalType(void) +{ + static PyObject *cachedType = NULL; + PyObject *decimalType = NULL; + PyObject *decimal; + + /* Use the cached object if running from the main interpreter. */ + int can_cache = psyco_is_main_interp(); + if (can_cache && cachedType) { + Py_INCREF(cachedType); + return cachedType; + } + + /* Get a new reference to the Decimal type. */ + decimal = PyImport_ImportModule("decimal"); + if (decimal) { + decimalType = PyObject_GetAttrString(decimal, "Decimal"); + Py_DECREF(decimal); + } + else { + PyErr_Clear(); + decimalType = NULL; + } + + /* Store the object from future uses. */ + if (can_cache && !cachedType && decimalType) { + Py_INCREF(decimalType); + cachedType = decimalType; + } + + return decimalType; +} diff --git a/psycopg/utils.h b/psycopg/utils.h new file mode 100644 index 00000000..fd3893c9 --- /dev/null +++ b/psycopg/utils.h @@ -0,0 +1,61 @@ +/* utils.h - function definitions for utility file + * + * Copyright (C) 2018 Daniele Varrazzo + * + * This file is part of psycopg. + * + * psycopg2 is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link this program with the OpenSSL library (or with + * modified versions of OpenSSL that use the same license as OpenSSL), + * and distribute linked combinations including the two. + * + * You must obey the GNU Lesser General Public License in all respects for + * all of the code used other than OpenSSL. + * + * psycopg2 is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + */ + +#ifndef UTILS_H +#define UTILS_H 1 + +/* forward declarations */ +typedef struct cursorObject cursorObject; +typedef struct connectionObject connectionObject; +typedef struct replicationMessageObject replicationMessageObject; + +HIDDEN char *psycopg_escape_string( + connectionObject *conn, + const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); + +HIDDEN char *psycopg_escape_identifier( + connectionObject *conn, const char *str, Py_ssize_t len); + +HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len); + +STEALS(1) HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj); +STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj); + +HIDDEN int psycopg_is_text_file(PyObject *f); + +HIDDEN PyObject *psycopg_dict_from_conninfo_options( + PQconninfoOption *options, int include_password); + +HIDDEN PyObject *psycopg_make_dsn(PyObject *dsn, PyObject *kwargs); + +HIDDEN PyObject *psycopg_text_from_chars_safe( + const char *str, Py_ssize_t len, PyObject *decoder); + +RAISES HIDDEN PyObject *psyco_set_error( + PyObject *exc, cursorObject *curs, const char *msg); + +HIDDEN PyObject *psyco_GetDecimalType(void); + +#endif /* !defined(UTILS_H) */ diff --git a/setup.py b/setup.py index 15cf267a..2c3be246 100644 --- a/setup.py +++ b/setup.py @@ -509,7 +509,7 @@ depends = [ 'replication_cursor.h', 'replication_message.h', 'notify.h', 'pqpath.h', 'xid.h', 'column.h', 'conninfo.h', - 'libpq_support.h', 'win32_support.h', + 'libpq_support.h', 'win32_support.h', 'utils.h', 'adapter_asis.h', 'adapter_binary.h', 'adapter_datetime.h', 'adapter_list.h', 'adapter_pboolean.h', 'adapter_pdecimal.h',