summaryrefslogtreecommitdiff
path: root/psycopg/cursor_int.c
diff options
context:
space:
mode:
authorJan UrbaƄski <wulczer@wulczer.org>2010-03-31 01:55:44 +0200
committerFederico Di Gregorio <fog@initd.org>2010-04-05 16:27:39 +0200
commit58eb868db6ef310a199abb45aea9fa8dd584cfc7 (patch)
treecb729a72c8773371948216d158397a754dbf90bf /psycopg/cursor_int.c
parent25a609c9a7379b758cd30f365e01d9601a67c37f (diff)
downloadpsycopg2-58eb868db6ef310a199abb45aea9fa8dd584cfc7.tar.gz
Avoid the possibility when curs_get_last_result would block
It was trying to get all pending results from the connection and if the client sent many and anyone except the first one would not be immediately available the loop in curs_get_last_result would call PQgetResult blockingly. Avoid that by calling PQisBusy every time and telling the client to wait for more data if it returns 1.
Diffstat (limited to 'psycopg/cursor_int.c')
-rw-r--r--psycopg/cursor_int.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/psycopg/cursor_int.c b/psycopg/cursor_int.c
index 653071c..4a63f0c 100644
--- a/psycopg/cursor_int.c
+++ b/psycopg/cursor_int.c
@@ -59,18 +59,30 @@ curs_reset(cursorObject *self)
* curs_get_last_result
*
* read all results from the connection, save the last one
+ * returns 0 if all results were read, 1 if there are remaining results, but
+ * their retrieval would block, -1 if there was an error
*/
-void
+int
curs_get_last_result(cursorObject *self) {
PGresult *pgres;
IFCLEARPGRES(self->pgres);
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&(self->conn->lock));
- /* read all results: there can be multiple if the client sent multiple
+ /* read one result, there can be multiple if the client sent multiple
statements */
while ((pgres = PQgetResult(self->conn->pgconn)) != NULL) {
+ if (PQisBusy(self->conn->pgconn) == 1) {
+ /* there is another result waiting, need to tell the client to
+ wait more */
+ Dprintf("curs_get_last_result: gut result, but more are pending");
+ self->pgres = pgres;
+ pthread_mutex_unlock(&(self->conn->lock));
+ Py_BLOCK_THREADS;
+ return 1;
+ }
+ Dprintf("curs_get_last_result: got result %p", pgres);
IFCLEARPGRES(self->pgres);
self->pgres = pgres;
}
@@ -79,6 +91,7 @@ curs_get_last_result(cursorObject *self) {
pthread_mutex_unlock(&(self->conn->lock));
Py_END_ALLOW_THREADS;
self->needsfetch = 1;
+ return 0;
}
/* curs_poll_send - handle cursor polling when flushing output */
@@ -114,6 +127,7 @@ PyObject *
curs_poll_fetch(cursorObject *self)
{
int is_busy;
+ int last_result;
/* consume the input */
is_busy = pq_is_busy(self->conn);
@@ -127,9 +141,19 @@ curs_poll_fetch(cursorObject *self)
return PyInt_FromLong(PSYCO_POLL_READ);
}
- /* all data has arrived */
- curs_get_last_result(self);
-
- Dprintf("cur_poll_fetch: returning %d", PSYCO_POLL_OK);
- return PyInt_FromLong(PSYCO_POLL_OK);
+ /* data has arrived, try to fetch all of it or, if it failed, tell the
+ user to wait more */
+ last_result = curs_get_last_result(self);
+ if (last_result == 0) {
+ Dprintf("cur_poll_fetch: returning %d", PSYCO_POLL_OK);
+ return PyInt_FromLong(PSYCO_POLL_OK);
+ }
+ else if (last_result == 1) {
+ Dprintf("cur_poll_fetch: got result, but data remaining, "
+ "returning %d", PSYCO_POLL_READ);
+ return PyInt_FromLong(PSYCO_POLL_READ);
+ }
+ else {
+ return NULL;
+ }
}