mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-07 12:50:32 +03:00
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.
This commit is contained in:
parent
25a609c9a7
commit
58eb868db6
|
@ -86,7 +86,7 @@ typedef struct {
|
|||
|
||||
/* C-callable functions in cursor_int.c and cursor_ext.c */
|
||||
HIDDEN void curs_reset(cursorObject *self);
|
||||
HIDDEN void curs_get_last_result(cursorObject *self);
|
||||
HIDDEN int curs_get_last_result(cursorObject *self);
|
||||
HIDDEN PyObject *curs_poll_send(cursorObject *self);
|
||||
HIDDEN PyObject *curs_poll_fetch(cursorObject *self);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user