Use the error on the connection instead of passing it explicitly around

This commit is contained in:
Daniele Varrazzo 2019-03-17 03:38:59 +00:00
parent 97220eadc6
commit 17a074b30a
6 changed files with 105 additions and 132 deletions

View File

@ -109,6 +109,7 @@ struct connectionObject {
PyObject *async_cursor; PyObject *async_cursor;
int async_status; /* asynchronous execution status */ int async_status; /* asynchronous execution status */
PGresult *pgres; /* temporary result across async calls */ PGresult *pgres; /* temporary result across async calls */
char *error; /* temporarily stored error before raising */
/* notice processing */ /* notice processing */
PyObject *notice_list; PyObject *notice_list;
@ -175,6 +176,7 @@ RAISES_NEG HIDDEN int conn_tpc_command(connectionObject *self,
const char *cmd, xidObject *xid); const char *cmd, xidObject *xid);
HIDDEN PyObject *conn_tpc_recover(connectionObject *self); HIDDEN PyObject *conn_tpc_recover(connectionObject *self);
HIDDEN void conn_set_result(connectionObject *self, PGresult *pgres); HIDDEN void conn_set_result(connectionObject *self, PGresult *pgres);
HIDDEN void conn_set_error(connectionObject *self, const char *msg);
/* 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) { \

View File

@ -651,7 +651,6 @@ conn_is_datestyle_ok(PGconn *pgconn)
RAISES_NEG int RAISES_NEG int
conn_setup(connectionObject *self) conn_setup(connectionObject *self)
{ {
char *error = NULL;
int rv = -1; int rv = -1;
self->equote = conn_get_standard_conforming_strings(self->pgconn); self->equote = conn_get_standard_conforming_strings(self->pgconn);
@ -677,10 +676,10 @@ conn_setup(connectionObject *self)
if (!dsn_has_replication(self->dsn) && !conn_is_datestyle_ok(self->pgconn)) { if (!dsn_has_replication(self->dsn) && !conn_is_datestyle_ok(self->pgconn)) {
int res; int res;
Py_UNBLOCK_THREADS; Py_UNBLOCK_THREADS;
res = pq_set_guc_locked(self, "datestyle", "ISO", &error, &_save); res = pq_set_guc_locked(self, "datestyle", "ISO", &_save);
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
if (res < 0) { if (res < 0) {
pq_complete_error(self, &error); pq_complete_error(self);
goto unlock; goto unlock;
} }
} }
@ -1221,7 +1220,6 @@ conn_set_session(connectionObject *self, int autocommit,
int isolevel, int readonly, int deferrable) int isolevel, int readonly, int deferrable)
{ {
int rv = -1; int rv = -1;
char *error = NULL;
int want_autocommit = autocommit == SRV_STATE_UNCHANGED ? int want_autocommit = autocommit == SRV_STATE_UNCHANGED ?
self->autocommit : autocommit; self->autocommit : autocommit;
@ -1251,21 +1249,21 @@ conn_set_session(connectionObject *self, int autocommit,
if (isolevel != SRV_STATE_UNCHANGED) { if (isolevel != SRV_STATE_UNCHANGED) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_isolation", srv_isolevels[isolevel], "default_transaction_isolation", srv_isolevels[isolevel],
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
if (readonly != SRV_STATE_UNCHANGED) { if (readonly != SRV_STATE_UNCHANGED) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_read_only", srv_state_guc[readonly], "default_transaction_read_only", srv_state_guc[readonly],
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
if (deferrable != SRV_STATE_UNCHANGED) { if (deferrable != SRV_STATE_UNCHANGED) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_deferrable", srv_state_guc[deferrable], "default_transaction_deferrable", srv_state_guc[deferrable],
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
@ -1276,21 +1274,21 @@ conn_set_session(connectionObject *self, int autocommit,
if (self->isolevel != ISOLATION_LEVEL_DEFAULT) { if (self->isolevel != ISOLATION_LEVEL_DEFAULT) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_isolation", "default", "default_transaction_isolation", "default",
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
if (self->readonly != STATE_DEFAULT) { if (self->readonly != STATE_DEFAULT) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_read_only", "default", "default_transaction_read_only", "default",
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
if (self->server_version >= 90100 && self->deferrable != STATE_DEFAULT) { if (self->server_version >= 90100 && self->deferrable != STATE_DEFAULT) {
if (0 > pq_set_guc_locked(self, if (0 > pq_set_guc_locked(self,
"default_transaction_deferrable", "default", "default_transaction_deferrable", "default",
&error, &_save)) { &_save)) {
goto endlock; goto endlock;
} }
} }
@ -1315,7 +1313,7 @@ endlock:
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (rv < 0) { if (rv < 0) {
pq_complete_error(self, &error); pq_complete_error(self);
goto exit; goto exit;
} }
@ -1334,7 +1332,6 @@ exit:
RAISES_NEG int RAISES_NEG int
conn_set_client_encoding(connectionObject *self, const char *pgenc) conn_set_client_encoding(connectionObject *self, const char *pgenc)
{ {
char *error = NULL;
int res = -1; int res = -1;
char *clean_enc = NULL; char *clean_enc = NULL;
@ -1350,12 +1347,11 @@ conn_set_client_encoding(connectionObject *self, const char *pgenc)
/* abort the current transaction, to set the encoding ouside of /* abort the current transaction, to set the encoding ouside of
transactions */ transactions */
if ((res = pq_abort_locked(self, &error, &_save))) { if ((res = pq_abort_locked(self, &_save))) {
goto endlock; goto endlock;
} }
if ((res = pq_set_guc_locked(self, "client_encoding", clean_enc, if ((res = pq_set_guc_locked(self, "client_encoding", clean_enc, &_save))) {
&error, &_save))) {
goto endlock; goto endlock;
} }
@ -1364,7 +1360,7 @@ endlock:
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (res < 0) { if (res < 0) {
pq_complete_error(self, &error); pq_complete_error(self);
goto exit; goto exit;
} }
@ -1390,17 +1386,15 @@ exit:
RAISES_NEG int RAISES_NEG int
conn_tpc_begin(connectionObject *self, xidObject *xid) conn_tpc_begin(connectionObject *self, xidObject *xid)
{ {
char *error = NULL;
Dprintf("conn_tpc_begin: starting transaction"); Dprintf("conn_tpc_begin: starting transaction");
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock); pthread_mutex_lock(&self->lock);
if (pq_begin_locked(self, &error, &_save) < 0) { if (pq_begin_locked(self, &_save) < 0) {
pthread_mutex_unlock(&(self->lock)); pthread_mutex_unlock(&(self->lock));
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
pq_complete_error(self, &error); pq_complete_error(self);
return -1; return -1;
} }
@ -1423,7 +1417,6 @@ conn_tpc_begin(connectionObject *self, xidObject *xid)
RAISES_NEG int RAISES_NEG int
conn_tpc_command(connectionObject *self, const char *cmd, xidObject *xid) conn_tpc_command(connectionObject *self, const char *cmd, xidObject *xid)
{ {
char *error = NULL;
PyObject *tid = NULL; PyObject *tid = NULL;
const char *ctid; const char *ctid;
int rv = -1; int rv = -1;
@ -1437,11 +1430,10 @@ conn_tpc_command(connectionObject *self, const char *cmd, xidObject *xid)
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock); pthread_mutex_lock(&self->lock);
if (0 > (rv = pq_tpc_command_locked(self, cmd, ctid, if (0 > (rv = pq_tpc_command_locked(self, cmd, ctid, &_save))) {
&error, &_save))) {
pthread_mutex_unlock(&self->lock); pthread_mutex_unlock(&self->lock);
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
pq_complete_error(self, &error); pq_complete_error(self);
goto exit; goto exit;
} }
@ -1494,3 +1486,16 @@ conn_set_result(connectionObject *self, PGresult *pgres)
PQclear(self->pgres); PQclear(self->pgres);
self->pgres = pgres; self->pgres = pgres;
} }
void
conn_set_error(connectionObject *self, const char *msg)
{
if (self->error) {
free(self->error);
self->error = NULL;
}
if (msg && *msg) {
self->error = strdup(msg);
}
}

View File

@ -1430,6 +1430,7 @@ connection_dealloc(PyObject* obj)
PyMem_Free(self->dsn); PyMem_Free(self->dsn);
PyMem_Free(self->encoding); PyMem_Free(self->encoding);
if (self->error) free(self->error);
if (self->critical) free(self->critical); if (self->critical) free(self->critical);
if (self->cancel) PQfreeCancel(self->cancel); if (self->cancel) PQfreeCancel(self->cancel);
PQclear(self->pgres); PQclear(self->pgres);

View File

@ -33,12 +33,9 @@
#include <string.h> #include <string.h>
static void static void
collect_error(connectionObject *conn, char **error) collect_error(connectionObject *conn)
{ {
const char *msg = PQerrorMessage(conn->pgconn); conn_set_error(conn, PQerrorMessage(conn->pgconn));
if (msg)
*error = strdup(msg);
} }
@ -150,7 +147,6 @@ lobject_open(lobjectObject *self, connectionObject *conn,
Oid oid, const char *smode, Oid new_oid, const char *new_file) Oid oid, const char *smode, Oid new_oid, const char *new_file)
{ {
int retvalue = -1; int retvalue = -1;
char *error = NULL;
int pgmode = 0; int pgmode = 0;
int mode; int mode;
@ -161,7 +157,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock)); pthread_mutex_lock(&(self->conn->lock));
retvalue = pq_begin_locked(self->conn, &error, &_save); retvalue = pq_begin_locked(self->conn, &_save);
if (retvalue < 0) if (retvalue < 0)
goto end; goto end;
@ -184,7 +180,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
self->oid); self->oid);
if (self->oid == InvalidOid) { if (self->oid == InvalidOid) {
collect_error(self->conn, &error); collect_error(self->conn);
retvalue = -1; retvalue = -1;
goto end; goto end;
} }
@ -204,7 +200,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
pgmode, self->fd); pgmode, self->fd);
if (self->fd == -1) { if (self->fd == -1) {
collect_error(self->conn, &error); collect_error(self->conn);
retvalue = -1; retvalue = -1;
goto end; goto end;
} }
@ -227,7 +223,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
/* if retvalue > 0, an exception is already set */ /* if retvalue > 0, an exception is already set */
return retvalue; return retvalue;
@ -236,7 +232,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
/* lobject_close - close an existing lo */ /* lobject_close - close an existing lo */
RAISES_NEG static int RAISES_NEG static int
lobject_close_locked(lobjectObject *self, char **error) lobject_close_locked(lobjectObject *self)
{ {
int retvalue; int retvalue;
@ -250,7 +246,7 @@ lobject_close_locked(lobjectObject *self, char **error)
return 0; return 0;
break; break;
default: default:
*error = strdup("the connection is broken"); conn_set_error(self->conn, "the connection is broken");
return -1; return -1;
break; break;
} }
@ -263,7 +259,7 @@ lobject_close_locked(lobjectObject *self, char **error)
retvalue = lo_close(self->conn->pgconn, self->fd); retvalue = lo_close(self->conn->pgconn, self->fd);
self->fd = -1; self->fd = -1;
if (retvalue < 0) if (retvalue < 0)
collect_error(self->conn, error); collect_error(self->conn);
return retvalue; return retvalue;
} }
@ -271,19 +267,18 @@ lobject_close_locked(lobjectObject *self, char **error)
RAISES_NEG int RAISES_NEG int
lobject_close(lobjectObject *self) lobject_close(lobjectObject *self)
{ {
char *error = NULL;
int retvalue; int retvalue;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock)); pthread_mutex_lock(&(self->conn->lock));
retvalue = lobject_close_locked(self, &error); retvalue = lobject_close_locked(self);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return retvalue; return retvalue;
} }
@ -292,31 +287,30 @@ lobject_close(lobjectObject *self)
RAISES_NEG int RAISES_NEG int
lobject_unlink(lobjectObject *self) lobject_unlink(lobjectObject *self)
{ {
char *error = NULL;
int retvalue = -1; int retvalue = -1;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock)); pthread_mutex_lock(&(self->conn->lock));
retvalue = pq_begin_locked(self->conn, &error, &_save); retvalue = pq_begin_locked(self->conn, &_save);
if (retvalue < 0) if (retvalue < 0)
goto end; goto end;
/* first we make sure the lobject is closed and then we unlink */ /* first we make sure the lobject is closed and then we unlink */
retvalue = lobject_close_locked(self, &error); retvalue = lobject_close_locked(self);
if (retvalue < 0) if (retvalue < 0)
goto end; goto end;
retvalue = lo_unlink(self->conn->pgconn, self->oid); retvalue = lo_unlink(self->conn->pgconn, self->oid);
if (retvalue < 0) if (retvalue < 0)
collect_error(self->conn, &error); collect_error(self->conn);
end: end:
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return retvalue; return retvalue;
} }
@ -326,7 +320,6 @@ RAISES_NEG Py_ssize_t
lobject_write(lobjectObject *self, const char *buf, size_t len) lobject_write(lobjectObject *self, const char *buf, size_t len)
{ {
Py_ssize_t written; Py_ssize_t written;
char *error = NULL;
Dprintf("lobject_writing: fd = %d, len = " FORMAT_CODE_SIZE_T, Dprintf("lobject_writing: fd = %d, len = " FORMAT_CODE_SIZE_T,
self->fd, len); self->fd, len);
@ -336,13 +329,13 @@ lobject_write(lobjectObject *self, const char *buf, size_t len)
written = lo_write(self->conn->pgconn, self->fd, buf, len); written = lo_write(self->conn->pgconn, self->fd, buf, len);
if (written < 0) if (written < 0)
collect_error(self->conn, &error); collect_error(self->conn);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (written < 0) if (written < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return written; return written;
} }
@ -352,20 +345,19 @@ RAISES_NEG Py_ssize_t
lobject_read(lobjectObject *self, char *buf, size_t len) lobject_read(lobjectObject *self, char *buf, size_t len)
{ {
Py_ssize_t n_read; Py_ssize_t n_read;
char *error = NULL;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock)); pthread_mutex_lock(&(self->conn->lock));
n_read = lo_read(self->conn->pgconn, self->fd, buf, len); n_read = lo_read(self->conn->pgconn, self->fd, buf, len);
if (n_read < 0) if (n_read < 0)
collect_error(self->conn, &error); collect_error(self->conn);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (n_read < 0) if (n_read < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return n_read; return n_read;
} }
@ -374,7 +366,6 @@ lobject_read(lobjectObject *self, char *buf, size_t len)
RAISES_NEG Py_ssize_t RAISES_NEG Py_ssize_t
lobject_seek(lobjectObject *self, Py_ssize_t pos, int whence) lobject_seek(lobjectObject *self, Py_ssize_t pos, int whence)
{ {
char *error = NULL;
Py_ssize_t where; Py_ssize_t where;
Dprintf("lobject_seek: fd = %d, pos = " FORMAT_CODE_PY_SSIZE_T ", whence = %d", Dprintf("lobject_seek: fd = %d, pos = " FORMAT_CODE_PY_SSIZE_T ", whence = %d",
@ -394,13 +385,13 @@ lobject_seek(lobjectObject *self, Py_ssize_t pos, int whence)
#endif #endif
Dprintf("lobject_seek: where = " FORMAT_CODE_PY_SSIZE_T, where); Dprintf("lobject_seek: where = " FORMAT_CODE_PY_SSIZE_T, where);
if (where < 0) if (where < 0)
collect_error(self->conn, &error); collect_error(self->conn);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (where < 0) if (where < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return where; return where;
} }
@ -409,7 +400,6 @@ lobject_seek(lobjectObject *self, Py_ssize_t pos, int whence)
RAISES_NEG Py_ssize_t RAISES_NEG Py_ssize_t
lobject_tell(lobjectObject *self) lobject_tell(lobjectObject *self)
{ {
char *error = NULL;
Py_ssize_t where; Py_ssize_t where;
Dprintf("lobject_tell: fd = %d", self->fd); Dprintf("lobject_tell: fd = %d", self->fd);
@ -428,13 +418,13 @@ lobject_tell(lobjectObject *self)
#endif #endif
Dprintf("lobject_tell: where = " FORMAT_CODE_PY_SSIZE_T, where); Dprintf("lobject_tell: where = " FORMAT_CODE_PY_SSIZE_T, where);
if (where < 0) if (where < 0)
collect_error(self->conn, &error); collect_error(self->conn);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (where < 0) if (where < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return where; return where;
} }
@ -443,26 +433,25 @@ lobject_tell(lobjectObject *self)
RAISES_NEG int RAISES_NEG int
lobject_export(lobjectObject *self, const char *filename) lobject_export(lobjectObject *self, const char *filename)
{ {
char *error = NULL;
int retvalue; int retvalue;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock)); pthread_mutex_lock(&(self->conn->lock));
retvalue = pq_begin_locked(self->conn, &error, &_save); retvalue = pq_begin_locked(self->conn, &_save);
if (retvalue < 0) if (retvalue < 0)
goto end; goto end;
retvalue = lo_export(self->conn->pgconn, self->oid, filename); retvalue = lo_export(self->conn->pgconn, self->oid, filename);
if (retvalue < 0) if (retvalue < 0)
collect_error(self->conn, &error); collect_error(self->conn);
end: end:
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return retvalue; return retvalue;
} }
@ -470,7 +459,6 @@ RAISES_NEG int
lobject_truncate(lobjectObject *self, size_t len) lobject_truncate(lobjectObject *self, size_t len)
{ {
int retvalue; int retvalue;
char *error = NULL;
Dprintf("lobject_truncate: fd = %d, len = " FORMAT_CODE_SIZE_T, Dprintf("lobject_truncate: fd = %d, len = " FORMAT_CODE_SIZE_T,
self->fd, len); self->fd, len);
@ -489,13 +477,13 @@ lobject_truncate(lobjectObject *self, size_t len)
#endif #endif
Dprintf("lobject_truncate: result = %d", retvalue); Dprintf("lobject_truncate: result = %d", retvalue);
if (retvalue < 0) if (retvalue < 0)
collect_error(self->conn, &error); collect_error(self->conn);
pthread_mutex_unlock(&(self->conn->lock)); pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(self->conn, &error); pq_complete_error(self->conn);
return retvalue; return retvalue;
} }

View File

@ -313,13 +313,12 @@ pq_set_non_blocking(connectionObject *conn, int arg)
again the GIL if needed, i.e. if a Python wait callback must be invoked. again the GIL if needed, i.e. if a Python wait callback must be invoked.
*/ */
int int
pq_execute_command_locked(connectionObject *conn, const char *query, pq_execute_command_locked(
char **error, PyThreadState **tstate) connectionObject *conn, const char *query, PyThreadState **tstate)
{ {
int pgstatus, retvalue = -1; int pgstatus, retvalue = -1;
Dprintf("pq_execute_command_locked: pgconn = %p, query = %s", Dprintf("pq_execute_command_locked: pgconn = %p, query = %s",
conn->pgconn, query); conn->pgconn, query);
*error = NULL;
if (!psyco_green()) { if (!psyco_green()) {
conn_set_result(conn, PQexec(conn->pgconn, query)); conn_set_result(conn, PQexec(conn->pgconn, query));
@ -332,9 +331,7 @@ pq_execute_command_locked(connectionObject *conn, const char *query,
Dprintf("pq_execute_command_locked: PQexec returned NULL"); Dprintf("pq_execute_command_locked: PQexec returned NULL");
PyEval_RestoreThread(*tstate); PyEval_RestoreThread(*tstate);
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
const char *msg; conn_set_error(conn, PQerrorMessage(conn->pgconn));
msg = PQerrorMessage(conn->pgconn);
if (msg && *msg) { *error = strdup(msg); }
} }
*tstate = PyEval_SaveThread(); *tstate = PyEval_SaveThread();
goto cleanup; goto cleanup;
@ -363,17 +360,17 @@ cleanup:
lock. lock.
*/ */
RAISES void RAISES void
pq_complete_error(connectionObject *conn, char **error) pq_complete_error(connectionObject *conn)
{ {
Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s", Dprintf("pq_complete_error: pgconn = %p, error = %s",
conn->pgconn, conn->pgres, *error ? *error : "(null)"); conn->pgconn, conn->error);
if (conn->pgres) { if (conn->pgres) {
pq_raise(conn, NULL, &conn->pgres); pq_raise(conn, NULL, &conn->pgres);
/* now conn->pgres is null */ /* now conn->pgres is null */
} }
else { else {
if (*error != NULL) { if (conn->error) {
PyErr_SetString(OperationalError, *error); PyErr_SetString(OperationalError, conn->error);
} else if (PyErr_Occurred()) { } else if (PyErr_Occurred()) {
/* There was a Python error (e.g. in the callback). Don't clobber /* There was a Python error (e.g. in the callback). Don't clobber
* it with an unknown exception. (see #410) */ * it with an unknown exception. (see #410) */
@ -390,11 +387,7 @@ pq_complete_error(connectionObject *conn, char **error)
conn->closed = 2; conn->closed = 2;
} }
} }
conn_set_error(conn, NULL);
if (*error) {
free(*error);
*error = NULL;
}
} }
@ -407,8 +400,7 @@ pq_complete_error(connectionObject *conn, char **error)
relevant result structure. relevant result structure.
*/ */
int int
pq_begin_locked(connectionObject *conn, char **error, pq_begin_locked(connectionObject *conn, PyThreadState **tstate)
PyThreadState **tstate)
{ {
const size_t bufsize = 256; const size_t bufsize = 256;
char buf[256]; /* buf size must be same as bufsize */ char buf[256]; /* buf size must be same as bufsize */
@ -439,7 +431,7 @@ pq_begin_locked(connectionObject *conn, char **error,
srv_deferrable[conn->deferrable]); srv_deferrable[conn->deferrable]);
} }
result = pq_execute_command_locked(conn, buf, error, tstate); result = pq_execute_command_locked(conn, buf, tstate);
if (result == 0) if (result == 0)
conn->status = CONN_STATUS_BEGIN; conn->status = CONN_STATUS_BEGIN;
@ -456,7 +448,6 @@ int
pq_commit(connectionObject *conn) pq_commit(connectionObject *conn)
{ {
int retvalue = -1; int retvalue = -1;
char *error = NULL;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&conn->lock); pthread_mutex_lock(&conn->lock);
@ -470,7 +461,7 @@ pq_commit(connectionObject *conn)
} }
else { else {
conn->mark += 1; conn->mark += 1;
retvalue = pq_execute_command_locked(conn, "COMMIT", &error, &_save); retvalue = pq_execute_command_locked(conn, "COMMIT", &_save);
} }
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
@ -485,14 +476,13 @@ pq_commit(connectionObject *conn)
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(conn, &error); pq_complete_error(conn);
return retvalue; return retvalue;
} }
RAISES_NEG int RAISES_NEG int
pq_abort_locked(connectionObject *conn, char **error, pq_abort_locked(connectionObject *conn, PyThreadState **tstate)
PyThreadState **tstate)
{ {
int retvalue = -1; int retvalue = -1;
@ -505,7 +495,7 @@ pq_abort_locked(connectionObject *conn, char **error,
} }
conn->mark += 1; conn->mark += 1;
retvalue = pq_execute_command_locked(conn, "ROLLBACK", error, tstate); retvalue = pq_execute_command_locked(conn, "ROLLBACK", tstate);
if (retvalue == 0) if (retvalue == 0)
conn->status = CONN_STATUS_READY; conn->status = CONN_STATUS_READY;
@ -521,7 +511,6 @@ RAISES_NEG int
pq_abort(connectionObject *conn) pq_abort(connectionObject *conn)
{ {
int retvalue = -1; int retvalue = -1;
char *error = NULL;
Dprintf("pq_abort: pgconn = %p, autocommit = %d, status = %d", Dprintf("pq_abort: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status); conn->pgconn, conn->autocommit, conn->status);
@ -529,7 +518,7 @@ pq_abort(connectionObject *conn)
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&conn->lock); pthread_mutex_lock(&conn->lock);
retvalue = pq_abort_locked(conn, &error, &_save); retvalue = pq_abort_locked(conn, &_save);
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
conn_notice_process(conn); conn_notice_process(conn);
@ -539,7 +528,7 @@ pq_abort(connectionObject *conn)
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) if (retvalue < 0)
pq_complete_error(conn, &error); pq_complete_error(conn);
return retvalue; return retvalue;
} }
@ -554,7 +543,7 @@ pq_abort(connectionObject *conn)
*/ */
RAISES_NEG int RAISES_NEG int
pq_reset_locked(connectionObject *conn, char **error, PyThreadState **tstate) pq_reset_locked(connectionObject *conn, PyThreadState **tstate)
{ {
int retvalue = -1; int retvalue = -1;
@ -564,20 +553,20 @@ pq_reset_locked(connectionObject *conn, char **error, PyThreadState **tstate)
conn->mark += 1; conn->mark += 1;
if (!conn->autocommit && conn->status == CONN_STATUS_BEGIN) { if (!conn->autocommit && conn->status == CONN_STATUS_BEGIN) {
retvalue = pq_execute_command_locked(conn, "ABORT", error, tstate); retvalue = pq_execute_command_locked(conn, "ABORT", tstate);
if (retvalue != 0) return retvalue; if (retvalue != 0) return retvalue;
} }
if (conn->server_version >= 80300) { if (conn->server_version >= 80300) {
retvalue = pq_execute_command_locked(conn, "DISCARD ALL", error, tstate); retvalue = pq_execute_command_locked(conn, "DISCARD ALL", tstate);
if (retvalue != 0) return retvalue; if (retvalue != 0) return retvalue;
} }
else { else {
retvalue = pq_execute_command_locked(conn, "RESET ALL", error, tstate); retvalue = pq_execute_command_locked(conn, "RESET ALL", tstate);
if (retvalue != 0) return retvalue; if (retvalue != 0) return retvalue;
retvalue = pq_execute_command_locked(conn, retvalue = pq_execute_command_locked(conn,
"SET SESSION AUTHORIZATION DEFAULT", error, tstate); "SET SESSION AUTHORIZATION DEFAULT", tstate);
if (retvalue != 0) return retvalue; if (retvalue != 0) return retvalue;
} }
@ -591,7 +580,6 @@ int
pq_reset(connectionObject *conn) pq_reset(connectionObject *conn)
{ {
int retvalue = -1; int retvalue = -1;
char *error = NULL;
Dprintf("pq_reset: pgconn = %p, autocommit = %d, status = %d", Dprintf("pq_reset: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status); conn->pgconn, conn->autocommit, conn->status);
@ -599,7 +587,7 @@ pq_reset(connectionObject *conn)
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&conn->lock); pthread_mutex_lock(&conn->lock);
retvalue = pq_reset_locked(conn, &error, &_save); retvalue = pq_reset_locked(conn, &_save);
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
conn_notice_process(conn); conn_notice_process(conn);
@ -609,7 +597,7 @@ pq_reset(connectionObject *conn)
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
if (retvalue < 0) { if (retvalue < 0) {
pq_complete_error(conn, &error); pq_complete_error(conn);
} }
else { else {
Py_CLEAR(conn->tpc_xid); Py_CLEAR(conn->tpc_xid);
@ -627,9 +615,7 @@ pq_reset(connectionObject *conn)
*/ */
char * char *
pq_get_guc_locked( pq_get_guc_locked(connectionObject *conn, const char *param, PyThreadState **tstate)
connectionObject *conn, const char *param,
char **error, PyThreadState **tstate)
{ {
char query[256]; char query[256];
int size; int size;
@ -639,14 +625,12 @@ pq_get_guc_locked(
size = PyOS_snprintf(query, sizeof(query), "SHOW %s", param); size = PyOS_snprintf(query, sizeof(query), "SHOW %s", param);
if (size < 0 || (size_t)size >= sizeof(query)) { if (size < 0 || (size_t)size >= sizeof(query)) {
*error = strdup("SHOW: query too large"); conn_set_error(conn, "SHOW: query too large");
goto cleanup; goto cleanup;
} }
Dprintf("pq_get_guc_locked: pgconn = %p, query = %s", conn->pgconn, query); Dprintf("pq_get_guc_locked: pgconn = %p, query = %s", conn->pgconn, query);
*error = NULL;
if (!psyco_green()) { if (!psyco_green()) {
conn_set_result(conn, PQexec(conn->pgconn, query)); conn_set_result(conn, PQexec(conn->pgconn, query));
} else { } else {
@ -659,9 +643,7 @@ pq_get_guc_locked(
Dprintf("pq_get_guc_locked: PQexec returned NULL"); Dprintf("pq_get_guc_locked: PQexec returned NULL");
PyEval_RestoreThread(*tstate); PyEval_RestoreThread(*tstate);
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
const char *msg; conn_set_error(conn, PQerrorMessage(conn->pgconn));
msg = PQerrorMessage(conn->pgconn);
if (msg && *msg) { *error = strdup(msg); }
} }
*tstate = PyEval_SaveThread(); *tstate = PyEval_SaveThread();
goto cleanup; goto cleanup;
@ -688,7 +670,7 @@ cleanup:
int int
pq_set_guc_locked( pq_set_guc_locked(
connectionObject *conn, const char *param, const char *value, connectionObject *conn, const char *param, const char *value,
char **error, PyThreadState **tstate) PyThreadState **tstate)
{ {
char query[256]; char query[256];
int size; int size;
@ -705,11 +687,11 @@ pq_set_guc_locked(
"SET %s TO '%s'", param, value); "SET %s TO '%s'", param, value);
} }
if (size < 0 || (size_t)size >= sizeof(query)) { if (size < 0 || (size_t)size >= sizeof(query)) {
*error = strdup("SET: query too large"); conn_set_error(conn, "SET: query too large");
goto exit; goto exit;
} }
rv = pq_execute_command_locked(conn, query, error, tstate); rv = pq_execute_command_locked(conn, query, tstate);
exit: exit:
return rv; return rv;
@ -721,8 +703,9 @@ exit:
* holding the global interpreter lock. */ * holding the global interpreter lock. */
int int
pq_tpc_command_locked(connectionObject *conn, const char *cmd, const char *tid, pq_tpc_command_locked(
char **error, PyThreadState **tstate) connectionObject *conn, const char *cmd, const char *tid,
PyThreadState **tstate)
{ {
int rv = -1; int rv = -1;
char *etid = NULL, *buf = NULL; char *etid = NULL, *buf = NULL;
@ -749,7 +732,7 @@ pq_tpc_command_locked(connectionObject *conn, const char *cmd, const char *tid,
/* run the command and let it handle the error cases */ /* run the command and let it handle the error cases */
*tstate = PyEval_SaveThread(); *tstate = PyEval_SaveThread();
rv = pq_execute_command_locked(conn, buf, error, tstate); rv = pq_execute_command_locked(conn, buf, tstate);
PyEval_RestoreThread(*tstate); PyEval_RestoreThread(*tstate);
exit: exit:
@ -885,7 +868,6 @@ pq_flush(connectionObject *conn)
RAISES_NEG int RAISES_NEG int
_pq_execute_sync(cursorObject *curs, const char *query, int no_result, int no_begin) _pq_execute_sync(cursorObject *curs, const char *query, int no_result, int no_begin)
{ {
char *error = NULL;
connectionObject *conn = curs->conn; connectionObject *conn = curs->conn;
CLEARPGRES(curs->pgres); CLEARPGRES(curs->pgres);
@ -893,10 +875,10 @@ _pq_execute_sync(cursorObject *curs, const char *query, int no_result, int no_be
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(conn->lock)); pthread_mutex_lock(&(conn->lock));
if (!no_begin && pq_begin_locked(conn, &error, &_save) < 0) { if (!no_begin && pq_begin_locked(conn, &_save) < 0) {
pthread_mutex_unlock(&(conn->lock)); pthread_mutex_unlock(&(conn->lock));
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
pq_complete_error(conn, &error); pq_complete_error(conn);
return -1; return -1;
} }

View File

@ -39,23 +39,20 @@ RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs, int no_result);
RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query, RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query,
int async, int no_result, int no_begin); int async, int no_result, int no_begin);
HIDDEN int pq_send_query(connectionObject *conn, const char *query); HIDDEN int pq_send_query(connectionObject *conn, const char *query);
HIDDEN int pq_begin_locked(connectionObject *conn, HIDDEN int pq_begin_locked(connectionObject *conn, PyThreadState **tstate);
char **error, PyThreadState **tstate);
HIDDEN int pq_commit(connectionObject *conn); HIDDEN int pq_commit(connectionObject *conn);
RAISES_NEG HIDDEN int pq_abort_locked(connectionObject *conn, RAISES_NEG HIDDEN int pq_abort_locked(connectionObject *conn,
char **error, PyThreadState **tstate); PyThreadState **tstate);
RAISES_NEG HIDDEN int pq_abort(connectionObject *conn); RAISES_NEG HIDDEN int pq_abort(connectionObject *conn);
HIDDEN int pq_reset_locked(connectionObject *conn, HIDDEN int pq_reset_locked(connectionObject *conn, PyThreadState **tstate);
char **error, PyThreadState **tstate);
RAISES_NEG HIDDEN int pq_reset(connectionObject *conn); RAISES_NEG HIDDEN int pq_reset(connectionObject *conn);
HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param, HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param,
char **error, PyThreadState **tstate); PyThreadState **tstate);
HIDDEN int pq_set_guc_locked(connectionObject *conn, const char *param, HIDDEN int pq_set_guc_locked(connectionObject *conn, const char *param,
const char *value, const char *value, PyThreadState **tstate);
char **error, PyThreadState **tstate);
HIDDEN int pq_tpc_command_locked(connectionObject *conn, HIDDEN int pq_tpc_command_locked(connectionObject *conn,
const char *cmd, const char *tid, const char *cmd, const char *tid,
char **error, PyThreadState **tstate); PyThreadState **tstate);
RAISES_NEG HIDDEN int pq_get_result_async(connectionObject *conn); RAISES_NEG HIDDEN int pq_get_result_async(connectionObject *conn);
HIDDEN int pq_flush(connectionObject *conn); HIDDEN int pq_flush(connectionObject *conn);
HIDDEN void pq_clear_async(connectionObject *conn); HIDDEN void pq_clear_async(connectionObject *conn);
@ -63,11 +60,9 @@ RAISES_NEG HIDDEN int pq_set_non_blocking(connectionObject *conn, int arg);
HIDDEN void pq_set_critical(connectionObject *conn, const char *msg); HIDDEN void pq_set_critical(connectionObject *conn, const char *msg);
HIDDEN int pq_execute_command_locked(connectionObject *conn, HIDDEN int pq_execute_command_locked(connectionObject *conn, const char *query,
const char *query,
char **error,
PyThreadState **tstate); PyThreadState **tstate);
RAISES HIDDEN void pq_complete_error(connectionObject *conn, char **error); RAISES HIDDEN void pq_complete_error(connectionObject *conn);
/* replication protocol support */ /* replication protocol support */
HIDDEN int pq_copy_both(replicationCursorObject *repl, PyObject *consumer, HIDDEN int pq_copy_both(replicationCursorObject *repl, PyObject *consumer,