2004-10-19 07:17:12 +04:00
|
|
|
/* connection_type.c - python interface to connection objects
|
|
|
|
*
|
2010-02-13 01:34:53 +03:00
|
|
|
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org>
|
2004-10-19 07:17:12 +04:00
|
|
|
*
|
|
|
|
* This file is part of psycopg.
|
|
|
|
*
|
2010-02-13 01:34:53 +03:00
|
|
|
* 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.
|
2004-10-19 07:17:12 +04:00
|
|
|
*
|
2010-02-13 01:34:53 +03:00
|
|
|
* 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.
|
2004-10-19 07:17:12 +04:00
|
|
|
*
|
2010-02-13 01:34:53 +03:00
|
|
|
* 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.
|
2004-10-19 07:17:12 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define PSYCOPG_MODULE
|
|
|
|
#include "psycopg/psycopg.h"
|
2010-12-12 13:55:19 +03:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
#include "psycopg/connection.h"
|
|
|
|
#include "psycopg/cursor.h"
|
2010-04-05 13:30:03 +04:00
|
|
|
#include "psycopg/pqpath.h"
|
2006-09-01 20:27:02 +04:00
|
|
|
#include "psycopg/lobject.h"
|
2010-05-09 23:34:02 +04:00
|
|
|
#include "psycopg/green.h"
|
2010-10-06 04:09:17 +04:00
|
|
|
#include "psycopg/xid.h"
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2010-12-12 13:55:19 +03:00
|
|
|
#include <structmember.h>
|
|
|
|
#include <stringobject.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
/** DBAPI methods **/
|
|
|
|
|
|
|
|
/* cursor method - allocate a new cursor */
|
|
|
|
|
|
|
|
#define psyco_conn_cursor_doc \
|
2006-01-12 21:36:57 +03:00
|
|
|
"cursor(cursor_factory=extensions.cursor) -- new cursor\n\n" \
|
2005-11-26 10:47:48 +03:00
|
|
|
"Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n" \
|
|
|
|
"create non-standard cursors by passing a class different from the\n" \
|
|
|
|
"default. Note that the new class *should* be a sub-class of\n" \
|
2006-01-12 21:36:57 +03:00
|
|
|
"`extensions.cursor`.\n\n" \
|
|
|
|
":rtype: `extensions.cursor`"
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
|
|
|
|
{
|
2008-01-22 00:01:08 +03:00
|
|
|
const char *name = NULL;
|
2004-10-19 07:17:12 +04:00
|
|
|
PyObject *obj, *factory = NULL;
|
|
|
|
|
2004-11-19 18:50:57 +03:00
|
|
|
static char *kwlist[] = {"name", "cursor_factory", NULL};
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sO", kwlist,
|
|
|
|
&name, &factory)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
2010-04-05 13:30:03 +04:00
|
|
|
if (self->status != CONN_STATUS_READY &&
|
2010-10-09 01:03:06 +04:00
|
|
|
self->status != CONN_STATUS_BEGIN &&
|
|
|
|
self->status != CONN_STATUS_PREPARED) {
|
2010-04-05 13:30:03 +04:00
|
|
|
PyErr_SetString(OperationalError,
|
|
|
|
"asynchronous connection attempt underway");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-31 04:00:27 +04:00
|
|
|
if (name != NULL && self->async == 1) {
|
|
|
|
PyErr_SetString(ProgrammingError,
|
2010-04-05 13:30:03 +04:00
|
|
|
"asynchronous connections "
|
|
|
|
"cannot produce named cursors");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
Dprintf("psyco_conn_cursor: new cursor for connection at %p", self);
|
|
|
|
Dprintf("psyco_conn_cursor: parameters: name = %s", name);
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
if (factory == NULL) factory = (PyObject *)&cursorType;
|
2005-10-22 10:59:31 +04:00
|
|
|
if (name)
|
2007-04-10 10:36:18 +04:00
|
|
|
obj = PyObject_CallFunction(factory, "Os", self, name);
|
2005-10-22 10:59:31 +04:00
|
|
|
else
|
2010-11-09 04:49:22 +03:00
|
|
|
obj = PyObject_CallFunctionObjArgs(factory, self, NULL);
|
2005-10-22 10:59:31 +04:00
|
|
|
|
|
|
|
if (obj == NULL) return NULL;
|
|
|
|
if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"cursor factory must be subclass of psycopg2._psycopg.cursor");
|
|
|
|
Py_DECREF(obj);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-10 10:36:18 +04:00
|
|
|
|
|
|
|
Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = "
|
|
|
|
FORMAT_CODE_PY_SSIZE_T,
|
|
|
|
obj, obj->ob_refcnt
|
|
|
|
);
|
2004-10-19 07:17:12 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* close method - close the connection and all related cursors */
|
|
|
|
|
2005-11-26 10:47:48 +03:00
|
|
|
#define psyco_conn_close_doc "close() -- Close the connection."
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_close(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
|
|
|
Dprintf("psyco_conn_close: closing connection at %p", self);
|
|
|
|
conn_close(self);
|
|
|
|
Dprintf("psyco_conn_close: connection at %p closed", self);
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* commit method - commit all changes to the database */
|
|
|
|
|
2005-11-26 10:47:48 +03:00
|
|
|
#define psyco_conn_commit_doc "commit() -- Commit all changes to database."
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_commit(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, commit);
|
2010-10-08 18:16:17 +04:00
|
|
|
EXC_IF_TPC_BEGIN(self, commit);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2008-01-10 09:14:20 +03:00
|
|
|
if (conn_commit(self) < 0)
|
2007-05-29 12:43:34 +04:00
|
|
|
return NULL;
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* rollback method - roll back all changes done to the database */
|
|
|
|
|
|
|
|
#define psyco_conn_rollback_doc \
|
2005-11-26 10:47:48 +03:00
|
|
|
"rollback() -- Roll back all changes done to database."
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_rollback(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, rollback);
|
2010-10-08 18:16:17 +04:00
|
|
|
EXC_IF_TPC_BEGIN(self, rollback);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2008-01-10 09:14:20 +03:00
|
|
|
if (conn_rollback(self) < 0)
|
2007-05-29 12:43:34 +04:00
|
|
|
return NULL;
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-06 04:09:17 +04:00
|
|
|
#define psyco_conn_xid_doc \
|
|
|
|
"xid(format_id, gtrid, bqual) -- create a transaction identifier."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_xid(connectionObject *self, PyObject *args, PyObject *kwargs)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-10-13 03:28:42 +04:00
|
|
|
EXC_IF_TPC_NOT_SUPPORTED(self);
|
2010-10-06 04:09:17 +04:00
|
|
|
|
|
|
|
return PyObject_Call((PyObject *)&XidType, args, kwargs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-08 13:15:50 +04:00
|
|
|
#define psyco_conn_tpc_begin_doc \
|
|
|
|
"tpc_begin(xid) -- begin a TPC transaction with given transaction ID xid."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_tpc_begin(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *rv = NULL;
|
|
|
|
XidObject *xid = NULL;
|
|
|
|
PyObject *oxid;
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
EXC_IF_CONN_ASYNC(self, tpc_begin);
|
2010-10-13 03:28:42 +04:00
|
|
|
EXC_IF_TPC_NOT_SUPPORTED(self);
|
2010-10-08 13:15:50 +04:00
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O", &oxid)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL == (xid = xid_ensure(oxid))) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check we are not in a transaction */
|
|
|
|
if (self->status != CONN_STATUS_READY) {
|
|
|
|
PyErr_SetString(ProgrammingError,
|
|
|
|
"tpc_begin must be called outside a transaction");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* two phase commit and autocommit make no point */
|
2010-11-18 03:20:39 +03:00
|
|
|
if (self->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT) {
|
2010-10-08 13:15:50 +04:00
|
|
|
PyErr_SetString(ProgrammingError,
|
|
|
|
"tpc_begin can't be called in autocommit mode");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn_tpc_begin(self, xid) < 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
rv = Py_None;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
Py_XDECREF(xid);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-09 01:03:06 +04:00
|
|
|
#define psyco_conn_tpc_prepare_doc \
|
|
|
|
"tpc_prepare() -- perform the first phase of a two-phase transaction."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_tpc_prepare(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
EXC_IF_CONN_ASYNC(self, tpc_prepare);
|
|
|
|
EXC_IF_TPC_PREPARED(self, tpc_prepare);
|
|
|
|
|
|
|
|
if (NULL == self->tpc_xid) {
|
|
|
|
PyErr_SetString(ProgrammingError,
|
|
|
|
"prepare must be called inside a two-phase transaction");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 > conn_tpc_command(self, "PREPARE TRANSACTION", self->tpc_xid)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* transaction prepared: set the state so that no operation
|
|
|
|
* can be performed until commit. */
|
|
|
|
self->status = CONN_STATUS_PREPARED;
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-10 16:34:09 +04:00
|
|
|
/* the type of conn_commit/conn_rollback */
|
|
|
|
typedef int (*_finish_f)(connectionObject *self);
|
|
|
|
|
|
|
|
/* Implement tpc_commit/tpc_rollback.
|
|
|
|
*
|
|
|
|
* This is a common framework performing the chechs and state manipulation
|
|
|
|
* common to the two functions.
|
|
|
|
*
|
|
|
|
* Parameters are:
|
|
|
|
* - self, args: passed by Python
|
|
|
|
* - opc_f: the function to call in case of one-phase commit/rollback
|
|
|
|
* one of conn_commit/conn_rollback
|
|
|
|
* - tpc_cmd: the command to execute for a two-phase commit/rollback
|
|
|
|
*
|
|
|
|
* The function can be called in three cases:
|
|
|
|
* - If xid is specified, the status must be "ready";
|
|
|
|
* issue the commit/rollback prepared.
|
|
|
|
* - if xid is not specified and status is "begin" with a xid,
|
|
|
|
* issue a normal commit/rollback.
|
|
|
|
* - if xid is not specified and status is "prepared",
|
|
|
|
* issue the commit/rollback prepared.
|
|
|
|
*/
|
|
|
|
static PyObject *
|
|
|
|
_psyco_conn_tpc_finish(connectionObject *self, PyObject *args,
|
|
|
|
_finish_f opc_f, char *tpc_cmd)
|
|
|
|
{
|
|
|
|
PyObject *oxid = NULL;
|
|
|
|
XidObject *xid = NULL;
|
|
|
|
PyObject *rv = NULL;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "|O", &oxid)) { goto exit; }
|
|
|
|
|
|
|
|
if (oxid) {
|
|
|
|
if (!(xid = xid_ensure(oxid))) { goto exit; }
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xid) {
|
|
|
|
/* committing/aborting a recovered transaction. */
|
|
|
|
if (self->status != CONN_STATUS_READY) {
|
|
|
|
PyErr_SetString(ProgrammingError,
|
|
|
|
"tpc_commit/tpc_rollback with a xid "
|
|
|
|
"must be called outside a transaction");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
if (0 > conn_tpc_command(self, tpc_cmd, xid)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PyObject *tmp;
|
|
|
|
|
|
|
|
/* committing/aborting our own transaction. */
|
|
|
|
if (!self->tpc_xid) {
|
|
|
|
PyErr_SetString(ProgrammingError,
|
|
|
|
"tpc_commit/tpc_rollback with no parameter "
|
|
|
|
"must be called in a two-phase transaction");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (self->status) {
|
|
|
|
case CONN_STATUS_BEGIN:
|
|
|
|
if (0 > opc_f(self)) { goto exit; }
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONN_STATUS_PREPARED:
|
|
|
|
if (0 > conn_tpc_command(self, tpc_cmd, self->tpc_xid)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
PyErr_SetString(InterfaceError,
|
|
|
|
"unexpected state in tpc_commit/tpc_rollback");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* connection goes ready */
|
|
|
|
self->status = CONN_STATUS_READY;
|
|
|
|
tmp = (PyObject *)self->tpc_xid;
|
|
|
|
self->tpc_xid = NULL;
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
rv = Py_None;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
Py_XDECREF(xid);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define psyco_conn_tpc_commit_doc \
|
|
|
|
"tpc_commit([xid]) -- commit a transaction previously prepared."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_tpc_commit(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
EXC_IF_CONN_ASYNC(self, tpc_commit);
|
2010-10-13 03:28:42 +04:00
|
|
|
EXC_IF_TPC_NOT_SUPPORTED(self);
|
2010-10-10 16:34:09 +04:00
|
|
|
|
|
|
|
return _psyco_conn_tpc_finish(self, args,
|
|
|
|
conn_commit, "COMMIT PREPARED");
|
|
|
|
}
|
|
|
|
|
|
|
|
#define psyco_conn_tpc_rollback_doc \
|
|
|
|
"tpc_rollback([xid]) -- abort a transaction previously prepared."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_tpc_rollback(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
EXC_IF_CONN_ASYNC(self, tpc_rollback);
|
2010-10-13 03:28:42 +04:00
|
|
|
EXC_IF_TPC_NOT_SUPPORTED(self);
|
2010-10-10 16:34:09 +04:00
|
|
|
|
|
|
|
return _psyco_conn_tpc_finish(self, args,
|
|
|
|
conn_rollback, "ROLLBACK PREPARED");
|
|
|
|
}
|
|
|
|
|
2010-10-11 16:03:37 +04:00
|
|
|
#define psyco_conn_tpc_recover_doc \
|
|
|
|
"tpc_recover() -- returns a list of pending transaction IDs."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_tpc_recover(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
EXC_IF_CONN_ASYNC(self, tpc_recover);
|
|
|
|
EXC_IF_TPC_PREPARED(self, tpc_recover);
|
2010-10-13 03:28:42 +04:00
|
|
|
EXC_IF_TPC_NOT_SUPPORTED(self);
|
2010-10-11 16:03:37 +04:00
|
|
|
|
|
|
|
return conn_tpc_recover(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-01 19:41:02 +03:00
|
|
|
#ifdef PSYCOPG_EXTENSIONS
|
2007-04-26 02:42:36 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
/* set_isolation_level method - switch connection isolation level */
|
|
|
|
|
|
|
|
#define psyco_conn_set_isolation_level_doc \
|
2005-11-26 10:47:48 +03:00
|
|
|
"set_isolation_level(level) -- Switch isolation level to ``level``."
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
int level = 1;
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, set_isolation_level);
|
2010-10-09 01:03:06 +04:00
|
|
|
EXC_IF_TPC_PREPARED(self, set_isolation_level);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "i", &level)) return NULL;
|
|
|
|
|
2005-10-08 07:15:17 +04:00
|
|
|
if (level < 0 || level > 2) {
|
2004-10-19 07:17:12 +04:00
|
|
|
PyErr_SetString(PyExc_ValueError,
|
2010-11-18 03:20:39 +03:00
|
|
|
"isolation level must be between 0 and 2");
|
2004-10-19 07:17:12 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2007-05-29 12:43:34 +04:00
|
|
|
if (conn_switch_isolation_level(self, level) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2006-09-01 20:27:02 +04:00
|
|
|
/* set_client_encoding method - set client encoding */
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
#define psyco_conn_set_client_encoding_doc \
|
2005-11-26 10:47:48 +03:00
|
|
|
"set_client_encoding(encoding) -- Set client encoding to ``encoding``."
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
|
|
|
|
{
|
2008-01-22 00:01:08 +03:00
|
|
|
const char *enc = NULL;
|
|
|
|
char *buffer;
|
2007-04-13 05:16:22 +04:00
|
|
|
size_t i, j;
|
2007-01-19 17:47:21 +03:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, set_client_encoding);
|
2010-10-09 01:03:06 +04:00
|
|
|
EXC_IF_TPC_PREPARED(self, set_client_encoding);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2007-01-19 17:47:21 +03:00
|
|
|
/* convert to upper case and remove '-' and '_' from string */
|
2008-02-13 19:01:10 +03:00
|
|
|
buffer = PyMem_Malloc(strlen(enc)+1);
|
2007-01-19 17:47:21 +03:00
|
|
|
for (i=j=0 ; i < strlen(enc) ; i++) {
|
|
|
|
if (enc[i] == '_' || enc[i] == '-')
|
2008-02-13 19:01:10 +03:00
|
|
|
continue;
|
|
|
|
else
|
|
|
|
buffer[j++] = toupper(enc[i]);
|
2007-01-19 17:47:21 +03:00
|
|
|
}
|
|
|
|
buffer[j] = '\0';
|
2007-01-17 02:39:08 +03:00
|
|
|
|
2007-01-19 17:47:21 +03:00
|
|
|
if (conn_set_client_encoding(self, buffer) == 0) {
|
2007-04-10 10:36:18 +04:00
|
|
|
PyMem_Free(buffer);
|
2004-10-19 07:17:12 +04:00
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
else {
|
2007-01-19 17:47:21 +03:00
|
|
|
PyMem_Free(buffer);
|
2004-10-19 07:17:12 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-04-26 02:42:36 +04:00
|
|
|
|
2008-05-05 06:37:24 +04:00
|
|
|
/* get_transaction_status method - Get backend transaction status */
|
2007-04-26 02:42:36 +04:00
|
|
|
|
|
|
|
#define psyco_conn_get_transaction_status_doc \
|
|
|
|
"get_transaction_status() -- Get backend transaction status."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_get_transaction_status(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
|
|
|
return PyInt_FromLong((long)PQtransactionStatus(self->pgconn));
|
|
|
|
}
|
|
|
|
|
2009-04-19 18:42:06 +04:00
|
|
|
/* get_parameter_status method - Get server parameter status */
|
|
|
|
|
|
|
|
#define psyco_conn_get_parameter_status_doc \
|
|
|
|
"get_parameter_status(parameter) -- Get backend parameter status.\n\n" \
|
|
|
|
"Potential values for ``parameter``:\n" \
|
|
|
|
" server_version, server_encoding, client_encoding, is_superuser,\n" \
|
|
|
|
" session_authorization, DateStyle, TimeZone, integer_datetimes,\n" \
|
|
|
|
" and standard_conforming_strings\n" \
|
|
|
|
"If server did not report requested parameter, None is returned.\n\n" \
|
|
|
|
"See libpq docs for PQparameterStatus() for further details."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
const char *param = NULL;
|
|
|
|
const char *val = NULL;
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "s", ¶m)) return NULL;
|
|
|
|
|
|
|
|
val = PQparameterStatus(self->pgconn, param);
|
|
|
|
if (!val) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
return PyString_FromString(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-01 20:27:02 +04:00
|
|
|
/* lobject method - allocate a new lobject */
|
|
|
|
|
|
|
|
#define psyco_conn_lobject_doc \
|
|
|
|
"cursor(oid=0, mode=0, new_oid=0, new_file=None,\n" \
|
|
|
|
" lobject_factory=extensions.lobject) -- new lobject\n\n" \
|
|
|
|
"Return a new lobject.\n\nThe ``lobject_factory`` argument can be used\n" \
|
|
|
|
"to create non-standard lobjects by passing a class different from the\n" \
|
|
|
|
"default. Note that the new class *should* be a sub-class of\n" \
|
|
|
|
"`extensions.lobject`.\n\n" \
|
|
|
|
":rtype: `extensions.lobject`"
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
|
|
|
|
{
|
2006-09-02 08:57:50 +04:00
|
|
|
Oid oid=InvalidOid, new_oid=InvalidOid;
|
|
|
|
char *smode = NULL, *new_file = NULL;
|
|
|
|
int mode=0;
|
2006-09-01 20:27:02 +04:00
|
|
|
PyObject *obj, *factory = NULL;
|
|
|
|
|
|
|
|
static char *kwlist[] = {"oid", "mode", "new_oid", "new_file",
|
|
|
|
"cursor_factory", NULL};
|
|
|
|
|
2006-09-02 09:33:03 +04:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izizO", kwlist,
|
2006-09-02 08:57:50 +04:00
|
|
|
&oid, &smode, &new_oid, &new_file,
|
2010-02-14 22:45:22 +03:00
|
|
|
&factory)) {
|
2006-09-01 20:27:02 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, lobject);
|
2010-05-09 23:34:02 +04:00
|
|
|
EXC_IF_GREEN(lobject);
|
2010-10-09 01:03:06 +04:00
|
|
|
EXC_IF_TPC_PREPARED(self, lobject);
|
2006-09-01 20:27:02 +04:00
|
|
|
|
|
|
|
Dprintf("psyco_conn_lobject: new lobject for connection at %p", self);
|
2006-09-02 08:57:50 +04:00
|
|
|
Dprintf("psyco_conn_lobject: parameters: oid = %d, mode = %s",
|
|
|
|
oid, smode);
|
2006-09-01 20:27:02 +04:00
|
|
|
Dprintf("psyco_conn_lobject: parameters: new_oid = %d, new_file = %s",
|
|
|
|
new_oid, new_file);
|
|
|
|
|
2006-09-02 08:57:50 +04:00
|
|
|
/* build a mode number out of the mode string: right now we only accept
|
|
|
|
'r', 'w' and 'rw' (but note that 'w' implies 'rw' because PostgreSQL
|
|
|
|
backend does that. */
|
|
|
|
if (smode) {
|
|
|
|
if (strncmp("rw", smode, 2) == 0)
|
|
|
|
mode = INV_READ+INV_WRITE;
|
|
|
|
else if (smode[0] == 'r')
|
|
|
|
mode = INV_READ;
|
|
|
|
else if (smode[0] == 'w')
|
|
|
|
mode = INV_WRITE;
|
2010-02-14 22:45:22 +03:00
|
|
|
else if (smode[0] == 'n')
|
|
|
|
mode = -1;
|
2006-09-02 08:57:50 +04:00
|
|
|
else {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"mode should be one of 'r', 'w' or 'rw'");
|
2010-02-14 22:45:22 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2006-09-02 08:57:50 +04:00
|
|
|
}
|
|
|
|
|
2006-09-01 20:27:02 +04:00
|
|
|
if (factory == NULL) factory = (PyObject *)&lobjectType;
|
|
|
|
if (new_file)
|
|
|
|
obj = PyObject_CallFunction(factory, "Oiiis",
|
2010-02-14 22:45:22 +03:00
|
|
|
self, oid, mode, new_oid, new_file);
|
2006-09-01 20:27:02 +04:00
|
|
|
else
|
|
|
|
obj = PyObject_CallFunction(factory, "Oiii",
|
2010-02-14 22:45:22 +03:00
|
|
|
self, oid, mode, new_oid);
|
2006-09-01 20:27:02 +04:00
|
|
|
|
|
|
|
if (obj == NULL) return NULL;
|
|
|
|
if (PyObject_IsInstance(obj, (PyObject *)&lobjectType) == 0) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"lobject factory must be subclass of psycopg2._psycopg.lobject");
|
|
|
|
Py_DECREF(obj);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-11-25 21:18:17 +03:00
|
|
|
Dprintf("psyco_conn_lobject: new lobject at %p: refcnt = "
|
|
|
|
FORMAT_CODE_PY_SSIZE_T,
|
2006-09-01 20:27:02 +04:00
|
|
|
obj, obj->ob_refcnt);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2008-07-26 17:09:20 +04:00
|
|
|
/* get the current backend pid */
|
|
|
|
|
|
|
|
#define psyco_conn_get_backend_pid_doc \
|
|
|
|
"get_backend_pid() -- Get backend process id."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_get_backend_pid(connectionObject *self)
|
|
|
|
{
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
|
|
|
return PyInt_FromLong((long)PQbackendPID(self->pgconn));
|
|
|
|
}
|
|
|
|
|
2009-08-09 18:19:08 +04:00
|
|
|
/* reset the currect connection */
|
|
|
|
|
|
|
|
#define psyco_conn_reset_doc \
|
|
|
|
"reset() -- Reset current connection to defaults."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_reset(connectionObject *self)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-03-31 03:50:21 +04:00
|
|
|
EXC_IF_CONN_ASYNC(self, reset);
|
2009-08-09 18:19:08 +04:00
|
|
|
|
|
|
|
if (pq_reset(self) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
res = conn_setup(self, self->pgconn);
|
|
|
|
if (res < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:14:24 +03:00
|
|
|
static PyObject *
|
|
|
|
psyco_conn_get_exception(PyObject *self, void *closure)
|
|
|
|
{
|
|
|
|
PyObject *exception = *(PyObject **)closure;
|
|
|
|
|
|
|
|
Py_INCREF(exception);
|
|
|
|
return exception;
|
|
|
|
}
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2010-04-02 04:59:31 +04:00
|
|
|
static PyObject *
|
|
|
|
psyco_conn_poll(connectionObject *self)
|
|
|
|
{
|
2010-04-22 22:59:00 +04:00
|
|
|
int res;
|
|
|
|
|
2010-04-02 04:59:31 +04:00
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
2010-04-22 22:59:00 +04:00
|
|
|
res = conn_poll(self);
|
|
|
|
if (res != PSYCO_POLL_ERROR || !PyErr_Occurred()) {
|
|
|
|
return PyInt_FromLong(res);
|
2010-04-02 04:59:31 +04:00
|
|
|
} else {
|
2010-04-22 22:59:00 +04:00
|
|
|
/* There is an error and an exception is already in place */
|
|
|
|
return NULL;
|
2010-04-02 04:59:31 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-05 13:30:03 +04:00
|
|
|
|
|
|
|
/* extension: fileno - return the file descriptor of the connection */
|
|
|
|
|
|
|
|
#define psyco_conn_fileno_doc \
|
|
|
|
"fileno() -> int -- Return file descriptor associated to database connection."
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_fileno(connectionObject *self)
|
|
|
|
{
|
|
|
|
long int socket;
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
|
|
|
|
|
|
|
socket = (long int)PQsocket(self->pgconn);
|
|
|
|
|
|
|
|
return PyInt_FromLong(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-20 03:50:34 +04:00
|
|
|
/* extension: isexecuting - check for asynchronous operations */
|
2010-04-05 13:30:03 +04:00
|
|
|
|
2010-04-20 03:50:34 +04:00
|
|
|
#define psyco_conn_isexecuting_doc \
|
|
|
|
"isexecuting() -> bool -- Return True if the connection is " \
|
2010-04-05 13:30:03 +04:00
|
|
|
"executing an asynchronous operation."
|
|
|
|
|
|
|
|
static PyObject *
|
2010-04-20 03:50:34 +04:00
|
|
|
psyco_conn_isexecuting(connectionObject *self)
|
2010-04-05 13:30:03 +04:00
|
|
|
{
|
2010-04-10 20:48:09 +04:00
|
|
|
/* synchronous connections will always return False */
|
|
|
|
if (self->async == 0) {
|
2010-04-05 13:30:03 +04:00
|
|
|
Py_INCREF(Py_False);
|
|
|
|
return Py_False;
|
|
|
|
}
|
2010-04-10 20:48:09 +04:00
|
|
|
|
|
|
|
/* check if the connection is still being built */
|
|
|
|
if (self->status != CONN_STATUS_READY) {
|
2010-04-05 13:30:03 +04:00
|
|
|
Py_INCREF(Py_True);
|
|
|
|
return Py_True;
|
|
|
|
}
|
2010-04-10 20:48:09 +04:00
|
|
|
|
|
|
|
/* check if there is a query being executed */
|
|
|
|
if (self->async_cursor != NULL) {
|
|
|
|
Py_INCREF(Py_True);
|
|
|
|
return Py_True;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* otherwise it's not executing */
|
|
|
|
Py_INCREF(Py_False);
|
|
|
|
return Py_False;
|
2010-04-05 13:30:03 +04:00
|
|
|
}
|
|
|
|
|
2010-07-25 01:01:27 +04:00
|
|
|
|
|
|
|
/* extension: cancel - cancel the current operation */
|
|
|
|
|
|
|
|
#define psyco_conn_cancel_doc \
|
|
|
|
"cancel() -- cancel the current operation"
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
psyco_conn_cancel(connectionObject *self)
|
|
|
|
{
|
|
|
|
char errbuf[256];
|
|
|
|
|
|
|
|
EXC_IF_CONN_CLOSED(self);
|
2010-11-28 15:15:26 +03:00
|
|
|
EXC_IF_TPC_PREPARED(self, cancel);
|
2010-07-25 01:01:27 +04:00
|
|
|
|
|
|
|
/* do not allow cancellation while the connection is being built */
|
|
|
|
Dprintf("psyco_conn_cancel: cancelling with key %p", self->cancel);
|
|
|
|
if (self->status != CONN_STATUS_READY &&
|
|
|
|
self->status != CONN_STATUS_BEGIN) {
|
|
|
|
PyErr_SetString(OperationalError,
|
|
|
|
"asynchronous connection attempt underway");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PQcancel(self->cancel, errbuf, sizeof(errbuf)) == 0) {
|
|
|
|
Dprintf("psyco_conn_cancel: cancelling failed: %s", errbuf);
|
|
|
|
PyErr_SetString(OperationalError, errbuf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2010-04-02 04:59:31 +04:00
|
|
|
#endif /* PSYCOPG_EXTENSIONS */
|
|
|
|
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
/** the connection object **/
|
|
|
|
|
|
|
|
|
|
|
|
/* object method list */
|
|
|
|
|
|
|
|
static struct PyMethodDef connectionObject_methods[] = {
|
|
|
|
{"cursor", (PyCFunction)psyco_conn_cursor,
|
|
|
|
METH_VARARGS|METH_KEYWORDS, psyco_conn_cursor_doc},
|
|
|
|
{"close", (PyCFunction)psyco_conn_close,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_close_doc},
|
2004-10-19 07:17:12 +04:00
|
|
|
{"commit", (PyCFunction)psyco_conn_commit,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_commit_doc},
|
2004-10-19 07:17:12 +04:00
|
|
|
{"rollback", (PyCFunction)psyco_conn_rollback,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_rollback_doc},
|
2010-10-06 04:09:17 +04:00
|
|
|
{"xid", (PyCFunction)psyco_conn_xid,
|
|
|
|
METH_VARARGS|METH_KEYWORDS, psyco_conn_xid_doc},
|
2010-10-08 13:15:50 +04:00
|
|
|
{"tpc_begin", (PyCFunction)psyco_conn_tpc_begin,
|
|
|
|
METH_VARARGS, psyco_conn_tpc_begin_doc},
|
2010-10-09 01:03:06 +04:00
|
|
|
{"tpc_prepare", (PyCFunction)psyco_conn_tpc_prepare,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_tpc_prepare_doc},
|
2010-10-10 16:34:09 +04:00
|
|
|
{"tpc_commit", (PyCFunction)psyco_conn_tpc_commit,
|
|
|
|
METH_VARARGS, psyco_conn_tpc_commit_doc},
|
|
|
|
{"tpc_rollback", (PyCFunction)psyco_conn_tpc_rollback,
|
|
|
|
METH_VARARGS, psyco_conn_tpc_rollback_doc},
|
2010-10-11 16:03:37 +04:00
|
|
|
{"tpc_recover", (PyCFunction)psyco_conn_tpc_recover,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_tpc_recover_doc},
|
2004-10-19 07:17:12 +04:00
|
|
|
#ifdef PSYCOPG_EXTENSIONS
|
|
|
|
{"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level,
|
|
|
|
METH_VARARGS, psyco_conn_set_isolation_level_doc},
|
|
|
|
{"set_client_encoding", (PyCFunction)psyco_conn_set_client_encoding,
|
2007-04-10 10:36:18 +04:00
|
|
|
METH_VARARGS, psyco_conn_set_client_encoding_doc},
|
2007-04-26 02:42:36 +04:00
|
|
|
{"get_transaction_status", (PyCFunction)psyco_conn_get_transaction_status,
|
2010-11-09 06:18:54 +03:00
|
|
|
METH_NOARGS, psyco_conn_get_transaction_status_doc},
|
2009-04-19 18:42:06 +04:00
|
|
|
{"get_parameter_status", (PyCFunction)psyco_conn_get_parameter_status,
|
|
|
|
METH_VARARGS, psyco_conn_get_parameter_status_doc},
|
2008-07-26 17:09:20 +04:00
|
|
|
{"get_backend_pid", (PyCFunction)psyco_conn_get_backend_pid,
|
|
|
|
METH_NOARGS, psyco_conn_get_backend_pid_doc},
|
2006-09-01 20:27:02 +04:00
|
|
|
{"lobject", (PyCFunction)psyco_conn_lobject,
|
|
|
|
METH_VARARGS|METH_KEYWORDS, psyco_conn_lobject_doc},
|
2009-08-09 18:19:08 +04:00
|
|
|
{"reset", (PyCFunction)psyco_conn_reset,
|
|
|
|
METH_NOARGS, psyco_conn_reset_doc},
|
2010-04-05 13:30:03 +04:00
|
|
|
{"poll", (PyCFunction)psyco_conn_poll,
|
|
|
|
METH_NOARGS, psyco_conn_lobject_doc},
|
|
|
|
{"fileno", (PyCFunction)psyco_conn_fileno,
|
|
|
|
METH_NOARGS, psyco_conn_fileno_doc},
|
2010-04-20 03:50:34 +04:00
|
|
|
{"isexecuting", (PyCFunction)psyco_conn_isexecuting,
|
|
|
|
METH_NOARGS, psyco_conn_isexecuting_doc},
|
2010-07-25 01:01:27 +04:00
|
|
|
{"cancel", (PyCFunction)psyco_conn_cancel,
|
|
|
|
METH_NOARGS, psyco_conn_cancel_doc},
|
2008-05-05 06:43:38 +04:00
|
|
|
#endif
|
2004-10-19 07:17:12 +04:00
|
|
|
{NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* object member list */
|
|
|
|
|
|
|
|
static struct PyMemberDef connectionObject_members[] = {
|
2007-04-10 10:36:18 +04:00
|
|
|
#ifdef PSYCOPG_EXTENSIONS
|
2005-11-26 10:47:48 +03:00
|
|
|
{"closed", T_LONG, offsetof(connectionObject, closed), RO,
|
|
|
|
"True if the connection is closed."},
|
2004-10-19 07:17:12 +04:00
|
|
|
{"isolation_level", T_LONG,
|
2005-11-26 10:47:48 +03:00
|
|
|
offsetof(connectionObject, isolation_level), RO,
|
|
|
|
"The current isolation level."},
|
|
|
|
{"encoding", T_STRING, offsetof(connectionObject, encoding), RO,
|
|
|
|
"The current client encoding."},
|
2004-10-19 07:17:12 +04:00
|
|
|
{"notices", T_OBJECT, offsetof(connectionObject, notice_list), RO},
|
|
|
|
{"notifies", T_OBJECT, offsetof(connectionObject, notifies), RO},
|
2005-11-26 10:47:48 +03:00
|
|
|
{"dsn", T_STRING, offsetof(connectionObject, dsn), RO,
|
|
|
|
"The current connection string."},
|
2010-04-20 03:44:42 +04:00
|
|
|
{"async", T_LONG, offsetof(connectionObject, async), RO,
|
|
|
|
"True if the connection is asynchronous."},
|
2007-04-10 10:36:18 +04:00
|
|
|
{"status", T_INT,
|
2006-09-01 12:20:11 +04:00
|
|
|
offsetof(connectionObject, status), RO,
|
2007-04-10 10:36:18 +04:00
|
|
|
"The current transaction status."},
|
2007-02-22 18:16:54 +03:00
|
|
|
{"string_types", T_OBJECT, offsetof(connectionObject, string_types), RO,
|
|
|
|
"A set of typecasters to convert textual values."},
|
|
|
|
{"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), RO,
|
|
|
|
"A set of typecasters to convert binary values."},
|
2009-04-19 18:36:10 +04:00
|
|
|
{"protocol_version", T_INT,
|
|
|
|
offsetof(connectionObject, protocol), RO,
|
2010-11-16 04:06:27 +03:00
|
|
|
"Protocol version used for this connection. Currently always 3."},
|
2009-04-19 18:36:10 +04:00
|
|
|
{"server_version", T_INT,
|
|
|
|
offsetof(connectionObject, server_version), RO,
|
|
|
|
"Server version."},
|
2007-04-10 10:36:18 +04:00
|
|
|
#endif
|
2004-10-19 07:17:12 +04:00
|
|
|
{NULL}
|
|
|
|
};
|
|
|
|
|
2008-01-16 08:14:24 +03:00
|
|
|
#define EXCEPTION_GETTER(exc) \
|
|
|
|
{ #exc, psyco_conn_get_exception, NULL, exc ## _doc, &exc }
|
|
|
|
|
|
|
|
static struct PyGetSetDef connectionObject_getsets[] = {
|
|
|
|
/* DBAPI-2.0 extensions (exception objects) */
|
|
|
|
EXCEPTION_GETTER(Error),
|
|
|
|
EXCEPTION_GETTER(Warning),
|
|
|
|
EXCEPTION_GETTER(InterfaceError),
|
|
|
|
EXCEPTION_GETTER(DatabaseError),
|
|
|
|
EXCEPTION_GETTER(InternalError),
|
|
|
|
EXCEPTION_GETTER(OperationalError),
|
|
|
|
EXCEPTION_GETTER(ProgrammingError),
|
|
|
|
EXCEPTION_GETTER(IntegrityError),
|
|
|
|
EXCEPTION_GETTER(DataError),
|
|
|
|
EXCEPTION_GETTER(NotSupportedError),
|
|
|
|
{NULL}
|
|
|
|
};
|
|
|
|
#undef EXCEPTION_GETTER
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
/* initialization and finalization methods */
|
|
|
|
|
|
|
|
static int
|
2010-04-05 13:30:03 +04:00
|
|
|
connection_setup(connectionObject *self, const char *dsn, long int async)
|
2004-10-19 07:17:12 +04:00
|
|
|
{
|
2007-01-16 14:29:07 +03:00
|
|
|
char *pos;
|
2007-02-11 11:11:22 +03:00
|
|
|
int res;
|
2007-01-16 14:29:07 +03:00
|
|
|
|
2010-04-05 13:30:03 +04:00
|
|
|
Dprintf("connection_setup: init connection object at %p, "
|
|
|
|
"async %ld, refcnt = " FORMAT_CODE_PY_SSIZE_T,
|
|
|
|
self, async, ((PyObject *)self)->ob_refcnt
|
2007-04-10 10:36:18 +04:00
|
|
|
);
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
self->dsn = strdup(dsn);
|
|
|
|
self->notice_list = PyList_New(0);
|
2005-10-18 18:07:17 +04:00
|
|
|
self->notifies = PyList_New(0);
|
2004-10-19 07:17:12 +04:00
|
|
|
self->closed = 0;
|
2010-04-05 13:30:03 +04:00
|
|
|
self->async = async;
|
2010-04-02 05:00:48 +04:00
|
|
|
self->status = CONN_STATUS_SETUP;
|
2004-10-19 07:17:12 +04:00
|
|
|
self->critical = NULL;
|
|
|
|
self->async_cursor = NULL;
|
2010-04-11 05:48:33 +04:00
|
|
|
self->async_status = ASYNC_DONE;
|
2004-10-19 07:17:12 +04:00
|
|
|
self->pgconn = NULL;
|
2010-07-25 01:01:27 +04:00
|
|
|
self->cancel = NULL;
|
2005-10-22 10:59:31 +04:00
|
|
|
self->mark = 0;
|
2007-04-10 10:36:18 +04:00
|
|
|
self->string_types = PyDict_New();
|
2007-02-22 18:16:54 +03:00
|
|
|
self->binary_types = PyDict_New();
|
2009-04-04 21:17:40 +04:00
|
|
|
self->notice_pending = NULL;
|
2009-08-09 18:19:08 +04:00
|
|
|
self->encoding = NULL;
|
2007-01-16 14:29:07 +03:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
pthread_mutex_init(&(self->lock), NULL);
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2010-04-05 13:30:03 +04:00
|
|
|
if (conn_connect(self, async) != 0) {
|
2004-10-19 07:17:12 +04:00
|
|
|
Dprintf("connection_init: FAILED");
|
2007-02-11 11:11:22 +03:00
|
|
|
res = -1;
|
2004-10-19 07:17:12 +04:00
|
|
|
}
|
2007-02-11 11:11:22 +03:00
|
|
|
else {
|
2007-04-10 10:36:18 +04:00
|
|
|
Dprintf("connection_setup: good connection object at %p, refcnt = "
|
|
|
|
FORMAT_CODE_PY_SSIZE_T,
|
|
|
|
self, ((PyObject *)self)->ob_refcnt
|
|
|
|
);
|
2007-02-11 11:11:22 +03:00
|
|
|
res = 0;
|
|
|
|
}
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2007-02-11 11:11:22 +03:00
|
|
|
/* here we obfuscate the password even if there was a connection error */
|
|
|
|
pos = strstr(self->dsn, "password");
|
|
|
|
if (pos != NULL) {
|
|
|
|
for (pos = pos+9 ; *pos != '\0' && *pos != ' '; pos++)
|
|
|
|
*pos = 'x';
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2004-10-19 07:17:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
connection_dealloc(PyObject* obj)
|
|
|
|
{
|
|
|
|
connectionObject *self = (connectionObject *)obj;
|
2009-04-19 18:51:31 +04:00
|
|
|
|
|
|
|
PyObject_GC_UnTrack(self);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
if (self->closed == 0) conn_close(self);
|
2009-04-04 21:17:40 +04:00
|
|
|
|
|
|
|
conn_notice_clean(self);
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
if (self->dsn) free(self->dsn);
|
2008-03-31 02:15:21 +04:00
|
|
|
if (self->encoding) free(self->encoding);
|
2004-10-19 07:17:12 +04:00
|
|
|
if (self->critical) free(self->critical);
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2009-04-04 21:17:40 +04:00
|
|
|
Py_CLEAR(self->async_cursor);
|
2008-05-28 05:00:36 +04:00
|
|
|
Py_CLEAR(self->notice_list);
|
2009-04-04 21:17:40 +04:00
|
|
|
Py_CLEAR(self->notice_filter);
|
2008-05-28 05:00:36 +04:00
|
|
|
Py_CLEAR(self->notifies);
|
|
|
|
Py_CLEAR(self->string_types);
|
|
|
|
Py_CLEAR(self->binary_types);
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
pthread_mutex_destroy(&(self->lock));
|
|
|
|
|
2007-04-10 10:36:18 +04:00
|
|
|
Dprintf("connection_dealloc: deleted connection object at %p, refcnt = "
|
|
|
|
FORMAT_CODE_PY_SSIZE_T,
|
|
|
|
obj, obj->ob_refcnt
|
|
|
|
);
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
obj->ob_type->tp_free(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
connection_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
2008-01-22 00:01:08 +03:00
|
|
|
const char *dsn;
|
2010-04-05 13:30:03 +04:00
|
|
|
long int async = 0;
|
2010-04-11 03:30:54 +04:00
|
|
|
static char *kwlist[] = {"dsn", "async", NULL};
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2010-04-11 03:30:54 +04:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|l", kwlist, &dsn, &async))
|
2004-10-19 07:17:12 +04:00
|
|
|
return -1;
|
|
|
|
|
2010-04-05 13:30:03 +04:00
|
|
|
return connection_setup((connectionObject *)obj, dsn, async);
|
2004-10-19 07:17:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
|
|
|
return type->tp_alloc(type, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
connection_del(PyObject* self)
|
|
|
|
{
|
2008-05-28 05:00:36 +04:00
|
|
|
PyObject_GC_Del(self);
|
2004-10-19 07:17:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
connection_repr(connectionObject *self)
|
|
|
|
{
|
|
|
|
return PyString_FromFormat(
|
|
|
|
"<connection object at %p; dsn: '%s', closed: %ld>",
|
|
|
|
self, self->dsn, self->closed);
|
|
|
|
}
|
|
|
|
|
2008-05-28 05:00:36 +04:00
|
|
|
static int
|
|
|
|
connection_traverse(connectionObject *self, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
Py_VISIT(self->async_cursor);
|
|
|
|
Py_VISIT(self->notice_list);
|
|
|
|
Py_VISIT(self->notice_filter);
|
|
|
|
Py_VISIT(self->notifies);
|
|
|
|
Py_VISIT(self->string_types);
|
|
|
|
Py_VISIT(self->binary_types);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
/* object type */
|
|
|
|
|
|
|
|
#define connectionType_doc \
|
2005-11-26 10:47:48 +03:00
|
|
|
"connection(dsn, ...) -> new connection object\n\n" \
|
|
|
|
":Groups:\n" \
|
2006-01-12 21:36:57 +03:00
|
|
|
" * `DBAPI-2.0 errors`: Error, Warning, InterfaceError,\n" \
|
|
|
|
" DatabaseError, InternalError, OperationalError,\n" \
|
|
|
|
" ProgrammingError, IntegrityError, DataError, NotSupportedError"
|
2004-10-19 07:17:12 +04:00
|
|
|
|
|
|
|
PyTypeObject connectionType = {
|
|
|
|
PyObject_HEAD_INIT(NULL)
|
|
|
|
0,
|
2005-10-18 05:29:47 +04:00
|
|
|
"psycopg2._psycopg.connection",
|
2004-10-19 07:17:12 +04:00
|
|
|
sizeof(connectionObject),
|
|
|
|
0,
|
|
|
|
connection_dealloc, /*tp_dealloc*/
|
2007-04-10 10:36:18 +04:00
|
|
|
0, /*tp_print*/
|
2004-10-19 07:17:12 +04:00
|
|
|
0, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
|
|
|
0, /*tp_compare*/
|
|
|
|
(reprfunc)connection_repr, /*tp_repr*/
|
|
|
|
0, /*tp_as_number*/
|
|
|
|
0, /*tp_as_sequence*/
|
|
|
|
0, /*tp_as_mapping*/
|
|
|
|
0, /*tp_hash */
|
|
|
|
|
|
|
|
0, /*tp_call*/
|
|
|
|
(reprfunc)connection_repr, /*tp_str*/
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
|
2008-05-28 05:00:36 +04:00
|
|
|
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
2004-10-19 07:17:12 +04:00
|
|
|
connectionType_doc, /*tp_doc*/
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2008-05-28 05:00:36 +04:00
|
|
|
(traverseproc)connection_traverse, /*tp_traverse*/
|
2004-10-19 07:17:12 +04:00
|
|
|
0, /*tp_clear*/
|
|
|
|
|
|
|
|
0, /*tp_richcompare*/
|
|
|
|
0, /*tp_weaklistoffset*/
|
|
|
|
|
|
|
|
0, /*tp_iter*/
|
|
|
|
0, /*tp_iternext*/
|
|
|
|
|
|
|
|
/* Attribute descriptor and subclassing stuff */
|
|
|
|
|
|
|
|
connectionObject_methods, /*tp_methods*/
|
|
|
|
connectionObject_members, /*tp_members*/
|
2008-01-16 08:14:24 +03:00
|
|
|
connectionObject_getsets, /*tp_getset*/
|
2004-10-19 07:17:12 +04:00
|
|
|
0, /*tp_base*/
|
|
|
|
0, /*tp_dict*/
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
0, /*tp_descr_get*/
|
|
|
|
0, /*tp_descr_set*/
|
|
|
|
0, /*tp_dictoffset*/
|
2007-04-10 10:36:18 +04:00
|
|
|
|
2004-10-19 07:17:12 +04:00
|
|
|
connection_init, /*tp_init*/
|
2005-04-10 07:05:39 +04:00
|
|
|
0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/
|
2004-10-19 07:17:12 +04:00
|
|
|
connection_new, /*tp_new*/
|
|
|
|
(freefunc)connection_del, /*tp_free Low-level free-memory routine */
|
|
|
|
0, /*tp_is_gc For PyObject_IS_GC */
|
|
|
|
0, /*tp_bases*/
|
|
|
|
0, /*tp_mro method resolution order */
|
|
|
|
0, /*tp_cache*/
|
|
|
|
0, /*tp_subclasses*/
|
|
|
|
0 /*tp_weaklist*/
|
|
|
|
};
|