1031 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1031 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* psycopgmodule.c - psycopg module (will import other C classes)
 | 
						|
 *
 | 
						|
 * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
 | 
						|
 * Copyright (C) 2020-2021 The Psycopg Team
 | 
						|
 *
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
 | 
						|
#define PSYCOPG_MODULE
 | 
						|
#include "psycopg/psycopg.h"
 | 
						|
 | 
						|
#include "psycopg/connection.h"
 | 
						|
#include "psycopg/cursor.h"
 | 
						|
#include "psycopg/replication_connection.h"
 | 
						|
#include "psycopg/replication_cursor.h"
 | 
						|
#include "psycopg/replication_message.h"
 | 
						|
#include "psycopg/green.h"
 | 
						|
#include "psycopg/column.h"
 | 
						|
#include "psycopg/lobject.h"
 | 
						|
#include "psycopg/notify.h"
 | 
						|
#include "psycopg/xid.h"
 | 
						|
#include "psycopg/typecast.h"
 | 
						|
#include "psycopg/microprotocols.h"
 | 
						|
#include "psycopg/microprotocols_proto.h"
 | 
						|
#include "psycopg/conninfo.h"
 | 
						|
#include "psycopg/diagnostics.h"
 | 
						|
 | 
						|
#include "psycopg/adapter_qstring.h"
 | 
						|
#include "psycopg/adapter_binary.h"
 | 
						|
#include "psycopg/adapter_pboolean.h"
 | 
						|
#include "psycopg/adapter_pint.h"
 | 
						|
#include "psycopg/adapter_pfloat.h"
 | 
						|
#include "psycopg/adapter_pdecimal.h"
 | 
						|
#include "psycopg/adapter_asis.h"
 | 
						|
#include "psycopg/adapter_list.h"
 | 
						|
#include "psycopg/typecast_binary.h"
 | 
						|
 | 
						|
/* some module-level variables, like the datetime module */
 | 
						|
#include <datetime.h>
 | 
						|
#include "psycopg/adapter_datetime.h"
 | 
						|
 | 
						|
HIDDEN PyObject *psycoEncodings = NULL;
 | 
						|
HIDDEN PyObject *sqlstate_errors = NULL;
 | 
						|
 | 
						|
#ifdef PSYCOPG_DEBUG
 | 
						|
HIDDEN int psycopg_debug_enabled = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
/* Python representation of SQL NULL */
 | 
						|
HIDDEN PyObject *psyco_null = NULL;
 | 
						|
 | 
						|
/* macro trick to stringify a macro expansion */
 | 
						|
#define xstr(s) str(s)
 | 
						|
#define str(s) #s
 | 
						|
 | 
						|
/** connect module-level function **/
 | 
						|
#define psyco_connect_doc \
 | 
						|
"_connect(dsn, [connection_factory], [async]) -- New database connection.\n\n"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
 | 
						|
{
 | 
						|
    PyObject *conn = NULL;
 | 
						|
    PyObject *factory = NULL;
 | 
						|
    const char *dsn = NULL;
 | 
						|
    int async = 0, async_ = 0;
 | 
						|
 | 
						|
    static char *kwlist[] = {"dsn", "connection_factory", "async", "async_", NULL};
 | 
						|
 | 
						|
    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|Oii", kwlist,
 | 
						|
            &dsn, &factory, &async, &async_)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (async_) { async = async_; }
 | 
						|
 | 
						|
    Dprintf("psyco_connect: dsn = '%s', async = %d", dsn, async);
 | 
						|
 | 
						|
    /* allocate connection, fill with errors and return it */
 | 
						|
    if (factory == NULL || factory == Py_None) {
 | 
						|
        factory = (PyObject *)&connectionType;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Here we are breaking the connection.__init__ interface defined
 | 
						|
     * by psycopg2. So, if not requiring an async conn, avoid passing
 | 
						|
     * the async parameter. */
 | 
						|
    /* TODO: would it be possible to avoid an additional parameter
 | 
						|
     * to the conn constructor? A subclass? (but it would require mixins
 | 
						|
     * to further subclass) Another dsn parameter (but is not really
 | 
						|
     * a connection parameter that can be configured) */
 | 
						|
    if (!async) {
 | 
						|
        conn = PyObject_CallFunction(factory, "s", dsn);
 | 
						|
    } else {
 | 
						|
        conn = PyObject_CallFunction(factory, "si", dsn, async);
 | 
						|
    }
 | 
						|
 | 
						|
    return conn;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#define parse_dsn_doc \
 | 
						|
"parse_dsn(dsn) -> dict -- parse a connection string into parameters"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs)
 | 
						|
{
 | 
						|
    char *err = NULL;
 | 
						|
    PQconninfoOption *options = NULL;
 | 
						|
    PyObject *res = NULL, *dsn;
 | 
						|
 | 
						|
    static char *kwlist[] = {"dsn", NULL};
 | 
						|
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Py_INCREF(dsn); /* for ensure_bytes */
 | 
						|
    if (!(dsn = psyco_ensure_bytes(dsn))) { goto exit; }
 | 
						|
 | 
						|
    options = PQconninfoParse(Bytes_AS_STRING(dsn), &err);
 | 
						|
    if (options == NULL) {
 | 
						|
        if (err != NULL) {
 | 
						|
            PyErr_Format(ProgrammingError, "invalid dsn: %s", err);
 | 
						|
            PQfreemem(err);
 | 
						|
        } else {
 | 
						|
            PyErr_SetString(OperationalError, "PQconninfoParse() failed");
 | 
						|
        }
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    res = psyco_dict_from_conninfo_options(options, /* include_password = */ 1);
 | 
						|
 | 
						|
exit:
 | 
						|
    PQconninfoFree(options);    /* safe on null */
 | 
						|
    Py_XDECREF(dsn);
 | 
						|
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#define quote_ident_doc \
 | 
						|
"quote_ident(str, conn_or_curs) -> str -- wrapper around PQescapeIdentifier\n\n" \
 | 
						|
":Parameters:\n" \
 | 
						|
"  * `str`: A bytes or unicode object\n" \
 | 
						|
"  * `conn_or_curs`: A connection or cursor, required"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
quote_ident(PyObject *self, PyObject *args, PyObject *kwargs)
 | 
						|
{
 | 
						|
    PyObject *ident = NULL, *obj = NULL, *result = NULL;
 | 
						|
    connectionObject *conn;
 | 
						|
    char *quoted = NULL;
 | 
						|
 | 
						|
    static char *kwlist[] = {"ident", "scope", NULL};
 | 
						|
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &ident, &obj)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PyObject_TypeCheck(obj, &cursorType)) {
 | 
						|
        conn = ((cursorObject*)obj)->conn;
 | 
						|
    }
 | 
						|
    else if (PyObject_TypeCheck(obj, &connectionType)) {
 | 
						|
        conn = (connectionObject*)obj;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        PyErr_SetString(PyExc_TypeError,
 | 
						|
                        "argument 2 must be a connection or a cursor");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Py_INCREF(ident); /* for ensure_bytes */
 | 
						|
    if (!(ident = psyco_ensure_bytes(ident))) { goto exit; }
 | 
						|
 | 
						|
    if (!(quoted = psyco_escape_identifier(conn,
 | 
						|
        Bytes_AS_STRING(ident), Bytes_GET_SIZE(ident)))) { goto exit; }
 | 
						|
 | 
						|
    result = conn_text_from_chars(conn, quoted);
 | 
						|
 | 
						|
exit:
 | 
						|
    PQfreemem(quoted);
 | 
						|
    Py_XDECREF(ident);
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
/** type registration **/
 | 
						|
#define register_type_doc \
 | 
						|
"register_type(obj, conn_or_curs) -> None -- register obj with psycopg type system\n\n" \
 | 
						|
":Parameters:\n" \
 | 
						|
"  * `obj`: A type adapter created by `new_type()`\n" \
 | 
						|
"  * `conn_or_curs`: A connection, cursor or None"
 | 
						|
 | 
						|
#define typecast_from_python_doc \
 | 
						|
"new_type(oids, name, castobj) -> new type object\n\n" \
 | 
						|
"Create a new binding object. The object can be used with the\n" \
 | 
						|
"`register_type()` function to bind PostgreSQL objects to python objects.\n\n" \
 | 
						|
":Parameters:\n" \
 | 
						|
"  * `oids`: Tuple of ``oid`` of the PostgreSQL types to convert.\n" \
 | 
						|
"  * `name`: Name for the new type\n" \
 | 
						|
"  * `adapter`: Callable to perform type conversion.\n" \
 | 
						|
"    It must have the signature ``fun(value, cur)`` where ``value`` is\n" \
 | 
						|
"    the string representation returned by PostgreSQL (`!None` if ``NULL``)\n" \
 | 
						|
"    and ``cur`` is the cursor from which data are read."
 | 
						|
 | 
						|
#define typecast_array_from_python_doc \
 | 
						|
"new_array_type(oids, name, baseobj) -> new type object\n\n" \
 | 
						|
"Create a new binding object to parse an array.\n\n" \
 | 
						|
"The object can be used with `register_type()`.\n\n" \
 | 
						|
":Parameters:\n" \
 | 
						|
"  * `oids`: Tuple of ``oid`` of the PostgreSQL types to convert.\n" \
 | 
						|
"  * `name`: Name for the new type\n" \
 | 
						|
"  * `baseobj`: Adapter to perform type conversion of a single array item."
 | 
						|
 | 
						|
static PyObject *
 | 
						|
register_type(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *type, *obj = NULL;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "O!|O", &typecastType, &type, &obj)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (obj != NULL && obj != Py_None) {
 | 
						|
        if (PyObject_TypeCheck(obj, &cursorType)) {
 | 
						|
            PyObject **dict = &(((cursorObject*)obj)->string_types);
 | 
						|
            if (*dict == NULL) {
 | 
						|
                if (!(*dict = PyDict_New())) { return NULL; }
 | 
						|
            }
 | 
						|
            if (0 > typecast_add(type, *dict, 0)) { return NULL; }
 | 
						|
        }
 | 
						|
        else if (PyObject_TypeCheck(obj, &connectionType)) {
 | 
						|
            if (0 > typecast_add(type, ((connectionObject*)obj)->string_types, 0)) {
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            PyErr_SetString(PyExc_TypeError,
 | 
						|
                "argument 2 must be a connection, cursor or None");
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        if (0 > typecast_add(type, NULL, 0)) { return NULL; }
 | 
						|
    }
 | 
						|
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Make sure libcrypto thread callbacks are set up. */
 | 
						|
static void
 | 
						|
libcrypto_threads_init(void)
 | 
						|
{
 | 
						|
    PyObject *m;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: configuring libpq libcrypto callbacks ");
 | 
						|
 | 
						|
    /* importing the ssl module sets up Python's libcrypto callbacks */
 | 
						|
    if ((m = PyImport_ImportModule("ssl"))) {
 | 
						|
        /* disable libcrypto setup in libpq, so it won't stomp on the callbacks
 | 
						|
           that have already been set up */
 | 
						|
        PQinitOpenSSL(1, 0);
 | 
						|
        Py_DECREF(m);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        /* might mean that Python has been compiled without OpenSSL support,
 | 
						|
           fall back to relying on libpq's libcrypto locking */
 | 
						|
        PyErr_Clear();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Initialize the default adapters map
 | 
						|
 *
 | 
						|
 * Return 0 on success, else -1 and set an exception.
 | 
						|
 */
 | 
						|
RAISES_NEG static int
 | 
						|
adapters_init(PyObject *module)
 | 
						|
{
 | 
						|
    PyObject *dict = NULL, *obj = NULL;
 | 
						|
    int rv = -1;
 | 
						|
 | 
						|
    if (0 > microprotocols_init(module)) { goto exit; }
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing adapters");
 | 
						|
 | 
						|
    if (0 > microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
    if (0 > microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
    if (0 > microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    /* strings */
 | 
						|
    if (0 > microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    /* binary */
 | 
						|
    if (0 > microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType)) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    /* the module has already been initialized, so we can obtain the callable
 | 
						|
       objects directly from its dictionary :) */
 | 
						|
    if (!(dict = PyModule_GetDict(module))) { goto exit; }
 | 
						|
 | 
						|
    if (!(obj = PyMapping_GetItemString(dict, "DateFromPy"))) { goto exit; }
 | 
						|
    if (0 > microprotocols_add(PyDateTimeAPI->DateType, NULL, obj)) { goto exit; }
 | 
						|
    Py_CLEAR(obj);
 | 
						|
 | 
						|
    if (!(obj = PyMapping_GetItemString(dict, "TimeFromPy"))) { goto exit; }
 | 
						|
    if (0 > microprotocols_add(PyDateTimeAPI->TimeType, NULL, obj)) { goto exit; }
 | 
						|
    Py_CLEAR(obj);
 | 
						|
 | 
						|
    if (!(obj = PyMapping_GetItemString(dict, "TimestampFromPy"))) { goto exit; }
 | 
						|
    if (0 > microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, obj)) { goto exit; }
 | 
						|
    Py_CLEAR(obj);
 | 
						|
 | 
						|
    if (!(obj = PyMapping_GetItemString(dict, "IntervalFromPy"))) { goto exit; }
 | 
						|
    if (0 > microprotocols_add(PyDateTimeAPI->DeltaType, NULL, obj)) { goto exit; }
 | 
						|
    Py_CLEAR(obj);
 | 
						|
 | 
						|
    /* Success! */
 | 
						|
    rv = 0;
 | 
						|
 | 
						|
exit:
 | 
						|
    Py_XDECREF(obj);
 | 
						|
 | 
						|
    return rv;
 | 
						|
}
 | 
						|
 | 
						|
#define libpq_version_doc "Query actual libpq version loaded."
 | 
						|
 | 
						|
static PyObject*
 | 
						|
libpq_version(PyObject *self, PyObject *dummy)
 | 
						|
{
 | 
						|
    return PyInt_FromLong(PQlibVersion());
 | 
						|
}
 | 
						|
 | 
						|
/* encrypt_password - Prepare the encrypted password form */
 | 
						|
#define encrypt_password_doc \
 | 
						|
"encrypt_password(password, user, [scope], [algorithm]) -- Prepares the encrypted form of a PostgreSQL password.\n\n"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
encrypt_password(PyObject *self, PyObject *args, PyObject *kwargs)
 | 
						|
{
 | 
						|
    char *encrypted = NULL;
 | 
						|
    PyObject *password = NULL, *user = NULL;
 | 
						|
    PyObject *scope = Py_None, *algorithm = Py_None;
 | 
						|
    PyObject *res = NULL;
 | 
						|
    connectionObject *conn = NULL;
 | 
						|
 | 
						|
    static char *kwlist[] = {"password", "user", "scope", "algorithm", NULL};
 | 
						|
 | 
						|
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|OO", kwlist,
 | 
						|
            &password, &user, &scope, &algorithm)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* for ensure_bytes */
 | 
						|
    Py_INCREF(user);
 | 
						|
    Py_INCREF(password);
 | 
						|
    Py_INCREF(algorithm);
 | 
						|
 | 
						|
    if (scope != Py_None) {
 | 
						|
        if (PyObject_TypeCheck(scope, &cursorType)) {
 | 
						|
            conn = ((cursorObject*)scope)->conn;
 | 
						|
        }
 | 
						|
        else if (PyObject_TypeCheck(scope, &connectionType)) {
 | 
						|
            conn = (connectionObject*)scope;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            PyErr_SetString(PyExc_TypeError,
 | 
						|
                "the scope must be a connection or a cursor");
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(user = psyco_ensure_bytes(user))) { goto exit; }
 | 
						|
    if (!(password = psyco_ensure_bytes(password))) { goto exit; }
 | 
						|
    if (algorithm != Py_None) {
 | 
						|
        if (!(algorithm = psyco_ensure_bytes(algorithm))) {
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* If we have to encrypt md5 we can use the libpq < 10 API */
 | 
						|
    if (algorithm != Py_None &&
 | 
						|
            strcmp(Bytes_AS_STRING(algorithm), "md5") == 0) {
 | 
						|
        encrypted = PQencryptPassword(
 | 
						|
            Bytes_AS_STRING(password), Bytes_AS_STRING(user));
 | 
						|
    }
 | 
						|
 | 
						|
    /* If the algorithm is not md5 we have to use the API available from
 | 
						|
     * libpq 10. */
 | 
						|
    else {
 | 
						|
#if PG_VERSION_NUM >= 100000
 | 
						|
        if (!conn) {
 | 
						|
            PyErr_SetString(ProgrammingError,
 | 
						|
                "password encryption (other than 'md5' algorithm)"
 | 
						|
                " requires a connection or cursor");
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
 | 
						|
        /* TODO: algo = None will block: forbid on async/green conn? */
 | 
						|
        encrypted = PQencryptPasswordConn(conn->pgconn,
 | 
						|
            Bytes_AS_STRING(password), Bytes_AS_STRING(user),
 | 
						|
            algorithm != Py_None ? Bytes_AS_STRING(algorithm) : NULL);
 | 
						|
#else
 | 
						|
        PyErr_SetString(NotSupportedError,
 | 
						|
            "password encryption (other than 'md5' algorithm)"
 | 
						|
            " requires libpq 10");
 | 
						|
        goto exit;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
 | 
						|
    if (encrypted) {
 | 
						|
        res = Text_FromUTF8(encrypted);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        const char *msg = PQerrorMessage(conn->pgconn);
 | 
						|
        PyErr_Format(ProgrammingError,
 | 
						|
            "password encryption failed: %s", msg ? msg : "no reason given");
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
exit:
 | 
						|
    if (encrypted) {
 | 
						|
        PQfreemem(encrypted);
 | 
						|
    }
 | 
						|
    Py_XDECREF(user);
 | 
						|
    Py_XDECREF(password);
 | 
						|
    Py_XDECREF(algorithm);
 | 
						|
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Fill the module's postgresql<->python encoding table */
 | 
						|
static struct {
 | 
						|
    char *pgenc;
 | 
						|
    char *pyenc;
 | 
						|
} enctable[] = {
 | 
						|
    {"ABC",          "cp1258"},
 | 
						|
    {"ALT",          "cp866"},
 | 
						|
    {"BIG5",         "big5"},
 | 
						|
    {"EUC_CN",       "euccn"},
 | 
						|
    {"EUC_JIS_2004", "euc_jis_2004"},
 | 
						|
    {"EUC_JP",       "euc_jp"},
 | 
						|
    {"EUC_KR",       "euc_kr"},
 | 
						|
    {"GB18030",      "gb18030"},
 | 
						|
    {"GBK",          "gbk"},
 | 
						|
    {"ISO_8859_1",   "iso8859_1"},
 | 
						|
    {"ISO_8859_2",   "iso8859_2"},
 | 
						|
    {"ISO_8859_3",   "iso8859_3"},
 | 
						|
    {"ISO_8859_5",   "iso8859_5"},
 | 
						|
    {"ISO_8859_6",   "iso8859_6"},
 | 
						|
    {"ISO_8859_7",   "iso8859_7"},
 | 
						|
    {"ISO_8859_8",   "iso8859_8"},
 | 
						|
    {"ISO_8859_9",   "iso8859_9"},
 | 
						|
    {"ISO_8859_10",  "iso8859_10"},
 | 
						|
    {"ISO_8859_13",  "iso8859_13"},
 | 
						|
    {"ISO_8859_14",  "iso8859_14"},
 | 
						|
    {"ISO_8859_15",  "iso8859_15"},
 | 
						|
    {"ISO_8859_16",  "iso8859_16"},
 | 
						|
    {"JOHAB",        "johab"},
 | 
						|
    {"KOI8",         "koi8_r"},
 | 
						|
    {"KOI8R",        "koi8_r"},
 | 
						|
    {"KOI8U",        "koi8_u"},
 | 
						|
    {"LATIN1",       "iso8859_1"},
 | 
						|
    {"LATIN2",       "iso8859_2"},
 | 
						|
    {"LATIN3",       "iso8859_3"},
 | 
						|
    {"LATIN4",       "iso8859_4"},
 | 
						|
    {"LATIN5",       "iso8859_9"},
 | 
						|
    {"LATIN6",       "iso8859_10"},
 | 
						|
    {"LATIN7",       "iso8859_13"},
 | 
						|
    {"LATIN8",       "iso8859_14"},
 | 
						|
    {"LATIN9",       "iso8859_15"},
 | 
						|
    {"LATIN10",      "iso8859_16"},
 | 
						|
    {"Mskanji",      "cp932"},
 | 
						|
    {"ShiftJIS",     "cp932"},
 | 
						|
    {"SHIFT_JIS_2004", "shift_jis_2004"},
 | 
						|
    {"SJIS",         "cp932"},
 | 
						|
    {"SQL_ASCII",    "ascii"},  /* XXX this is wrong: SQL_ASCII means "no
 | 
						|
                                 *  encoding" we should fix the unicode
 | 
						|
                                 *  typecaster to return a str or bytes in Py3
 | 
						|
                                 */
 | 
						|
    {"TCVN",         "cp1258"},
 | 
						|
    {"TCVN5712",     "cp1258"},
 | 
						|
    {"UHC",          "cp949"},
 | 
						|
    {"UNICODE",      "utf_8"}, /* Not valid in 8.2, backward compatibility */
 | 
						|
    {"UTF8",         "utf_8"},
 | 
						|
    {"VSCII",        "cp1258"},
 | 
						|
    {"WIN",          "cp1251"},
 | 
						|
    {"WIN866",       "cp866"},
 | 
						|
    {"WIN874",       "cp874"},
 | 
						|
    {"WIN932",       "cp932"},
 | 
						|
    {"WIN936",       "gbk"},
 | 
						|
    {"WIN949",       "cp949"},
 | 
						|
    {"WIN950",       "cp950"},
 | 
						|
    {"WIN1250",      "cp1250"},
 | 
						|
    {"WIN1251",      "cp1251"},
 | 
						|
    {"WIN1252",      "cp1252"},
 | 
						|
    {"WIN1253",      "cp1253"},
 | 
						|
    {"WIN1254",      "cp1254"},
 | 
						|
    {"WIN1255",      "cp1255"},
 | 
						|
    {"WIN1256",      "cp1256"},
 | 
						|
    {"WIN1257",      "cp1257"},
 | 
						|
    {"WIN1258",      "cp1258"},
 | 
						|
    {"Windows932",   "cp932"},
 | 
						|
    {"Windows936",   "gbk"},
 | 
						|
    {"Windows949",   "cp949"},
 | 
						|
    {"Windows950",   "cp950"},
 | 
						|
 | 
						|
/* those are missing from Python:                */
 | 
						|
/*    {"EUC_TW", "?"},                           */
 | 
						|
/*    {"MULE_INTERNAL", "?"},                    */
 | 
						|
    {NULL, NULL}
 | 
						|
};
 | 
						|
 | 
						|
/* Initialize the encodings table.
 | 
						|
 *
 | 
						|
 * Return 0 on success, else -1 and set an exception.
 | 
						|
 */
 | 
						|
RAISES_NEG static int
 | 
						|
encodings_init(PyObject *module)
 | 
						|
{
 | 
						|
    PyObject *value = NULL;
 | 
						|
    int i;
 | 
						|
    int rv = -1;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing encodings table");
 | 
						|
    if (psycoEncodings) {
 | 
						|
        Dprintf("encodings_init(): already called");
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(psycoEncodings = PyDict_New())) { goto exit; }
 | 
						|
    Py_INCREF(psycoEncodings);
 | 
						|
    if (0 > PyModule_AddObject(module, "encodings", psycoEncodings)) {
 | 
						|
        Py_DECREF(psycoEncodings);
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; enctable[i].pgenc != NULL; i++) {
 | 
						|
        if (!(value = Text_FromUTF8(enctable[i].pyenc))) { goto exit; }
 | 
						|
        if (0 > PyDict_SetItemString(
 | 
						|
                psycoEncodings, enctable[i].pgenc, value)) {
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
        Py_CLEAR(value);
 | 
						|
    }
 | 
						|
    rv = 0;
 | 
						|
 | 
						|
exit:
 | 
						|
    Py_XDECREF(value);
 | 
						|
 | 
						|
    return rv;
 | 
						|
}
 | 
						|
 | 
						|
/* Initialize the module's exceptions and after that a dictionary with a full
 | 
						|
   set of exceptions. */
 | 
						|
 | 
						|
PyObject *Error, *Warning, *InterfaceError, *DatabaseError,
 | 
						|
    *InternalError, *OperationalError, *ProgrammingError,
 | 
						|
    *IntegrityError, *DataError, *NotSupportedError;
 | 
						|
PyObject *QueryCanceledError, *TransactionRollbackError;
 | 
						|
 | 
						|
/* mapping between exception names and their PyObject */
 | 
						|
static struct {
 | 
						|
    char *name;
 | 
						|
    PyObject **exc;
 | 
						|
    PyObject **base;
 | 
						|
    const char *docstr;
 | 
						|
} exctable[] = {
 | 
						|
    { "psycopg2.Error", &Error, NULL, Error_doc },
 | 
						|
    { "psycopg2.Warning", &Warning, NULL, Warning_doc },
 | 
						|
    { "psycopg2.InterfaceError", &InterfaceError, &Error, InterfaceError_doc },
 | 
						|
    { "psycopg2.DatabaseError", &DatabaseError, &Error, DatabaseError_doc },
 | 
						|
    { "psycopg2.InternalError", &InternalError, &DatabaseError, InternalError_doc },
 | 
						|
    { "psycopg2.OperationalError", &OperationalError, &DatabaseError,
 | 
						|
        OperationalError_doc },
 | 
						|
    { "psycopg2.ProgrammingError", &ProgrammingError, &DatabaseError,
 | 
						|
        ProgrammingError_doc },
 | 
						|
    { "psycopg2.IntegrityError", &IntegrityError, &DatabaseError,
 | 
						|
        IntegrityError_doc },
 | 
						|
    { "psycopg2.DataError", &DataError, &DatabaseError, DataError_doc },
 | 
						|
    { "psycopg2.NotSupportedError", &NotSupportedError, &DatabaseError,
 | 
						|
        NotSupportedError_doc },
 | 
						|
    { "psycopg2.extensions.QueryCanceledError", &QueryCanceledError,
 | 
						|
      &OperationalError, QueryCanceledError_doc },
 | 
						|
    { "psycopg2.extensions.TransactionRollbackError",
 | 
						|
      &TransactionRollbackError, &OperationalError,
 | 
						|
      TransactionRollbackError_doc },
 | 
						|
    {NULL}  /* Sentinel */
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
RAISES_NEG static int
 | 
						|
basic_errors_init(PyObject *module)
 | 
						|
{
 | 
						|
    /* the names of the exceptions here reflect the organization of the
 | 
						|
       psycopg2 module and not the fact the original error objects live in
 | 
						|
       _psycopg */
 | 
						|
 | 
						|
    int i;
 | 
						|
    PyObject *dict = NULL;
 | 
						|
    PyObject *str = NULL;
 | 
						|
    PyObject *errmodule = NULL;
 | 
						|
    int rv = -1;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing basic exceptions");
 | 
						|
 | 
						|
    /* 'Error' has been defined elsewhere: only init the other classes */
 | 
						|
    Error = (PyObject *)&errorType;
 | 
						|
 | 
						|
    for (i = 1; exctable[i].name; i++) {
 | 
						|
        if (!(dict = PyDict_New())) { goto exit; }
 | 
						|
 | 
						|
        if (exctable[i].docstr) {
 | 
						|
            if (!(str = Text_FromUTF8(exctable[i].docstr))) { goto exit; }
 | 
						|
            if (0 > PyDict_SetItemString(dict, "__doc__", str)) { goto exit; }
 | 
						|
            Py_CLEAR(str);
 | 
						|
        }
 | 
						|
 | 
						|
        /* can't put PyExc_StandardError in the static exctable:
 | 
						|
         * windows build will fail */
 | 
						|
        if (!(*exctable[i].exc = PyErr_NewException(
 | 
						|
                exctable[i].name,
 | 
						|
                exctable[i].base ? *exctable[i].base : PyExc_StandardError,
 | 
						|
                dict))) {
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
        Py_CLEAR(dict);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(errmodule = PyImport_ImportModule("psycopg2.errors"))) {
 | 
						|
        /* don't inject the exceptions into the errors module */
 | 
						|
        PyErr_Clear();
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; exctable[i].name; i++) {
 | 
						|
        char *name;
 | 
						|
        if (NULL == exctable[i].exc) { continue; }
 | 
						|
 | 
						|
        /* the name is the part after the last dot */
 | 
						|
        name = strrchr(exctable[i].name, '.');
 | 
						|
        name = name ? name + 1 : exctable[i].name;
 | 
						|
 | 
						|
        Py_INCREF(*exctable[i].exc);
 | 
						|
        if (0 > PyModule_AddObject(module, name, *exctable[i].exc)) {
 | 
						|
            Py_DECREF(*exctable[i].exc);
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
        if (errmodule) {
 | 
						|
            Py_INCREF(*exctable[i].exc);
 | 
						|
            if (0 > PyModule_AddObject(errmodule, name, *exctable[i].exc)) {
 | 
						|
                Py_DECREF(*exctable[i].exc);
 | 
						|
                goto exit;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    rv = 0;
 | 
						|
 | 
						|
exit:
 | 
						|
    Py_XDECREF(errmodule);
 | 
						|
    Py_XDECREF(str);
 | 
						|
    Py_XDECREF(dict);
 | 
						|
    return rv;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* mapping between sqlstate and exception name */
 | 
						|
static struct {
 | 
						|
    char *sqlstate;
 | 
						|
    char *name;
 | 
						|
} sqlstate_table[] = {
 | 
						|
#include "sqlstate_errors.h"
 | 
						|
    {NULL}  /* Sentinel */
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
RAISES_NEG static int
 | 
						|
sqlstate_errors_init(PyObject *module)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    char namebuf[120];
 | 
						|
    char prefix[] = "psycopg2.errors.";
 | 
						|
    char *suffix;
 | 
						|
    size_t bufsize;
 | 
						|
    PyObject *exc = NULL;
 | 
						|
    PyObject *errmodule = NULL;
 | 
						|
    int rv = -1;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing sqlstate exceptions");
 | 
						|
 | 
						|
    if (sqlstate_errors) {
 | 
						|
		Dprintf("sqlstate_errors_init(): already called");
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    if (!(errmodule = PyImport_ImportModule("psycopg2.errors"))) {
 | 
						|
        /* don't inject the exceptions into the errors module */
 | 
						|
        PyErr_Clear();
 | 
						|
    }
 | 
						|
    if (!(sqlstate_errors = PyDict_New())) {
 | 
						|
        goto exit;
 | 
						|
    }
 | 
						|
    Py_INCREF(sqlstate_errors);
 | 
						|
    if (0 > PyModule_AddObject(module, "sqlstate_errors", sqlstate_errors)) {
 | 
						|
        Py_DECREF(sqlstate_errors);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    strcpy(namebuf, prefix);
 | 
						|
    suffix = namebuf + sizeof(prefix) - 1;
 | 
						|
    bufsize = sizeof(namebuf) - sizeof(prefix) - 1;
 | 
						|
    /* If this 0 gets deleted the buffer was too small. */
 | 
						|
    namebuf[sizeof(namebuf) - 1] = '\0';
 | 
						|
 | 
						|
    for (i = 0; sqlstate_table[i].sqlstate; i++) {
 | 
						|
        PyObject *base;
 | 
						|
 | 
						|
        base = base_exception_from_sqlstate(sqlstate_table[i].sqlstate);
 | 
						|
        strncpy(suffix, sqlstate_table[i].name, bufsize);
 | 
						|
        if (namebuf[sizeof(namebuf) - 1] != '\0') {
 | 
						|
            PyErr_SetString(
 | 
						|
                PyExc_SystemError, "sqlstate_errors_init(): buffer too small");
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
        if (!(exc = PyErr_NewException(namebuf, base, NULL))) {
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
        if (0 > PyDict_SetItemString(
 | 
						|
                sqlstate_errors, sqlstate_table[i].sqlstate, exc)) {
 | 
						|
            goto exit;
 | 
						|
        }
 | 
						|
 | 
						|
        /* Expose the exceptions to psycopg2.errors */
 | 
						|
        if (errmodule) {
 | 
						|
            if (0 > PyModule_AddObject(
 | 
						|
                    errmodule, sqlstate_table[i].name, exc)) {
 | 
						|
                goto exit;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                exc = NULL;     /* ref stolen by the module */
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            Py_CLEAR(exc);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    rv = 0;
 | 
						|
 | 
						|
exit:
 | 
						|
    Py_XDECREF(errmodule);
 | 
						|
    Py_XDECREF(exc);
 | 
						|
    return rv;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
RAISES_NEG static int
 | 
						|
add_module_constants(PyObject *module)
 | 
						|
{
 | 
						|
    PyObject *tmp;
 | 
						|
    Dprintf("psycopgmodule: initializing module constants");
 | 
						|
 | 
						|
    if (0 > PyModule_AddStringConstant(module,
 | 
						|
        "__version__", xstr(PSYCOPG_VERSION)))
 | 
						|
    { return -1; }
 | 
						|
 | 
						|
    if (0 > PyModule_AddStringConstant(module,
 | 
						|
        "__doc__", "psycopg2 PostgreSQL driver"))
 | 
						|
    { return -1; }
 | 
						|
 | 
						|
    if (0 > PyModule_AddIntConstant(module,
 | 
						|
        "__libpq_version__", PG_VERSION_NUM))
 | 
						|
    { return -1; }
 | 
						|
 | 
						|
    if (0 > PyModule_AddObject(module,
 | 
						|
        "apilevel", tmp = Text_FromUTF8(APILEVEL)))
 | 
						|
    {
 | 
						|
        Py_XDECREF(tmp);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > PyModule_AddObject(module,
 | 
						|
        "threadsafety", tmp = PyInt_FromLong(THREADSAFETY)))
 | 
						|
    {
 | 
						|
        Py_XDECREF(tmp);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > PyModule_AddObject(module,
 | 
						|
        "paramstyle", tmp = Text_FromUTF8(PARAMSTYLE)))
 | 
						|
    {
 | 
						|
        Py_XDECREF(tmp);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (0 > PyModule_AddIntMacro(module, REPLICATION_PHYSICAL)) { return -1; }
 | 
						|
    if (0 > PyModule_AddIntMacro(module, REPLICATION_LOGICAL)) { return -1; }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static struct {
 | 
						|
    char *name;
 | 
						|
    PyTypeObject *type;
 | 
						|
} typetable[] = {
 | 
						|
    { "connection", &connectionType },
 | 
						|
    { "cursor", &cursorType },
 | 
						|
    { "ReplicationConnection", &replicationConnectionType },
 | 
						|
    { "ReplicationCursor", &replicationCursorType },
 | 
						|
    { "ReplicationMessage", &replicationMessageType },
 | 
						|
    { "ISQLQuote", &isqlquoteType },
 | 
						|
    { "Column", &columnType },
 | 
						|
    { "Notify", ¬ifyType },
 | 
						|
    { "Xid", &xidType },
 | 
						|
    { "ConnectionInfo", &connInfoType },
 | 
						|
    { "Diagnostics", &diagnosticsType },
 | 
						|
    { "AsIs", &asisType },
 | 
						|
    { "Binary", &binaryType },
 | 
						|
    { "Boolean", &pbooleanType },
 | 
						|
    { "Decimal", &pdecimalType },
 | 
						|
    { "Int", &pintType },
 | 
						|
    { "Float", &pfloatType },
 | 
						|
    { "List", &listType },
 | 
						|
    { "QuotedString", &qstringType },
 | 
						|
    { "lobject", &lobjectType },
 | 
						|
    {NULL}  /* Sentinel */
 | 
						|
};
 | 
						|
 | 
						|
RAISES_NEG static int
 | 
						|
add_module_types(PyObject *module)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing module types");
 | 
						|
 | 
						|
    for (i = 0; typetable[i].name; i++) {
 | 
						|
        PyObject *type = (PyObject *)typetable[i].type;
 | 
						|
 | 
						|
        Py_SET_TYPE(typetable[i].type, &PyType_Type);
 | 
						|
        if (0 > PyType_Ready(typetable[i].type)) { return -1; }
 | 
						|
 | 
						|
        Py_INCREF(type);
 | 
						|
        if (0 > PyModule_AddObject(module, typetable[i].name, type)) {
 | 
						|
            Py_DECREF(type);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
RAISES_NEG static int
 | 
						|
datetime_init(void)
 | 
						|
{
 | 
						|
    PyObject *dt = NULL;
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing datetime module");
 | 
						|
 | 
						|
    /* import python builtin datetime module, if available */
 | 
						|
    if (!(dt = PyImport_ImportModule("datetime"))) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    Py_DECREF(dt);
 | 
						|
 | 
						|
    /* Initialize the PyDateTimeAPI everywhere is used */
 | 
						|
    PyDateTime_IMPORT;
 | 
						|
    if (0 > adapter_datetime_init()) { return -1; }
 | 
						|
    if (0 > repl_curs_datetime_init()) { return -1; }
 | 
						|
    if (0 > replmsg_datetime_init()) { return -1; }
 | 
						|
 | 
						|
    Py_SET_TYPE(&pydatetimeType, &PyType_Type);
 | 
						|
    if (0 > PyType_Ready(&pydatetimeType)) { return -1; }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/** method table and module initialization **/
 | 
						|
 | 
						|
static PyMethodDef psycopgMethods[] = {
 | 
						|
    {"_connect",  (PyCFunction)psyco_connect,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, psyco_connect_doc},
 | 
						|
    {"parse_dsn",  (PyCFunction)parse_dsn,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, parse_dsn_doc},
 | 
						|
    {"quote_ident", (PyCFunction)quote_ident,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, quote_ident_doc},
 | 
						|
    {"adapt",  (PyCFunction)psyco_microprotocols_adapt,
 | 
						|
     METH_VARARGS, psyco_microprotocols_adapt_doc},
 | 
						|
 | 
						|
    {"register_type", (PyCFunction)register_type,
 | 
						|
     METH_VARARGS, register_type_doc},
 | 
						|
    {"new_type", (PyCFunction)typecast_from_python,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, typecast_from_python_doc},
 | 
						|
    {"new_array_type", (PyCFunction)typecast_array_from_python,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, typecast_array_from_python_doc},
 | 
						|
    {"libpq_version", (PyCFunction)libpq_version,
 | 
						|
     METH_NOARGS, libpq_version_doc},
 | 
						|
 | 
						|
    {"Date",  (PyCFunction)psyco_Date,
 | 
						|
     METH_VARARGS, psyco_Date_doc},
 | 
						|
    {"Time",  (PyCFunction)psyco_Time,
 | 
						|
     METH_VARARGS, psyco_Time_doc},
 | 
						|
    {"Timestamp",  (PyCFunction)psyco_Timestamp,
 | 
						|
     METH_VARARGS, psyco_Timestamp_doc},
 | 
						|
    {"DateFromTicks",  (PyCFunction)psyco_DateFromTicks,
 | 
						|
     METH_VARARGS, psyco_DateFromTicks_doc},
 | 
						|
    {"TimeFromTicks",  (PyCFunction)psyco_TimeFromTicks,
 | 
						|
     METH_VARARGS, psyco_TimeFromTicks_doc},
 | 
						|
    {"TimestampFromTicks",  (PyCFunction)psyco_TimestampFromTicks,
 | 
						|
     METH_VARARGS, psyco_TimestampFromTicks_doc},
 | 
						|
 | 
						|
    {"DateFromPy",  (PyCFunction)psyco_DateFromPy,
 | 
						|
     METH_VARARGS, psyco_DateFromPy_doc},
 | 
						|
    {"TimeFromPy",  (PyCFunction)psyco_TimeFromPy,
 | 
						|
     METH_VARARGS, psyco_TimeFromPy_doc},
 | 
						|
    {"TimestampFromPy",  (PyCFunction)psyco_TimestampFromPy,
 | 
						|
     METH_VARARGS, psyco_TimestampFromPy_doc},
 | 
						|
    {"IntervalFromPy",  (PyCFunction)psyco_IntervalFromPy,
 | 
						|
     METH_VARARGS, psyco_IntervalFromPy_doc},
 | 
						|
 | 
						|
    {"set_wait_callback",  (PyCFunction)psyco_set_wait_callback,
 | 
						|
     METH_O, psyco_set_wait_callback_doc},
 | 
						|
    {"get_wait_callback",  (PyCFunction)psyco_get_wait_callback,
 | 
						|
     METH_NOARGS, psyco_get_wait_callback_doc},
 | 
						|
    {"encrypt_password", (PyCFunction)encrypt_password,
 | 
						|
     METH_VARARGS|METH_KEYWORDS, encrypt_password_doc},
 | 
						|
 | 
						|
    {NULL, NULL, 0, NULL}        /* Sentinel */
 | 
						|
};
 | 
						|
 | 
						|
static struct PyModuleDef psycopgmodule = {
 | 
						|
        PyModuleDef_HEAD_INIT,
 | 
						|
        "_psycopg",
 | 
						|
        NULL,
 | 
						|
        -1,
 | 
						|
        psycopgMethods,
 | 
						|
        NULL,
 | 
						|
        NULL,
 | 
						|
        NULL,
 | 
						|
        NULL
 | 
						|
};
 | 
						|
 | 
						|
#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
 | 
						|
#define PyMODINIT_FUNC void
 | 
						|
#endif
 | 
						|
PyMODINIT_FUNC
 | 
						|
INIT_MODULE(_psycopg)(void)
 | 
						|
{
 | 
						|
    PyObject *module = NULL;
 | 
						|
 | 
						|
#ifdef PSYCOPG_DEBUG
 | 
						|
    if (getenv("PSYCOPG_DEBUG"))
 | 
						|
        psycopg_debug_enabled = 1;
 | 
						|
#endif
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: initializing psycopg %s", xstr(PSYCOPG_VERSION));
 | 
						|
 | 
						|
    /* initialize libcrypto threading callbacks */
 | 
						|
    libcrypto_threads_init();
 | 
						|
 | 
						|
    /* initialize types and objects not exposed to the module */
 | 
						|
    Py_SET_TYPE(&typecastType, &PyType_Type);
 | 
						|
    if (0 > PyType_Ready(&typecastType)) { goto exit; }
 | 
						|
 | 
						|
    Py_SET_TYPE(&chunkType, &PyType_Type);
 | 
						|
    if (0 > PyType_Ready(&chunkType)) { goto exit; }
 | 
						|
 | 
						|
    Py_SET_TYPE(&errorType, &PyType_Type);
 | 
						|
    errorType.tp_base = (PyTypeObject *)PyExc_StandardError;
 | 
						|
    if (0 > PyType_Ready(&errorType)) { goto exit; }
 | 
						|
 | 
						|
    if (!(psyco_null = Bytes_FromString("NULL"))) { goto exit; }
 | 
						|
 | 
						|
    /* initialize the module */
 | 
						|
    module = PyModule_Create(&psycopgmodule);
 | 
						|
    if (!module) { goto exit; }
 | 
						|
 | 
						|
    if (0 > add_module_constants(module)) { goto exit; }
 | 
						|
    if (0 > add_module_types(module)) { goto exit; }
 | 
						|
    if (0 > datetime_init()) { goto exit; }
 | 
						|
    if (0 > encodings_init(module)) { goto exit; }
 | 
						|
    if (0 > typecast_init(module)) { goto exit; }
 | 
						|
    if (0 > adapters_init(module)) { goto exit; }
 | 
						|
    if (0 > basic_errors_init(module)) { goto exit; }
 | 
						|
    if (0 > sqlstate_errors_init(module)) { goto exit; }
 | 
						|
 | 
						|
    Dprintf("psycopgmodule: module initialization complete");
 | 
						|
 | 
						|
exit:
 | 
						|
    return module;
 | 
						|
}
 |