The PQexec
function is adequate
for submitting commands in simple synchronous applications. It
has a couple of major deficiencies however:
PQexec
waits 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 control is buried inside PQexec
, it is hard for the frontend to
decide it would like to try to cancel the ongoing command.
(It can be done from a signal handler, but not
otherwise.)
PQexec
can return only one
PGresult structure. If the
submitted command string contains multiple SQL commands, all but the last PGresult are discarded by PQexec
.
Applications that do not like these limitations can instead
use the underlying functions that PQexec
is built from: PQsendQuery
and PQgetResult
.
Older programs that used this functionality as well as
PQputline
and PQputnbytes
could block waiting to send data to
the backend. To address that issue, the function PQsetnonblocking
was added.
Old applications can neglect to use PQsetnonblocking
and get the older potentially
blocking behavior. Newer programs can use PQsetnonblocking
to achieve a completely
nonblocking connection to the backend.
PQsetnonblocking
Sets the
nonblocking status of the connection.
int PQsetnonblocking(PGconn *conn, int arg)
Sets the state of the connection to nonblocking if
arg
is 1, blocking if
arg
is 0. Returns 0 if OK, -1
if error.
In the nonblocking state, calls to PQputline
, PQputnbytes
, PQsendQuery
and PQendcopy
will not block but instead return
an error if they need to be called again.
When a database connection has been set to nonblocking
mode and PQexec
is called, it
will temporarily set the state of the connection to blocking
until the PQexec
completes.
More of libpq is expected
to be made safe for PQsetnonblocking
functionality in the near
future.
PQisnonblocking
Returns the
blocking status of the database connection.
int PQisnonblocking(const PGconn *conn)
Returns 1 if the connection is set to nonblocking mode, 0 if blocking.
PQsendQuery
Submit a command
to the server without waiting for the result(s). 1 is
returned if the command was successfully dispatched, 0 if not
(in which case, use PQerrorMessage
to get more information
about the failure).
int PQsendQuery(PGconn *conn, const char *query);
After successfully calling PQsendQuery
, call PQgetResult
one or more times to obtain the
results. PQsendQuery
may not be
called again (on the same connection) until PQgetResult
has returned NULL, indicating
that the command is done.
PQgetResult
Wait for the
next result from a prior PQsendQuery
, and return it. NULL is
returned when the query is complete and there will be no more
results.
PGresult *PQgetResult(PGconn *conn);
PQgetResult
must be called
repeatedly until it returns NULL, indicating that the command
is done. (If called when no command is active, PQgetResult
will just return NULL at once.)
Each non-NULL result from PQgetResult
should be processed using the
same PGresult accessor functions
previously described. Don't forget to free each result object
with PQclear
when done with it.
Note that PQgetResult
will
block only if a query is active and the necessary response
data has not yet been read by PQconsumeInput
.
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 frontend can be handling the results
of one query while the backend is still working on later queries
in the same command string.) However, calling PQgetResult
will still cause the frontend to
block until the backend completes the next SQL command. This can be avoided by proper
use of three more functions:
PQconsumeInput
If input is
available from the backend, consume it.
int PQconsumeInput(PGconn *conn);
PQconsumeInput
normally
returns 1 indicating "no error",
but returns 0 if there was some kind of trouble (in which
case PQerrorMessage
is set).
Note that the result does not say whether any input data was
actually collected. After calling PQconsumeInput
, the application may check
PQisBusy
and/or PQnotifies
to see if their state has
changed.
PQconsumeInput
may be called
even if the application is not prepared to deal with a result
or notification just yet. The routine will read available
data and save it in a buffer, thereby causing a select()
read-ready indication to go away.
The application can thus use PQconsumeInput
to clear the select()
condition immediately, and then
examine the results at leisure.
PQisBusy
Returns 1 if a
query is busy, that is, PQgetResult
would block waiting for input.
A 0 return indicates that PQgetResult
can be called with assurance of
not blocking.
int PQisBusy(PGconn *conn);
PQisBusy
will not itself
attempt to read data from the backend; therefore PQconsumeInput
must be invoked first, or
the busy state will never end.
PQflush
Attempt to flush any
data queued to the backend, returns 0 if successful (or if
the send queue is empty) or EOF if it
failed for some reason.
int PQflush(PGconn *conn);
PQflush
needs to be called
on a nonblocking connection before calling select()
to determine if a response has
arrived. If 0 is returned it ensures that there is no data
queued to the backend that has not actually been sent. Only
applications that have used PQsetnonblocking
have a need for this.
PQsocket
Obtain the file
descriptor number for the backend connection socket. A valid
descriptor will be >= 0; a result of -1 indicates that no
backend connection is currently open.
int PQsocket(const PGconn *conn);
PQsocket
should be used to
obtain the backend socket descriptor in preparation for
executing select()
. This allows
an application using a blocking connection to wait for either
backend responses or other conditions. If the result of
select()
indicates that data
can be read from the backend socket, then PQconsumeInput
should be called to read the
data; after which, PQisBusy
,
PQgetResult
, and/or
PQnotifies
can be used to
process the response.
Nonblocking connections (that have used PQsetnonblocking
) should not use
select()
until PQflush
has returned 0 indicating that
there is no buffered data waiting to be sent to the
backend.
A typical frontend using these functions will have a main loop
that uses select
to wait for all
the conditions that it must respond to. One of the conditions
will be input available from the backend, which in select
's terms is 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.6).
A frontend that uses PQsendQuery
/PQgetResult
can also attempt to cancel a
command that is still being processed by the backend.
PQrequestCancel
Request that
PostgreSQL abandon
processing of the current command.
int PQrequestCancel(PGconn *conn);
The return value is 1 if the cancel request was
successfully dispatched, 0 if not. (If not, PQerrorMessage
tells why not.) Successful
dispatch is no guarantee that the request will have any
effect, however. Regardless of the return value of
PQrequestCancel
, the
application must continue with the normal result-reading
sequence using PQgetResult
. If
the cancellation is effective, the current command will
terminate early and return an error result. If the
cancellation fails (say, because the backend was already done
processing the command), then there will be no visible result
at all.
Note that if the current command is part of a transaction, cancellation will abort the whole transaction.
PQrequestCancel
can safely be
invoked from a signal handler. So, it is also possible to use it
in conjunction with plain PQexec
,
if the decision to cancel can be made in a signal handler. For
example, psql invokes
PQrequestCancel
from a SIGINT signal handler, thus allowing
interactive cancellation of queries that it issues through
PQexec
. Note that PQrequestCancel
will have no effect if the
connection is not currently open or the backend is not currently
processing a command.