From 71393b9ae96fecb0d6be24ccb8486526c1a7e102 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Thu, 11 Oct 2012 22:17:47 +0100 Subject: [PATCH] Discard any result produced by cursor.executemany() --- NEWS | 1 + psycopg/connection_int.c | 2 +- psycopg/cursor_type.c | 32 +++++++++++++++++--------------- psycopg/pqpath.c | 32 ++++++++++++++++++++++---------- psycopg/pqpath.h | 5 +++-- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index 2e5477e8..cde58b69 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ What's new in psycopg 2.4.6 RealDictConnection and Cursor (ticket #114). - connect() raises an exception instead of swallowing keyword arguments when a connection string is specified as well (ticket #131). + - Discard any result produced by 'executemany()' (ticket #133). - 'errorcodes' map updated to PostgreSQL 9.2. diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c index a93c233a..ad495750 100644 --- a/psycopg/connection_int.c +++ b/psycopg/connection_int.c @@ -896,7 +896,7 @@ conn_poll(connectionObject *self) /* fetch the tuples (if there are any) and build the result. We * don't care if pq_fetch return 0 or 1, but if there was an error, * we want to signal it to the caller. */ - if (pq_fetch(curs) == -1) { + if (pq_fetch(curs, 0) == -1) { res = PSYCO_POLL_ERROR; } diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index ff5c7515..bc8195ab 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -63,7 +63,7 @@ psyco_curs_close(cursorObject *self, PyObject *args) EXC_IF_NO_MARK(self); PyOS_snprintf(buffer, 127, "CLOSE \"%s\"", self->name); - if (pq_execute(self, buffer, 0) == -1) return NULL; + if (pq_execute(self, buffer, 0, 0) == -1) return NULL; } self->closed = 1; @@ -365,7 +365,8 @@ _psyco_curs_merge_query_args(cursorObject *self, RAISES_NEG static int _psyco_curs_execute(cursorObject *self, - PyObject *operation, PyObject *vars, long int async) + PyObject *operation, PyObject *vars, + long int async, int no_result) { int res = -1; int tmp; @@ -450,7 +451,7 @@ _psyco_curs_execute(cursorObject *self, /* At this point, the SQL statement must be str, not unicode */ - tmp = pq_execute(self, Bytes_AS_STRING(self->query), async); + tmp = pq_execute(self, Bytes_AS_STRING(self->query), async, no_result); Dprintf("psyco_curs_execute: res = %d, pgres = %p", tmp, self->pgres); if (tmp < 0) { goto exit; } @@ -497,7 +498,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs) EXC_IF_ASYNC_IN_PROGRESS(self, execute); EXC_IF_TPC_PREPARED(self->conn, execute); - if (0 > _psyco_curs_execute(self, operation, vars, self->conn->async)) { + if (0 > _psyco_curs_execute(self, operation, vars, self->conn->async, 0)) { return NULL; } @@ -542,7 +543,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs) } while ((v = PyIter_Next(vars)) != NULL) { - if (0 > _psyco_curs_execute(self, operation, v, 0)) { + if (0 > _psyco_curs_execute(self, operation, v, 0, 1)) { Py_DECREF(v); Py_XDECREF(iter); return NULL; @@ -673,7 +674,7 @@ _psyco_curs_prefetch(cursorObject *self) if (self->pgres == NULL) { Dprintf("_psyco_curs_prefetch: trying to fetch data"); do { - i = pq_fetch(self); + i = pq_fetch(self, 0); Dprintf("_psycopg_curs_prefetch: result = %d", i); } while(i == 1); } @@ -775,7 +776,7 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args) EXC_IF_ASYNC_IN_PROGRESS(self, fetchone); EXC_IF_TPC_PREPARED(self->conn, fetchone); 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, 0) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; } @@ -826,7 +827,7 @@ psyco_curs_next_named(cursorObject *self) PyOS_snprintf(buffer, 127, "FETCH FORWARD %ld FROM \"%s\"", self->itersize, self->name); - if (pq_execute(self, buffer, 0) == -1) return NULL; + if (pq_execute(self, buffer, 0, 0) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; } @@ -895,7 +896,7 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) EXC_IF_TPC_PREPARED(self->conn, fetchone); PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"", (int)size, self->name); - if (pq_execute(self, buffer, 0) == -1) { goto exit; } + if (pq_execute(self, buffer, 0, 0) == -1) { goto exit; } if (_psyco_curs_prefetch(self) < 0) { goto exit; } } @@ -970,7 +971,7 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args) EXC_IF_ASYNC_IN_PROGRESS(self, fetchall); EXC_IF_TPC_PREPARED(self->conn, fetchall); PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name); - if (pq_execute(self, buffer, 0) == -1) { goto exit; } + if (pq_execute(self, buffer, 0, 0) == -1) { goto exit; } if (_psyco_curs_prefetch(self) < 0) { goto exit; } } @@ -1063,7 +1064,8 @@ psyco_curs_callproc(cursorObject *self, PyObject *args) if (!(operation = Bytes_FromString(sql))) { goto exit; } - if (0 <= _psyco_curs_execute(self, operation, parameters, self->conn->async)) { + if (0 <= _psyco_curs_execute(self, operation, parameters, + self->conn->async, 0)) { Py_INCREF(parameters); res = parameters; } @@ -1190,7 +1192,7 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs) else { PyOS_snprintf(buffer, 127, "MOVE %d FROM \"%s\"", value, self->name); } - if (pq_execute(self, buffer, 0) == -1) return NULL; + if (pq_execute(self, buffer, 0, 0) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; } @@ -1370,7 +1372,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(file); self->copyfile = file; - if (pq_execute(self, query, 0) >= 0) { + if (pq_execute(self, query, 0, 0) >= 0) { res = Py_None; Py_INCREF(Py_None); } @@ -1466,7 +1468,7 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(file); self->copyfile = file; - if (pq_execute(self, query, 0) >= 0) { + if (pq_execute(self, query, 0, 0) >= 0) { res = Py_None; Py_INCREF(Py_None); } @@ -1540,7 +1542,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs) self->copyfile = file; /* At this point, the SQL statement must be str, not unicode */ - if (pq_execute(self, Bytes_AS_STRING(sql), 0) >= 0) { + if (pq_execute(self, Bytes_AS_STRING(sql), 0, 0) >= 0) { res = Py_None; Py_INCREF(res); } diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c index a996bd7b..4e9d69f5 100644 --- a/psycopg/pqpath.c +++ b/psycopg/pqpath.c @@ -835,12 +835,16 @@ pq_flush(connectionObject *conn) } /* pq_execute - execute a query, possibly asynchronously - - this fucntion locks the connection object - this function call Py_*_ALLOW_THREADS macros */ + * + * With no_result an eventual query result is discarded. + * Currently only used to implement cursor.executemany(). + * + * This function locks the connection object + * This function call Py_*_ALLOW_THREADS macros +*/ RAISES_NEG int -pq_execute(cursorObject *curs, const char *query, int async) +pq_execute(cursorObject *curs, const char *query, int async, int no_result) { PGresult *pgres = NULL; char *error = NULL; @@ -944,7 +948,7 @@ pq_execute(cursorObject *curs, const char *query, int async) to respect the old DBAPI-2.0 compatible behaviour */ if (async == 0) { Dprintf("pq_execute: entering syncronous DBAPI compatibility mode"); - if (pq_fetch(curs) < 0) return -1; + if (pq_fetch(curs, no_result) < 0) return -1; } else { PyObject *tmp; @@ -1405,7 +1409,7 @@ exit: } int -pq_fetch(cursorObject *curs) +pq_fetch(cursorObject *curs, int no_result) { int pgstatus, ex = -1; const char *rowcount; @@ -1469,10 +1473,18 @@ pq_fetch(cursorObject *curs) break; case PGRES_TUPLES_OK: - Dprintf("pq_fetch: data from a SELECT (got tuples)"); - curs->rowcount = PQntuples(curs->pgres); - if (0 == _pq_fetch_tuples(curs)) { ex = 0; } - /* don't clear curs->pgres, because it contains the results! */ + if (!no_result) { + Dprintf("pq_fetch: got tuples"); + curs->rowcount = PQntuples(curs->pgres); + if (0 == _pq_fetch_tuples(curs)) { ex = 0; } + /* don't clear curs->pgres, because it contains the results! */ + } + else { + Dprintf("pq_fetch: got tuples, discarding them"); + IFCLEARPGRES(curs->pgres); + curs->rowcount = -1; + ex = 0; + } break; case PGRES_EMPTY_QUERY: diff --git a/psycopg/pqpath.h b/psycopg/pqpath.h index a8f39c18..d697e48f 100644 --- a/psycopg/pqpath.h +++ b/psycopg/pqpath.h @@ -35,8 +35,9 @@ /* exported functions */ HIDDEN PGresult *pq_get_last_result(connectionObject *conn); -RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs); -RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query, int async); +RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs, int no_result); +RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query, + int async, int no_result); HIDDEN int pq_send_query(connectionObject *conn, const char *query); HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres, char **error, PyThreadState **tstate);