提交 efc3a25b 编写于 作者: T Tom Lane

Update libpq to make new features of FE/BE protocol available to

client applications.  Some editorial work on libpq.sgml, too.
上级 b8d601e7
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.124 2003/06/13 23:10:07 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.125 2003/06/21 21:51:30 tgl Exp $
-->
<chapter id="libpq">
......@@ -24,7 +24,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.124 2003/06/13 23:10:07 momj
</para>
<para>
Three short programs are included at the end of this chapter (<xref linkend="libpq-example">) to show how
Some short programs are included at the end of this chapter (<xref linkend="libpq-example">) to show how
to write programs that use <application>libpq</application>. There are also several
complete examples of <application>libpq</application> applications in the
directory <filename>src/test/examples</filename> in the source code distribution.
......@@ -37,7 +37,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.124 2003/06/13 23:10:07 momj
</para>
<sect1 id="libpq-connect">
<title>Database Connection Functions</title>
<title>Database Connection Control Functions</title>
<para>
The following functions deal with making a connection to a
......@@ -68,8 +68,8 @@ PGconn *PQconnectdb(const char *conninfo);
This function opens a new database connection using the parameters taken
from the string <literal>conninfo</literal>. Unlike <function>PQsetdbLogin</> below,
the parameter set can be extended without changing the function signature,
so use either of this function or the nonblocking analogues <function>PQconnectStart</>
and <function>PQconnectPoll</function> is preferred for new application programming.
so use of this function (or its nonblocking analogues <function>PQconnectStart</>
and <function>PQconnectPoll</function>) is preferred for new application programming.
</para>
<para>
......@@ -86,7 +86,7 @@ PGconn *PQconnectdb(const char *conninfo);
</para>
<para>
The currently recognized parameter key words are:
The currently recognized parameter keywords are:
<variablelist>
<varlistentry>
......@@ -107,11 +107,11 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>hostaddr</literal></term>
<listitem>
<para>
IP address of host to connect to. This should be in the
Numeric IP address of host to connect to. This should be in the
standard IPv4 address format, e.g., <literal>172.28.40.9</>. If
your machine supports IPv6, you can also use those addresses. If
a nonzero-length string is specified, TCP/IP communication is
used.
your machine supports IPv6, you can also use those addresses.
TCP/IP communication is
always used when a nonempty string is specified for this parameter.
</para>
<para>
Using <literal>hostaddr</> instead of <literal>host</> allows the
......@@ -119,9 +119,10 @@ PGconn *PQconnectdb(const char *conninfo);
applications with time constraints. However, Kerberos authentication
requires the host name. The following therefore applies: If
<literal>host</> is specified without <literal>hostaddr</>, a host name
lookup is forced. If <literal>hostaddr</> is specified without
lookup occurs. If <literal>hostaddr</> is specified without
<literal>host</>, the value for <literal>hostaddr</> gives the remote
address; if Kerberos is used, this causes a reverse name query. If both
address. When Kerberos is used, a reverse name query occurs to obtain
the host name for Kerberos. If both
<literal>host</> and <literal>hostaddr</> are specified, the value for
<literal>hostaddr</> gives the remote address; the value for
<literal>host</> is ignored, unless Kerberos is used, in which case that
......@@ -153,7 +154,7 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>dbname</literal></term>
<listitem>
<para>
The database name.
The database name. Defaults to be the same as the user name.
</para>
</listitem>
</varlistentry>
......@@ -162,7 +163,7 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>user</literal></term>
<listitem>
<para>
User name to connect as.
<productname>PostgreSQL</productname> user name to connect as.
</para>
</listitem>
</varlistentry>
......@@ -182,7 +183,7 @@ PGconn *PQconnectdb(const char *conninfo);
<para>
Maximum wait for connection, in seconds (write as a decimal integer
string). Zero or not specified means wait indefinitely. It is not
recommended to set the timeout to less than 2 seconds.
recommended to use a timeout of less than 2 seconds.
</para>
</listitem>
</varlistentry>
......@@ -237,7 +238,7 @@ PGconn *PQconnectdb(const char *conninfo);
If any parameter is unspecified, then the corresponding
environment variable (see <xref linkend="libpq-envars">)
is checked. If the environment variable is not set either,
then hardwired defaults are used.
then built-in defaults are used.
</para>
</listitem>
</varlistentry>
......@@ -260,8 +261,9 @@ PGconn *PQsetdbLogin(const char *pghost,
<para>
This is the predecessor of <function>PQconnectdb</function> with a fixed
number of parameters. It has the same functionality except that the
missing parameters cannot be specified in the call.
set of parameters. It has the same functionality except that the
missing parameters will always take on default values. Write NULL or an
empty string for any one of the fixed parameters that is to be defaulted.
</para>
</listitem>
</varlistentry>
......@@ -306,6 +308,10 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
These two functions are used to open a connection to a database server such
that your application's thread of execution is not blocked on remote I/O
whilst doing so.
The point of this approach is that the waits for I/O to complete can occur
in the application's main loop, rather than down inside
<function>PQconnectdb()</>, and so the application can manage this
operation in parallel with other activities.
</para>
<para>
The database connection is made using the parameters taken from the string
......@@ -313,7 +319,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
the same format as described above for <function>PQconnectdb</function>.
</para>
<para>
Neither <function>PQconnectStart</function> nor <function>PQconnectPoll</function> will block, as long as a number of
Neither <function>PQconnectStart</function> nor <function>PQconnectPoll</function> will block, so long as a number of
restrictions are met:
<itemizedlist>
<listitem>
......@@ -326,14 +332,14 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<listitem>
<para>
If you call <function>PQtrace</function>, ensure that the stream object into which you trace
will not block.
If you call <function>PQtrace</function>, ensure that the stream object
into which you trace will not block.
</para>
</listitem>
<listitem>
<para>
You ensure for yourself that the socket is in the appropriate state
You ensure that the socket is in the appropriate state
before calling <function>PQconnectPoll</function>, as described below.
</para>
</listitem>
......@@ -349,28 +355,31 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<symbol>CONNECTION_BAD</symbol>, <function>PQconnectStart</function> has failed.
</para>
<para>
If <function>PQconnectStart</> succeeds, the next stage is to poll <application>libpq</> so that it may
proceed with the connection sequence. Loop thus: If <function>PQconnectPoll(conn)</function> last returned
<symbol>PGRES_POLLING_READING</symbol>, perform a <function>select()</> for reading on the socket determined using <function>PQsocket(conn)</function>. If
it last returned <symbol>PGRES_POLLING_WRITING</symbol>, perform a <function>select()</> for writing on
that same socket. If you have yet to call <function>PQconnectPoll</function>, i.e., after the call
to <function>PQconnectStart</function>, behave as if it last returned <symbol>PGRES_POLLING_WRITING</symbol>. If
<function>select()</> shows that the socket is ready, consider it <quote>active</quote>. If it has
been decided that this connection is <quote>active</quote>, call <function>PQconnectPoll(conn)</function>
again. If this call returns <symbol>PGRES_POLLING_FAILED</symbol>, the connection procedure
has failed. If this call returns <symbol>PGRES_POLLING_OK</symbol>, the connection has been
successfully made.
</para>
<para>
Note that the use of <function>select()</function> to ensure that the socket is ready is merely
a (likely) example; those with other facilities available, such as a
<function>poll()</function> call, may of course use that instead.
If <function>PQconnectStart</> succeeds, the next stage is to poll
<application>libpq</> so that it may proceed with the connection sequence.
Use <function>PQsocket(conn)</function> to obtain the descriptor of the
socket underlying the database connection.
Loop thus: If <function>PQconnectPoll(conn)</function> last returned
<symbol>PGRES_POLLING_READING</symbol>, wait until the socket is ready to
read (as indicated by <function>select()</>, <function>poll()</>, or
similar system function).
Then call <function>PQconnectPoll(conn)</function> again.
Conversely, if <function>PQconnectPoll(conn)</function> last returned
<symbol>PGRES_POLLING_WRITING</symbol>, wait until the socket is ready
to write, then call <function>PQconnectPoll(conn)</function> again.
If you have yet to call
<function>PQconnectPoll</function>, i.e., just after the call to
<function>PQconnectStart</function>, behave as if it last returned
<symbol>PGRES_POLLING_WRITING</symbol>. Continue this loop until
<function>PQconnectPoll(conn)</function> returns
<symbol>PGRES_POLLING_FAILED</symbol>, indicating the connection procedure
has failed, or <symbol>PGRES_POLLING_OK</symbol>, indicating the connection
has been successfully made.
</para>
<para>
At any time during connection, the status of the connection may be
checked, by calling <function>PQstatus</>. If this gives <symbol>CONNECTION_BAD</>, then the
checked by calling <function>PQstatus</>. If this gives <symbol>CONNECTION_BAD</>, then the
connection procedure has failed; if it gives <function>CONNECTION_OK</>, then the
connection is ready. Both of these states are equally detectable
from the return value of <function>PQconnectPoll</>, described above. Other states may also occur
......@@ -410,17 +419,25 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<term><symbol>CONNECTION_AUTH_OK</symbol></term>
<listitem>
<para>
Received authentication; waiting for connection start-up to continue.
Received authentication; waiting for backend start-up to finish.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>CONNECTION_SETENV</symbol></term>
<term><symbol>CONNECTION_SSL_STARTUP</symbol></term>
<listitem>
<para>
Negotiating SSL encryption.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><symbol>CONNECTION_SETENV</symbol></term>
<listitem>
<para>
Negotiating environment (part of the connection start-up).
Negotiating environment-driven parameter settings.
</para>
</listitem>
</varlistentry>
......@@ -429,7 +446,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
Note that, although these constants will remain (in order to maintain
compatibility), an application should never rely upon these appearing in a
particular order, or at all, or on the status always being one of these
documented values. An application may do something like this:
documented values. An application might do something like this:
<programlisting>
switch(PQstatus(conn))
{
......@@ -450,20 +467,19 @@ switch(PQstatus(conn))
</para>
<para>
Note that if <function>PQconnectStart</function> returns a non-null pointer, you must call
<function>PQfinish</function> when you are finished with it, in order to dispose of
the structure and any associated memory blocks. This must be done even if a
call to <function>PQconnectStart</function> or <function>PQconnectPoll</function> failed.
</para>
<para>
<function>PQconnectPoll</function> will currently block if
<application>libpq</> is compiled with SSL support. This restriction may be removed in the future.
The <literal>connect_timeout</literal> connection parameter is ignored
when using <function>PQconnectPoll</function>; it is the application's
responsibility to decide whether an excessive amount of time has elapsed.
Otherwise, <function>PQconnectStart</function> followed by a
<function>PQconnectPoll</function> loop is equivalent to
<function>PQconnectdb</function>.
</para>
<para>
Finally, these functions leave the connection in a nonblocking state as if
<function>PQsetnonblocking</function> had been called.
Note that if <function>PQconnectStart</function> returns a non-null pointer, you must call
<function>PQfinish</function> when you are finished with it, in order to dispose of
the structure and any associated memory blocks. This must be done even if
the connection attempt fails or is abandoned.
</para>
</listitem>
</varlistentry>
......@@ -498,7 +514,8 @@ typedef struct
be used to determine all possible <function>PQconnectdb</function> options and their
current default values. The return value points to an array of
<structname>PQconninfoOption</structname> structures, which ends with an entry having a null
key-word pointer. Note that the current default values (<structfield>val</structfield> fields)
<structfield>keyword</> pointer. Note that the current default values
(<structfield>val</structfield> fields)
will depend on environment variables and other context.
Callers must treat the connection options data as read-only.
</para>
......@@ -527,7 +544,8 @@ void PQfinish(PGconn *conn);
Note that even if the server connection attempt fails (as
indicated by <function>PQstatus</function>), the application should call <function>PQfinish</function>
to free the memory used by the <structname>PGconn</structname> object.
The <structname>PGconn</> pointer should not be used after <function>PQfinish</function> has been called.
The <structname>PGconn</> pointer must not be used again after
<function>PQfinish</function> has been called.
</para>
</listitem>
</varlistentry>
......@@ -584,12 +602,23 @@ PostgresPollingStatusType PQresetPoll(PGconn *conn);
</variablelist>
</para>
</sect1>
<sect1 id="libpq-status">
<title>Connection Status Functions</title>
<para>
These functions may be used to interrogate the status
of an existing database connection object.
</para>
<tip>
<para>
<indexterm><primary>libpq-fe.h</></>
<indexterm><primary>libpq-int.h</></>
<application>libpq</application> application programmers should be careful to
maintain the <structname>PGconn</structname> abstraction. Use the accessor functions below to get
maintain the <structname>PGconn</structname> abstraction. Use the accessor
functions described below to get
at the contents of <structname>PGconn</structname>. Avoid directly referencing the fields of the
<structname>PGconn</> structure because they are subject to change in the future.
(Beginning in <productname>PostgreSQL</productname> release 6.4, the
......@@ -597,6 +626,12 @@ definition of the <type>struct</type> behind <structname>PGconn</> is not even p
If you have old code that accesses <structname>PGconn</structname> fields directly, you can keep using it
by including <filename>libpq-int.h</filename> too, but you are encouraged to fix the code
soon.)
</para>
</tip>
<para>
The following functions return parameter values established at connection.
These values are fixed for the life of the <structname>PGconn</> object.
<variablelist>
<varlistentry>
......@@ -608,12 +643,6 @@ soon.)
char *PQdb(const PGconn *conn);
</synopsis>
</para>
<para>
<function>PQdb</> and the next several functions return the values established
at connection. These values are fixed for the life of the <structname>PGconn</>
object.
</para>
</listitem>
</varlistentry>
......@@ -691,7 +720,14 @@ char *PQoptions(const PGconn *conn);
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
The following functions return status data that can change as operations
are executed on the <structname>PGconn</> object.
<variablelist>
<varlistentry>
<term><function>PQstatus</function></term>
<listitem>
......@@ -728,6 +764,91 @@ ConnStatusType PQstatus(const PGconn *conn);
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQtransactionStatus</function></term>
<listitem>
<para>
Returns the current in-transaction status of the server.
<synopsis>
PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
</synopsis>
The status can be <literal>PQTRANS_IDLE</literal> (currently idle),
<literal>PQTRANS_ACTIVE</literal> (a command is in progress),
<literal>PQTRANS_INTRANS</literal> (idle, in a valid transaction block),
or <literal>PQTRANS_INERROR</literal> (idle, in a failed transaction block).
<literal>PQTRANS_UNKNOWN</literal> is reported if the connection is bad.
<literal>PQTRANS_ACTIVE</literal> is reported only when a query
has been sent to the server and not yet completed.
</para>
<caution>
<para>
<function>PQtransactionStatus</> will give incorrect results when using
a <productname>PostgreSQL</> 7.3 server that has <literal>AUTOCOMMIT</>
set to <literal>OFF</>. The server-side autocommit feature has been
deprecated and does not exist in later server versions.
</para>
</caution>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQparameterStatus</function></term>
<listitem>
<para>
Looks up a current parameter setting of the server.
<synopsis>
const char *PQparameterStatus(const PGconn *conn, const char *paramName);
</synopsis>
Certain parameter values are reported by the server automatically at
connection startup or whenever their values change.
<function>PQparameterStatus</> can be used to interrogate these settings.
It returns the current value of a parameter if known, or NULL if the parameter
is not known.
</para>
<para>
Parameters reported as of the current release include
<literal>server_version</> (cannot change after startup);
<literal>server_encoding</> (also not presently changeable after start);
<literal>client_encoding</>, and
<literal>DateStyle</>.
</para>
<para>
Pre-3.0-protocol servers do not report parameter settings,
but <application>libpq</> includes logic to obtain values for
<literal>server_version</>, <literal>server_encoding</>, and
<literal>client_encoding</>. Applications are encouraged to use
<function>PQparameterStatus</> rather than ad-hoc code to determine these
values. (Beware however that on a pre-3.0 connection, changing
<literal>client_encoding</> via <command>SET</> after connection startup
will not be reflected by <function>PQparameterStatus</>.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQprotocolVersion</function></term>
<listitem>
<para>
Interrogates the frontend/backend protocol being used.
<synopsis>
int PQprotocolVersion(const PGconn *conn);
</synopsis>
Applications may wish to use this to determine whether certain features
are supported.
Currently, the possible values are 2 (2.0 protocol), 3 (3.0 protocol),
or zero (connection bad). This will not change after connection
startup is complete, but it could theoretically change during a reset.
The 3.0 protocol will normally be used when communicating with
<productname>PostgreSQL</> 7.4 or later servers; pre-7.4 servers support
only protocol 2.0. (Protocol 1.0 is obsolete and not supported by libpq.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQerrorMessage</function></term>
<listitem>
......@@ -757,7 +878,8 @@ char *PQerrorMessage(const PGconn* conn);
Obtains the file descriptor number of the connection socket to
the server. A valid descriptor will be greater than or equal
to 0; a result of -1 indicates that no server connection is
currently open.
currently open. (This will not change during normal operation,
but could change during connection setup or reset.)
<synopsis>
int PQsocket(const PGconn *conn);
</synopsis>
......@@ -812,9 +934,10 @@ SSL *PQgetssl(const PGconn *conn);
</listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
</variablelist>
</para>
</sect1>
<sect1 id="libpq-exec">
<title>Command Execution Functions</title>
......@@ -828,6 +951,7 @@ SQL queries and commands.
<sect2 id="libpq-exec-main">
<title>Main Functions</title>
<para>
<variablelist>
<varlistentry>
<term><function>PQexec</function></term>
......@@ -836,8 +960,7 @@ SQL queries and commands.
Submits a command to the server
and waits for the result.
<synopsis>
PGresult *PQexec(PGconn *conn,
const char *command);
PGresult *PQexec(PGconn *conn, const char *command);
</synopsis>
</para>
......@@ -854,21 +977,95 @@ PGresult *PQexec(PGconn *conn,
</varlistentry>
</variablelist>
It is allowed to include multiple SQL commands (separated by semicolons) in
the command string. Multiple queries sent in a single <function>PQexec</>
call are processed in a single transaction, unless there are explicit
BEGIN/COMMIT commands included in the query string to divide it into multiple
transactions. Note however that the returned <structname>PGresult</structname>
structure describes only the result of the last command executed from the
string. Should one of the commands fail, processing of the string stops with
it and the returned <structname>PGresult</structname> describes the error
condition.
</para>
<para>
<variablelist>
<varlistentry>
<term><function>PQexecParams</function></term>
<listitem>
<para>
Submits a command to the server and waits for the result,
with the ability to pass parameters separately from the SQL
command text.
<synopsis>
PGresult *PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
</synopsis>
</para>
<para>
<function>PQexecParams</> is like <function>PQexec</>, but offers additional
functionality: parameter values can be specified separately from the command
string proper, and query results can be requested in either text or binary
format. <function>PQexecParams</> is supported only in protocol 3.0 and later
connections; it will fail when using protocol 2.0.
</para>
<para>
If parameters are used, they are referred to in the command string
as <literal>$1</>, <literal>$2</>, etc.
<parameter>nParams</> is the number of parameters supplied; it is the length
of the arrays <parameter>paramTypes[]</>, <parameter>paramValues[]</>,
<parameter>paramLengths[]</>, and <parameter>paramFormats[]</>. (The
array pointers may be NULL when <parameter>nParams</> is zero.)
<parameter>paramTypes[]</> specifies, by OID, the datatypes to be assigned to
the parameter symbols. If <parameter>paramTypes</> is NULL, or any particular
element in the array is zero, the backend assigns a datatype to the parameter
symbol in the same way it would do for an untyped literal string.
<parameter>paramValues[]</> specifies the actual values of the parameters.
A NULL pointer in this array means the corresponding parameter is NULL;
otherwise the pointer points to a zero-terminated text string (for text
format) or binary data in the format expected by the backend (for binary
format).
<parameter>paramLengths[]</> specifies the actual data lengths of
binary-format parameters. It is ignored for NULL parameters and text-format
parameters. The array pointer may be NULL when there are no binary
parameters.
<parameter>paramFormats[]</> specifies whether parameters are text (put a zero
in the array) or binary (put a one in the array). If the array pointer is
NULL then all parameters are presumed to be text.
<parameter>resultFormat</> is zero to obtain results in text format, or one to
obtain results in binary format. (There is not currently a provision to
obtain different result columns in different formats, although that is
possible in the underlying protocol.)
</para>
</listitem>
</varlistentry>
</variablelist>
The primary advantage of <function>PQexecParams</> over <function>PQexec</>
is that parameter values may be separated from the command string, thus
avoiding the need for tedious and error-prone quoting and escaping.
Unlike <function>PQexec</>, <function>PQexecParams</> allows at most one SQL
command in the given string. (There can be semicolons in it, but not more
than one nonempty command.) This is a limitation of the underlying protocol,
but has some usefulness as an extra defense against SQL-injection attacks.
</para>
<para>
The <function>PGresult</function> structure encapsulates the result
The <structname>PGresult</structname> structure encapsulates the result
returned by the server.
<application>libpq</application> application programmers should be careful to
maintain the <structname>PGresult</structname> abstraction. Use the accessor functions below to get
at the contents of <structname>PGresult</structname>. Avoid directly referencing the fields of the
<structname>PGresult</structname> structure because they are subject to change in the future.
</para>
<para>
Multiple queries sent in a single
function call are processed in a single transaction, unless there are explicit
BEGIN/COMMIT commands included in the query string to divide it into multiple
transactions.
</para>
<variablelist>
<varlistentry>
......@@ -902,7 +1099,8 @@ ExecStatusType PQresultStatus(const PGresult *res);
<varlistentry>
<term><literal>PGRES_TUPLES_OK</literal></term>
<listitem>
<para>The query successfully executed.</para>
<para>Successful completion of a command returning data (such as
a <command>SELECT</> or <command>SHOW</>).</para>
</listitem>
</varlistentry>
......@@ -930,7 +1128,7 @@ ExecStatusType PQresultStatus(const PGresult *res);
<varlistentry>
<term><literal>PGRES_NONFATAL_ERROR</literal></term>
<listitem>
<para>A nonfatal error occurred.</para>
<para>A nonfatal error (a notice or warning) occurred.</para>
</listitem>
</varlistentry>
......@@ -948,8 +1146,15 @@ the query. Note that a <command>SELECT</command> command that happens
to retrieve zero rows still shows <literal>PGRES_TUPLES_OK</literal>.
<literal>PGRES_COMMAND_OK</literal> is for commands that can never
return rows (<command>INSERT</command>, <command>UPDATE</command>,
etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> often
exposes a bug in the client software.
etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> may indicate
a bug in the client software.
</para>
<para>
A result of status <symbol>PGRES_NONFATAL_ERROR</symbol> will never be
returned directly by <function>PQexec</function> or other query
execution functions; results of this kind are instead passed to the notice
processor (see <xref linkend="libpq-notice-processing">).
</para>
</listitem>
</varlistentry>
......@@ -976,6 +1181,7 @@ if there was no error.
<synopsis>
char *PQresultErrorMessage(const PGresult *res);
</synopsis>
If there was an error, the returned string will include a trailing newline.
</para>
<para>
......@@ -991,6 +1197,39 @@ when you want to know the status from the latest operation on the connection.
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQresultErrorField</function></term>
<listitem>
<para>
Returns an individual field of an error report.
<synopsis>
char *PQresultErrorField(const PGresult *res, int fieldcode);
</synopsis>
<parameter>fieldcode</> is an error field identifier defined by the
<productname>PostgreSQL</> protocol (see <xref
linkend="protocol-error-fields">), for example <literal>'C'</> for
the SQLSTATE error code. NULL is returned if the
<structname>PGresult</structname> is not an error or warning result,
or does not include the specified field. Field values will normally
not include a trailing newline.
</para>
<para>
Errors generated internally by libpq will have severity and primary message,
but typically no other fields. Errors returned by a pre-3.0-protocol server
will include severity and primary message, and sometimes a detail message,
but no other fields.
</para>
<para>
Note that error fields are only available from
<structname>PGresult</structname> objects, not
<structname>PGconn</structname> objects; there is no
<function>PQerrorField</function> function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQclear</function></term>
<listitem>
......@@ -1008,7 +1247,7 @@ void PQclear(PQresult *res);
need it; it does not go away when you issue a new command,
nor even if you close the connection. To get rid of it,
you must call <function>PQclear</function>. Failure to do this will
result in memory leaks in your client application.
result in memory leaks in your application.
</para>
</listitem>
</varlistentry>
......@@ -1035,161 +1274,20 @@ as with a <structname>PGresult</structname> returned by <application>libpq</appl
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-exec-escape-string">
<title>Escaping Strings for Inclusion in SQL Commands</title>
<indexterm zone="libpq-exec-escape-string"><primary>escaping strings</></>
<para>
<function>PQescapeString</function> escapes a string for use within an SQL commmand.
<synopsis>
size_t PQescapeString (char *to, const char *from, size_t length);
</synopsis>
</para>
<para>
If you want to use strings that have been received
from a source that is not trustworthy (for example, because a random user
entered them), you should not directly include them in SQL
commands for security reasons. Instead, you have to escape certain
characters that are otherwise interpreted specially by the SQL parser.
<function>PQescapeString</> performs this operation.
</para>
<para>
The parameter <parameter>from</> points to the first character of the string that
is to be escaped, and the <parameter>length</> parameter counts the
number of characters in this string. (A terminating zero byte is
neither necessary nor counted.) <parameter>to</> shall point to a
buffer that is able to hold at least one more character than twice
the value of <parameter>length</>, otherwise the behavior is
undefined. A call to <function>PQescapeString</> writes an escaped
version of the <parameter>from</> string to the <parameter>to</>
buffer, replacing special characters so that they cannot cause any
harm, and adding a terminating zero byte. The single quotes that
must surround <productname>PostgreSQL</> string literals are not part of the result
string.
</para>
<para>
<function>PQescapeString</> returns the number of characters written
to <parameter>to</>, not including the terminating zero byte.
Behavior is undefined when the <parameter>to</> and <parameter>from</>
strings overlap.
</para>
</sect2>
<sect2 id="libpq-exec-escape-bytea">
<title>Escaping Binary Strings for Inclusion in SQL Commands</title>
<indexterm zone="libpq-exec-escape-bytea">
<primary>escaping binary strings</primary>
</indexterm>
<variablelist>
<varlistentry>
<term><function>PQescapeBytea</function></term>
<listitem>
<para>
Escapes binary data for use within an SQL command with the type <type>bytea</type>.
<synopsis>
unsigned char *PQescapeBytea(const unsigned char *from,
size_t from_length,
size_t *to_length);
</synopsis>
</para>
<para>
Certain byte values <emphasis>must</emphasis> be escaped (but all
byte values <emphasis>may</emphasis> be escaped) when used as part
of a <type>bytea</type> literal in an <acronym>SQL</acronym>
statement. In general, to escape a byte, it is converted into the
three digit octal number equal to the octet value, and preceded by
two backslashes. The single quote (<literal>'</>) and backslash
(<literal>\</>) characters have special alternative escape
sequences. See <xref linkend="datatype-binary"> for more
information. <function>PQescapeBytea</function> performs this
operation, escaping only the minimally required bytes.
</para>
<para>
The <parameter>from</parameter> parameter points to the first
byte of the string that is to be escaped, and the
<parameter>from_length</parameter> parameter reflects the number of
bytes in this binary string. (A terminating zero byte is
neither necessary nor counted.) The <parameter>to_length</parameter>
parameter points to a variable that will hold the resultant
escaped string length. The result string length includes the terminating
zero byte of the result.
</para>
<para>
<function>PQescapeBytea</> returns an escaped version of the
<parameter>from</parameter> parameter binary string in memory
allocated with <function>malloc()</>, and must be freed using
<function>PQfreemem()</>.
The return string has all special characters replaced
so that they can be properly processed by the PostgreSQL string literal
parser, and the <type>bytea</type> input function. A terminating zero
byte is also added. The single quotes that must surround
PostgreSQL string literals are not part of the result string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQunescapeBytea</function></term>
<listitem>
<para>
Converts an escaped string representation of binary data into binary
data --- the reverse of <function>PQescapeBytea</function>.
<synopsis>
unsigned char *PQunescapeBytea(const unsigned char *from, size_t *to_length);
</synopsis>
</para>
<sect2 id="libpq-exec-select-info">
<title>Retrieving Query Result Information</title>
<para>
The <parameter>from</parameter> parameter points to an escaped string
such as might be returned by <function>PQgetvalue</function> when applied to a
<type>bytea</type> column. <function>PQunescapeBytea</function> converts
this string representation into its binary representation.
It returns a pointer to a buffer allocated with
<function>malloc()</function>, or null on error, and puts the size of
the buffer in <parameter>to_length</parameter>. The memory must be
freed using <function>PQfreemem()</>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQfreemem</function></term>
<listitem>
<para>
Frees memory allocated by <application>libpq</>
<synopsis>
void PQfreemem(void *ptr);
</synopsis>
These functions are used to extract information from a
<structname>PGresult</structname> object that represents a successful
query result (that is, one that has status
<literal>PGRES_TUPLES_OK</literal>). For objects with other status
values they will act as though the result has zero rows and zero columns.
</para>
<para>
Frees memory allocated by <application>libpq</>, particularly
<function>PQescapeBytea</function>,
<function>PQunescapeBytea</function>,
and <function>PQnotifies</function>.
It is needed by Win32, which can not free memory across
DLL's, unless multithreaded DLL's (/MD in VC6) are used.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-exec-select-info">
<title>Retrieving Query Result Information</title>
<variablelist>
<varlistentry>
<term><function>PQntuples</function></term>
......@@ -1228,6 +1326,10 @@ char *PQfname(const PGresult *res,
int column_number);
</synopsis>
</para>
<para>
NULL is returned if the column number is out of range.
</para>
</listitem>
</varlistentry>
......@@ -1250,13 +1352,83 @@ int PQfnumber(const PGresult *res,
</varlistentry>
<varlistentry>
<term><function>PQftype</function></term>
<term><function>PQftable</function></term>
<listitem>
<para>
Returns the column data type associated with the
given column number. The integer returned is the
internal OID number of the type. Column numbers start
at 0.
Returns the OID of the table from which the given column was fetched.
Column numbers start at 0.
<synopsis>
Oid PQftable(const PGresult *res,
int column_number);
</synopsis>
</para>
<para>
<literal>InvalidOid</> is returned if the column number is out of range,
or if the specified column is not a simple reference to a table column,
or when using pre-3.0 protocol.
You can query the system table <literal>pg_class</literal> to determine
exactly which table is referenced.
</para>
<para>
The type <type>Oid</type> and the constant
<literal>InvalidOid</literal> will be defined when you include
the <application>libpq</application> header file. They will
both be some integer type.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQftablecol</function></term>
<listitem>
<para>
Returns the column number (within its table) of the column making up
the specified query result column.
Result column numbers start at 0.
<synopsis>
int PQftablecol(const PGresult *res,
int column_number);
</synopsis>
</para>
<para>
Zero is returned if the column number is out of range,
or if the specified column is not a simple reference to a table column,
or when using pre-3.0 protocol.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQfformat</function></term>
<listitem>
<para>
Returns the format code indicating the format of the given column.
Column numbers start at 0.
<synopsis>
int PQfformat(const PGresult *res,
int column_number);
</synopsis>
</para>
<para>
Format code zero indicates textual data representation, while format
code one indicates binary representation. (Other codes are reserved
for future definition.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQftype</function></term>
<listitem>
<para>
Returns the data type associated with the
given column number. The integer returned is the
internal OID number of the type. Column numbers start
at 0.
<synopsis>
Oid PQftype(const PGresult *res,
int column_number);
......@@ -1265,7 +1437,7 @@ Oid PQftype(const PGresult *res,
<para>
You can query the system table <literal>pg_type</literal> to obtain
the name and properties of the various data types. The <acronym>OID</acronym>s
the names and properties of the various data types. The <acronym>OID</acronym>s
of the built-in data types are defined in the file <filename>src/include/catalog/pg_type.h</filename>
in the source tree.
</para>
......@@ -1276,7 +1448,7 @@ in the source tree.
<term><function>PQfmod</function></term>
<listitem>
<para>
Returns the type-specific modification data of the column
Returns the type modifier of the column
associated with the given column number.
Column numbers start at 0.
<synopsis>
......@@ -1284,6 +1456,13 @@ int PQfmod(const PGresult *res,
int column_number);
</synopsis>
</para>
<para>
The interpretation of modifier values is type-specific; they typically
indicate precision or size limits. The value -1 is used to indicate
<quote>no information available</>. Most data types do not use modifiers,
in which case the value is always -1.
</para>
</listitem>
</varlistentry>
......@@ -1301,9 +1480,10 @@ int PQfsize(const PGresult *res,
</para>
<para>
<function>PQfsize</> returns the space allocated for this column in a database
row, in other words the size of the server's binary representation
of the data type. -1 is returned if the column has a variable size.
<function>PQfsize</> returns the space allocated for this column in a database
row, in other words the size of the server's internal representation
of the data type. (Accordingly, it is not really very useful to clients.)
A negative value indicates the data type is variable-length.
</para>
</listitem>
</varlistentry>
......@@ -1312,33 +1492,31 @@ int PQfsize(const PGresult *res,
<term><function>PQbinaryTuples</function></term>
<listitem>
<para>
Returns 1 if the <structname>PGresult</> contains binary row data
and 0 if it contains text data.
Returns 1 if the <structname>PGresult</> contains binary data
and 0 if it contains text data.
<synopsis>
int PQbinaryTuples(const PGresult *res);
</synopsis>
</para>
<para>
Currently, binary row data can only be returned by a query that
extracts data from a binary cursor.
This function is deprecated (except for its use in connection with
<command>COPY</>), because it is possible for a single
<structname>PGresult</>
to contain text data in some columns and binary data in others.
<function>PQfformat()</> is preferred. <function>PQbinaryTuples</>
returns 1 only if all columns of the result are binary (format 1).
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-exec-select-values">
<title>Retrieving Query Result Values</title>
<variablelist>
<varlistentry>
<term><function>PQgetvalue</function></term>
<listitem>
<para>
Returns a single column value of one row
Returns a single field value of one row
of a <structname>PGresult</structname>.
Row and colums indices start at 0.
Row and column numbers start at 0.
<synopsis>
char* PQgetvalue(const PGresult *res,
int row_number,
......@@ -1347,15 +1525,18 @@ char* PQgetvalue(const PGresult *res,
</para>
<para>
For most queries, the value returned by <function>PQgetvalue</function>
For data in text format, the value returned by <function>PQgetvalue</function>
is a null-terminated character string representation
of the column value. But if <function>PQbinaryTuples</function> returns 1,
the value returned by <function>PQgetvalue</function> is the binary
representation of the
type in the internal format of the backend server
(but not including the size word, if the column is variable-length).
It is then the programmer's responsibility to cast and
convert the data to the correct C type.
of the field value. For data in binary format, the value is in the binary
representation determined by the datatype's <function>typsend</> and
<function>typreceive</> functions. (The value is actually followed by
a zero byte in this case too, but that is not ordinarily useful, since
the value is likely to contain embedded nulls.)
</para>
<para>
An empty string is returned if the field value is NULL. See
<function>PQgetisnull</> to distinguish NULLs from empty-string values.
</para>
<para>
......@@ -1373,7 +1554,7 @@ be used past the lifetime of the <structname>PGresult</structname> structure i
<term><function>PQgetisnull</function></term>
<listitem>
<para>
Tests a column for a null value.
Tests a field for a null value.
Row and column numbers start at 0.
<synopsis>
int PQgetisnull(const PGresult *res,
......@@ -1383,10 +1564,9 @@ int PQgetisnull(const PGresult *res,
</para>
<para>
This function returns 1 if the column is null and 0 if
it contains a non-null value. (Note that <function>PQgetvalue</function>
will return an empty string, not a null pointer, for a null
column.)
This function returns 1 if the field is null and 0 if
it contains a non-null value. (Note that <function>PQgetvalue</function>
will return an empty string, not a null pointer, for a null field.)
</para>
</listitem>
</varlistentry>
......@@ -1395,7 +1575,7 @@ int PQgetisnull(const PGresult *res,
<term><function>PQgetlength</function></term>
<listitem>
<para>
Returns the length of a column value in bytes.
Returns the actual length of a field value in bytes.
Row and column numbers start at 0.
<synopsis>
int PQgetlength(const PGresult *res,
......@@ -1406,8 +1586,10 @@ int PQgetlength(const PGresult *res,
<para>
This is the actual data length for the particular data value, that is, the
size of the object pointed to by <function>PQgetvalue</function>. Note that for character-represented
values, this size has little to do with the binary size reported by <function>PQfsize</function>.
size of the object pointed to by <function>PQgetvalue</function>. For text
data format this is the same as <function>strlen()</>. For binary format
this is essential information. Note that one should <emphasis>not</> rely
on <function>PQfsize</function> to obtain the actual data length.
</para>
</listitem>
</varlistentry>
......@@ -1440,8 +1622,8 @@ typedef struct {
<para>
This function was formerly used by <application>psql</application>
to print query results, but this is no longer the case and this
function is no longer actively supported.
to print query results, but this is no longer the case. Note that it
assumes all the data is in text format.
</para>
</listitem>
</varlistentry>
......@@ -1451,17 +1633,27 @@ function is no longer actively supported.
<sect2 id="libpq-exec-nonselect">
<title>Retrieving Result Information for Other Commands</title>
<para>
These functions are used to extract information from
<structname>PGresult</structname> objects that are not <command>SELECT</>
results.
</para>
<variablelist>
<varlistentry>
<term><function>PQcmdStatus</function></term>
<listitem>
<para>
Returns the command status string from the SQL command that
Returns the command status tag from the SQL command that
generated the <structname>PGresult</structname>.
<synopsis>
char * PQcmdStatus(PGresult *res);
</synopsis>
</para>
<para>
Commonly this is just the name of the command, but it may include additional
data such as the number of rows processed.
</para>
</listitem>
</varlistentry>
......@@ -1477,7 +1669,9 @@ char * PQcmdTuples(PGresult *res);
<para>
If the <acronym>SQL</acronym> command that generated the
<structname>PGresult</structname> was <command>INSERT</>, <command>UPDATE</>, or <command>DELETE</command>, this returns a
<structname>PGresult</structname> was <command>INSERT</>,
<command>UPDATE</>, <command>DELETE</command>, <command>MOVE</>,
or <command>FETCH</>, this returns a
string containing the number of rows affected. If the
command was anything else, it returns the empty string.
</para>
......@@ -1496,13 +1690,6 @@ char * PQcmdTuples(PGresult *res);
Oid PQoidValue(const PGresult *res);
</synopsis>
</para>
<para>
The type <type>Oid</type> and the constant
<literal>InvalidOid</literal> will be defined if you include
the <application>libpq</application> header file. They will
both be some integer type.
</para>
</listitem>
</varlistentry>
......@@ -1523,14 +1710,184 @@ char * PQoidStatus(const PGresult *res);
</para>
<para>
This function is deprecated in favor of <function>PQoidValue</function>
and is not thread-safe.
This function is deprecated in favor of <function>PQoidValue</function>.
It is not thread-safe.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-exec-escape-string">
<title>Escaping Strings for Inclusion in SQL Commands</title>
<indexterm zone="libpq-exec-escape-string"><primary>escaping strings</></>
<para>
<function>PQescapeString</function> escapes a string for use within an SQL
commmand. This is useful when inserting data values as literal constants
in SQL commands. Certain characters (such as quotes and backslashes) must
be escaped to prevent them from being interpreted specially by the SQL parser.
<function>PQescapeString</> performs this operation.
</para>
<tip>
<para>
It is especially important to do proper escaping when handling strings that
were received from an untrustworthy source. Otherwise there is a security
risk: you are vulnerable to <quote>SQL injection</> attacks wherein unwanted
SQL commands are fed to your database.
</para>
</tip>
<para>
Note that it is not necessary nor correct to do escaping when a data
value is passed as a separate parameter in <function>PQexecParams</> or
<function>PQsendQueryParams</>.
<synopsis>
size_t PQescapeString (char *to, const char *from, size_t length);
</synopsis>
</para>
<para>
The parameter <parameter>from</> points to the first character of the string
that
is to be escaped, and the <parameter>length</> parameter gives the
number of characters in this string. (A terminating zero byte is
neither necessary nor counted.) <parameter>to</> shall point to a
buffer that is able to hold at least one more character than twice
the value of <parameter>length</>, otherwise the behavior is
undefined. A call to <function>PQescapeString</> writes an escaped
version of the <parameter>from</> string to the <parameter>to</>
buffer, replacing special characters so that they cannot cause any
harm, and adding a terminating zero byte. The single quotes that
must surround <productname>PostgreSQL</> string literals are not
included in the result string; they should be provided in the SQL
command that the result is inserted into.
</para>
<para>
<function>PQescapeString</> returns the number of characters written
to <parameter>to</>, not including the terminating zero byte.
</para>
<para>
Behavior is undefined if the <parameter>to</> and <parameter>from</>
strings overlap.
</para>
</sect2>
<sect2 id="libpq-exec-escape-bytea">
<title>Escaping Binary Strings for Inclusion in SQL Commands</title>
<indexterm zone="libpq-exec-escape-bytea">
<primary>escaping binary strings</primary>
</indexterm>
<variablelist>
<varlistentry>
<term><function>PQescapeBytea</function></term>
<listitem>
<para>
Escapes binary data for use within an SQL command with the type
<type>bytea</type>. As with <function>PQescapeString</function>,
this is only used when inserting data directly into an SQL command string.
<synopsis>
unsigned char *PQescapeBytea(const unsigned char *from,
size_t from_length,
size_t *to_length);
</synopsis>
</para>
<para>
Certain byte values <emphasis>must</emphasis> be escaped (but all
byte values <emphasis>may</emphasis> be escaped) when used as part
of a <type>bytea</type> literal in an <acronym>SQL</acronym>
statement. In general, to escape a byte, it is converted into the
three digit octal number equal to the octet value, and preceded by
two backslashes. The single quote (<literal>'</>) and backslash
(<literal>\</>) characters have special alternative escape
sequences. See <xref linkend="datatype-binary"> for more
information. <function>PQescapeBytea</function> performs this
operation, escaping only the minimally required bytes.
</para>
<para>
The <parameter>from</parameter> parameter points to the first
byte of the string that is to be escaped, and the
<parameter>from_length</parameter> parameter gives the number of
bytes in this binary string. (A terminating zero byte is
neither necessary nor counted.) The <parameter>to_length</parameter>
parameter points to a variable that will hold the resultant
escaped string length. The result string length includes the terminating
zero byte of the result.
</para>
<para>
<function>PQescapeBytea</> returns an escaped version of the
<parameter>from</parameter> parameter binary string in memory
allocated with <function>malloc()</>. This memory must be freed
using <function>PQfreemem()</> when the result is no longer needed.
The return string has all special characters replaced
so that they can be properly processed by the PostgreSQL string literal
parser, and the <type>bytea</type> input function. A terminating zero
byte is also added. The single quotes that must surround
PostgreSQL string literals are not part of the result string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQunescapeBytea</function></term>
<listitem>
<para>
Converts an escaped string representation of binary data into binary
data --- the reverse of <function>PQescapeBytea</function>.
This is needed when retrieving <type>bytea</type> data in text format,
but not when retrieving it in binary format.
<synopsis>
unsigned char *PQunescapeBytea(const unsigned char *from, size_t *to_length);
</synopsis>
</para>
<para>
The <parameter>from</parameter> parameter points to an escaped string
such as might be returned by <function>PQgetvalue</function> when applied to a
<type>bytea</type> column. <function>PQunescapeBytea</function> converts
this string representation into its binary representation.
It returns a pointer to a buffer allocated with
<function>malloc()</function>, or null on error, and puts the size of
the buffer in <parameter>to_length</parameter>. The result must be
freed using <function>PQfreemem()</> when it is no longer needed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQfreemem</function></term>
<listitem>
<para>
Frees memory allocated by <application>libpq</>.
<synopsis>
void PQfreemem(void *ptr);
</synopsis>
</para>
<para>
Frees memory allocated by <application>libpq</>, particularly
<function>PQescapeBytea</function>,
<function>PQunescapeBytea</function>,
and <function>PQnotifies</function>.
It is needed by Win32, which can not free memory across
DLL's, unless multithreaded DLL's (/MD in VC6) are used.
On other platforms it is the same as <function>free()</>.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="libpq-async">
......@@ -1573,70 +1930,11 @@ discarded by <function>PQexec</function>.
Applications that do not like these limitations can instead use the
underlying functions that <function>PQexec</function> is built from:
<function>PQsendQuery</function> and <function>PQgetResult</function>.
</para>
<para>
Older programs that used this functionality as well as
<function>PQputline</function> and <function>PQputnbytes</function>
could block waiting to send data to the server. To
address that issue, the function <function>PQsetnonblocking</function>
was added.
Old applications can neglect to use <function>PQsetnonblocking</function>
and get the old potentially blocking behavior. Newer programs can use
<function>PQsetnonblocking</function> to achieve a completely nonblocking
connection to the server.
There is also <function>PQsendQueryParams</function>, which can be
used with <function>PQgetResult</function> to duplicate the functionality
of <function>PQexecParams</function>.
<variablelist>
<varlistentry>
<term><function>PQsetnonblocking</function></term>
<listitem>
<para>
Sets the nonblocking status of the connection.
<synopsis>
int PQsetnonblocking(PGconn *conn, int arg);
</synopsis>
</para>
<para>
Sets the state of the connection to nonblocking if <parameter>arg</parameter> is 1 and
blocking if <parameter>arg</parameter> is 0. Returns 0 if OK, -1 if error.
</para>
<para>
In the nonblocking state, calls to
<function>PQputline</function>, <function>PQputnbytes</function>,
<function>PQsendQuery</function>, and <function>PQendcopy</function>
will not block but instead return an error if they need to be called
again.
</para>
<para>
When a database connection has been set to nonblocking mode and
<function>PQexec</function> is called, it will temporarily set the state
of the connection to blocking until the <function>PQexec</function> call
completes.
</para>
<para>
More of <application>libpq</application> is expected to be made safe for
the nonblocking mode in the future.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQisnonblocking</function></term>
<listitem>
<para>
Returns the blocking status of the database connection.
<synopsis>
int PQisnonblocking(const PGconn *conn);
</synopsis>
</para>
<para>
Returns 1 if the connection is set to nonblocking mode and
0 if blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQsendQuery</function></term>
<listitem>
......@@ -1646,12 +1944,9 @@ int PQisnonblocking(const PGconn *conn);
successfully dispatched and 0 if not (in which case, use
<function>PQerrorMessage</> to get more information about the failure).
<synopsis>
int PQsendQuery(PGconn *conn,
const char *command);
int PQsendQuery(PGconn *conn, const char *command);
</synopsis>
</para>
<para>
After successfully calling <function>PQsendQuery</function>, call
<function>PQgetResult</function> one or more
times to obtain the results. <function>PQsendQuery</function> may not be called
......@@ -1661,12 +1956,41 @@ int PQsendQuery(PGconn *conn,
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQsendQueryParams</function></term>
<listitem>
<para>
Submits a command and separate parameters to the server without
waiting for the result(s).
<synopsis>
int PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
</synopsis>
This is equivalent to <function>PQsendQuery</function> except that
query parameters can be specified separately from the query string.
The function's parameters are handled identically to
<function>PQexecParams</function>. Like
<function>PQexecParams</function>, it will not work on 2.0-protocol
connections, and it allows only one command in the query string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQgetResult</function></term>
<listitem>
<para>
Waits for the next result from a prior <function>PQsendQuery</function>,
and return it. A null pointer is returned when the command is complete
Waits for the next result from a prior
<function>PQsendQuery</function> or
<function>PQsendQueryParams</function>,
and returns it. A null pointer is returned when the command is complete
and there will be no more results.
<synopsis>
PGresult *PQgetResult(PGconn *conn);
......@@ -1697,8 +2021,8 @@ 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 <function>PQgetResult</function> will
still cause the client to block until the server completes the
next <acronym>SQL</acronym> command. This can be avoided by proper use of three more
functions:
next <acronym>SQL</acronym> command. This can be avoided by proper use of two
more functions:
<variablelist>
<varlistentry>
......@@ -1714,7 +2038,8 @@ int PQconsumeInput(PGconn *conn);
<para>
<function>PQconsumeInput</function> normally returns 1 indicating <quote>no error</quote>,
but returns 0 if there was some kind of trouble (in which case
<function>PQerrorMessage</function> can be used). Note that the result does not say
<function>PQerrorMessage</function> can be consulted). Note that the result
does not say
whether any input data was actually collected. After calling
<function>PQconsumeInput</function>, the application may check
<function>PQisBusy</function> and/or <function>PQnotifies</function> to see if
......@@ -1750,35 +2075,13 @@ state will never end.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQflush</function></term>
<listitem>
<para>
Attempts to flush any data queued 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).
<synopsis>
int PQflush(PGconn *conn);
</synopsis>
</para>
<para>
<function>PQflush</function> needs to be called on a nonblocking connection
before calling <function>select()</function> to determine if a response has
arrived. If 0 is returned it ensures that there is no data queued to the
server that has not actually been sent. Only applications that have used
<function>PQsetnonblocking</function> have a need for this.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
A typical application using these functions will have a main loop that uses
<function>select()</function> to wait for all the conditions that it must
<function>select()</function> or <function>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 <function>select()</function> means readable data on the file
descriptor identified by <function>PQsocket</function>.
......@@ -1789,13 +2092,6 @@ if <function>PQisBusy</function> returns false (0). It can also call
<function>PQnotifies</function> to detect <command>NOTIFY</> messages (see <xref linkend="libpq-notify">).
</para>
<para>
Nonblocking connections (that have used <function>PQsetnonblocking</function>)
should not use <function>select()</function> until <function>PQflush</function>
has returned 0 indicating that there is no buffered data waiting to be sent
to the server.
</para>
<para>
A client that uses <function>PQsendQuery</function>/<function>PQgetResult</function>
can also attempt to cancel a command that is still being processed by the server.
......@@ -1843,6 +2139,89 @@ interactive cancellation of commands that it issues through <function>PQexec</fu
</variablelist>
</para>
<para>
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.
<variablelist>
<varlistentry>
<term><function>PQsetnonblocking</function></term>
<listitem>
<para>
Sets the nonblocking status of the connection.
<synopsis>
int PQsetnonblocking(PGconn *conn, int arg);
</synopsis>
</para>
<para>
Sets the state of the connection to nonblocking if
<parameter>arg</parameter> is 1, or
blocking if <parameter>arg</parameter> is 0. Returns 0 if OK, -1 if error.
</para>
<para>
In the nonblocking state, calls to
<function>PQsendQuery</function>,
<function>PQputline</function>, <function>PQputnbytes</function>,
and <function>PQendcopy</function>
will not block but instead return an error if they need to be called
again.
</para>
<para>
Note that <function>PQexec</function> does not honor nonblocking mode;
if it is called, it will act in blocking fashion anyway.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQisnonblocking</function></term>
<listitem>
<para>
Returns the blocking status of the database connection.
<synopsis>
int PQisnonblocking(const PGconn *conn);
</synopsis>
</para>
<para>
Returns 1 if the connection is set to nonblocking mode and
0 if blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQflush</function></term>
<listitem>
<para>
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).
<synopsis>
int PQflush(PGconn *conn);
</synopsis>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
After sending any command or data on a nonblocking connection, call
<function>PQflush</function>. If it returns 1, wait for the socket to be
write-ready and call it again; repeat until it returns 0. Once
<function>PQflush</function> returns 0, wait for the socket to be read-ready
and then read the response as described above.
</para>
</sect1>
<sect1 id="libpq-fastpath">
......@@ -1850,9 +2229,17 @@ interactive cancellation of commands that it issues through <function>PQexec</fu
<para>
<productname>PostgreSQL</productname> provides a fast-path interface to send
function calls to the server. This is a trapdoor into system internals and
can be a potential security hole. Most users will not need this feature.
simple function calls to the server.
</para>
<tip>
<para>
This interface is somewhat obsolete, as one may achieve similar performance
and greater functionality by setting up a prepared statement to define the
function call. Then, executing the statement with binary transmission of
parameters and results substitutes for a fast-path function call.
</para>
</tip>
<para>
The function <function>PQfn</function> requests execution of a server
......@@ -1879,25 +2266,42 @@ typedef struct {
<para>
The <parameter>fnid</> argument is the OID of the function to be
executed.
executed. <parameter>args</> and <parameter>nargs</> define the
parameters to be passed to the function; they must match the declared
function argument list. When the <parameter>isint</> field of a
parameter
struct is true,
the <parameter>u.integer</> value is sent to the server as an integer
of the indicated length (this must be 1, 2, or 4 bytes); proper
byte-swapping occurs. When <parameter>isint</> is false, the
indicated number of bytes at <parameter>*u.ptr</> are sent with no
processing; the data must be in the format expected by the server for
binary transmission of the function's argument datatype.
<parameter>result_buf</parameter> is the buffer in which
to place the return value. The caller must have allocated
sufficient space to store the return value. (There is no check!)
The actual result length will be returned in the integer pointed
to by <parameter>result_len</parameter>. If a 4-byte integer result is expected, set
<parameter>result_is_int</parameter> to 1, otherwise set it to 0. (Setting <parameter>result_is_int</parameter> to 1
tells <application>libpq</> to byte-swap the value if necessary, so that it is
to by <parameter>result_len</parameter>.
If a 1, 2, or 4-byte integer result is expected, set
<parameter>result_is_int</parameter> to 1, otherwise set it to 0.
Setting <parameter>result_is_int</parameter> to 1
causes <application>libpq</> to byte-swap the value if necessary, so that
it is
delivered as a proper <type>int</type> value for the client machine. When
<parameter>result_is_int</> is 0, the byte string sent by the server is returned
unmodified.)
<parameter>args</> and <parameter>nargs</> specify the arguments to be passed to the function.
<parameter>result_is_int</> is 0, the binary-format byte string sent by
the server is returned unmodified.
</para>
<para>
<function>PQfn</function> always returns a valid <structname>PGresult</structname> pointer. The result status
should be checked before the result is used. The
caller is responsible for freeing the <structname>PGresult</structname> with
<function>PQclear</function> when it is no longer needed.
</para>
<para>
<function>PQfn</function> always returns a valid <structname>PGresult</structname> pointer. The result status
should be checked before the result is used. The
caller is responsible for freeing the <structname>PGresult</structname> with
<function>PQclear</function> when it is no longer needed.
Note that it is not possible to handle NULL arguments, NULL results, nor
set-valued results when using this interface.
</para>
</sect1>
......@@ -1909,7 +2313,7 @@ typedef struct {
<para>
<productname>PostgreSQL</productname> offers asynchronous notification via the
<command>LISTEN</command> and <command>NOTIFY</command> commands. A server-side session registers its interest in a particular
<command>LISTEN</command> and <command>NOTIFY</command> commands. A client session registers its interest in a particular
notification condition with the <command>LISTEN</command> command (and can stop listening
with the <command>UNLISTEN</command> command). All sessions listening on a
particular condition will be notified asynchronously when a <command>NOTIFY</command> command with that
......@@ -1922,7 +2326,7 @@ not necessary for there to be any associated table.
<para>
<application>libpq</application> applications submit <command>LISTEN</command> and <command>UNLISTEN</command>
commands as ordinary SQL command. The arrival of <command>NOTIFY</command>
commands as ordinary SQL commands. The arrival of <command>NOTIFY</command>
messages can subsequently be detected by calling <function>PQnotifies</function>.
</para>
......@@ -1937,18 +2341,30 @@ The function <function>PQnotifies</function>
PGnotify* PQnotifies(PGconn *conn);
typedef struct pgNotify {
char *relname; /* notification name */
char *relname; /* notification condition name */
int be_pid; /* process ID of server process */
char *extra; /* notification parameter */
} PGnotify;
</synopsis>
After processing a <structname>PGnotify</structname> object returned by <function>PQnotifies</function>,
be sure to free it with <function>PQfreemem()</function>.
After processing a <structname>PGnotify</structname> object returned by
<function>PQnotifies</function>, be sure to free it with
<function>PQfreemem</function>. It is sufficient to free the
<structname>PGnotify</structname> pointer; the
<structfield>relname</structfield> and <structfield>extra</structfield> fields
do not represent separate allocations.
</para>
<note>
<para>
At present the <structfield>extra</structfield> field is unused and will
always point to an empty string.
</para>
</note>
<note>
<para>
In <productname>PostgreSQL</productname> 6.4 and later,
the <literal>be_pid</literal> is that of the notifying backend process,
the <structfield>be_pid</structfield> is that of the notifying backend process,
whereas in earlier versions it was always the <acronym>PID</acronym> of your own backend process.
</para>
</note>
......@@ -1996,19 +2412,263 @@ if any notifications came in during the processing of the command.
</indexterm>
<para>
The <command>COPY</command> command in <productname>PostgreSQL</productname> has options to read from
or write to the network connection used by <application>libpq</application>.
Therefore, functions are necessary to access this network
connection directly so applications may take advantage of this capability.
The <command>COPY</command> command in <productname>PostgreSQL</productname>
has options to read from or write to the network connection used by
<application>libpq</application>. The functions described in this section
allow applications to take advantage of this capability by supplying or
consuming copied data.
</para>
<para>
The overall process is that the application first issues the SQL
<command>COPY</command> command via <function>PQexec</function> or one
of the equivalent functions. The response to this (if there is no error
in the command) will be a <structname>PGresult</> object bearing a status
code of <literal>PGRES_COPY_OUT</literal> or <literal>PGRES_COPY_IN</literal>
(depending on the specified copy direction). The application should then
use the functions of this section to receive or transmit data rows.
When the data transfer is complete, another <structname>PGresult</> object
is returned to indicate success or failure of the transfer. Its status
will be <literal>PGRES_COMMAND_OK</literal> for success or
<literal>PGRES_FATAL_ERROR</literal> if some problem was encountered.
At this point further SQL commands may be issued via
<function>PQexec</function>. (It is not possible to execute other SQL
commands using the same connection while the <command>COPY</command>
operation is in progress.)
</para>
<para>
These functions should be executed only after obtaining a result
status of <literal>PGRES_COPY_OUT</literal> or
If a <command>COPY</command> command is issued via
<function>PQexec</function> in a string that could contain additional
commands, the application must continue fetching results via
<function>PQgetResult</> after completing the <command>COPY</command>
sequence. Only when <function>PQgetResult</> returns NULL is it certain
that the <function>PQexec</function> command string is done and it is
safe to issue more commands.
</para>
<para>
The functions of this section should be executed only after obtaining a
result status of <literal>PGRES_COPY_OUT</literal> or
<literal>PGRES_COPY_IN</literal> from <function>PQexec</function> or
<function>PQgetResult</function>.
</para>
<para>
A <structname>PGresult</> object bearing one of these status values
carries some additional data about the <command>COPY</command> operation that
is starting. This additional data is available using functions that are
also used in connection with query results:
<variablelist>
<varlistentry>
<term><function>PQnfields</function></term>
<listitem>
<para>
Returns the number of columns (fields) to be copied.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQbinaryTuples</function></term>
<listitem>
<para>
0 indicates the overall copy format is textual (rows
separated by newlines, columns separated by separator
characters, etc).
1 indicates the overall copy format is binary.
See <xref linkend="sql-copy" endterm="sql-copy-title">
for more information.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQfformat</function></term>
<listitem>
<para>
Returns the format code (0 for text, 1 for binary) associated
with each column of the copy operation. The per-column format
codes will always be zero when the overall copy format is textual,
but the binary format can support both text and binary columns.
(However, as of the current implementation of <command>COPY</>,
only binary columns appear in a binary copy; so the per-column
formats always match the overall format at present.)
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<note>
<para>
These additional data values are only available when using protocol 3.0.
When using protocol 2.0, all these functions will return 0.
</para>
</note>
<sect2 id="libpq-copy-send">
<title>Functions for Sending <command>COPY</command> Data</title>
<para>
These functions are used to send data during <literal>COPY FROM STDIN</>.
They will fail if called when the connection is not in <literal>COPY_IN</>
state.
</para>
<variablelist>
<varlistentry>
<term><function>PQputCopyData</function></term>
<listitem>
<para>
Sends data to the server during <literal>COPY_IN</> state.
<synopsis>
int PQputCopyData(PGconn *conn,
const char *buffer,
int nbytes);
</synopsis>
</para>
<para>
Transmits the COPY data in the specified <parameter>buffer</>, of length
<parameter>nbytes</>, to the server. The result is 1 if the data was sent,
zero if it was not sent because the attempt would block (this case is only
possible if the connection is in nonblock mode), or -1 if an error occurred.
(Use <function>PQerrorMessage</function> to retrieve details if the return
value is -1. If the value is zero, wait for write-ready and try again.)
</para>
<para>
The application may divide the COPY datastream into bufferloads of any
convenient size. Bufferload boundaries have no semantic significance when
sending. The contents of the datastream must match the data format expected
by the <command>COPY</> command; see
<xref linkend="sql-copy" endterm="sql-copy-title"> for details.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQputCopyEnd</function></term>
<listitem>
<para>
Sends end-of-data indication to the server during <literal>COPY_IN</> state.
<synopsis>
int PQputCopyEnd(PGconn *conn,
const char *errormsg);
</synopsis>
</para>
<para>
Ends the <literal>COPY_IN</> operation successfully if <parameter>errormsg</>
is NULL. If <parameter>errormsg</> is not NULL then the <command>COPY</>
is forced to fail, with the string pointed to by <parameter>errormsg</>
used as the error message. (One should not assume that this exact error
message will come back from the server, however, as the server might have
already failed the <command>COPY</> for its own reasons. Also note that the
option to force failure does not work when using pre-3.0-protocol connections.)
</para>
<para>
The result is 1 if the termination data was sent,
zero if it was not sent because the attempt would block (this case is only
possible if the connection is in nonblock mode), or -1 if an error occurred.
(Use <function>PQerrorMessage</function> to retrieve details if the return
value is -1. If the value is zero, wait for write-ready and try again.)
</para>
<para>
After successfully calling <function>PQputCopyEnd</>, call
<function>PQgetResult</> to obtain the final result status of the
<command>COPY</> command. One may wait for
this result to be available in the usual way. Then return to normal
operation.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-copy-receive">
<title>Functions for Receiving <command>COPY</command> Data</title>
<para>
These functions are used to receive data during <literal>COPY TO STDOUT</>.
They will fail if called when the connection is not in <literal>COPY_OUT</>
state.
</para>
<variablelist>
<varlistentry>
<term><function>PQgetCopyData</function></term>
<listitem>
<para>
Receives data from the server during <literal>COPY_OUT</> state.
<synopsis>
int PQgetCopyData(PGconn *conn,
char **buffer,
int async);
</synopsis>
</para>
<para>
Attempts to obtain another row of data from the server during a COPY.
Data is always returned one data row at a time; if only a partial row
is available, it is not returned. Successful return of a data row
involves allocating a chunk of memory to hold the data. The
<parameter>buffer</> parameter must be non-NULL. <parameter>*buffer</>
is set to point to the allocated memory, or to NULL in cases where no
buffer is returned. A non-NULL result buffer must be freed using
<function>PQfreemem</> when no longer needed.
</para>
<para>
When a row is successfully returned, the return value is the number of
data bytes in the row (this will always be greater than zero). The
returned string is always null-terminated, though this is probably only
useful for textual COPY. A result of zero indicates that the COPY is
still in progress, but no row is yet available (this is only possible
when <parameter>async</> is true). A
result of -1 indicates that the COPY is done.
A result of -2 indicates that an error occurred (consult
<function>PQerrorMessage</> for the reason).
</para>
<para>
When <parameter>async</> is true (not zero), <function>PQgetCopyData</>
will not block waiting for input; it will return zero if the COPY is still
in progress but no complete row is available. (In this case wait for
read-ready before trying again; it does not matter whether you call
<function>PQconsumeInput</>.) When <parameter>async</> is
false (zero), <function>PQgetCopyData</> will block until data is available
or the operation completes.
</para>
<para>
After <function>PQgetCopyData</> returns -1, call
<function>PQgetResult</> to obtain the final result status of the
<command>COPY</> command. One may wait for
this result to be available in the usual way. Then return to normal
operation.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-copy-deprecated">
<title>Obsolete Functions for <command>COPY</command></title>
<para>
These functions represent older methods of handling <command>COPY</>.
Although they still work, they are deprecated due to poor error handling,
inconvenient methods of detecting end-of-data, and lack of support for binary
or nonblocking transfers.
</para>
<variablelist>
<varlistentry>
<term><function>PQgetline</function></term>
......@@ -2042,9 +2702,6 @@ receive lines that are more than <parameter>length</>-1 characters long,
care is needed to be sure it recognizes the <literal>\.</literal> line correctly
(and does not, for example, mistake the end of a long data line
for a terminator line).
The code in the file
<filename>src/bin/psql/copy.c</filename>
contains example functions that correctly handle the <command>COPY</command> protocol.
</para>
</listitem>
</varlistentry>
......@@ -2123,13 +2780,13 @@ call; it is okay to send a partial line or multiple lines per call.
<note>
<para>
Before <productname>PostgreSQL</productname> 7.4, it was necessary for the
application to explicitly send the two characters <literal>\.</literal> as a
final line to indicate to the server that it had finished sending COPY data.
While this still works, it is deprecated and the special meaning of
<literal>\.</literal> can be expected to be removed in a future release.
It is sufficient to call <function>PQendcopy</function> after having sent the
actual data.
Before <productname>PostgreSQL</productname> protocol 3.0, it was necessary
for the application to explicitly send the two characters
<literal>\.</literal> as a final line to indicate to the server that it had
finished sending COPY data. While this still works, it is deprecated and the
special meaning of <literal>\.</literal> can be expected to be removed in a
future release. It is sufficient to call <function>PQendcopy</function> after
having sent the actual data.
</para>
</note>
</listitem>
......@@ -2202,33 +2859,52 @@ This will work correctly only if the <command>COPY</command> is the only
</varlistentry>
</variablelist>
<para>
An example:
<programlisting>
PQexec(conn, "CREATE TABLE foo (a integer, b varchar(16), d double precision);");
PQexec(conn, "COPY foo FROM STDIN;");
PQputline(conn, "3\thello world\t4.5\n");
PQputline(conn, "4\tgoodbye world\t7.11\n");
...
PQendcopy(conn);
</programlisting>
</para>
</sect2>
</sect1>
<sect1 id="libpq-trace">
<title>Tracing Functions</title>
<sect1 id="libpq-control">
<title>Control Functions</title>
<para>
These functions control miscellaneous details of
<application>libpq</>'s behavior.
</para>
<variablelist>
<varlistentry>
<term><function>PQsetErrorVerbosity</function></term>
<listitem>
<para>
Determines the verbosity of messages returned by
<function>PQerrorMessage</> and <function>PQresultErrorMessage</>.
<synopsis>
typedef enum {
PQERRORS_TERSE, PQERRORS_DEFAULT, PQERRORS_VERBOSE
} PGVerbosity;
PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
</synopsis>
<function>PQsetErrorVerbosity</> sets the verbosity mode, returning the
connection's previous setting.
In TERSE mode, returned messages include severity, primary text, and position
only; this will normally fit on a single line. The DEFAULT mode produces
messages that include the above plus any detail, hint, or context fields
(these may span multiple lines). The VERBOSE mode includes all available
fields. Changing the verbosity does not affect the messages available from
already-existing <structname>PGresult</> objects, only subsequently-created
ones.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>PQtrace</function></term>
<listitem>
<para>
Enables tracing of the client/server communication to a debugging file stream.
<synopsis>
void PQtrace(PGconn *conn
FILE *stream);
void PQtrace(PGconn *conn, FILE *stream);
</synopsis>
</para>
</listitem>
......@@ -2249,14 +2925,43 @@ void PQuntrace(PGconn *conn);
</sect1>
<sect1 id="libpq-control">
<sect1 id="libpq-notice-processing">
<title>Notice Processing</title>
<para>
The function <function>PQsetNoticeProcessor</function>
Notice and warning messages generated by the server are not returned by the
query execution functions, since they do not imply failure of the query.
Instead they are passed to a notice handling function, and execution continues
normally after the handler returns. The default notice handling function
prints the message on <filename>stderr</filename>, but the application can
override this behavior by supplying its own handling function.
</para>
<para>
For historical reasons, there are two levels of notice handling, called the
notice receiver and notice processor. The default behavior is for the notice
receiver to format the notice and pass a string to the notice processor
for printing. However, an application that chooses to provide its own notice
receiver will typically ignore the notice processor layer and just do all the
work in the notice receiver.
</para>
<para>
The function <function>PQsetNoticeReceiver</function>
<indexterm><primary>notice receiver</></>
sets or examines the current notice receiver for a connection object.
Similarly, <function>PQsetNoticeProcessor</function>
<indexterm><primary>notice processor</></>
controls the reporting of notice and warning messages generated by the server.
sets or examines the current notice processor.
<synopsis>
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
PQnoticeReceiver
PQsetNoticeReceiver(PGconn *conn,
PQnoticeReceiver proc,
void *arg);
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
PQnoticeProcessor
......@@ -2264,19 +2969,41 @@ PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc,
void *arg);
</synopsis>
Each of these functions returns the previous notice receiver or processor
function pointer, and sets the new value.
If you supply a null function pointer, no action is taken,
but the current pointer is returned.
</para>
<para>
When a notice or warning message is received from the server, or generated
internally by <application>libpq</application>, the notice receiver function
is called. It is passed the message in the form of a
<symbol>PGRES_NONFATAL_ERROR</symbol> <structname>PGresult</structname>.
(This allows the receiver to extract individual fields using
<function>PQresultErrorField</>, or the complete preformatted message using
<function>PQresultErrorMessage</>.)
The same void pointer passed to
<function>PQsetNoticeReceiver</function> is also passed.
(This pointer can be used to access application-specific state if needed.)
</para>
<para>
The default notice receiver simply extracts the message (using
<function>PQresultErrorMessage</>) and passes it to the notice processor.
</para>
<para>
By default, <application>libpq</application> prints notice messages
from the server, as well as a few error messages that it generates by
itself, on <filename>stderr</filename>.
This behavior can be overridden by supplying a callback function that
does something else with the messages, a so-called notice processor.
The callback function is passed
the text of the message (which includes a trailing newline), plus
The notice processor is responsible for handling a notice or warning message
given in text form. It is passed the string text of the message
(including a trailing newline), plus
a void pointer that is the same one passed to
<function>PQsetNoticeProcessor</function>.
(This pointer can be used to access application-specific state if needed.)
</para>
<para>
The default notice processor is simply
<programlisting>
static void
......@@ -2285,22 +3012,14 @@ defaultNoticeProcessor(void * arg, const char * message)
fprintf(stderr, "%s", message);
}
</programlisting>
To use a special notice processor, call
<function>PQsetNoticeProcessor</function> just after
creation of a new <structname>PGconn</> object.
</para>
<para>
The return value is the pointer to the previous notice processor.
If you supply a null callback function pointer, no action is taken,
but the current pointer is returned.
</para>
<para>
Once you have set a notice processor, you should expect that that function
could be called as long as either the <structname>PGconn</> object or <structname>PGresult</> objects
made from it exist. At creation of a <structname>PGresult</>, the <structname>PGconn</>'s current
notice processor pointer is copied into the <structname>PGresult</> for possible use by
Once you have set a notice receiver or processor, you should expect that that
function could be called as long as either the <structname>PGconn</> object or
<structname>PGresult</> objects made from it exist. At creation of a
<structname>PGresult</>, the <structname>PGconn</>'s current notice handling
pointers are copied into the <structname>PGresult</> for possible use by
functions like <function>PQgetvalue</function>.
</para>
......@@ -2449,7 +3168,10 @@ It is not recommended to set the timeout to less than 2 seconds.
<para>
The following environment variables can be used to specify default
behavior for every <productname>PostgreSQL</productname> session.
behavior for each <productname>PostgreSQL</productname> session.
(See also the <command>ALTER USER</> and <command>ALTER DATABASE</>
commands for ways to set default behavior on a per-user or per-database
basis.)
<itemizedlist>
<listitem>
......@@ -2545,8 +3267,8 @@ If the permissions are less strict than this, the file will be ignored.
<para>
<application>libpq</application> is thread-safe if the library is
compiled using the <literal>--with-threads</>
<filename>configure</filename> command-line option. (You might need to
compiled using <filename>configure</filename>'s <literal>--with-threads</>
command-line option. (In addition, you might need to
use other threading command-line options to compile your client code.)
</para>
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/lobj.sgml,v 1.28 2003/03/13 01:30:28 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/lobj.sgml,v 1.29 2003/06/21 21:51:33 tgl Exp $
-->
<chapter id="largeObjects">
......@@ -181,7 +181,8 @@ int lo_open(PGconn *conn, Oid lobjId, int mode);
<function>lo_open</function> returns a large object descriptor
for later use in <function>lo_read</function>, <function>lo_write</function>,
<function>lo_lseek</function>, <function>lo_tell</function>, and
<function>lo_close</function>.
<function>lo_close</function>. The descriptor is only valid for
the duration of the current transaction.
</para>
</sect2>
......@@ -256,6 +257,11 @@ int lo_close(PGconn *conn, int fd);
<function>lo_open</function>. On success, <function>lo_close</function>
returns zero. On error, the return value is negative.
</para>
<para>
Any large object descriptors that remain open at the end of a
transaction will be closed automatically.
</para>
</sect2>
<sect2>
......@@ -296,6 +302,14 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image
WHERE name = 'beautiful image';
</programlisting>
</para>
<para>
These functions read and write files in the server's filesystem, using the
permissions of the database's owning user. Therefore, their use is restricted
to superusers. (In contrast, the client-side import and export functions
read and write files in the client's filesystem, using the permissions of
the client program. Their use is not restricted.)
</para>
</sect1>
<sect1 id="lo-examplesect">
......
......@@ -97,6 +97,20 @@ EXPORTS
_pg_utf_mblen @ 93
_PQunescapeBytea @ 94
_PQfreemem @ 95
_PQtransactionStatus @ 96
_PQparameterStatus @ 97
_PQprotocolVersion @ 98
_PQsetErrorVerbosity @ 99
_PQsetNoticeReceiver @ 100
_PQexecParams @ 101
_PQsendQueryParams @ 102
_PQputCopyData @ 103
_PQputCopyEnd @ 104
_PQgetCopyData @ 105
_PQresultErrorField @ 106
_PQftable @ 107
_PQftablecol @ 108
_PQfformat @ 109
; Aliases for MS compatible names
PQconnectdb = _PQconnectdb
......@@ -194,4 +208,17 @@ EXPORTS
pg_utf_mblen = _pg_utf_mblen
PQunescapeBytea = _PQunescapeBytea
PQfreemem = _PQfreemem
PQtransactionStatus = _PQtransactionStatus
PQparameterStatus = _PQparameterStatus
PQprotocolVersion = _PQprotocolVersion
PQsetErrorVerbosity = _PQsetErrorVerbosity
PQsetNoticeReceiver = _PQsetNoticeReceiver
PQexecParams = _PQexecParams
PQsendQueryParams = _PQsendQueryParams
PQputCopyData = _PQputCopyData
PQputCopyEnd = _PQputCopyEnd
PQgetCopyData = _PQgetCopyData
PQresultErrorField = _PQresultErrorField
PQftable = _PQftable
PQftablecol = _PQftablecol
PQfformat = _PQfformat
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.249 2003/06/20 04:09:12 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.250 2003/06/21 21:51:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -176,6 +176,7 @@ static PQconninfoOption *conninfo_parse(const char *conninfo,
PQExpBuffer errorMessage);
static char *conninfo_getval(PQconninfoOption *connOptions,
const char *keyword);
static void defaultNoticeReceiver(void *arg, const PGresult *res);
static void defaultNoticeProcessor(void *arg, const char *message);
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
......@@ -1804,11 +1805,14 @@ makeEmptyPGconn(void)
/* Zero all pointers and booleans */
MemSet((char *) conn, 0, sizeof(PGconn));
conn->noticeHook = defaultNoticeProcessor;
conn->noticeHooks.noticeRec = defaultNoticeReceiver;
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
conn->status = CONNECTION_BAD;
conn->asyncStatus = PGASYNC_IDLE;
conn->xactStatus = PQTRANS_IDLE;
conn->setenv_state = SETENV_STATE_IDLE;
conn->client_encoding = PG_SQL_ASCII;
conn->verbosity = PQERRORS_DEFAULT;
conn->notifyList = DLNewList();
conn->sock = -1;
#ifdef USE_SSL
......@@ -1850,7 +1854,6 @@ makeEmptyPGconn(void)
/*
* freePGconn
* - free the PGconn data structure
*
*/
static void
freePGconn(PGconn *conn)
......@@ -1899,9 +1902,9 @@ freePGconn(PGconn *conn)
}
/*
closePGconn
- properly close a connection to the backend
*/
* closePGconn
* - properly close a connection to the backend
*/
static void
closePGconn(PGconn *conn)
{
......@@ -2662,6 +2665,41 @@ PQstatus(const PGconn *conn)
return conn->status;
}
PGTransactionStatusType
PQtransactionStatus(const PGconn *conn)
{
if (!conn || conn->status != CONNECTION_OK)
return PQTRANS_UNKNOWN;
if (conn->asyncStatus != PGASYNC_IDLE)
return PQTRANS_ACTIVE;
return conn->xactStatus;
}
const char *
PQparameterStatus(const PGconn *conn, const char *paramName)
{
const pgParameterStatus *pstatus;
if (!conn || !paramName)
return NULL;
for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next)
{
if (strcmp(pstatus->name, paramName) == 0)
return pstatus->value;
}
return NULL;
}
int
PQprotocolVersion(const PGconn *conn)
{
if (!conn)
return 0;
if (conn->status == CONNECTION_BAD)
return 0;
return PG_PROTOCOL_MAJOR(conn->pversion);
}
char *
PQerrorMessage(const PGconn *conn)
{
......@@ -2731,11 +2769,22 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
return (status);
}
PGVerbosity
PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
{
PGVerbosity old;
if (!conn)
return PQERRORS_DEFAULT;
old = conn->verbosity;
conn->verbosity = verbosity;
return old;
}
void
PQtrace(PGconn *conn, FILE *debug_port)
{
if (conn == NULL ||
conn->status == CONNECTION_BAD)
if (conn == NULL)
return;
PQuntrace(conn);
conn->Pfdebug = debug_port;
......@@ -2744,7 +2793,6 @@ PQtrace(PGconn *conn, FILE *debug_port)
void
PQuntrace(PGconn *conn)
{
/* note: better allow untrace even when connection bad */
if (conn == NULL)
return;
if (conn->Pfdebug)
......@@ -2754,6 +2802,23 @@ PQuntrace(PGconn *conn)
}
}
PQnoticeReceiver
PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
{
PQnoticeReceiver old;
if (conn == NULL)
return NULL;
old = conn->noticeHooks.noticeRec;
if (proc)
{
conn->noticeHooks.noticeRec = proc;
conn->noticeHooks.noticeRecArg = arg;
}
return old;
}
PQnoticeProcessor
PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
{
......@@ -2762,22 +2827,35 @@ PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
if (conn == NULL)
return NULL;
old = conn->noticeHook;
old = conn->noticeHooks.noticeProc;
if (proc)
{
conn->noticeHook = proc;
conn->noticeArg = arg;
conn->noticeHooks.noticeProc = proc;
conn->noticeHooks.noticeProcArg = arg;
}
return old;
}
/*
* The default notice/error message processor just prints the
* The default notice message receiver just gets the standard notice text
* and sends it to the notice processor. This two-level setup exists
* mostly for backwards compatibility; perhaps we should deprecate use of
* PQsetNoticeProcessor?
*/
static void
defaultNoticeReceiver(void *arg, const PGresult *res)
{
(void) arg; /* not used */
(*res->noticeHooks.noticeProc) (res->noticeHooks.noticeProcArg,
PQresultErrorMessage(res));
}
/*
* The default notice message processor just prints the
* message on stderr. Applications can override this if they
* want the messages to go elsewhere (a window, for example).
* Note that simply discarding notices is probably a bad idea.
*/
static void
defaultNoticeProcessor(void *arg, const char *message)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.138 2003/06/12 01:17:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.139 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,7 +43,10 @@ char *const pgresStatus[] = {
static bool PQsendQueryStart(PGconn *conn);
static void parseInput(PGconn *conn);
static bool PQexecStart(PGconn *conn);
static PGresult *PQexecFinish(PGconn *conn);
/* ----------------
......@@ -137,16 +140,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
result->cmdStatus[0] = '\0';
result->binary = 0;
result->errMsg = NULL;
result->errSeverity = NULL;
result->errCode = NULL;
result->errPrimary = NULL;
result->errDetail = NULL;
result->errHint = NULL;
result->errPosition = NULL;
result->errContext = NULL;
result->errFilename = NULL;
result->errLineno = NULL;
result->errFuncname = NULL;
result->errFields = NULL;
result->null_field[0] = '\0';
result->curBlock = NULL;
result->curOffset = 0;
......@@ -155,8 +149,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
if (conn)
{
/* copy connection data we might need for operations on PGresult */
result->noticeHook = conn->noticeHook;
result->noticeArg = conn->noticeArg;
result->noticeHooks = conn->noticeHooks;
result->client_encoding = conn->client_encoding;
/* consider copying conn's errorMessage */
......@@ -177,9 +170,11 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
else
{
/* defaults... */
result->noticeHook = NULL;
result->noticeArg = NULL;
result->client_encoding = 0; /* should be SQL_ASCII */
result->noticeHooks.noticeRec = NULL;
result->noticeHooks.noticeRecArg = NULL;
result->noticeHooks.noticeProc = NULL;
result->noticeHooks.noticeProcArg = NULL;
result->client_encoding = PG_SQL_ASCII;
}
return result;
......@@ -444,6 +439,41 @@ pqPrepareAsyncResult(PGconn *conn)
return res;
}
/*
* pqInternalNotice - helper routine for internally-generated notices
*
* The supplied text is taken as primary message (ie., it should not include
* a trailing newline, and should not be more than one line).
*/
void
pqInternalNotice(const PGNoticeHooks *hooks, const char *msgtext)
{
PGresult *res;
if (hooks->noticeRec == NULL)
return; /* nobody home? */
/* Make a PGresult to pass to the notice receiver */
res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR);
res->noticeHooks = *hooks;
/*
* Set up fields of notice.
*/
pqSaveMessageField(res, 'M', msgtext);
pqSaveMessageField(res, 'S', libpq_gettext("NOTICE"));
/* XXX should provide a SQLSTATE too? */
/*
* Result text is always just the primary message + newline.
*/
res->errMsg = (char *) pqResultAlloc(res, strlen(msgtext) + 2, FALSE);
sprintf(res->errMsg, "%s\n", msgtext);
/*
* Pass to receiver, then free it.
*/
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
PQclear(res);
}
/*
* pqAddTuple
* add a row pointer to the PGresult structure, growing it if necessary
......@@ -484,6 +514,25 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
return TRUE;
}
/*
* pqSaveMessageField - save one field of an error or notice message
*/
void
pqSaveMessageField(PGresult *res, char code, const char *value)
{
PGMessageField *pfield;
pfield = (PGMessageField *)
pqResultAlloc(res,
sizeof(PGMessageField) + strlen(value),
TRUE);
if (!pfield)
return; /* out of memory? */
pfield->code = code;
strcpy(pfield->contents, value);
pfield->next = res->errFields;
res->errFields = pfield;
}
/*
* pqSaveParameterStatus - remember parameter status sent by backend
......@@ -543,26 +592,6 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
StrNCpy(conn->sversion, value, sizeof(conn->sversion));
}
/*
* pqGetParameterStatus - fetch parameter value, if available
*
* Returns NULL if info not available
*
* XXX this probably should be exported for client use
*/
const char *
pqGetParameterStatus(PGconn *conn, const char *name)
{
pgParameterStatus *pstatus;
for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next)
{
if (strcmp(pstatus->name, name) == 0)
return pstatus->value;
}
return NULL;
}
/*
* PQsendQuery
......@@ -574,12 +603,9 @@ pqGetParameterStatus(PGconn *conn, const char *name)
int
PQsendQuery(PGconn *conn, const char *query)
{
if (!conn)
if (!PQsendQueryStart(conn))
return 0;
/* clear the error string */
resetPQExpBuffer(&conn->errorMessage);
if (!query)
{
printfPQExpBuffer(&conn->errorMessage,
......@@ -587,25 +613,6 @@ PQsendQuery(PGconn *conn, const char *query)
return 0;
}
/* Don't try to send if we know there's no live connection. */
if (conn->status != CONNECTION_OK)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("no connection to the server\n"));
return 0;
}
/* Can't send while already busy, either. */
if (conn->asyncStatus != PGASYNC_IDLE)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("another command is already in progress\n"));
return 0;
}
/* initialize async result-accumulation state */
conn->result = NULL;
conn->curTuple = NULL;
/* construct the outgoing Query message */
if (pqPutMsgStart('Q', false, conn) < 0 ||
pqPuts(query, conn) < 0 ||
......@@ -617,7 +624,7 @@ PQsendQuery(PGconn *conn, const char *query)
/*
* Give the data a push. In nonblock mode, don't complain if we're
* unable to send it all; PQconsumeInput() will do any additional flushing
* unable to send it all; PQgetResult() will do any additional flushing
* needed.
*/
if (pqFlush(conn) < 0)
......@@ -631,6 +638,194 @@ PQsendQuery(PGconn *conn, const char *query)
return 1;
}
/*
* PQsendQueryParams
* Like PQsendQuery, but use 3.0 protocol so we can pass parameters
*/
int
PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat)
{
int i;
if (!PQsendQueryStart(conn))
return 0;
/* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("function requires at least 3.0 protocol\n"));
return 0;
}
if (!command)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("command string is a null pointer\n"));
return 0;
}
/*
* We will send Parse, Bind, Describe Portal, Execute, Sync, using
* unnamed statement and portal.
*/
/* construct the Parse message */
if (pqPutMsgStart('P', false, conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPuts(command, conn) < 0)
goto sendFailed;
if (nParams > 0 && paramTypes)
{
if (pqPutInt(nParams, 2, conn) < 0)
goto sendFailed;
for (i = 0; i < nParams; i++)
{
if (pqPutInt(paramTypes[i], 4, conn) < 0)
goto sendFailed;
}
}
else
{
if (pqPutInt(0, 2, conn) < 0)
goto sendFailed;
}
if (pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Bind message */
if (pqPutMsgStart('B', false, conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPuts("", conn) < 0)
goto sendFailed;
if (nParams > 0 && paramFormats)
{
if (pqPutInt(nParams, 2, conn) < 0)
goto sendFailed;
for (i = 0; i < nParams; i++)
{
if (pqPutInt(paramFormats[i], 2, conn) < 0)
goto sendFailed;
}
}
else
{
if (pqPutInt(0, 2, conn) < 0)
goto sendFailed;
}
if (pqPutInt(nParams, 2, conn) < 0)
goto sendFailed;
for (i = 0; i < nParams; i++)
{
if (paramValues && paramValues[i])
{
int nbytes;
if (paramFormats && paramFormats[i] != 0)
{
/* binary parameter */
nbytes = paramLengths[i];
}
else
{
/* text parameter, do not use paramLengths */
nbytes = strlen(paramValues[i]);
}
if (pqPutInt(nbytes, 4, conn) < 0 ||
pqPutnchar(paramValues[i], nbytes, conn) < 0)
goto sendFailed;
}
else
{
/* take the param as NULL */
if (pqPutInt(-1, 4, conn) < 0)
goto sendFailed;
}
}
if (pqPutInt(1, 2, conn) < 0 ||
pqPutInt(resultFormat, 2, conn))
goto sendFailed;
if (pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Describe Portal message */
if (pqPutMsgStart('D', false, conn) < 0 ||
pqPutc('P', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Execute message */
if (pqPutMsgStart('E', false, conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutInt(0, 4, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Sync message */
if (pqPutMsgStart('S', false, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/*
* Give the data a push. In nonblock mode, don't complain if we're
* unable to send it all; PQgetResult() will do any additional flushing
* needed.
*/
if (pqFlush(conn) < 0)
goto sendFailed;
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
return 1;
sendFailed:
pqHandleSendFailure(conn);
return 0;
}
/*
* Common startup code for PQsendQuery and PQsendQueryParams
*/
static bool
PQsendQueryStart(PGconn *conn)
{
if (!conn)
return false;
/* clear the error string */
resetPQExpBuffer(&conn->errorMessage);
/* Don't try to send if we know there's no live connection. */
if (conn->status != CONNECTION_OK)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("no connection to the server\n"));
return false;
}
/* Can't send while already busy, either. */
if (conn->asyncStatus != PGASYNC_IDLE)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("another command is already in progress\n"));
return false;
}
/* initialize async result-accumulation state */
conn->result = NULL;
conn->curTuple = NULL;
/* ready to send command message */
return true;
}
/*
* pqHandleSendFailure: try to clean up after failure to send command.
*
......@@ -746,8 +941,24 @@ PQgetResult(PGconn *conn)
/* If not ready to return something, block until we are. */
while (conn->asyncStatus == PGASYNC_BUSY)
{
int flushResult;
/*
* If data remains unsent, send it. Else we might be waiting
* for the result of a command the backend hasn't even got yet.
*/
while ((flushResult = pqFlush(conn)) > 0)
{
if (pqWait(FALSE, TRUE, conn))
{
flushResult = -1;
break;
}
}
/* Wait for some more data, and load it. */
if (pqWait(TRUE, FALSE, conn) ||
if (flushResult ||
pqWait(TRUE, FALSE, conn) ||
pqReadData(conn) < 0)
{
/*
......@@ -758,6 +969,7 @@ PQgetResult(PGconn *conn)
conn->asyncStatus = PGASYNC_IDLE;
return pqPrepareAsyncResult(conn);
}
/* Parse it. */
parseInput(conn);
}
......@@ -774,10 +986,16 @@ PQgetResult(PGconn *conn)
conn->asyncStatus = PGASYNC_BUSY;
break;
case PGASYNC_COPY_IN:
res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
if (conn->result && conn->result->resultStatus == PGRES_COPY_IN)
res = pqPrepareAsyncResult(conn);
else
res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
break;
case PGASYNC_COPY_OUT:
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
if (conn->result && conn->result->resultStatus == PGRES_COPY_OUT)
res = pqPrepareAsyncResult(conn);
else
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
break;
default:
printfPQExpBuffer(&conn->errorMessage,
......@@ -806,18 +1024,46 @@ PQgetResult(PGconn *conn)
PGresult *
PQexec(PGconn *conn, const char *query)
{
PGresult *result;
PGresult *lastResult;
bool savedblocking;
if (!PQexecStart(conn))
return NULL;
if (!PQsendQuery(conn, query))
return NULL;
return PQexecFinish(conn);
}
/*
* we assume anyone calling PQexec wants blocking behaviour, we force
* the blocking status of the connection to blocking for the duration
* of this function and restore it on return
*/
savedblocking = pqIsnonblocking(conn);
if (PQsetnonblocking(conn, FALSE) == -1)
/*
* PQexecParams
* Like PQexec, but use 3.0 protocol so we can pass parameters
*/
PGresult *
PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat)
{
if (!PQexecStart(conn))
return NULL;
if (!PQsendQueryParams(conn, command,
nParams, paramTypes, paramValues, paramLengths,
paramFormats, resultFormat))
return NULL;
return PQexecFinish(conn);
}
/*
* Common code for PQexec and PQexecParams: prepare to send command
*/
static bool
PQexecStart(PGconn *conn)
{
PGresult *result;
if (!conn)
return false;
/*
* Silently discard any prior query result that application didn't
......@@ -832,15 +1078,23 @@ PQexec(PGconn *conn, const char *query)
PQclear(result);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("COPY state must be terminated first\n"));
/* restore blocking status */
goto errout;
return false;
}
PQclear(result);
}
/* OK to send the message */
if (!PQsendQuery(conn, query))
goto errout; /* restore blocking status */
/* OK to send a command */
return true;
}
/*
* Common code for PQexec and PQexecParams: wait for command result
*/
static PGresult *
PQexecFinish(PGconn *conn)
{
PGresult *result;
PGresult *lastResult;
/*
* For backwards compatibility, return the last result if there are
......@@ -848,7 +1102,7 @@ PQexec(PGconn *conn, const char *query)
* error result.
*
* We have to stop if we see copy in/out, however. We will resume parsing
* when application calls PQendcopy.
* after application performs the data transfer.
*/
lastResult = NULL;
while ((result = PQgetResult(conn)) != NULL)
......@@ -874,14 +1128,7 @@ PQexec(PGconn *conn, const char *query)
break;
}
if (PQsetnonblocking(conn, savedblocking) == -1)
return NULL;
return lastResult;
errout:
if (PQsetnonblocking(conn, savedblocking) == -1)
return NULL;
return NULL;
}
/*
......@@ -894,7 +1141,6 @@ errout:
*
* the CALLER is responsible for FREE'ing the structure returned
*/
PGnotify *
PQnotifies(PGconn *conn)
{
......@@ -916,6 +1162,156 @@ PQnotifies(PGconn *conn)
return event;
}
/*
* PQputCopyData - send some data to the backend during COPY IN
*
* Returns 1 if successful, 0 if data could not be sent (only possible
* in nonblock mode), or -1 if an error occurs.
*/
int
PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
{
if (!conn)
return -1;
if (conn->asyncStatus != PGASYNC_COPY_IN)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("no COPY in progress\n"));
return -1;
}
if (nbytes > 0)
{
/*
* Try to flush any previously sent data in preference to growing
* the output buffer. If we can't enlarge the buffer enough to hold
* the data, return 0 in the nonblock case, else hard error.
* (For simplicity, always assume 5 bytes of overhead even in
* protocol 2.0 case.)
*/
if ((conn->outBufSize - conn->outCount - 5) < nbytes)
{
if (pqFlush(conn) < 0)
return -1;
if (pqCheckOutBufferSpace(conn->outCount + 5 + nbytes, conn))
return pqIsnonblocking(conn) ? 0 : -1;
}
/* Send the data (too simple to delegate to fe-protocol files) */
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
if (pqPutMsgStart('d', false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
}
return 1;
}
/*
* PQputCopyEnd - send EOF indication to the backend during COPY IN
*
* After calling this, use PQgetResult() to check command completion status.
*
* Returns 1 if successful, 0 if data could not be sent (only possible
* in nonblock mode), or -1 if an error occurs.
*/
int
PQputCopyEnd(PGconn *conn, const char *errormsg)
{
if (!conn)
return -1;
if (conn->asyncStatus != PGASYNC_COPY_IN)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("no COPY in progress\n"));
return -1;
}
/*
* Send the COPY END indicator. This is simple enough that we don't
* bother delegating it to the fe-protocol files.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
if (errormsg)
{
/* Send COPY FAIL */
if (pqPutMsgStart('f', false, conn) < 0 ||
pqPuts(errormsg, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
/* Send COPY DONE */
if (pqPutMsgStart('c', false, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
}
else
{
if (errormsg)
{
/* Ooops, no way to do this in 2.0 */
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("function requires at least 3.0 protocol\n"));
return -1;
}
else
{
/* Send old-style end-of-data marker */
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPuts("\\.\n", conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
}
/* Return to active duty */
conn->asyncStatus = PGASYNC_BUSY;
resetPQExpBuffer(&conn->errorMessage);
/* Try to flush data */
if (pqFlush(conn) < 0)
return -1;
return 1;
}
/*
* PQgetCopyData - read a row of data from the backend during COPY OUT
*
* If successful, sets *buffer to point to a malloc'd row of data, and
* returns row length (always > 0) as result.
* Returns 0 if no row available yet (only possible if async is true),
* -1 if end of copy (consult PQgetResult), or -2 if error (consult
* PQerrorMessage).
*/
int
PQgetCopyData(PGconn *conn, char **buffer, int async)
{
*buffer = NULL; /* for all failure cases */
if (!conn)
return -2;
if (conn->asyncStatus != PGASYNC_COPY_OUT)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("no COPY in progress\n"));
return -2;
}
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqGetCopyData3(conn, buffer, async);
else
return pqGetCopyData2(conn, buffer, async);
}
/*
* PQgetline - gets a newline-terminated string from the backend.
*
......@@ -1002,11 +1398,12 @@ PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
}
/*
* PQputline -- sends a string to the backend.
* PQputline -- sends a string to the backend during COPY IN.
* Returns 0 if OK, EOF if not.
*
* This exists to support "COPY <rel> from stdin". The backend will ignore
* the string if not doing COPY.
* This is deprecated primarily because the return convention doesn't allow
* caller to tell the difference between a hard error and a nonblock-mode
* send failure.
*/
int
PQputline(PGconn *conn, const char *s)
......@@ -1021,27 +1418,10 @@ PQputline(PGconn *conn, const char *s)
int
PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
{
if (!conn || conn->sock < 0)
if (PQputCopyData(conn, buffer, nbytes) > 0)
return 0;
else
return EOF;
if (nbytes > 0)
{
/* This is too simple to bother with separate subroutines */
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
if (pqPutMsgStart('d', false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return EOF;
}
else
{
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return EOF;
}
}
return 0;
}
/*
......@@ -1049,6 +1429,11 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
* After completing the data transfer portion of a copy in/out,
* the application must call this routine to finish the command protocol.
*
* When using 3.0 protocol this is deprecated; it's cleaner to use PQgetResult
* to get the transfer status. Note however that when using 2.0 protocol,
* recovering from a copy failure often requires a PQreset. PQendcopy will
* take care of that, PQgetResult won't.
*
* RETURNS:
* 0 on success
* 1 on failure
......@@ -1133,7 +1518,7 @@ ExecStatusType
PQresultStatus(const PGresult *res)
{
if (!res)
return PGRES_NONFATAL_ERROR;
return PGRES_FATAL_ERROR;
return res->resultStatus;
}
......@@ -1153,6 +1538,21 @@ PQresultErrorMessage(const PGresult *res)
return res->errMsg;
}
char *
PQresultErrorField(const PGresult *res, int fieldcode)
{
PGMessageField *pfield;
if (!res)
return NULL;
for (pfield = res->errFields; pfield != NULL; pfield = pfield->next)
{
if (pfield->code == fieldcode)
return pfield->contents;
}
return NULL;
}
int
PQntuples(const PGresult *res)
{
......@@ -1191,13 +1591,10 @@ check_field_number(const PGresult *res, int field_num)
return FALSE; /* no way to display error message... */
if (field_num < 0 || field_num >= res->numAttributes)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d\n"),
field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf);
}
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d"),
field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf);
return FALSE;
}
return TRUE;
......@@ -1213,32 +1610,26 @@ check_tuple_field_number(const PGresult *res,
return FALSE; /* no way to display error message... */
if (tup_num < 0 || tup_num >= res->ntups)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("row number %d is out of range 0..%d\n"),
tup_num, res->ntups - 1);
PGDONOTICE(res, noticeBuf);
}
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("row number %d is out of range 0..%d"),
tup_num, res->ntups - 1);
PGDONOTICE(res, noticeBuf);
return FALSE;
}
if (field_num < 0 || field_num >= res->numAttributes)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d\n"),
field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf);
}
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d"),
field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf);
return FALSE;
}
return TRUE;
}
/*
returns NULL if the field_num is invalid
*/
* returns NULL if the field_num is invalid
*/
char *
PQfname(const PGresult *res, int field_num)
{
......@@ -1251,8 +1642,8 @@ PQfname(const PGresult *res, int field_num)
}
/*
returns -1 on a bad field name
*/
* returns -1 on a bad field name
*/
int
PQfnumber(const PGresult *res, const char *field_name)
{
......@@ -1290,6 +1681,39 @@ PQfnumber(const PGresult *res, const char *field_name)
return -1;
}
Oid
PQftable(const PGresult *res, int field_num)
{
if (!check_field_number(res, field_num))
return InvalidOid;
if (res->attDescs)
return res->attDescs[field_num].tableid;
else
return InvalidOid;
}
int
PQftablecol(const PGresult *res, int field_num)
{
if (!check_field_number(res, field_num))
return 0;
if (res->attDescs)
return res->attDescs[field_num].columnid;
else
return 0;
}
int
PQfformat(const PGresult *res, int field_num)
{
if (!check_field_number(res, field_num))
return 0;
if (res->attDescs)
return res->attDescs[field_num].format;
else
return 0;
}
Oid
PQftype(const PGresult *res, int field_num)
{
......@@ -1332,10 +1756,10 @@ PQcmdStatus(PGresult *res)
}
/*
PQoidStatus -
if the last command was an INSERT, return the oid string
if not, return ""
*/
* PQoidStatus -
* if the last command was an INSERT, return the oid string
* if not, return ""
*/
char *
PQoidStatus(const PGresult *res)
{
......@@ -1360,10 +1784,10 @@ PQoidStatus(const PGresult *res)
}
/*
PQoidValue -
a perhaps preferable form of the above which just returns
an Oid type
*/
* PQoidValue -
* a perhaps preferable form of the above which just returns
* an Oid type
*/
Oid
PQoidValue(const PGresult *res)
{
......@@ -1388,13 +1812,13 @@ PQoidValue(const PGresult *res)
/*
PQcmdTuples -
If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a
string containing the number of inserted/affected tuples. If not,
return "".
XXX: this should probably return an int
*/
* PQcmdTuples -
* If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a
* string containing the number of inserted/affected tuples. If not,
* return "".
*
* XXX: this should probably return an int
*/
char *
PQcmdTuples(PGresult *res)
{
......@@ -1426,13 +1850,10 @@ PQcmdTuples(PGresult *res)
if (*p == 0)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("could not interpret result from server: %s\n"),
res->cmdStatus);
PGDONOTICE(res, noticeBuf);
}
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("could not interpret result from server: %s"),
res->cmdStatus);
PGDONOTICE(res, noticeBuf);
return "";
}
......@@ -1440,15 +1861,9 @@ PQcmdTuples(PGresult *res)
}
/*
PQgetvalue:
return the value of field 'field_num' of row 'tup_num'
If res is binary, then the value returned is NOT a null-terminated
ASCII string, but the binary representation in the server's native
format.
if res is not binary, a null-terminated ASCII string is returned.
*/
* PQgetvalue:
* return the value of field 'field_num' of row 'tup_num'
*/
char *
PQgetvalue(const PGresult *res, int tup_num, int field_num)
{
......@@ -1458,11 +1873,8 @@ PQgetvalue(const PGresult *res, int tup_num, int field_num)
}
/* PQgetlength:
returns the length of a field value in bytes. If res is binary,
i.e. a result of a binary portal, then the length returned does
NOT include the size field of the varlena. (The data returned
by PQgetvalue doesn't either.)
*/
* returns the actual length of a field value in bytes.
*/
int
PQgetlength(const PGresult *res, int tup_num, int field_num)
{
......@@ -1475,8 +1887,8 @@ PQgetlength(const PGresult *res, int tup_num, int field_num)
}
/* PQgetisnull:
returns the null status of a field value.
*/
* returns the null status of a field value.
*/
int
PQgetisnull(const PGresult *res, int tup_num, int field_num)
{
......@@ -1489,16 +1901,17 @@ PQgetisnull(const PGresult *res, int tup_num, int field_num)
}
/* PQsetnonblocking:
sets the PGconn's database connection non-blocking if the arg is TRUE
or makes it non-blocking if the arg is FALSE, this will not protect
you from PQexec(), you'll only be safe when using the non-blocking
API
Needs to be called only on a connected database connection.
*/
* sets the PGconn's database connection non-blocking if the arg is TRUE
* or makes it non-blocking if the arg is FALSE, this will not protect
* you from PQexec(), you'll only be safe when using the non-blocking API.
* Needs to be called only on a connected database connection.
*/
int
PQsetnonblocking(PGconn *conn, int arg)
{
if (!conn || conn->status == CONNECTION_BAD)
return -1;
arg = (arg == TRUE) ? 1 : 0;
/* early out if the socket is already in the state requested */
if (arg == conn->nonblocking)
......@@ -1520,9 +1933,10 @@ PQsetnonblocking(PGconn *conn, int arg)
return (0);
}
/* return the blocking status of the database connection, TRUE == nonblocking,
FALSE == blocking
*/
/*
* return the blocking status of the database connection
* TRUE == nonblocking, FALSE == blocking
*/
int
PQisnonblocking(const PGconn *conn)
{
......
......@@ -23,7 +23,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.96 2003/06/14 17:49:54 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.97 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -197,7 +197,7 @@ pqPutnchar(const char *s, size_t len, PGconn *conn)
}
/*
* pgGetInt
* pqGetInt
* read a 2 or 4 byte integer and convert from network byte order
* to local byte order
*/
......@@ -226,7 +226,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
break;
default:
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("integer of size %lu not supported by pqGetInt\n"),
libpq_gettext("integer of size %lu not supported by pqGetInt"),
(unsigned long) bytes);
PGDONOTICE(conn, noticeBuf);
return EOF;
......@@ -239,7 +239,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
}
/*
* pgPutInt
* pqPutInt
* write an integer of 2 or 4 bytes, converting from host byte order
* to network byte order.
*/
......@@ -264,7 +264,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
break;
default:
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("integer of size %lu not supported by pqPutInt\n"),
libpq_gettext("integer of size %lu not supported by pqPutInt"),
(unsigned long) bytes);
PGDONOTICE(conn, noticeBuf);
return EOF;
......@@ -282,7 +282,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
*
* Returns 0 on success, EOF if failed to enlarge buffer
*/
static int
int
pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
{
int newsize = conn->outBufSize;
......@@ -748,7 +748,7 @@ pqSendSome(PGconn *conn, int len)
if (sent < 0)
{
/*
* Anything except EAGAIN or EWOULDBLOCK is trouble. If it's
* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's
* EPIPE or ECONNRESET, assume we've lost the backend
* connection permanently.
*/
......@@ -804,25 +804,17 @@ pqSendSome(PGconn *conn, int len)
if (len > 0)
{
/* We didn't send it all, wait till we can send more */
/*
* if the socket is in non-blocking mode we may need to abort
* here and return 1 to indicate that data is still pending.
* We didn't send it all, wait till we can send more.
*
* If the connection is in non-blocking mode we don't wait,
* but return 1 to indicate that data is still pending.
*/
#ifdef USE_SSL
/* can't do anything for our SSL users yet */
if (conn->ssl == NULL)
if (pqIsnonblocking(conn))
{
#endif
if (pqIsnonblocking(conn))
{
result = 1;
break;
}
#ifdef USE_SSL
result = 1;
break;
}
#endif
if (pqWait(FALSE, TRUE, conn))
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.1 2003/06/08 17:43:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.2 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -38,6 +38,7 @@
static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn, bool binary);
static int pqGetErrorNotice2(PGconn *conn, bool isError);
static void checkXactStatus(PGconn *conn, const char *cmdTag);
static int getNotify(PGconn *conn);
......@@ -312,7 +313,7 @@ pqSetenvPoll(PGconn *conn)
val);
else
{
val = pqGetParameterStatus(conn, "server_encoding");
val = PQparameterStatus(conn, "server_encoding");
if (val && *val)
pqSaveParameterStatus(conn, "client_encoding",
val);
......@@ -424,7 +425,7 @@ pqParseInput2(PGconn *conn)
else
{
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
libpq_gettext("message type 0x%02x arrived from server while idle\n"),
libpq_gettext("message type 0x%02x arrived from server while idle"),
id);
PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */
......@@ -447,6 +448,7 @@ pqParseInput2(PGconn *conn)
PGRES_COMMAND_OK);
strncpy(conn->result->cmdStatus, conn->workBuffer.data,
CMDSTATUS_LEN);
checkXactStatus(conn, conn->workBuffer.data);
conn->asyncStatus = PGASYNC_READY;
break;
case 'E': /* error return */
......@@ -464,7 +466,7 @@ pqParseInput2(PGconn *conn)
if (id != '\0')
{
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
libpq_gettext("unexpected character %c following empty query response (\"I\" message)\n"),
libpq_gettext("unexpected character %c following empty query response (\"I\" message)"),
id);
PGDONOTICE(conn, noticeWorkspace);
}
......@@ -521,7 +523,7 @@ pqParseInput2(PGconn *conn)
else
{
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n"));
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)"));
PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd;
......@@ -538,7 +540,7 @@ pqParseInput2(PGconn *conn)
else
{
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
libpq_gettext("server sent binary data (\"B\" message) without prior row description (\"T\" message)\n"));
libpq_gettext("server sent binary data (\"B\" message) without prior row description (\"T\" message)"));
PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd;
......@@ -628,6 +630,9 @@ getRowDescriptions(PGconn *conn)
result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data);
result->attDescs[i].tableid = 0;
result->attDescs[i].columnid = 0;
result->attDescs[i].format = 0;
result->attDescs[i].typid = typid;
result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod;
......@@ -674,6 +679,15 @@ getAnotherTuple(PGconn *conn, bool binary)
if (conn->curTuple == NULL)
goto outOfMemory;
MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue));
/*
* If it's binary, fix the column format indicators. We assume
* the backend will consistently send either B or D, not a mix.
*/
if (binary)
{
for (i = 0; i < nfields; i++)
result->attDescs[i].format = 1;
}
}
tup = conn->curTuple;
......@@ -778,6 +792,8 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
{
PGresult *res;
PQExpBufferData workBuf;
char *startp;
char *splitp;
/*
* Since the message might be pretty long, we create a temporary
......@@ -800,19 +816,63 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
res->errMsg = pqResultStrdup(res, workBuf.data);
/*
* Break the message into fields. We can't do very much here, but we
* can split the severity code off, and remove trailing newlines. Also,
* we use the heuristic that the primary message extends only to the
* first newline --- anything after that is detail message. (In some
* cases it'd be better classed as hint, but we can hardly be expected
* to guess that here.)
*/
while (workBuf.len > 0 && workBuf.data[workBuf.len-1] == '\n')
workBuf.data[--workBuf.len] = '\0';
splitp = strstr(workBuf.data, ": ");
if (splitp)
{
/* what comes before the colon is severity */
*splitp = '\0';
pqSaveMessageField(res, 'S', workBuf.data);
startp = splitp + 3;
}
else
{
/* can't find a colon? oh well... */
startp = workBuf.data;
}
splitp = strchr(startp, '\n');
if (splitp)
{
/* what comes before the newline is primary message */
*splitp++ = '\0';
pqSaveMessageField(res, 'M', startp);
/* the rest is detail; strip any leading whitespace */
while (*splitp && isspace((unsigned char) *splitp))
splitp++;
pqSaveMessageField(res, 'D', splitp);
}
else
{
/* single-line message, so all primary */
pqSaveMessageField(res, 'M', startp);
}
/*
* Either save error as current async result, or just emit the notice.
* Also, if it's an error and we were in a transaction block, assume
* the server has now gone to error-in-transaction state.
*/
if (isError)
{
pqClearAsyncResult(conn);
conn->result = res;
resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
if (conn->xactStatus == PQTRANS_INTRANS)
conn->xactStatus = PQTRANS_INERROR;
}
else
{
PGDONOTICE(conn, workBuf.data);
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
PQclear(res);
}
......@@ -820,6 +880,37 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
return 0;
}
/*
* checkXactStatus - attempt to track transaction-block status of server
*
* This is called each time we receive a command-complete message. By
* watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do
* a passable job of tracking the server's xact status. BUT: this does
* not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that
* feature ever a mistake.) Caveat user.
*
* The tags known here are all those used as far back as 7.0; is it worth
* adding those from even-older servers?
*/
static void
checkXactStatus(PGconn *conn, const char *cmdTag)
{
if (strcmp(cmdTag, "BEGIN") == 0)
conn->xactStatus = PQTRANS_INTRANS;
else if (strcmp(cmdTag, "COMMIT") == 0)
conn->xactStatus = PQTRANS_IDLE;
else if (strcmp(cmdTag, "ROLLBACK") == 0)
conn->xactStatus = PQTRANS_IDLE;
else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */
conn->xactStatus = PQTRANS_INTRANS;
/*
* Normally we get into INERROR state by detecting an Error message.
* However, if we see one of these tags then we know for sure the
* server is in abort state ...
*/
else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */
conn->xactStatus = PQTRANS_INERROR;
}
/*
* Attempt to read a Notify response message.
......@@ -832,6 +923,7 @@ static int
getNotify(PGconn *conn)
{
int be_pid;
int nmlen;
PGnotify *newNotify;
if (pqGetInt(&be_pid, 4, conn))
......@@ -844,12 +936,14 @@ getNotify(PGconn *conn)
* can all be freed at once. We don't use NAMEDATALEN because we
* don't want to tie this interface to a specific server name length.
*/
newNotify = (PGnotify *) malloc(sizeof(PGnotify) +
strlen(conn->workBuffer.data) +1);
nmlen = strlen(conn->workBuffer.data);
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
if (newNotify)
{
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
strcpy(newNotify->relname, conn->workBuffer.data);
/* fake up an empty-string extra field */
newNotify->extra = newNotify->relname + nmlen;
newNotify->be_pid = be_pid;
DLAddTail(conn->notifyList, DLNewElem(newNotify));
}
......@@ -858,6 +952,84 @@ getNotify(PGconn *conn)
}
/*
* PQgetCopyData - read a row of data from the backend during COPY OUT
*
* If successful, sets *buffer to point to a malloc'd row of data, and
* returns row length (always > 0) as result.
* Returns 0 if no row available yet (only possible if async is true),
* -1 if end of copy (consult PQgetResult), or -2 if error (consult
* PQerrorMessage).
*/
int
pqGetCopyData2(PGconn *conn, char **buffer, int async)
{
bool found;
int msgLength;
for (;;)
{
/*
* Do we have a complete line of data?
*/
conn->inCursor = conn->inStart;
found = false;
while (conn->inCursor < conn->inEnd)
{
char c = conn->inBuffer[conn->inCursor++];
if (c == '\n')
{
found = true;
break;
}
}
if (!found)
goto nodata;
msgLength = conn->inCursor - conn->inStart;
/*
* If it's the end-of-data marker, consume it, exit COPY_OUT mode,
* and let caller read status with PQgetResult().
*/
if (msgLength == 3 &&
strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0)
{
conn->inStart = conn->inCursor;
conn->asyncStatus = PGASYNC_BUSY;
return -1;
}
/*
* Pass the line back to the caller.
*/
*buffer = (char *) malloc(msgLength + 1);
if (*buffer == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return -2;
}
memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength);
(*buffer)[msgLength] = '\0'; /* Add terminating null */
/* Mark message consumed */
conn->inStart = conn->inCursor;
return msgLength;
nodata:
/* Don't block if async read requested */
if (async)
return 0;
/* Need to load more data */
if (pqWait(TRUE, FALSE, conn) ||
pqReadData(conn) < 0)
return -2;
}
}
/*
* PQgetline - gets a newline-terminated string from the backend.
*
......@@ -1020,7 +1192,7 @@ pqEndcopy2(PGconn *conn)
if (conn->errorMessage.len > 0)
PGDONOTICE(conn, conn->errorMessage.data);
PGDONOTICE(conn, libpq_gettext("lost synchronization with server, resetting connection\n"));
PGDONOTICE(conn, libpq_gettext("lost synchronization with server, resetting connection"));
/*
* Users doing non-blocking connections need to handle the reset
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.1 2003/06/08 17:43:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.2 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -40,6 +40,8 @@ static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn, int msgLength);
static int getParameterStatus(PGconn *conn);
static int getNotify(PGconn *conn);
static int getCopyStart(PGconn *conn, ExecStatusType copytype);
static int getReadyForQuery(PGconn *conn);
static int build_startup_packet(const PGconn *conn, char *packet,
const PQEnvironmentOption *options);
......@@ -171,7 +173,7 @@ pqParseInput3(PGconn *conn)
else
{
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
libpq_gettext("message type 0x%02x arrived from server while idle\n"),
libpq_gettext("message type 0x%02x arrived from server while idle"),
id);
PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message */
......@@ -201,7 +203,7 @@ pqParseInput3(PGconn *conn)
conn->asyncStatus = PGASYNC_READY;
break;
case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn))
if (getReadyForQuery(conn))
return;
conn->asyncStatus = PGASYNC_IDLE;
break;
......@@ -211,6 +213,11 @@ pqParseInput3(PGconn *conn)
PGRES_EMPTY_QUERY);
conn->asyncStatus = PGASYNC_READY;
break;
case '1': /* Parse Complete */
case '2': /* Bind Complete */
case '3': /* Close Complete */
/* Nothing to do for these message types */
break;
case 'S': /* parameter status */
if (getParameterStatus(conn))
return;
......@@ -276,17 +283,13 @@ pqParseInput3(PGconn *conn)
}
break;
case 'G': /* Start Copy In */
if (pqGetc(&conn->copy_is_binary, conn))
if (getCopyStart(conn, PGRES_COPY_IN))
return;
/* XXX we currently ignore the rest of the message */
conn->inCursor = conn->inStart + 5 + msgLength;
conn->asyncStatus = PGASYNC_COPY_IN;
break;
case 'H': /* Start Copy Out */
if (pqGetc(&conn->copy_is_binary, conn))
if (getCopyStart(conn, PGRES_COPY_OUT))
return;
/* XXX we currently ignore the rest of the message */
conn->inCursor = conn->inStart + 5 + msgLength;
conn->asyncStatus = PGASYNC_COPY_OUT;
conn->copy_already_done = 0;
break;
......@@ -398,6 +401,9 @@ getRowDescriptions(PGconn *conn)
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
}
/* result->binary is true only if ALL columns are binary */
result->binary = (nfields > 0) ? 1 : 0;
/* get type info */
for (i = 0; i < nfields; i++)
{
......@@ -430,10 +436,15 @@ getRowDescriptions(PGconn *conn)
result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data);
result->attDescs[i].tableid = tableid;
result->attDescs[i].columnid = columnid;
result->attDescs[i].format = format;
result->attDescs[i].typid = typid;
result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod;
/* XXX todo: save tableid/columnid, format too */
if (format != 1)
result->binary = 0;
}
/* Success! */
......@@ -503,7 +514,9 @@ getAnotherTuple(PGconn *conn, int msgLength)
vlen = 0;
if (tup[i].value == NULL)
{
tup[i].value = (char *) pqResultAlloc(result, vlen + 1, false);
bool isbinary = (result->attDescs[i].format != 0);
tup[i].value = (char *) pqResultAlloc(result, vlen + 1, isbinary);
if (tup[i].value == NULL)
goto outOfMemory;
}
......@@ -553,6 +566,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
PGresult *res;
PQExpBufferData workBuf;
char id;
const char *val;
/*
* Make a PGresult to hold the accumulated fields. We temporarily
......@@ -580,68 +594,63 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
break; /* terminator found */
if (pqGets(&workBuf, conn))
goto fail;
switch (id)
{
case 'S':
res->errSeverity = pqResultStrdup(res, workBuf.data);
break;
case 'C':
res->errCode = pqResultStrdup(res, workBuf.data);
break;
case 'M':
res->errPrimary = pqResultStrdup(res, workBuf.data);
break;
case 'D':
res->errDetail = pqResultStrdup(res, workBuf.data);
break;
case 'H':
res->errHint = pqResultStrdup(res, workBuf.data);
break;
case 'P':
res->errPosition = pqResultStrdup(res, workBuf.data);
break;
case 'W':
res->errContext = pqResultStrdup(res, workBuf.data);
break;
case 'F':
res->errFilename = pqResultStrdup(res, workBuf.data);
break;
case 'L':
res->errLineno = pqResultStrdup(res, workBuf.data);
break;
case 'R':
res->errFuncname = pqResultStrdup(res, workBuf.data);
break;
default:
/* silently ignore any other field type */
break;
}
pqSaveMessageField(res, id, workBuf.data);
}
/*
* Now build the "overall" error message for PQresultErrorMessage.
*
* XXX this should be configurable somehow.
*/
resetPQExpBuffer(&workBuf);
if (res->errSeverity)
appendPQExpBuffer(&workBuf, "%s: ", res->errSeverity);
if (res->errPrimary)
appendPQExpBufferStr(&workBuf, res->errPrimary);
/* translator: %s represents a digit string */
if (res->errPosition)
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
res->errPosition);
val = PQresultErrorField(res, 'S'); /* Severity */
if (val)
appendPQExpBuffer(&workBuf, "%s: ", val);
if (conn->verbosity == PQERRORS_VERBOSE)
{
val = PQresultErrorField(res, 'C'); /* SQLSTATE Code */
if (val)
appendPQExpBuffer(&workBuf, "%s: ", val);
}
val = PQresultErrorField(res, 'M'); /* Primary message */
if (val)
appendPQExpBufferStr(&workBuf, val);
val = PQresultErrorField(res, 'P'); /* Position */
if (val)
{
/* translator: %s represents a digit string */
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val);
}
appendPQExpBufferChar(&workBuf, '\n');
if (res->errDetail)
appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"),
res->errDetail);
if (res->errHint)
appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"),
res->errHint);
if (res->errContext)
appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"),
res->errContext);
if (conn->verbosity != PQERRORS_TERSE)
{
val = PQresultErrorField(res, 'D'); /* Detail */
if (val)
appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val);
val = PQresultErrorField(res, 'H'); /* Hint */
if (val)
appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val);
val = PQresultErrorField(res, 'W'); /* Where */
if (val)
appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"), val);
}
if (conn->verbosity == PQERRORS_VERBOSE)
{
const char *valf;
const char *vall;
valf = PQresultErrorField(res, 'F'); /* File */
vall = PQresultErrorField(res, 'L'); /* Line */
val = PQresultErrorField(res, 'R'); /* Routine */
if (val || valf || vall)
{
appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION: "));
if (val)
appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val);
if (valf && vall) /* unlikely we'd have just one */
appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"),
valf, vall);
appendPQExpBufferChar(&workBuf, '\n');
}
}
/*
* Either save error as current async result, or just emit the notice.
......@@ -656,7 +665,9 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
}
else
{
PGDONOTICE(conn, workBuf.data);
/* We can cheat a little here and not copy the message. */
res->errMsg = workBuf.data;
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
PQclear(res);
}
......@@ -710,35 +721,216 @@ static int
getNotify(PGconn *conn)
{
int be_pid;
char *svname;
int nmlen;
int extralen;
PGnotify *newNotify;
if (pqGetInt(&be_pid, 4, conn))
return EOF;
if (pqGets(&conn->workBuffer, conn))
return EOF;
/* must save name while getting extra string */
svname = strdup(conn->workBuffer.data);
if (!svname)
return EOF;
if (pqGets(&conn->workBuffer, conn))
{
free(svname);
return EOF;
}
/*
* Store the relation name right after the PQnotify structure so it
* Store the strings right after the PQnotify structure so it
* can all be freed at once. We don't use NAMEDATALEN because we
* don't want to tie this interface to a specific server name length.
*/
newNotify = (PGnotify *) malloc(sizeof(PGnotify) +
strlen(conn->workBuffer.data) +1);
nmlen = strlen(svname);
extralen = strlen(conn->workBuffer.data);
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
if (newNotify)
{
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
strcpy(newNotify->relname, conn->workBuffer.data);
strcpy(newNotify->relname, svname);
newNotify->extra = newNotify->relname + nmlen + 1;
strcpy(newNotify->extra, conn->workBuffer.data);
newNotify->be_pid = be_pid;
DLAddTail(conn->notifyList, DLNewElem(newNotify));
}
/* Swallow extra string (not presently used) */
if (pqGets(&conn->workBuffer, conn))
free(svname);
return 0;
}
/*
* getCopyStart - process CopyInResponse or CopyOutResponse message
*
* parseInput already read the message type and length.
*/
static int
getCopyStart(PGconn *conn, ExecStatusType copytype)
{
PGresult *result;
int nfields;
int i;
result = PQmakeEmptyPGresult(conn, copytype);
if (pqGetc(&conn->copy_is_binary, conn))
{
PQclear(result);
return EOF;
}
result->binary = conn->copy_is_binary;
/* the next two bytes are the number of fields */
if (pqGetInt(&(result->numAttributes), 2, conn))
{
PQclear(result);
return EOF;
}
nfields = result->numAttributes;
/* allocate space for the attribute descriptors */
if (nfields > 0)
{
result->attDescs = (PGresAttDesc *)
pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
}
for (i = 0; i < nfields; i++)
{
int format;
if (pqGetInt(&format, 2, conn))
{
PQclear(result);
return EOF;
}
/*
* Since pqGetInt treats 2-byte integers as unsigned, we need to
* coerce these results to signed form.
*/
format = (int) ((int16) format);
result->attDescs[i].format = format;
}
/* Success! */
conn->result = result;
return 0;
}
/*
* getReadyForQuery - process ReadyForQuery message
*/
static int
getReadyForQuery(PGconn *conn)
{
char xact_status;
if (pqGetc(&xact_status, conn))
return EOF;
switch (xact_status)
{
case 'I':
conn->xactStatus = PQTRANS_IDLE;
break;
case 'T':
conn->xactStatus = PQTRANS_INTRANS;
break;
case 'E':
conn->xactStatus = PQTRANS_INERROR;
break;
default:
conn->xactStatus = PQTRANS_UNKNOWN;
break;
}
return 0;
}
/*
* PQgetCopyData - read a row of data from the backend during COPY OUT
*
* If successful, sets *buffer to point to a malloc'd row of data, and
* returns row length (always > 0) as result.
* Returns 0 if no row available yet (only possible if async is true),
* -1 if end of copy (consult PQgetResult), or -2 if error (consult
* PQerrorMessage).
*/
int
pqGetCopyData3(PGconn *conn, char **buffer, int async)
{
char id;
int msgLength;
int avail;
for (;;)
{
/*
* Do we have the next input message? To make life simpler for async
* callers, we keep returning 0 until the next message is fully
* available, even if it is not Copy Data.
*/
conn->inCursor = conn->inStart;
if (pqGetc(&id, conn))
goto nodata;
if (pqGetInt(&msgLength, 4, conn))
goto nodata;
avail = conn->inEnd - conn->inCursor;
if (avail < msgLength - 4)
goto nodata;
/*
* If it's anything except Copy Data, exit COPY_OUT mode and let
* caller read status with PQgetResult(). The normal case is that
* it's Copy Done, but we let parseInput read that.
*/
if (id != 'd')
{
conn->asyncStatus = PGASYNC_BUSY;
return -1;
}
/*
* Drop zero-length messages (shouldn't happen anyway). Otherwise
* pass the data back to the caller.
*/
msgLength -= 4;
if (msgLength > 0)
{
*buffer = (char *) malloc(msgLength + 1);
if (*buffer == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return -2;
}
memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
(*buffer)[msgLength] = '\0'; /* Add terminating null */
/* Mark message consumed */
conn->inStart = conn->inCursor + msgLength;
return msgLength;
}
/* Empty, so drop it and loop around for another */
conn->inStart = conn->inCursor;
continue;
nodata:
/* Don't block if async read requested */
if (async)
return 0;
/* Need to load more data */
if (pqWait(TRUE, FALSE, conn) ||
pqReadData(conn) < 0)
return -2;
}
}
/*
* PQgetline - gets a newline-terminated string from the backend.
......@@ -1108,7 +1300,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
continue;
break;
case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn))
if (getReadyForQuery(conn))
continue;
/* consume the message and exit */
conn->inStart += 5 + msgLength;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-fe.h,v 1.93 2003/06/08 17:43:00 tgl Exp $
* $Id: libpq-fe.h,v 1.94 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -88,6 +88,22 @@ typedef enum
PGRES_FATAL_ERROR /* query failed */
} ExecStatusType;
typedef enum
{
PQTRANS_IDLE, /* connection idle */
PQTRANS_ACTIVE, /* command in progress */
PQTRANS_INTRANS, /* idle, within transaction block */
PQTRANS_INERROR, /* idle, within failed transaction */
PQTRANS_UNKNOWN /* cannot determine status */
} PGTransactionStatusType;
typedef enum
{
PQERRORS_TERSE, /* single-line error messages */
PQERRORS_DEFAULT, /* recommended style */
PQERRORS_VERBOSE /* all the facts, ma'am */
} PGVerbosity;
/* PGconn encapsulates a connection to the backend.
* The contents of this struct are not supposed to be known to applications.
*/
......@@ -108,12 +124,13 @@ typedef struct pg_result PGresult;
*/
typedef struct pgNotify
{
char *relname; /* name of relation containing data */
int be_pid; /* process id of backend */
char *relname; /* notification condition name */
int be_pid; /* process ID of server process */
char *extra; /* notification parameter */
} PGnotify;
/* PQnoticeProcessor is the function type for the notice-message callback.
*/
/* Function types for notice-handling callbacks */
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
/* Print options for PQprint() */
......@@ -227,6 +244,10 @@ extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
extern const char *PQparameterStatus(const PGconn *conn,
const char *paramName);
extern int PQprotocolVersion(const PGconn *conn);
extern char *PQerrorMessage(const PGconn *conn);
extern int PQsocket(const PGconn *conn);
extern int PQbackendPID(const PGconn *conn);
......@@ -238,42 +259,58 @@ extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
extern SSL *PQgetssl(PGconn *conn);
#endif
/* Set verbosity for PQerrorMessage and PQresultErrorMessage */
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
/* Enable/disable tracing */
extern void PQtrace(PGconn *conn, FILE *debug_port);
extern void PQuntrace(PGconn *conn);
/* Override default notice processor */
/* Override default notice handling routines */
extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn,
PQnoticeReceiver proc,
void *arg);
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc,
void *arg);
/* === in fe-exec.c === */
/* Quoting strings before inclusion in queries. */
extern size_t PQescapeString(char *to, const char *from, size_t length);
extern unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen,
size_t *bytealen);
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
size_t *retbuflen);
extern void PQfreemem(void *ptr);
/* Simple synchronous query */
extern PGresult *PQexec(PGconn *conn, const char *query);
extern PGnotify *PQnotifies(PGconn *conn);
/* Exists for backward compatibility. bjm 2003-03-24 */
#define PQfreeNotify(ptr) PQfreemem(ptr)
extern PGresult *PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
/* Interface for multiple-result or asynchronous queries */
extern int PQsendQuery(PGconn *conn, const char *query);
extern int PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
extern PGresult *PQgetResult(PGconn *conn);
/* Routines for managing an asynchronous query */
extern int PQisBusy(PGconn *conn);
extern int PQconsumeInput(PGconn *conn);
/* LISTEN/NOTIFY support */
extern PGnotify *PQnotifies(PGconn *conn);
/* Routines for copy in/out */
extern int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
extern int PQputCopyEnd(PGconn *conn, const char *errormsg);
extern int PQgetCopyData(PGconn *conn, char **buffer, int async);
/* Deprecated routines for copy in/out */
extern int PQgetline(PGconn *conn, char *string, int length);
extern int PQputline(PGconn *conn, const char *string);
extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
......@@ -303,11 +340,15 @@ extern PGresult *PQfn(PGconn *conn,
extern ExecStatusType PQresultStatus(const PGresult *res);
extern char *PQresStatus(ExecStatusType status);
extern char *PQresultErrorMessage(const PGresult *res);
extern char *PQresultErrorField(const PGresult *res, int fieldcode);
extern int PQntuples(const PGresult *res);
extern int PQnfields(const PGresult *res);
extern int PQbinaryTuples(const PGresult *res);
extern char *PQfname(const PGresult *res, int field_num);
extern int PQfnumber(const PGresult *res, const char *field_name);
extern Oid PQftable(const PGresult *res, int field_num);
extern int PQftablecol(const PGresult *res, int field_num);
extern int PQfformat(const PGresult *res, int field_num);
extern Oid PQftype(const PGresult *res, int field_num);
extern int PQfsize(const PGresult *res, int field_num);
extern int PQfmod(const PGresult *res, int field_num);
......@@ -322,6 +363,12 @@ extern int PQgetisnull(const PGresult *res, int tup_num, int field_num);
/* Delete a PGresult */
extern void PQclear(PGresult *res);
/* For freeing other alloc'd results, such as PGnotify structs */
extern void PQfreemem(void *ptr);
/* Exists for backward compatibility. bjm 2003-03-24 */
#define PQfreeNotify(ptr) PQfreemem(ptr)
/*
* Make an empty PGresult with given status (some apps find this
* useful). If conn is not NULL and status indicates an error, the
......@@ -329,26 +376,33 @@ extern void PQclear(PGresult *res);
*/
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
/* Quoting strings before inclusion in queries. */
extern size_t PQescapeString(char *to, const char *from, size_t length);
extern unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen,
size_t *bytealen);
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
size_t *retbuflen);
/* === in fe-print.c === */
extern void
PQprint(FILE *fout, /* output stream */
const PGresult *res,
const PQprintOpt *ps); /* option structure */
extern void PQprint(FILE *fout, /* output stream */
const PGresult *res,
const PQprintOpt *ps); /* option structure */
/*
* really old printing routines
*/
extern void
PQdisplayTuples(const PGresult *res,
extern void PQdisplayTuples(const PGresult *res,
FILE *fp, /* where to send the output */
int fillAlign, /* pad the fields with spaces */
const char *fieldSep, /* field separator */
int printHeader, /* display headers? */
int quiet);
extern void
PQprintTuples(const PGresult *res,
extern void PQprintTuples(const PGresult *res,
FILE *fout, /* output stream */
int printAttName, /* print attribute names */
int terseOutput, /* delimiter bars */
......
......@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-int.h,v 1.74 2003/06/14 17:49:54 momjian Exp $
* $Id: libpq-int.h,v 1.75 2003/06/21 21:51:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -20,6 +20,9 @@
#ifndef LIBPQ_INT_H
#define LIBPQ_INT_H
/* We assume libpq-fe.h has already been included. */
#include "postgres_fe.h"
#include <time.h>
#include <sys/types.h>
#ifndef WIN32
......@@ -28,13 +31,10 @@
#if defined(WIN32) && (!defined(ssize_t))
typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
typedef int ssize_t; /* ssize_t doesn't exist in VC (at least
* not VC6) */
#endif
/* We assume libpq-fe.h has already been included. */
#include "postgres_fe.h"
/* include stuff common to fe and be */
#include "getaddrinfo.h"
#include "libpq/pqcomm.h"
......@@ -78,7 +78,10 @@ union pgresult_data
typedef struct pgresAttDesc
{
char *name; /* type name */
char *name; /* column name */
Oid tableid; /* source table, if known */
int columnid; /* source column, if known */
int format; /* format code for value (text/binary) */
Oid typid; /* type id */
int typlen; /* type size */
int atttypmod; /* type-specific modifier info */
......@@ -91,7 +94,7 @@ typedef struct pgresAttDesc
*
* The value pointer always points to a null-terminated area; we add a
* null (zero) byte after whatever the backend sends us. This is only
* particularly useful for text tuples ... with a binary value, the
* particularly useful for text values ... with a binary value, the
* value might have embedded nulls, so the application can't use C string
* operators on it. But we add a null anyway for consistency.
* Note that the value itself does not contain a length word.
......@@ -111,6 +114,23 @@ typedef struct pgresAttValue
* byte */
} PGresAttValue;
/* Typedef for message-field list entries */
typedef struct pgMessageField
{
struct pgMessageField *next; /* list link */
char code; /* field code */
char contents[1]; /* field value (VARIABLE LENGTH) */
} PGMessageField;
/* Fields needed for notice handling */
typedef struct
{
PQnoticeReceiver noticeRec; /* notice message receiver */
void *noticeRecArg;
PQnoticeProcessor noticeProc; /* notice message processor */
void *noticeProcArg;
} PGNoticeHooks;
struct pg_result
{
int ntups;
......@@ -118,10 +138,10 @@ struct pg_result
PGresAttDesc *attDescs;
PGresAttValue **tuples; /* each PGresTuple is an array of
* PGresAttValue's */
int tupArrSize; /* size of tuples array allocated */
int tupArrSize; /* allocated size of tuples array */
ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
* last query */
* query */
int binary; /* binary tuple values if binary == 1,
* otherwise text */
......@@ -129,35 +149,23 @@ struct pg_result
* These fields are copied from the originating PGconn, so that
* operations on the PGresult don't have to reference the PGconn.
*/
PQnoticeProcessor noticeHook; /* notice/error message processor */
void *noticeArg;
PGNoticeHooks noticeHooks;
int client_encoding; /* encoding id */
/*
* Error information (all NULL if not an error result). errMsg is the
* "overall" error message returned by PQresultErrorMessage. If we
* got a field-ized error from the server then the additional fields
* may be set.
* have per-field info then it is stored in a linked list.
*/
char *errMsg; /* error message, or NULL if no error */
char *errSeverity; /* severity code */
char *errCode; /* SQLSTATE code */
char *errPrimary; /* primary message text */
char *errDetail; /* detail text */
char *errHint; /* hint text */
char *errPosition; /* cursor position */
char *errContext; /* location information */
char *errFilename; /* source-code file name */
char *errLineno; /* source-code line number */
char *errFuncname; /* source-code function name */
PGMessageField *errFields; /* message broken into fields */
/* All NULL attributes in the query result point to this null string */
char null_field[1];
/*
* Space management information. Note that attDescs and errMsg, if
* not null, point into allocated blocks. But tuples points to a
* Space management information. Note that attDescs and error stuff,
* if not null, point into allocated blocks. But tuples points to a
* separately malloc'd block, so that we can realloc it.
*/
PGresult_data *curBlock; /* most recently allocated block */
......@@ -245,18 +253,18 @@ struct pg_conn
/* Optional file to write trace info to */
FILE *Pfdebug;
/* Callback procedure for notice/error message processing */
PQnoticeProcessor noticeHook;
void *noticeArg;
/* Callback procedures for notice message processing */
PGNoticeHooks noticeHooks;
/* Status indicators */
ConnStatusType status;
PGAsyncStatusType asyncStatus;
char xact_status; /* status flag from latest ReadyForQuery */
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
int copy_already_done; /* # bytes already returned in COPY OUT */
PGTransactionStatusType xactStatus;
/* note: xactStatus never changes to ACTIVE */
int nonblocking; /* whether this connection is using a
* blocking socket to the backend or not */
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
int copy_already_done; /* # bytes already returned in COPY OUT */
Dllist *notifyList; /* Notify msgs not yet handed to
* application */
......@@ -281,6 +289,7 @@ struct pg_conn
char cryptSalt[2]; /* password salt received from backend */
pgParameterStatus *pstatus; /* ParameterStatus data */
int client_encoding; /* encoding id */
PGVerbosity verbosity; /* error/notice message verbosity */
PGlobjfuncs *lobjfuncs; /* private state for large-object access
* fns */
......@@ -351,10 +360,12 @@ extern char *pqResultStrdup(PGresult *res, const char *str);
extern void pqClearAsyncResult(PGconn *conn);
extern void pqSaveErrorResult(PGconn *conn);
extern PGresult *pqPrepareAsyncResult(PGconn *conn);
extern void pqInternalNotice(const PGNoticeHooks *hooks, const char *msgtext);
extern int pqAddTuple(PGresult *res, PGresAttValue *tup);
extern void pqSaveMessageField(PGresult *res, char code,
const char *value);
extern void pqSaveParameterStatus(PGconn *conn, const char *name,
const char *value);
extern const char *pqGetParameterStatus(PGconn *conn, const char *name);
extern void pqHandleSendFailure(PGconn *conn);
/* === in fe-protocol2.c === */
......@@ -364,6 +375,7 @@ extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
const PQEnvironmentOption *options);
extern void pqParseInput2(PGconn *conn);
extern int pqGetCopyData2(PGconn *conn, char **buffer, int async);
extern int pqGetline2(PGconn *conn, char *s, int maxlen);
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy2(PGconn *conn);
......@@ -378,6 +390,7 @@ extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
const PQEnvironmentOption *options);
extern void pqParseInput3(PGconn *conn);
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
extern int pqGetCopyData3(PGconn *conn, char **buffer, int async);
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy3(PGconn *conn);
......@@ -393,6 +406,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
* for Get, EOF merely means the buffer is exhausted, not that there is
* necessarily any error.
*/
extern int pqCheckOutBufferSpace(int bytes_needed, PGconn *conn);
extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
extern int pqGetc(char *result, PGconn *conn);
extern int pqPutc(char c, PGconn *conn);
......@@ -423,10 +437,10 @@ extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
/* Note: PGDONOTICE macro will work if applied to either PGconn or PGresult */
#define PGDONOTICE(conn,message) \
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
pqInternalNotice(&(conn)->noticeHooks, (message))
/*
* this is so that we can check is a connection is non-blocking internally
* this is so that we can check if a connection is non-blocking internally
* without the overhead of a function call
*/
#define pqIsnonblocking(conn) ((conn)->nonblocking)
......
......@@ -97,4 +97,17 @@ EXPORTS
pg_utf_mblen @ 93
PQunescapeBytea @ 94
PQfreemem @ 95
PQtransactionStatus @ 96
PQparameterStatus @ 97
PQprotocolVersion @ 98
PQsetErrorVerbosity @ 99
PQsetNoticeReceiver @ 100
PQexecParams @ 101
PQsendQueryParams @ 102
PQputCopyData @ 103
PQputCopyEnd @ 104
PQgetCopyData @ 105
PQresultErrorField @ 106
PQftable @ 107
PQftablecol @ 108
PQfformat @ 109
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册