mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-17 01:20:32 +03:00
Added tpc_prepare and CONN_STATUS_PREPARED.
This commit is contained in:
parent
4588fa50f2
commit
4f66de494b
|
@ -80,8 +80,9 @@ ISOLATION_LEVEL_READ_UNCOMMITTED = ISOLATION_LEVEL_READ_COMMITTED
|
||||||
STATUS_SETUP = 0
|
STATUS_SETUP = 0
|
||||||
STATUS_READY = 1
|
STATUS_READY = 1
|
||||||
STATUS_BEGIN = 2
|
STATUS_BEGIN = 2
|
||||||
STATUS_SYNC = 3
|
STATUS_SYNC = 3 # currently unused
|
||||||
STATUS_ASYNC = 4
|
STATUS_ASYNC = 4 # currently unused
|
||||||
|
STATUS_PREPARED = 5
|
||||||
|
|
||||||
# This is a usefull mnemonic to check if the connection is in a transaction
|
# This is a usefull mnemonic to check if the connection is in a transaction
|
||||||
STATUS_IN_TRANSACTION = STATUS_BEGIN
|
STATUS_IN_TRANSACTION = STATUS_BEGIN
|
||||||
|
|
|
@ -38,9 +38,10 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* connection status */
|
/* connection status */
|
||||||
#define CONN_STATUS_SETUP 0
|
#define CONN_STATUS_SETUP 0
|
||||||
#define CONN_STATUS_READY 1
|
#define CONN_STATUS_READY 1
|
||||||
#define CONN_STATUS_BEGIN 2
|
#define CONN_STATUS_BEGIN 2
|
||||||
|
#define CONN_STATUS_PREPARED 5
|
||||||
/* async connection building statuses */
|
/* async connection building statuses */
|
||||||
#define CONN_STATUS_CONNECTING 20
|
#define CONN_STATUS_CONNECTING 20
|
||||||
#define CONN_STATUS_DATESTYLE 21
|
#define CONN_STATUS_DATESTYLE 21
|
||||||
|
@ -132,6 +133,8 @@ HIDDEN int conn_switch_isolation_level(connectionObject *self, int level);
|
||||||
HIDDEN int conn_set_client_encoding(connectionObject *self, const char *enc);
|
HIDDEN int conn_set_client_encoding(connectionObject *self, const char *enc);
|
||||||
HIDDEN int conn_poll(connectionObject *self);
|
HIDDEN int conn_poll(connectionObject *self);
|
||||||
HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
|
HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
|
||||||
|
HIDDEN int conn_tpc_command(connectionObject *self,
|
||||||
|
const char *cmd, XidObject *xid);
|
||||||
|
|
||||||
/* exception-raising macros */
|
/* exception-raising macros */
|
||||||
#define EXC_IF_CONN_CLOSED(self) if ((self)->closed > 0) { \
|
#define EXC_IF_CONN_CLOSED(self) if ((self)->closed > 0) { \
|
||||||
|
@ -148,6 +151,12 @@ HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
|
||||||
"during a two-phase transaction", #cmd); \
|
"during a two-phase transaction", #cmd); \
|
||||||
return NULL; }
|
return NULL; }
|
||||||
|
|
||||||
|
#define EXC_IF_TPC_PREPARED(self, cmd) \
|
||||||
|
if ((self)->status == CONN_STATUS_PREPARED) { \
|
||||||
|
PyErr_Format(ProgrammingError, "%s cannot be used " \
|
||||||
|
"with a prepared two-phase transaction", #cmd); \
|
||||||
|
return NULL; }
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -928,3 +928,32 @@ conn_tpc_begin(connectionObject *self, XidObject *xid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* conn_tpc_command -- run one of the TPC-related PostgreSQL commands.
|
||||||
|
*
|
||||||
|
* The function doesn't change the connection state as it can be used
|
||||||
|
* for many commands and for recovered transactions. */
|
||||||
|
|
||||||
|
int
|
||||||
|
conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid)
|
||||||
|
{
|
||||||
|
PGresult *pgres = NULL;
|
||||||
|
char *error = NULL;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
Dprintf("conn_tpc_command: %s", cmd);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
pthread_mutex_lock(&self->lock);
|
||||||
|
|
||||||
|
rv = pq_tpc_command_locked(self, cmd, xid, &pgres, &error, &_save);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rv < 0) {
|
||||||
|
pq_complete_error(self, &pgres, &error);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,8 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
|
||||||
EXC_IF_CONN_CLOSED(self);
|
EXC_IF_CONN_CLOSED(self);
|
||||||
|
|
||||||
if (self->status != CONN_STATUS_READY &&
|
if (self->status != CONN_STATUS_READY &&
|
||||||
self->status != CONN_STATUS_BEGIN) {
|
self->status != CONN_STATUS_BEGIN &&
|
||||||
|
self->status != CONN_STATUS_PREPARED) {
|
||||||
PyErr_SetString(OperationalError,
|
PyErr_SetString(OperationalError,
|
||||||
"asynchronous connection attempt underway");
|
"asynchronous connection attempt underway");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -231,6 +232,39 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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 (!PyArg_ParseTuple(args, "")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef PSYCOPG_EXTENSIONS
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
|
|
||||||
/* set_isolation_level method - switch connection isolation level */
|
/* set_isolation_level method - switch connection isolation level */
|
||||||
|
@ -245,6 +279,7 @@ psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
|
||||||
|
|
||||||
EXC_IF_CONN_CLOSED(self);
|
EXC_IF_CONN_CLOSED(self);
|
||||||
EXC_IF_CONN_ASYNC(self, set_isolation_level);
|
EXC_IF_CONN_ASYNC(self, set_isolation_level);
|
||||||
|
EXC_IF_TPC_PREPARED(self, set_isolation_level);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &level)) return NULL;
|
if (!PyArg_ParseTuple(args, "i", &level)) return NULL;
|
||||||
|
|
||||||
|
@ -279,6 +314,7 @@ psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
|
||||||
|
|
||||||
EXC_IF_CONN_CLOSED(self);
|
EXC_IF_CONN_CLOSED(self);
|
||||||
EXC_IF_CONN_ASYNC(self, set_client_encoding);
|
EXC_IF_CONN_ASYNC(self, set_client_encoding);
|
||||||
|
EXC_IF_TPC_PREPARED(self, set_client_encoding);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
|
if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
|
||||||
|
|
||||||
|
@ -379,6 +415,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
|
||||||
EXC_IF_CONN_CLOSED(self);
|
EXC_IF_CONN_CLOSED(self);
|
||||||
EXC_IF_CONN_ASYNC(self, lobject);
|
EXC_IF_CONN_ASYNC(self, lobject);
|
||||||
EXC_IF_GREEN(lobject);
|
EXC_IF_GREEN(lobject);
|
||||||
|
EXC_IF_TPC_PREPARED(self, lobject);
|
||||||
|
|
||||||
Dprintf("psyco_conn_lobject: new lobject for connection at %p", self);
|
Dprintf("psyco_conn_lobject: new lobject for connection at %p", self);
|
||||||
Dprintf("psyco_conn_lobject: parameters: oid = %d, mode = %s",
|
Dprintf("psyco_conn_lobject: parameters: oid = %d, mode = %s",
|
||||||
|
@ -561,6 +598,8 @@ static struct PyMethodDef connectionObject_methods[] = {
|
||||||
METH_VARARGS|METH_KEYWORDS, psyco_conn_xid_doc},
|
METH_VARARGS|METH_KEYWORDS, psyco_conn_xid_doc},
|
||||||
{"tpc_begin", (PyCFunction)psyco_conn_tpc_begin,
|
{"tpc_begin", (PyCFunction)psyco_conn_tpc_begin,
|
||||||
METH_VARARGS, psyco_conn_tpc_begin_doc},
|
METH_VARARGS, psyco_conn_tpc_begin_doc},
|
||||||
|
{"tpc_prepare", (PyCFunction)psyco_conn_tpc_prepare,
|
||||||
|
METH_VARARGS, psyco_conn_tpc_prepare_doc},
|
||||||
#ifdef PSYCOPG_EXTENSIONS
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
{"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level,
|
{"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level,
|
||||||
METH_VARARGS, psyco_conn_set_isolation_level_doc},
|
METH_VARARGS, psyco_conn_set_isolation_level_doc},
|
||||||
|
|
|
@ -492,6 +492,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_ASYNC_IN_PROGRESS(self, execute);
|
EXC_IF_ASYNC_IN_PROGRESS(self, execute);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, execute);
|
||||||
|
|
||||||
if (_psyco_curs_execute(self, operation, vars, self->conn->async)) {
|
if (_psyco_curs_execute(self, operation, vars, self->conn->async)) {
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
|
@ -511,12 +512,12 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
PyObject *operation = NULL, *vars = NULL;
|
PyObject *operation = NULL, *vars = NULL;
|
||||||
PyObject *v, *iter = NULL;
|
PyObject *v, *iter = NULL;
|
||||||
int rowcount = 0;
|
int rowcount = 0;
|
||||||
|
|
||||||
static char *kwlist[] = {"query", "vars_list", NULL};
|
static char *kwlist[] = {"query", "vars_list", NULL};
|
||||||
|
|
||||||
/* reset rowcount to -1 to avoid setting it when an exception is raised */
|
/* reset rowcount to -1 to avoid setting it when an exception is raised */
|
||||||
self->rowcount = -1;
|
self->rowcount = -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist,
|
||||||
&operation, &vars)) {
|
&operation, &vars)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -524,6 +525,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_CURS_ASYNC(self, executemany);
|
EXC_IF_CURS_ASYNC(self, executemany);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, executemany);
|
||||||
|
|
||||||
if (self->name != NULL) {
|
if (self->name != NULL) {
|
||||||
psyco_set_error(ProgrammingError, (PyObject*)self,
|
psyco_set_error(ProgrammingError, (PyObject*)self,
|
||||||
|
@ -746,6 +748,7 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args)
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
|
||||||
EXC_IF_NO_MARK(self);
|
EXC_IF_NO_MARK(self);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, fetchone);
|
||||||
PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM %s", self->name);
|
PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM %s", self->name);
|
||||||
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
||||||
if (_psyco_curs_prefetch(self) < 0) return NULL;
|
if (_psyco_curs_prefetch(self) < 0) return NULL;
|
||||||
|
@ -807,6 +810,7 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
|
||||||
EXC_IF_NO_MARK(self);
|
EXC_IF_NO_MARK(self);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, fetchone);
|
||||||
PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM %s",
|
PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM %s",
|
||||||
(int)size, self->name);
|
(int)size, self->name);
|
||||||
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
||||||
|
@ -880,6 +884,7 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
|
||||||
EXC_IF_NO_MARK(self);
|
EXC_IF_NO_MARK(self);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, fetchall);
|
||||||
PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM %s", self->name);
|
PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM %s", self->name);
|
||||||
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
if (pq_execute(self, buffer, 0) == -1) return NULL;
|
||||||
if (_psyco_curs_prefetch(self) < 0) return NULL;
|
if (_psyco_curs_prefetch(self) < 0) return NULL;
|
||||||
|
@ -941,6 +946,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_ASYNC_IN_PROGRESS(self, callproc);
|
EXC_IF_ASYNC_IN_PROGRESS(self, callproc);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, callproc);
|
||||||
|
|
||||||
if (self->name != NULL) {
|
if (self->name != NULL) {
|
||||||
psyco_set_error(ProgrammingError, (PyObject*)self,
|
psyco_set_error(ProgrammingError, (PyObject*)self,
|
||||||
|
@ -1086,6 +1092,7 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
|
||||||
EXC_IF_NO_MARK(self);
|
EXC_IF_NO_MARK(self);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, scroll);
|
||||||
|
|
||||||
if (strcmp(mode, "absolute") == 0) {
|
if (strcmp(mode, "absolute") == 0) {
|
||||||
PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM %s",
|
PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM %s",
|
||||||
|
@ -1209,6 +1216,8 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_CURS_ASYNC(self, copy_from);
|
EXC_IF_CURS_ASYNC(self, copy_from);
|
||||||
EXC_IF_GREEN(copy_from);
|
EXC_IF_GREEN(copy_from);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, copy_from);
|
||||||
|
|
||||||
|
|
||||||
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
||||||
if (quoted_delimiter == NULL) {
|
if (quoted_delimiter == NULL) {
|
||||||
|
@ -1315,6 +1324,7 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_CURS_ASYNC(self, copy_to);
|
EXC_IF_CURS_ASYNC(self, copy_to);
|
||||||
EXC_IF_GREEN(copy_to);
|
EXC_IF_GREEN(copy_to);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, copy_to);
|
||||||
|
|
||||||
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
quoted_delimiter = psycopg_escape_string((PyObject*)self->conn, sep, 0, NULL, NULL);
|
||||||
if (quoted_delimiter == NULL) {
|
if (quoted_delimiter == NULL) {
|
||||||
|
@ -1401,6 +1411,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
EXC_IF_CURS_ASYNC(self, copy_expert);
|
EXC_IF_CURS_ASYNC(self, copy_expert);
|
||||||
EXC_IF_GREEN(copy_expert);
|
EXC_IF_GREEN(copy_expert);
|
||||||
|
EXC_IF_TPC_PREPARED(self->conn, copy_expert);
|
||||||
|
|
||||||
sql = _psyco_curs_validate_sql_basic(self, sql);
|
sql = _psyco_curs_validate_sql_basic(self, sql);
|
||||||
|
|
||||||
|
|
|
@ -575,6 +575,7 @@ pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error,
|
||||||
"SET SESSION AUTHORIZATION DEFAULT", pgres, error, tstate);
|
"SET SESSION AUTHORIZATION DEFAULT", pgres, error, tstate);
|
||||||
if (retvalue != 0) return retvalue;
|
if (retvalue != 0) return retvalue;
|
||||||
|
|
||||||
|
/* should set the tpc xid to null: postponed until we get the GIL again */
|
||||||
conn->status = CONN_STATUS_READY;
|
conn->status = CONN_STATUS_READY;
|
||||||
|
|
||||||
return retvalue;
|
return retvalue;
|
||||||
|
@ -600,12 +601,58 @@ pq_reset(connectionObject *conn)
|
||||||
|
|
||||||
conn_notice_process(conn);
|
conn_notice_process(conn);
|
||||||
|
|
||||||
if (retvalue < 0)
|
if (retvalue < 0) {
|
||||||
pq_complete_error(conn, &pgres, &error);
|
pq_complete_error(conn, &pgres, &error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_CLEAR(conn->tpc_xid);
|
||||||
|
}
|
||||||
return retvalue;
|
return retvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Call one of the PostgreSQL tpc-related commands.
|
||||||
|
*
|
||||||
|
* This function should only be called on a locked connection without
|
||||||
|
* holding the global interpreter lock. */
|
||||||
|
|
||||||
|
int
|
||||||
|
pq_tpc_command_locked(connectionObject *conn, const char *cmd, XidObject *xid,
|
||||||
|
PGresult **pgres, char **error,
|
||||||
|
PyThreadState **tstate)
|
||||||
|
{
|
||||||
|
int rv = -1;
|
||||||
|
char *tid = NULL, *etid = NULL, *buf = NULL;
|
||||||
|
Py_ssize_t buflen;
|
||||||
|
|
||||||
|
Dprintf("_pq_tpc_command: pgconn = %p, command = %s",
|
||||||
|
conn->pgconn, cmd);
|
||||||
|
|
||||||
|
/* convert the xid into the postgres transaction_id and quote it. */
|
||||||
|
if (!(tid = xid_get_tid(xid))) { goto exit; }
|
||||||
|
if (!(etid = psycopg_escape_string((PyObject *)conn, tid, 0, NULL, NULL)))
|
||||||
|
{ goto exit; }
|
||||||
|
|
||||||
|
/* prepare the command to the server */
|
||||||
|
buflen = 3 + strlen(cmd) + strlen(etid); /* add space, semicolon, zero */
|
||||||
|
if (!(buf = PyMem_Malloc(buflen))) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (0 > PyOS_snprintf(buf, buflen, "%s %s;", cmd, etid)) { goto exit; }
|
||||||
|
|
||||||
|
/* run the command and let it handle the error cases */
|
||||||
|
rv = pq_execute_command_locked(conn, buf, pgres, error, tstate);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PyMem_Free(buf);
|
||||||
|
PyMem_Free(etid);
|
||||||
|
PyMem_Free(tid);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* pq_is_busy - consume input and return connection status
|
/* pq_is_busy - consume input and return connection status
|
||||||
|
|
||||||
a status of 1 means that a call to pq_fetch will block, while a status of 0
|
a status of 1 means that a call to pq_fetch will block, while a status of 0
|
||||||
|
|
|
@ -46,6 +46,10 @@ HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres,
|
||||||
char **error, PyThreadState **tstate);
|
char **error, PyThreadState **tstate);
|
||||||
HIDDEN int pq_abort(connectionObject *conn);
|
HIDDEN int pq_abort(connectionObject *conn);
|
||||||
HIDDEN int pq_reset(connectionObject *conn);
|
HIDDEN int pq_reset(connectionObject *conn);
|
||||||
|
HIDDEN int pq_tpc_command_locked(connectionObject *conn,
|
||||||
|
const char *cmd, XidObject *xid,
|
||||||
|
PGresult **pgres, char **error,
|
||||||
|
PyThreadState **tstate);
|
||||||
HIDDEN int pq_is_busy(connectionObject *conn);
|
HIDDEN int pq_is_busy(connectionObject *conn);
|
||||||
HIDDEN int pq_is_busy_locked(connectionObject *conn);
|
HIDDEN int pq_is_busy_locked(connectionObject *conn);
|
||||||
HIDDEN int pq_flush(connectionObject *conn);
|
HIDDEN int pq_flush(connectionObject *conn);
|
||||||
|
|
|
@ -51,5 +51,6 @@ typedef struct {
|
||||||
} XidObject;
|
} XidObject;
|
||||||
|
|
||||||
HIDDEN XidObject *xid_ensure(PyObject *oxid);
|
HIDDEN XidObject *xid_ensure(PyObject *oxid);
|
||||||
|
HIDDEN char *xid_get_tid(XidObject *self);
|
||||||
|
|
||||||
#endif /* PSYCOPG_XID_H */
|
#endif /* PSYCOPG_XID_H */
|
||||||
|
|
|
@ -319,3 +319,33 @@ XidObject *xid_ensure(PyObject *oxid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the PostgreSQL transaction_id for this XA xid.
|
||||||
|
*
|
||||||
|
* PostgreSQL wants just a string, while the DBAPI supports the XA standard
|
||||||
|
* and thus a triple. We use the same conversion algorithm implemented by JDBC
|
||||||
|
* in order to allow some form of interoperation.
|
||||||
|
*
|
||||||
|
* Return a buffer allocated with PyMem_Malloc. Use PyMem_Free to free it.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
xid_get_tid(XidObject *self)
|
||||||
|
{
|
||||||
|
/* TODO: for the moment just use the string mashed up by James.
|
||||||
|
* later will implement the JDBC algorithm. */
|
||||||
|
char *buf;
|
||||||
|
Py_ssize_t bufsize = 0;
|
||||||
|
|
||||||
|
if (self->pg_xact_id) {
|
||||||
|
bufsize = 1 + strlen(self->pg_xact_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = (char *)PyMem_Malloc(bufsize);
|
||||||
|
if (buf) {
|
||||||
|
strncpy(buf, self->pg_xact_id, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user