/* Replacement for PQexec using the user-provided wait function. * * The function should be called helding the connection lock, and * the GIL because some Python code is expected to be called. * * If PGresult is NULL, there may have been either a libpq error * or an exception raised by Python code: before raising an exception * check if there is already one using `PyErr_Occurred()` */ PGresult * psyco_exec_green(connectionObject *conn, const char *command) { PGresult *result = NULL; /* Send the query asynchronously */ if (0 == pq_send_query(conn, command)) { goto end; } /* Enter the poll loop with a write. When writing is finished the poll implementation will set the status to ASYNC_READ without exiting the loop. If read is finished the status is finally set to ASYNC_DONE. */ conn->async_status = ASYNC_WRITE; if (0 != psyco_wait(conn)) { psyco_clear_result_blocking(conn); goto end; } /* Now we can read the data without fear of blocking. */ result = pq_get_last_result(conn); end: conn->async_status = ASYNC_DONE; return result; }
static int _conn_sync_connect(connectionObject *self) { PGconn *pgconn; int green; /* store this value to prevent inconsistencies due to a change * in the middle of the function. */ green = psyco_green(); if (!green) { Py_BEGIN_ALLOW_THREADS; self->pgconn = pgconn = PQconnectdb(self->dsn); Py_END_ALLOW_THREADS; Dprintf("conn_connect: new postgresql connection at %p", pgconn); } else { Py_BEGIN_ALLOW_THREADS; self->pgconn = pgconn = PQconnectStart(self->dsn); Py_END_ALLOW_THREADS; Dprintf("conn_connect: new green postgresql connection at %p", pgconn); } if (pgconn == NULL) { Dprintf("conn_connect: PQconnectdb(%s) FAILED", self->dsn); PyErr_SetString(OperationalError, "PQconnectdb() failed"); return -1; } else if (PQstatus(pgconn) == CONNECTION_BAD) { Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn); PyErr_SetString(OperationalError, PQerrorMessage(pgconn)); return -1; } PQsetNoticeProcessor(pgconn, conn_notice_callback, (void*)self); /* if the connection is green, wait to finish connection */ if (green) { if (0 > pq_set_non_blocking(self, 1)) { return -1; } if (0 != psyco_wait(self)) { return -1; } } /* From here the connection is considered ready: with the new status, * poll() will use PQisBusy instead of PQconnectPoll. */ self->status = CONN_STATUS_READY; if (conn_setup(self, self->pgconn) == -1) { return -1; } return 0; }
/* Replacement for PQexec using the user-provided wait function. * * The function should be called helding the connection lock, and * the GIL because some Python code is expected to be called. * * If PGresult is NULL, there may have been either a libpq error * or an exception raised by Python code: before raising an exception * check if there is already one using `PyErr_Occurred()` */ PGresult * psyco_exec_green(connectionObject *conn, const char *command) { PGresult *result = NULL; /* Check that there is a single concurrently executing query */ if (conn->async_cursor) { PyErr_SetString(ProgrammingError, "a single async query can be executed on the same connection"); goto end; } /* we don't care about which cursor is executing the query, and * it may also be that no cursor is involved at all and this is * an internal query. So just store anything in the async_cursor, * respecting the code expecting it to be a weakref */ if (!(conn->async_cursor = PyWeakref_NewRef((PyObject*)conn, NULL))) { goto end; } /* Send the query asynchronously */ if (0 == pq_send_query(conn, command)) { goto end; } /* Enter the poll loop with a write. When writing is finished the poll implementation will set the status to ASYNC_READ without exiting the loop. If read is finished the status is finally set to ASYNC_DONE. */ conn->async_status = ASYNC_WRITE; if (0 != psyco_wait(conn)) { psyco_clear_result_blocking(conn); goto end; } /* Now we can read the data without fear of blocking. */ result = pq_get_last_result(conn); end: conn->async_status = ASYNC_DONE; Py_CLEAR(conn->async_cursor); return result; }