| PostgreSQL Reference Manual - Volume 2 - Programming Guide by The PostgreSQL Global Development Group Paperback (6"x9"), 408 pages ISBN 0954612035 RRP £19.95 ($34.95) Sales of this book support the PostgreSQL project! Get a printed copy>>> |
1.4 Asynchronous Command Processing
The PQexec function is adequate for submitting commands in
normal, synchronous
applications. It has a couple of deficiencies, however, that can be of importance to some users:
-
PQexecwaits for the command to be completed. The application may have other work to do (such as maintaining a user interface), in which case it won't want to block waiting for the response. - Since the execution of the client application is suspended while it waits for the result, it is hard for the application to decide that it would like to try to cancel the ongoing command. (It can be done from a signal handler, but not otherwise.)
-
PQexeccan return only onePGresultstructure. If the submitted command string contains multiple SQL commands, all but the lastPGresultare discarded byPQexec.
Applications that do not like these limitations can instead use the
underlying functions that PQexec is built from:
PQsendQuery and PQgetResult.
There are also
PQsendQueryParams,
PQsendPrepare,
PQsendQueryPrepared,
PQsendDescribePrepared, and
PQsendDescribePortal,
which can be used with PQgetResult to duplicate the
functionality of
PQexecParams,
PQprepare,
PQexecPrepared,
PQdescribePrepared, and
PQdescribePortal
respectively.
PQsendQuery-
Submits a command to the server without
waiting for the result(s). 1 is returned if the command was
successfully dispatched and 0 if not (in which case, use
PQerrorMessageto get more information about the failure).int PQsendQuery(PGconn *conn, const char *command);
After successfully callingPQsendQuery, callPQgetResultone or more times to obtain the results.PQsendQuerymay not be called again (on the same connection) untilPQgetResulthas returned a null pointer, indicating that the command is done. PQsendQueryParams-
Submits a command and separate parameters to the server without
waiting for the result(s).
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);This is equivalent toPQsendQueryexcept that query parameters can be specified separately from the query string. The function's parameters are handled identically toPQexecParams. LikePQexecParams, it will not work on 2.0-protocol connections, and it allows only one command in the query string. PQsendPrepare-
Sends a request to create a prepared statement with the given
parameters, without waiting for completion.
int PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes);This is an asynchronous version ofPQprepare: it returns 1 if it was able to dispatch the request, and 0 if not. After a successful call, callPQgetResultto determine whether the server successfully created the prepared statement. The function's parameters are handled identically toPQprepare. LikePQprepare, it will not work on 2.0-protocol connections. PQsendQueryPrepared-
Sends a request to execute a prepared statement with given
parameters, without waiting for the result(s).
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);This is similar toPQsendQueryParams, but the command to be executed is specified by naming a previously-prepared statement, instead of giving a query string. The function's parameters are handled identically toPQexecPrepared. LikePQexecPrepared, it will not work on 2.0-protocol connections. PQsendDescribePrepared-
Submits a request to obtain information about the specified
prepared statement, without waiting for completion.
int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
This is an asynchronous version ofPQdescribePrepared: it returns 1 if it was able to dispatch the request, and 0 if not. After a successful call, callPQgetResultto obtain the results. The function's parameters are handled identically toPQdescribePrepared. LikePQdescribePrepared, it will not work on 2.0-protocol connections. PQsendDescribePortal-
Submits a request to obtain information about the specified
portal, without waiting for completion.
int PQsendDescribePortal(PGconn *conn, const char *portalName);
This is an asynchronous version ofPQdescribePortal: it returns 1 if it was able to dispatch the request, and 0 if not. After a successful call, callPQgetResultto obtain the results. The function's parameters are handled identically toPQdescribePortal. LikePQdescribePortal, it will not work on 2.0-protocol connections. PQgetResult-
Waits for the next result from a prior
PQsendQuery,PQsendQueryParams,PQsendPrepare, orPQsendQueryPreparedcall, and returns it. A null pointer is returned when the command is complete and there will be no more results.PGresult *PQgetResult(PGconn *conn);
PQgetResultmust be called repeatedly until it returns a null pointer, indicating that the command is done. (If called when no command is active,PQgetResultwill just return a null pointer at once.) Each non-null result fromPQgetResultshould be processed using the samePGresultaccessor functions previously described. Don't forget to free each result object withPQclearwhen done with it. Note thatPQgetResultwill block only if a command is active and the necessary response data has not yet been read byPQconsumeInput.
Using PQsendQuery and PQgetResult
solves one of PQexec's problems:
If a command string contains multiple SQL commands, the results of those
commands can be obtained individually. (This allows a simple form of
overlapped processing, by the way: the client can be handling the
results of one command while the server is still working on later
queries in the same command string.) However, calling PQgetResult will
still cause the client to block until the server completes the
next SQL command. This can be avoided by proper use of two
more functions:
PQconsumeInput-
If input is available from the server, consume it.
int PQconsumeInput(PGconn *conn);
PQconsumeInputnormally returns 1 indicating “no error”, but returns 0 if there was some kind of trouble (in which casePQerrorMessagecan be consulted). Note that the result does not say whether any input data was actually collected. After callingPQconsumeInput, the application may checkPQisBusyand/orPQnotifiesto see if their state has changed.PQconsumeInputmay be called even if the application is not prepared to deal with a result or notification just yet. The function will read available data and save it in a buffer, thereby causing aselect()read-ready indication to go away. The application can thus usePQconsumeInputto clear theselect()condition immediately, and then examine the results at leisure. PQisBusy-
Returns 1 if a command is busy, that is,
PQgetResultwould block waiting for input. A 0 return indicates thatPQgetResultcan be called with assurance of not blocking.int PQisBusy(PGconn *conn);
PQisBusywill not itself attempt to read data from the server; thereforePQconsumeInputmust be invoked first, or the busy state will never end.
A typical application using these functions will have a main loop that uses
select() or poll() to wait for all the
conditions that it must
respond to. One of the conditions will be input available from the server,
which in terms of select() means readable data on the file
descriptor identified by PQsocket.
When the main loop detects input ready, it should call
PQconsumeInput to read the input. It can then call
PQisBusy, followed by PQgetResult
if PQisBusy returns false (0). It can also call
PQnotifies to detect NOTIFY messages (see section 1.7 Asynchronous Notification).
A client that uses
PQsendQuery/PQgetResult can
also attempt to cancel a command that is still being processed by the
server; see section 1.5 Cancelling Queries in Progress. But regardless of the return value
of PQcancel, the application must continue with the
normal result-reading sequence using PQgetResult.
A successful cancellation will simply cause the command to terminate
sooner than it would have otherwise.
By using the functions described above, it is possible to avoid blocking
while waiting for input from the database server. However, it is still
possible that the application will block waiting to send output to the
server. This is relatively uncommon but can happen if very long SQL commands
or data values are sent. (It is much more probable if the application
sends data via COPY IN, however.) To prevent this possibility and achieve
completely nonblocking database operation, the following additional
functions may be used.
PQsetnonblocking-
Sets the nonblocking status of the connection.
int PQsetnonblocking(PGconn *conn, int arg);
Sets the state of the connection to nonblocking ifargis 1, or blocking ifargis 0. Returns 0 if OK, -1 if error. In the nonblocking state, calls toPQsendQuery,PQputline,PQputnbytes, andPQendcopywill not block but instead return an error if they need to be called again. Note thatPQexecdoes not honor nonblocking mode; if it is called, it will act in blocking fashion anyway. PQisnonblocking-
Returns the blocking status of the database connection.
int PQisnonblocking(const PGconn *conn);
Returns 1 if the connection is set to nonblocking mode and 0 if blocking. PQflush-
Attempts to flush any queued output data to the server.
Returns 0 if successful (or if the send queue is empty), -1 if it failed for
some reason, or 1 if it was unable to send all the data in the send queue yet
(this case can only occur if the connection is nonblocking).
int PQflush(PGconn *conn);
After sending any command or data on a nonblocking connection, call
PQflush. If it returns 1, wait for the socket to be
write-ready and call it again; repeat until it returns 0. Once
PQflush returns 0, wait for the socket to be read-ready
and then read the response as described above.
| ISBN 0954612035 | PostgreSQL Reference Manual - Volume 2 - Programming Guide | See the print edition |