Commit efc3a25b authored by Tom Lane's avatar Tom Lane

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

client applications.  Some editorial work on libpq.sgml, too.
parent 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"> <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 ...@@ -24,7 +24,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.124 2003/06/13 23:10:07 momj
</para> </para>
<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 to write programs that use <application>libpq</application>. There are also several
complete examples of <application>libpq</application> applications in the complete examples of <application>libpq</application> applications in the
directory <filename>src/test/examples</filename> in the source code distribution. 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 ...@@ -37,7 +37,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.124 2003/06/13 23:10:07 momj
</para> </para>
<sect1 id="libpq-connect"> <sect1 id="libpq-connect">
<title>Database Connection Functions</title> <title>Database Connection Control Functions</title>
<para> <para>
The following functions deal with making a connection to a The following functions deal with making a connection to a
...@@ -68,8 +68,8 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -68,8 +68,8 @@ PGconn *PQconnectdb(const char *conninfo);
This function opens a new database connection using the parameters taken This function opens a new database connection using the parameters taken
from the string <literal>conninfo</literal>. Unlike <function>PQsetdbLogin</> below, from the string <literal>conninfo</literal>. Unlike <function>PQsetdbLogin</> below,
the parameter set can be extended without changing the function signature, the parameter set can be extended without changing the function signature,
so use either of this function or the nonblocking analogues <function>PQconnectStart</> so use of this function (or its nonblocking analogues <function>PQconnectStart</>
and <function>PQconnectPoll</function> is preferred for new application programming. and <function>PQconnectPoll</function>) is preferred for new application programming.
</para> </para>
<para> <para>
...@@ -86,7 +86,7 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -86,7 +86,7 @@ PGconn *PQconnectdb(const char *conninfo);
</para> </para>
<para> <para>
The currently recognized parameter key words are: The currently recognized parameter keywords are:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
...@@ -107,11 +107,11 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -107,11 +107,11 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>hostaddr</literal></term> <term><literal>hostaddr</literal></term>
<listitem> <listitem>
<para> <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 standard IPv4 address format, e.g., <literal>172.28.40.9</>. If
your machine supports IPv6, you can also use those addresses. If your machine supports IPv6, you can also use those addresses.
a nonzero-length string is specified, TCP/IP communication is TCP/IP communication is
used. always used when a nonempty string is specified for this parameter.
</para> </para>
<para> <para>
Using <literal>hostaddr</> instead of <literal>host</> allows the Using <literal>hostaddr</> instead of <literal>host</> allows the
...@@ -119,9 +119,10 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -119,9 +119,10 @@ PGconn *PQconnectdb(const char *conninfo);
applications with time constraints. However, Kerberos authentication applications with time constraints. However, Kerberos authentication
requires the host name. The following therefore applies: If requires the host name. The following therefore applies: If
<literal>host</> is specified without <literal>hostaddr</>, a host name <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 <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>host</> and <literal>hostaddr</> are specified, the value for
<literal>hostaddr</> gives the remote address; the value for <literal>hostaddr</> gives the remote address; the value for
<literal>host</> is ignored, unless Kerberos is used, in which case that <literal>host</> is ignored, unless Kerberos is used, in which case that
...@@ -153,7 +154,7 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -153,7 +154,7 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>dbname</literal></term> <term><literal>dbname</literal></term>
<listitem> <listitem>
<para> <para>
The database name. The database name. Defaults to be the same as the user name.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -162,7 +163,7 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -162,7 +163,7 @@ PGconn *PQconnectdb(const char *conninfo);
<term><literal>user</literal></term> <term><literal>user</literal></term>
<listitem> <listitem>
<para> <para>
User name to connect as. <productname>PostgreSQL</productname> user name to connect as.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -182,7 +183,7 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -182,7 +183,7 @@ PGconn *PQconnectdb(const char *conninfo);
<para> <para>
Maximum wait for connection, in seconds (write as a decimal integer Maximum wait for connection, in seconds (write as a decimal integer
string). Zero or not specified means wait indefinitely. It is not 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -237,7 +238,7 @@ PGconn *PQconnectdb(const char *conninfo); ...@@ -237,7 +238,7 @@ PGconn *PQconnectdb(const char *conninfo);
If any parameter is unspecified, then the corresponding If any parameter is unspecified, then the corresponding
environment variable (see <xref linkend="libpq-envars">) environment variable (see <xref linkend="libpq-envars">)
is checked. If the environment variable is not set either, is checked. If the environment variable is not set either,
then hardwired defaults are used. then built-in defaults are used.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -260,8 +261,9 @@ PGconn *PQsetdbLogin(const char *pghost, ...@@ -260,8 +261,9 @@ PGconn *PQsetdbLogin(const char *pghost,
<para> <para>
This is the predecessor of <function>PQconnectdb</function> with a fixed This is the predecessor of <function>PQconnectdb</function> with a fixed
number of parameters. It has the same functionality except that the set of parameters. It has the same functionality except that the
missing parameters cannot be specified in the call. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -306,6 +308,10 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -306,6 +308,10 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
These two functions are used to open a connection to a database server such 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 that your application's thread of execution is not blocked on remote I/O
whilst doing so. 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>
<para> <para>
The database connection is made using the parameters taken from the string The database connection is made using the parameters taken from the string
...@@ -313,7 +319,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -313,7 +319,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
the same format as described above for <function>PQconnectdb</function>. the same format as described above for <function>PQconnectdb</function>.
</para> </para>
<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: restrictions are met:
<itemizedlist> <itemizedlist>
<listitem> <listitem>
...@@ -326,14 +332,14 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -326,14 +332,14 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<listitem> <listitem>
<para> <para>
If you call <function>PQtrace</function>, ensure that the stream object into which you trace If you call <function>PQtrace</function>, ensure that the stream object
will not block. into which you trace will not block.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <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. before calling <function>PQconnectPoll</function>, as described below.
</para> </para>
</listitem> </listitem>
...@@ -349,28 +355,31 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -349,28 +355,31 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<symbol>CONNECTION_BAD</symbol>, <function>PQconnectStart</function> has failed. <symbol>CONNECTION_BAD</symbol>, <function>PQconnectStart</function> has failed.
</para> </para>
<para> <para>
If <function>PQconnectStart</> succeeds, the next stage is to poll <application>libpq</> so that it may If <function>PQconnectStart</> succeeds, the next stage is to poll
proceed with the connection sequence. Loop thus: If <function>PQconnectPoll(conn)</function> last returned <application>libpq</> so that it may proceed with the connection sequence.
<symbol>PGRES_POLLING_READING</symbol>, perform a <function>select()</> for reading on the socket determined using <function>PQsocket(conn)</function>. If Use <function>PQsocket(conn)</function> to obtain the descriptor of the
it last returned <symbol>PGRES_POLLING_WRITING</symbol>, perform a <function>select()</> for writing on socket underlying the database connection.
that same socket. If you have yet to call <function>PQconnectPoll</function>, i.e., after the call Loop thus: If <function>PQconnectPoll(conn)</function> last returned
to <function>PQconnectStart</function>, behave as if it last returned <symbol>PGRES_POLLING_WRITING</symbol>. If <symbol>PGRES_POLLING_READING</symbol>, wait until the socket is ready to
<function>select()</> shows that the socket is ready, consider it <quote>active</quote>. If it has read (as indicated by <function>select()</>, <function>poll()</>, or
been decided that this connection is <quote>active</quote>, call <function>PQconnectPoll(conn)</function> similar system function).
again. If this call returns <symbol>PGRES_POLLING_FAILED</symbol>, the connection procedure Then call <function>PQconnectPoll(conn)</function> again.
has failed. If this call returns <symbol>PGRES_POLLING_OK</symbol>, the connection has been Conversely, if <function>PQconnectPoll(conn)</function> last returned
successfully made. <symbol>PGRES_POLLING_WRITING</symbol>, wait until the socket is ready
</para> to write, then call <function>PQconnectPoll(conn)</function> again.
If you have yet to call
<para> <function>PQconnectPoll</function>, i.e., just after the call to
Note that the use of <function>select()</function> to ensure that the socket is ready is merely <function>PQconnectStart</function>, behave as if it last returned
a (likely) example; those with other facilities available, such as a <symbol>PGRES_POLLING_WRITING</symbol>. Continue this loop until
<function>poll()</function> call, may of course use that instead. <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>
<para> <para>
At any time during connection, the status of the connection may be 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 procedure has failed; if it gives <function>CONNECTION_OK</>, then the
connection is ready. Both of these states are equally detectable connection is ready. Both of these states are equally detectable
from the return value of <function>PQconnectPoll</>, described above. Other states may also occur from the return value of <function>PQconnectPoll</>, described above. Other states may also occur
...@@ -410,17 +419,25 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -410,17 +419,25 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
<term><symbol>CONNECTION_AUTH_OK</symbol></term> <term><symbol>CONNECTION_AUTH_OK</symbol></term>
<listitem> <listitem>
<para> <para>
Received authentication; waiting for connection start-up to continue. Received authentication; waiting for backend start-up to finish.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<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> <listitem>
<para> <para>
Negotiating environment (part of the connection start-up). Negotiating environment-driven parameter settings.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -429,7 +446,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); ...@@ -429,7 +446,7 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn);
Note that, although these constants will remain (in order to maintain Note that, although these constants will remain (in order to maintain
compatibility), an application should never rely upon these appearing in a 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 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> <programlisting>
switch(PQstatus(conn)) switch(PQstatus(conn))
{ {
...@@ -450,20 +467,19 @@ switch(PQstatus(conn)) ...@@ -450,20 +467,19 @@ switch(PQstatus(conn))
</para> </para>
<para> <para>
Note that if <function>PQconnectStart</function> returns a non-null pointer, you must call The <literal>connect_timeout</literal> connection parameter is ignored
<function>PQfinish</function> when you are finished with it, in order to dispose of when using <function>PQconnectPoll</function>; it is the application's
the structure and any associated memory blocks. This must be done even if a responsibility to decide whether an excessive amount of time has elapsed.
call to <function>PQconnectStart</function> or <function>PQconnectPoll</function> failed. Otherwise, <function>PQconnectStart</function> followed by a
</para> <function>PQconnectPoll</function> loop is equivalent to
<function>PQconnectdb</function>.
<para>
<function>PQconnectPoll</function> will currently block if
<application>libpq</> is compiled with SSL support. This restriction may be removed in the future.
</para> </para>
<para> <para>
Finally, these functions leave the connection in a nonblocking state as if Note that if <function>PQconnectStart</function> returns a non-null pointer, you must call
<function>PQsetnonblocking</function> had been called. <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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -498,7 +514,8 @@ typedef struct ...@@ -498,7 +514,8 @@ typedef struct
be used to determine all possible <function>PQconnectdb</function> options and their be used to determine all possible <function>PQconnectdb</function> options and their
current default values. The return value points to an array of current default values. The return value points to an array of
<structname>PQconninfoOption</structname> structures, which ends with an entry having a null <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. will depend on environment variables and other context.
Callers must treat the connection options data as read-only. Callers must treat the connection options data as read-only.
</para> </para>
...@@ -527,7 +544,8 @@ void PQfinish(PGconn *conn); ...@@ -527,7 +544,8 @@ void PQfinish(PGconn *conn);
Note that even if the server connection attempt fails (as Note that even if the server connection attempt fails (as
indicated by <function>PQstatus</function>), the application should call <function>PQfinish</function> indicated by <function>PQstatus</function>), the application should call <function>PQfinish</function>
to free the memory used by the <structname>PGconn</structname> object. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -584,12 +602,23 @@ PostgresPollingStatusType PQresetPoll(PGconn *conn); ...@@ -584,12 +602,23 @@ PostgresPollingStatusType PQresetPoll(PGconn *conn);
</variablelist> </variablelist>
</para> </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> <para>
<indexterm><primary>libpq-fe.h</></> <indexterm><primary>libpq-fe.h</></>
<indexterm><primary>libpq-int.h</></> <indexterm><primary>libpq-int.h</></>
<application>libpq</application> application programmers should be careful to <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 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. <structname>PGconn</> structure because they are subject to change in the future.
(Beginning in <productname>PostgreSQL</productname> release 6.4, the (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 ...@@ -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 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 by including <filename>libpq-int.h</filename> too, but you are encouraged to fix the code
soon.) 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> <variablelist>
<varlistentry> <varlistentry>
...@@ -608,12 +643,6 @@ soon.) ...@@ -608,12 +643,6 @@ soon.)
char *PQdb(const PGconn *conn); char *PQdb(const PGconn *conn);
</synopsis> </synopsis>
</para> </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> </listitem>
</varlistentry> </varlistentry>
...@@ -691,7 +720,14 @@ char *PQoptions(const PGconn *conn); ...@@ -691,7 +720,14 @@ char *PQoptions(const PGconn *conn);
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
</para>
<para>
The following functions return status data that can change as operations
are executed on the <structname>PGconn</> object.
<variablelist>
<varlistentry> <varlistentry>
<term><function>PQstatus</function></term> <term><function>PQstatus</function></term>
<listitem> <listitem>
...@@ -728,6 +764,91 @@ ConnStatusType PQstatus(const PGconn *conn); ...@@ -728,6 +764,91 @@ ConnStatusType PQstatus(const PGconn *conn);
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><function>PQerrorMessage</function></term> <term><function>PQerrorMessage</function></term>
<listitem> <listitem>
...@@ -757,7 +878,8 @@ char *PQerrorMessage(const PGconn* conn); ...@@ -757,7 +878,8 @@ char *PQerrorMessage(const PGconn* conn);
Obtains the file descriptor number of the connection socket to Obtains the file descriptor number of the connection socket to
the server. A valid descriptor will be greater than or equal the server. A valid descriptor will be greater than or equal
to 0; a result of -1 indicates that no server connection is 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> <synopsis>
int PQsocket(const PGconn *conn); int PQsocket(const PGconn *conn);
</synopsis> </synopsis>
...@@ -812,9 +934,10 @@ SSL *PQgetssl(const PGconn *conn); ...@@ -812,9 +934,10 @@ SSL *PQgetssl(const PGconn *conn);
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
</sect1>
</sect1>
<sect1 id="libpq-exec"> <sect1 id="libpq-exec">
<title>Command Execution Functions</title> <title>Command Execution Functions</title>
...@@ -828,6 +951,7 @@ SQL queries and commands. ...@@ -828,6 +951,7 @@ SQL queries and commands.
<sect2 id="libpq-exec-main"> <sect2 id="libpq-exec-main">
<title>Main Functions</title> <title>Main Functions</title>
<para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><function>PQexec</function></term> <term><function>PQexec</function></term>
...@@ -836,8 +960,7 @@ SQL queries and commands. ...@@ -836,8 +960,7 @@ SQL queries and commands.
Submits a command to the server Submits a command to the server
and waits for the result. and waits for the result.
<synopsis> <synopsis>
PGresult *PQexec(PGconn *conn, PGresult *PQexec(PGconn *conn, const char *command);
const char *command);
</synopsis> </synopsis>
</para> </para>
...@@ -854,21 +977,95 @@ PGresult *PQexec(PGconn *conn, ...@@ -854,21 +977,95 @@ PGresult *PQexec(PGconn *conn,
</varlistentry> </varlistentry>
</variablelist> </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> <para>
The <function>PGresult</function> structure encapsulates the result The <structname>PGresult</structname> structure encapsulates the result
returned by the server. returned by the server.
<application>libpq</application> application programmers should be careful to <application>libpq</application> application programmers should be careful to
maintain the <structname>PGresult</structname> abstraction. Use the accessor functions below to get 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 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. <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> <variablelist>
<varlistentry> <varlistentry>
...@@ -902,7 +1099,8 @@ ExecStatusType PQresultStatus(const PGresult *res); ...@@ -902,7 +1099,8 @@ ExecStatusType PQresultStatus(const PGresult *res);
<varlistentry> <varlistentry>
<term><literal>PGRES_TUPLES_OK</literal></term> <term><literal>PGRES_TUPLES_OK</literal></term>
<listitem> <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> </listitem>
</varlistentry> </varlistentry>
...@@ -930,7 +1128,7 @@ ExecStatusType PQresultStatus(const PGresult *res); ...@@ -930,7 +1128,7 @@ ExecStatusType PQresultStatus(const PGresult *res);
<varlistentry> <varlistentry>
<term><literal>PGRES_NONFATAL_ERROR</literal></term> <term><literal>PGRES_NONFATAL_ERROR</literal></term>
<listitem> <listitem>
<para>A nonfatal error occurred.</para> <para>A nonfatal error (a notice or warning) occurred.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -948,8 +1146,15 @@ the query. Note that a <command>SELECT</command> command that happens ...@@ -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>. to retrieve zero rows still shows <literal>PGRES_TUPLES_OK</literal>.
<literal>PGRES_COMMAND_OK</literal> is for commands that can never <literal>PGRES_COMMAND_OK</literal> is for commands that can never
return rows (<command>INSERT</command>, <command>UPDATE</command>, return rows (<command>INSERT</command>, <command>UPDATE</command>,
etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> often etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> may indicate
exposes a bug in the client software. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -976,6 +1181,7 @@ if there was no error. ...@@ -976,6 +1181,7 @@ if there was no error.
<synopsis> <synopsis>
char *PQresultErrorMessage(const PGresult *res); char *PQresultErrorMessage(const PGresult *res);
</synopsis> </synopsis>
If there was an error, the returned string will include a trailing newline.
</para> </para>
<para> <para>
...@@ -991,6 +1197,39 @@ when you want to know the status from the latest operation on the connection. ...@@ -991,6 +1197,39 @@ when you want to know the status from the latest operation on the connection.
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><function>PQclear</function></term> <term><function>PQclear</function></term>
<listitem> <listitem>
...@@ -1008,7 +1247,7 @@ void PQclear(PQresult *res); ...@@ -1008,7 +1247,7 @@ void PQclear(PQresult *res);
need it; it does not go away when you issue a new command, 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, nor even if you close the connection. To get rid of it,
you must call <function>PQclear</function>. Failure to do this will 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1035,161 +1274,20 @@ as with a <structname>PGresult</structname> returned by <application>libpq</appl ...@@ -1035,161 +1274,20 @@ as with a <structname>PGresult</structname> returned by <application>libpq</appl
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </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> </para>
</sect2> </sect2>
<sect2 id="libpq-exec-select-info">
<sect2 id="libpq-exec-escape-bytea"> <title>Retrieving Query Result Information</title>
<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>
<para> <para>
The <parameter>from</parameter> parameter points to an escaped string These functions are used to extract information from a
such as might be returned by <function>PQgetvalue</function> when applied to a <structname>PGresult</structname> object that represents a successful
<type>bytea</type> column. <function>PQunescapeBytea</function> converts query result (that is, one that has status
this string representation into its binary representation. <literal>PGRES_TUPLES_OK</literal>). For objects with other status
It returns a pointer to a buffer allocated with values they will act as though the result has zero rows and zero columns.
<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>
</para> </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> <variablelist>
<varlistentry> <varlistentry>
<term><function>PQntuples</function></term> <term><function>PQntuples</function></term>
...@@ -1228,6 +1326,10 @@ char *PQfname(const PGresult *res, ...@@ -1228,6 +1326,10 @@ char *PQfname(const PGresult *res,
int column_number); int column_number);
</synopsis> </synopsis>
</para> </para>
<para>
NULL is returned if the column number is out of range.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1250,12 +1352,82 @@ int PQfnumber(const PGresult *res, ...@@ -1250,12 +1352,82 @@ int PQfnumber(const PGresult *res,
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><function>PQftype</function></term> <term><function>PQftable</function></term>
<listitem> <listitem>
<para> <para>
Returns the column data type associated with the Returns the OID of the table from which the given column was fetched.
given column number. The integer returned is the Column numbers start at 0.
internal OID number of the type. Column numbers start <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. at 0.
<synopsis> <synopsis>
Oid PQftype(const PGresult *res, Oid PQftype(const PGresult *res,
...@@ -1265,7 +1437,7 @@ Oid PQftype(const PGresult *res, ...@@ -1265,7 +1437,7 @@ Oid PQftype(const PGresult *res,
<para> <para>
You can query the system table <literal>pg_type</literal> to obtain 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> of the built-in data types are defined in the file <filename>src/include/catalog/pg_type.h</filename>
in the source tree. in the source tree.
</para> </para>
...@@ -1276,7 +1448,7 @@ in the source tree. ...@@ -1276,7 +1448,7 @@ in the source tree.
<term><function>PQfmod</function></term> <term><function>PQfmod</function></term>
<listitem> <listitem>
<para> <para>
Returns the type-specific modification data of the column Returns the type modifier of the column
associated with the given column number. associated with the given column number.
Column numbers start at 0. Column numbers start at 0.
<synopsis> <synopsis>
...@@ -1284,6 +1456,13 @@ int PQfmod(const PGresult *res, ...@@ -1284,6 +1456,13 @@ int PQfmod(const PGresult *res,
int column_number); int column_number);
</synopsis> </synopsis>
</para> </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> </listitem>
</varlistentry> </varlistentry>
...@@ -1301,9 +1480,10 @@ int PQfsize(const PGresult *res, ...@@ -1301,9 +1480,10 @@ int PQfsize(const PGresult *res,
</para> </para>
<para> <para>
<function>PQfsize</> returns the space allocated for this column in a database <function>PQfsize</> returns the space allocated for this column in a database
row, in other words the size of the server's binary representation row, in other words the size of the server's internal representation
of the data type. -1 is returned if the column has a variable size. of the data type. (Accordingly, it is not really very useful to clients.)
A negative value indicates the data type is variable-length.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1312,33 +1492,31 @@ int PQfsize(const PGresult *res, ...@@ -1312,33 +1492,31 @@ int PQfsize(const PGresult *res,
<term><function>PQbinaryTuples</function></term> <term><function>PQbinaryTuples</function></term>
<listitem> <listitem>
<para> <para>
Returns 1 if the <structname>PGresult</> contains binary row data Returns 1 if the <structname>PGresult</> contains binary data
and 0 if it contains text data. and 0 if it contains text data.
<synopsis> <synopsis>
int PQbinaryTuples(const PGresult *res); int PQbinaryTuples(const PGresult *res);
</synopsis> </synopsis>
</para> </para>
<para> <para>
Currently, binary row data can only be returned by a query that This function is deprecated (except for its use in connection with
extracts data from a binary cursor. <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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
</sect2>
<sect2 id="libpq-exec-select-values">
<title>Retrieving Query Result Values</title>
<variablelist>
<varlistentry> <varlistentry>
<term><function>PQgetvalue</function></term> <term><function>PQgetvalue</function></term>
<listitem> <listitem>
<para> <para>
Returns a single column value of one row Returns a single field value of one row
of a <structname>PGresult</structname>. of a <structname>PGresult</structname>.
Row and colums indices start at 0. Row and column numbers start at 0.
<synopsis> <synopsis>
char* PQgetvalue(const PGresult *res, char* PQgetvalue(const PGresult *res,
int row_number, int row_number,
...@@ -1347,15 +1525,18 @@ char* PQgetvalue(const PGresult *res, ...@@ -1347,15 +1525,18 @@ char* PQgetvalue(const PGresult *res,
</para> </para>
<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 is a null-terminated character string representation
of the column value. But if <function>PQbinaryTuples</function> returns 1, of the field value. For data in binary format, the value is in the binary
the value returned by <function>PQgetvalue</function> is the binary representation determined by the datatype's <function>typsend</> and
representation of the <function>typreceive</> functions. (The value is actually followed by
type in the internal format of the backend server a zero byte in this case too, but that is not ordinarily useful, since
(but not including the size word, if the column is variable-length). the value is likely to contain embedded nulls.)
It is then the programmer's responsibility to cast and </para>
convert the data to the correct C type.
<para>
An empty string is returned if the field value is NULL. See
<function>PQgetisnull</> to distinguish NULLs from empty-string values.
</para> </para>
<para> <para>
...@@ -1373,7 +1554,7 @@ be used past the lifetime of the <structname>PGresult</structname> structure i ...@@ -1373,7 +1554,7 @@ be used past the lifetime of the <structname>PGresult</structname> structure i
<term><function>PQgetisnull</function></term> <term><function>PQgetisnull</function></term>
<listitem> <listitem>
<para> <para>
Tests a column for a null value. Tests a field for a null value.
Row and column numbers start at 0. Row and column numbers start at 0.
<synopsis> <synopsis>
int PQgetisnull(const PGresult *res, int PQgetisnull(const PGresult *res,
...@@ -1383,10 +1564,9 @@ int PQgetisnull(const PGresult *res, ...@@ -1383,10 +1564,9 @@ int PQgetisnull(const PGresult *res,
</para> </para>
<para> <para>
This function returns 1 if the column is null and 0 if This function returns 1 if the field is null and 0 if
it contains a non-null value. (Note that <function>PQgetvalue</function> it contains a non-null value. (Note that <function>PQgetvalue</function>
will return an empty string, not a null pointer, for a null will return an empty string, not a null pointer, for a null field.)
column.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1395,7 +1575,7 @@ int PQgetisnull(const PGresult *res, ...@@ -1395,7 +1575,7 @@ int PQgetisnull(const PGresult *res,
<term><function>PQgetlength</function></term> <term><function>PQgetlength</function></term>
<listitem> <listitem>
<para> <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. Row and column numbers start at 0.
<synopsis> <synopsis>
int PQgetlength(const PGresult *res, int PQgetlength(const PGresult *res,
...@@ -1406,8 +1586,10 @@ int PQgetlength(const PGresult *res, ...@@ -1406,8 +1586,10 @@ int PQgetlength(const PGresult *res,
<para> <para>
This is the actual data length for the particular data value, that is, the 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 size of the object pointed to by <function>PQgetvalue</function>. For text
values, this size has little to do with the binary size reported by <function>PQfsize</function>. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1440,8 +1622,8 @@ typedef struct { ...@@ -1440,8 +1622,8 @@ typedef struct {
<para> <para>
This function was formerly used by <application>psql</application> This function was formerly used by <application>psql</application>
to print query results, but this is no longer the case and this to print query results, but this is no longer the case. Note that it
function is no longer actively supported. assumes all the data is in text format.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1451,17 +1633,27 @@ function is no longer actively supported. ...@@ -1451,17 +1633,27 @@ function is no longer actively supported.
<sect2 id="libpq-exec-nonselect"> <sect2 id="libpq-exec-nonselect">
<title>Retrieving Result Information for Other Commands</title> <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> <variablelist>
<varlistentry> <varlistentry>
<term><function>PQcmdStatus</function></term> <term><function>PQcmdStatus</function></term>
<listitem> <listitem>
<para> <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>. generated the <structname>PGresult</structname>.
<synopsis> <synopsis>
char * PQcmdStatus(PGresult *res); char * PQcmdStatus(PGresult *res);
</synopsis> </synopsis>
</para> </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> </listitem>
</varlistentry> </varlistentry>
...@@ -1477,7 +1669,9 @@ char * PQcmdTuples(PGresult *res); ...@@ -1477,7 +1669,9 @@ char * PQcmdTuples(PGresult *res);
<para> <para>
If the <acronym>SQL</acronym> command that generated the 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 string containing the number of rows affected. If the
command was anything else, it returns the empty string. command was anything else, it returns the empty string.
</para> </para>
...@@ -1496,13 +1690,6 @@ char * PQcmdTuples(PGresult *res); ...@@ -1496,13 +1690,6 @@ char * PQcmdTuples(PGresult *res);
Oid PQoidValue(const PGresult *res); Oid PQoidValue(const PGresult *res);
</synopsis> </synopsis>
</para> </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> </listitem>
</varlistentry> </varlistentry>
...@@ -1523,14 +1710,184 @@ char * PQoidStatus(const PGresult *res); ...@@ -1523,14 +1710,184 @@ char * PQoidStatus(const PGresult *res);
</para> </para>
<para> <para>
This function is deprecated in favor of <function>PQoidValue</function> This function is deprecated in favor of <function>PQoidValue</function>.
and is not thread-safe. It is not thread-safe.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</sect2> </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>
<sect1 id="libpq-async"> <sect1 id="libpq-async">
...@@ -1573,70 +1930,11 @@ discarded by <function>PQexec</function>. ...@@ -1573,70 +1930,11 @@ discarded by <function>PQexec</function>.
Applications that do not like these limitations can instead use the Applications that do not like these limitations can instead use the
underlying functions that <function>PQexec</function> is built from: underlying functions that <function>PQexec</function> is built from:
<function>PQsendQuery</function> and <function>PQgetResult</function>. <function>PQsendQuery</function> and <function>PQgetResult</function>.
</para> There is also <function>PQsendQueryParams</function>, which can be
<para> used with <function>PQgetResult</function> to duplicate the functionality
Older programs that used this functionality as well as of <function>PQexecParams</function>.
<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.
<variablelist> <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> <varlistentry>
<term><function>PQsendQuery</function></term> <term><function>PQsendQuery</function></term>
<listitem> <listitem>
...@@ -1646,12 +1944,9 @@ int PQisnonblocking(const PGconn *conn); ...@@ -1646,12 +1944,9 @@ int PQisnonblocking(const PGconn *conn);
successfully dispatched and 0 if not (in which case, use successfully dispatched and 0 if not (in which case, use
<function>PQerrorMessage</> to get more information about the failure). <function>PQerrorMessage</> to get more information about the failure).
<synopsis> <synopsis>
int PQsendQuery(PGconn *conn, int PQsendQuery(PGconn *conn, const char *command);
const char *command);
</synopsis> </synopsis>
</para>
<para>
After successfully calling <function>PQsendQuery</function>, call After successfully calling <function>PQsendQuery</function>, call
<function>PQgetResult</function> one or more <function>PQgetResult</function> one or more
times to obtain the results. <function>PQsendQuery</function> may not be called times to obtain the results. <function>PQsendQuery</function> may not be called
...@@ -1661,12 +1956,41 @@ int PQsendQuery(PGconn *conn, ...@@ -1661,12 +1956,41 @@ int PQsendQuery(PGconn *conn,
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><function>PQgetResult</function></term> <term><function>PQgetResult</function></term>
<listitem> <listitem>
<para> <para>
Waits for the next result from a prior <function>PQsendQuery</function>, Waits for the next result from a prior
and return it. A null pointer is returned when the command is complete <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. and there will be no more results.
<synopsis> <synopsis>
PGresult *PQgetResult(PGconn *conn); PGresult *PQgetResult(PGconn *conn);
...@@ -1697,8 +2021,8 @@ overlapped processing, by the way: the client can be handling the ...@@ -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 results of one command while the server is still working on later
queries in the same command string.) However, calling <function>PQgetResult</function> will queries in the same command string.) However, calling <function>PQgetResult</function> will
still cause the client to block until the server completes the 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 next <acronym>SQL</acronym> command. This can be avoided by proper use of two
functions: more functions:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
...@@ -1714,7 +2038,8 @@ int PQconsumeInput(PGconn *conn); ...@@ -1714,7 +2038,8 @@ int PQconsumeInput(PGconn *conn);
<para> <para>
<function>PQconsumeInput</function> normally returns 1 indicating <quote>no error</quote>, <function>PQconsumeInput</function> normally returns 1 indicating <quote>no error</quote>,
but returns 0 if there was some kind of trouble (in which case 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 whether any input data was actually collected. After calling
<function>PQconsumeInput</function>, the application may check <function>PQconsumeInput</function>, the application may check
<function>PQisBusy</function> and/or <function>PQnotifies</function> to see if <function>PQisBusy</function> and/or <function>PQnotifies</function> to see if
...@@ -1750,35 +2075,13 @@ state will never end. ...@@ -1750,35 +2075,13 @@ state will never end.
</para> </para>
</listitem> </listitem>
</varlistentry> </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> </variablelist>
</para> </para>
<para> <para>
A typical application using these functions will have a main loop that uses 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, 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 which in terms of <function>select()</function> means readable data on the file
descriptor identified by <function>PQsocket</function>. descriptor identified by <function>PQsocket</function>.
...@@ -1789,13 +2092,6 @@ if <function>PQisBusy</function> returns false (0). It can also call ...@@ -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">). <function>PQnotifies</function> to detect <command>NOTIFY</> messages (see <xref linkend="libpq-notify">).
</para> </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> <para>
A client that uses <function>PQsendQuery</function>/<function>PQgetResult</function> 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. 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 ...@@ -1843,6 +2139,89 @@ interactive cancellation of commands that it issues through <function>PQexec</fu
</variablelist> </variablelist>
</para> </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>
<sect1 id="libpq-fastpath"> <sect1 id="libpq-fastpath">
...@@ -1850,9 +2229,17 @@ interactive cancellation of commands that it issues through <function>PQexec</fu ...@@ -1850,9 +2229,17 @@ interactive cancellation of commands that it issues through <function>PQexec</fu
<para> <para>
<productname>PostgreSQL</productname> provides a fast-path interface to send <productname>PostgreSQL</productname> provides a fast-path interface to send
function calls to the server. This is a trapdoor into system internals and simple function calls to the server.
can be a potential security hole. Most users will not need this feature. </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> </para>
</tip>
<para> <para>
The function <function>PQfn</function> requests execution of a server The function <function>PQfn</function> requests execution of a server
...@@ -1879,25 +2266,42 @@ typedef struct { ...@@ -1879,25 +2266,42 @@ typedef struct {
<para> <para>
The <parameter>fnid</> argument is the OID of the function to be 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 <parameter>result_buf</parameter> is the buffer in which
to place the return value. The caller must have allocated to place the return value. The caller must have allocated
sufficient space to store the return value. (There is no check!) sufficient space to store the return value. (There is no check!)
The actual result length will be returned in the integer pointed 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 to by <parameter>result_len</parameter>.
<parameter>result_is_int</parameter> to 1, otherwise set it to 0. (Setting <parameter>result_is_int</parameter> to 1 If a 1, 2, or 4-byte integer result is expected, set
tells <application>libpq</> to byte-swap the value if necessary, so that it is <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 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 <parameter>result_is_int</> is 0, the binary-format byte string sent by
unmodified.) the server is returned unmodified.
<parameter>args</> and <parameter>nargs</> specify the arguments to be passed to the function. </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>
<para> <para>
<function>PQfn</function> always returns a valid <structname>PGresult</structname> pointer. The result status Note that it is not possible to handle NULL arguments, NULL results, nor
should be checked before the result is used. The set-valued results when using this interface.
caller is responsible for freeing the <structname>PGresult</structname> with
<function>PQclear</function> when it is no longer needed.
</para> </para>
</sect1> </sect1>
...@@ -1909,7 +2313,7 @@ typedef struct { ...@@ -1909,7 +2313,7 @@ typedef struct {
<para> <para>
<productname>PostgreSQL</productname> offers asynchronous notification via the <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 notification condition with the <command>LISTEN</command> command (and can stop listening
with the <command>UNLISTEN</command> command). All sessions listening on a 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 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. ...@@ -1922,7 +2326,7 @@ not necessary for there to be any associated table.
<para> <para>
<application>libpq</application> applications submit <command>LISTEN</command> and <command>UNLISTEN</command> <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>. messages can subsequently be detected by calling <function>PQnotifies</function>.
</para> </para>
...@@ -1937,18 +2341,30 @@ The function <function>PQnotifies</function> ...@@ -1937,18 +2341,30 @@ The function <function>PQnotifies</function>
PGnotify* PQnotifies(PGconn *conn); PGnotify* PQnotifies(PGconn *conn);
typedef struct pgNotify { typedef struct pgNotify {
char *relname; /* notification name */ char *relname; /* notification condition name */
int be_pid; /* process ID of server process */ int be_pid; /* process ID of server process */
char *extra; /* notification parameter */
} PGnotify; } PGnotify;
</synopsis> </synopsis>
After processing a <structname>PGnotify</structname> object returned by <function>PQnotifies</function>, After processing a <structname>PGnotify</structname> object returned by
be sure to free it with <function>PQfreemem()</function>. <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> </para>
</note>
<note> <note>
<para> <para>
In <productname>PostgreSQL</productname> 6.4 and later, 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. whereas in earlier versions it was always the <acronym>PID</acronym> of your own backend process.
</para> </para>
</note> </note>
...@@ -1996,19 +2412,263 @@ if any notifications came in during the processing of the command. ...@@ -1996,19 +2412,263 @@ if any notifications came in during the processing of the command.
</indexterm> </indexterm>
<para> <para>
The <command>COPY</command> command in <productname>PostgreSQL</productname> has options to read from The <command>COPY</command> command in <productname>PostgreSQL</productname>
or write to the network connection used by <application>libpq</application>. has options to read from or write to the network connection used by
Therefore, functions are necessary to access this network <application>libpq</application>. The functions described in this section
connection directly so applications may take advantage of this capability. 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>
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>
<para> <para>
These functions should be executed only after obtaining a result The functions of this section should be executed only after obtaining a
status of <literal>PGRES_COPY_OUT</literal> or result status of <literal>PGRES_COPY_OUT</literal> or
<literal>PGRES_COPY_IN</literal> from <function>PQexec</function> or <literal>PGRES_COPY_IN</literal> from <function>PQexec</function> or
<function>PQgetResult</function>. <function>PQgetResult</function>.
</para> </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> <variablelist>
<varlistentry> <varlistentry>
<term><function>PQgetline</function></term> <term><function>PQgetline</function></term>
...@@ -2042,9 +2702,6 @@ receive lines that are more than <parameter>length</>-1 characters long, ...@@ -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 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 (and does not, for example, mistake the end of a long data line
for a terminator 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -2123,13 +2780,13 @@ call; it is okay to send a partial line or multiple lines per call. ...@@ -2123,13 +2780,13 @@ call; it is okay to send a partial line or multiple lines per call.
<note> <note>
<para> <para>
Before <productname>PostgreSQL</productname> 7.4, it was necessary for the Before <productname>PostgreSQL</productname> protocol 3.0, it was necessary
application to explicitly send the two characters <literal>\.</literal> as a for the application to explicitly send the two characters
final line to indicate to the server that it had finished sending COPY data. <literal>\.</literal> as a final line to indicate to the server that it had
While this still works, it is deprecated and the special meaning of finished sending COPY data. While this still works, it is deprecated and the
<literal>\.</literal> can be expected to be removed in a future release. special meaning of <literal>\.</literal> can be expected to be removed in a
It is sufficient to call <function>PQendcopy</function> after having sent the future release. It is sufficient to call <function>PQendcopy</function> after
actual data. having sent the actual data.
</para> </para>
</note> </note>
</listitem> </listitem>
...@@ -2202,33 +2859,52 @@ This will work correctly only if the <command>COPY</command> is the only ...@@ -2202,33 +2859,52 @@ This will work correctly only if the <command>COPY</command> is the only
</varlistentry> </varlistentry>
</variablelist> </variablelist>
<para> </sect2>
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>
</sect1> </sect1>
<sect1 id="libpq-trace"> <sect1 id="libpq-control">
<title>Tracing Functions</title> <title>Control Functions</title>
<para>
These functions control miscellaneous details of
<application>libpq</>'s behavior.
</para>
<variablelist> <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> <varlistentry>
<term><function>PQtrace</function></term> <term><function>PQtrace</function></term>
<listitem> <listitem>
<para> <para>
Enables tracing of the client/server communication to a debugging file stream. Enables tracing of the client/server communication to a debugging file stream.
<synopsis> <synopsis>
void PQtrace(PGconn *conn void PQtrace(PGconn *conn, FILE *stream);
FILE *stream);
</synopsis> </synopsis>
</para> </para>
</listitem> </listitem>
...@@ -2249,14 +2925,43 @@ void PQuntrace(PGconn *conn); ...@@ -2249,14 +2925,43 @@ void PQuntrace(PGconn *conn);
</sect1> </sect1>
<sect1 id="libpq-control"> <sect1 id="libpq-notice-processing">
<title>Notice Processing</title> <title>Notice Processing</title>
<para> <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</></> <indexterm><primary>notice processor</></>
controls the reporting of notice and warning messages generated by the server. sets or examines the current notice processor.
<synopsis> <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); typedef void (*PQnoticeProcessor) (void *arg, const char *message);
PQnoticeProcessor PQnoticeProcessor
...@@ -2264,19 +2969,41 @@ PQsetNoticeProcessor(PGconn *conn, ...@@ -2264,19 +2969,41 @@ PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc, PQnoticeProcessor proc,
void *arg); void *arg);
</synopsis> </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>
<para> <para>
By default, <application>libpq</application> prints notice messages The notice processor is responsible for handling a notice or warning message
from the server, as well as a few error messages that it generates by given in text form. It is passed the string text of the message
itself, on <filename>stderr</filename>. (including a trailing newline), plus
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
a void pointer that is the same one passed to a void pointer that is the same one passed to
<function>PQsetNoticeProcessor</function>. <function>PQsetNoticeProcessor</function>.
(This pointer can be used to access application-specific state if needed.) (This pointer can be used to access application-specific state if needed.)
</para>
<para>
The default notice processor is simply The default notice processor is simply
<programlisting> <programlisting>
static void static void
...@@ -2285,22 +3012,14 @@ defaultNoticeProcessor(void * arg, const char * message) ...@@ -2285,22 +3012,14 @@ defaultNoticeProcessor(void * arg, const char * message)
fprintf(stderr, "%s", message); fprintf(stderr, "%s", message);
} }
</programlisting> </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>
<para> <para>
Once you have set a notice processor, you should expect that that function Once you have set a notice receiver or processor, you should expect that that
could be called as long as either the <structname>PGconn</> object or <structname>PGresult</> objects function could be called as long as either the <structname>PGconn</> object or
made from it exist. At creation of a <structname>PGresult</>, the <structname>PGconn</>'s current <structname>PGresult</> objects made from it exist. At creation of a
notice processor pointer is copied into the <structname>PGresult</> for possible use by <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>. functions like <function>PQgetvalue</function>.
</para> </para>
...@@ -2449,7 +3168,10 @@ It is not recommended to set the timeout to less than 2 seconds. ...@@ -2449,7 +3168,10 @@ It is not recommended to set the timeout to less than 2 seconds.
<para> <para>
The following environment variables can be used to specify default 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> <itemizedlist>
<listitem> <listitem>
...@@ -2545,8 +3267,8 @@ If the permissions are less strict than this, the file will be ignored. ...@@ -2545,8 +3267,8 @@ If the permissions are less strict than this, the file will be ignored.
<para> <para>
<application>libpq</application> is thread-safe if the library is <application>libpq</application> is thread-safe if the library is
compiled using the <literal>--with-threads</> compiled using <filename>configure</filename>'s <literal>--with-threads</>
<filename>configure</filename> command-line option. (You might need to command-line option. (In addition, you might need to
use other threading command-line options to compile your client code.) use other threading command-line options to compile your client code.)
</para> </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"> <chapter id="largeObjects">
...@@ -181,7 +181,8 @@ int lo_open(PGconn *conn, Oid lobjId, int mode); ...@@ -181,7 +181,8 @@ int lo_open(PGconn *conn, Oid lobjId, int mode);
<function>lo_open</function> returns a large object descriptor <function>lo_open</function> returns a large object descriptor
for later use in <function>lo_read</function>, <function>lo_write</function>, for later use in <function>lo_read</function>, <function>lo_write</function>,
<function>lo_lseek</function>, <function>lo_tell</function>, and <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> </para>
</sect2> </sect2>
...@@ -256,6 +257,11 @@ int lo_close(PGconn *conn, int fd); ...@@ -256,6 +257,11 @@ int lo_close(PGconn *conn, int fd);
<function>lo_open</function>. On success, <function>lo_close</function> <function>lo_open</function>. On success, <function>lo_close</function>
returns zero. On error, the return value is negative. returns zero. On error, the return value is negative.
</para> </para>
<para>
Any large object descriptors that remain open at the end of a
transaction will be closed automatically.
</para>
</sect2> </sect2>
<sect2> <sect2>
...@@ -296,6 +302,14 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image ...@@ -296,6 +302,14 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image
WHERE name = 'beautiful image'; WHERE name = 'beautiful image';
</programlisting> </programlisting>
</para> </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>
<sect1 id="lo-examplesect"> <sect1 id="lo-examplesect">
......
...@@ -97,6 +97,20 @@ EXPORTS ...@@ -97,6 +97,20 @@ EXPORTS
_pg_utf_mblen @ 93 _pg_utf_mblen @ 93
_PQunescapeBytea @ 94 _PQunescapeBytea @ 94
_PQfreemem @ 95 _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 ; Aliases for MS compatible names
PQconnectdb = _PQconnectdb PQconnectdb = _PQconnectdb
...@@ -194,4 +208,17 @@ EXPORTS ...@@ -194,4 +208,17 @@ EXPORTS
pg_utf_mblen = _pg_utf_mblen pg_utf_mblen = _pg_utf_mblen
PQunescapeBytea = _PQunescapeBytea PQunescapeBytea = _PQunescapeBytea
PQfreemem = _PQfreemem 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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -176,6 +176,7 @@ static PQconninfoOption *conninfo_parse(const char *conninfo,
PQExpBuffer errorMessage); PQExpBuffer errorMessage);
static char *conninfo_getval(PQconninfoOption *connOptions, static char *conninfo_getval(PQconninfoOption *connOptions,
const char *keyword); const char *keyword);
static void defaultNoticeReceiver(void *arg, const PGresult *res);
static void defaultNoticeProcessor(void *arg, const char *message); static void defaultNoticeProcessor(void *arg, const char *message);
static int parseServiceInfo(PQconninfoOption *options, static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage); PQExpBuffer errorMessage);
...@@ -1804,11 +1805,14 @@ makeEmptyPGconn(void) ...@@ -1804,11 +1805,14 @@ makeEmptyPGconn(void)
/* Zero all pointers and booleans */ /* Zero all pointers and booleans */
MemSet((char *) conn, 0, sizeof(PGconn)); MemSet((char *) conn, 0, sizeof(PGconn));
conn->noticeHook = defaultNoticeProcessor; conn->noticeHooks.noticeRec = defaultNoticeReceiver;
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
conn->xactStatus = PQTRANS_IDLE;
conn->setenv_state = SETENV_STATE_IDLE; conn->setenv_state = SETENV_STATE_IDLE;
conn->client_encoding = PG_SQL_ASCII; conn->client_encoding = PG_SQL_ASCII;
conn->verbosity = PQERRORS_DEFAULT;
conn->notifyList = DLNewList(); conn->notifyList = DLNewList();
conn->sock = -1; conn->sock = -1;
#ifdef USE_SSL #ifdef USE_SSL
...@@ -1850,7 +1854,6 @@ makeEmptyPGconn(void) ...@@ -1850,7 +1854,6 @@ makeEmptyPGconn(void)
/* /*
* freePGconn * freePGconn
* - free the PGconn data structure * - free the PGconn data structure
*
*/ */
static void static void
freePGconn(PGconn *conn) freePGconn(PGconn *conn)
...@@ -1899,9 +1902,9 @@ freePGconn(PGconn *conn) ...@@ -1899,9 +1902,9 @@ freePGconn(PGconn *conn)
} }
/* /*
closePGconn * closePGconn
- properly close a connection to the backend * - properly close a connection to the backend
*/ */
static void static void
closePGconn(PGconn *conn) closePGconn(PGconn *conn)
{ {
...@@ -2662,6 +2665,41 @@ PQstatus(const PGconn *conn) ...@@ -2662,6 +2665,41 @@ PQstatus(const PGconn *conn)
return conn->status; 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 * char *
PQerrorMessage(const PGconn *conn) PQerrorMessage(const PGconn *conn)
{ {
...@@ -2731,11 +2769,22 @@ PQsetClientEncoding(PGconn *conn, const char *encoding) ...@@ -2731,11 +2769,22 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
return (status); return (status);
} }
PGVerbosity
PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
{
PGVerbosity old;
if (!conn)
return PQERRORS_DEFAULT;
old = conn->verbosity;
conn->verbosity = verbosity;
return old;
}
void void
PQtrace(PGconn *conn, FILE *debug_port) PQtrace(PGconn *conn, FILE *debug_port)
{ {
if (conn == NULL || if (conn == NULL)
conn->status == CONNECTION_BAD)
return; return;
PQuntrace(conn); PQuntrace(conn);
conn->Pfdebug = debug_port; conn->Pfdebug = debug_port;
...@@ -2744,7 +2793,6 @@ PQtrace(PGconn *conn, FILE *debug_port) ...@@ -2744,7 +2793,6 @@ PQtrace(PGconn *conn, FILE *debug_port)
void void
PQuntrace(PGconn *conn) PQuntrace(PGconn *conn)
{ {
/* note: better allow untrace even when connection bad */
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->Pfdebug) if (conn->Pfdebug)
...@@ -2754,6 +2802,23 @@ PQuntrace(PGconn *conn) ...@@ -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 PQnoticeProcessor
PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg) PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
{ {
...@@ -2762,22 +2827,35 @@ PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg) ...@@ -2762,22 +2827,35 @@ PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
if (conn == NULL) if (conn == NULL)
return NULL; return NULL;
old = conn->noticeHook; old = conn->noticeHooks.noticeProc;
if (proc) if (proc)
{ {
conn->noticeHook = proc; conn->noticeHooks.noticeProc = proc;
conn->noticeArg = arg; conn->noticeHooks.noticeProcArg = arg;
} }
return old; 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 * message on stderr. Applications can override this if they
* want the messages to go elsewhere (a window, for example). * want the messages to go elsewhere (a window, for example).
* Note that simply discarding notices is probably a bad idea. * Note that simply discarding notices is probably a bad idea.
*/ */
static void static void
defaultNoticeProcessor(void *arg, const char *message) defaultNoticeProcessor(void *arg, const char *message)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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[] = { ...@@ -43,7 +43,10 @@ char *const pgresStatus[] = {
static bool PQsendQueryStart(PGconn *conn);
static void parseInput(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) ...@@ -137,16 +140,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
result->cmdStatus[0] = '\0'; result->cmdStatus[0] = '\0';
result->binary = 0; result->binary = 0;
result->errMsg = NULL; result->errMsg = NULL;
result->errSeverity = NULL; result->errFields = 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->null_field[0] = '\0'; result->null_field[0] = '\0';
result->curBlock = NULL; result->curBlock = NULL;
result->curOffset = 0; result->curOffset = 0;
...@@ -155,8 +149,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) ...@@ -155,8 +149,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
if (conn) if (conn)
{ {
/* copy connection data we might need for operations on PGresult */ /* copy connection data we might need for operations on PGresult */
result->noticeHook = conn->noticeHook; result->noticeHooks = conn->noticeHooks;
result->noticeArg = conn->noticeArg;
result->client_encoding = conn->client_encoding; result->client_encoding = conn->client_encoding;
/* consider copying conn's errorMessage */ /* consider copying conn's errorMessage */
...@@ -177,9 +170,11 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) ...@@ -177,9 +170,11 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
else else
{ {
/* defaults... */ /* defaults... */
result->noticeHook = NULL; result->noticeHooks.noticeRec = NULL;
result->noticeArg = NULL; result->noticeHooks.noticeRecArg = NULL;
result->client_encoding = 0; /* should be SQL_ASCII */ result->noticeHooks.noticeProc = NULL;
result->noticeHooks.noticeProcArg = NULL;
result->client_encoding = PG_SQL_ASCII;
} }
return result; return result;
...@@ -444,6 +439,41 @@ pqPrepareAsyncResult(PGconn *conn) ...@@ -444,6 +439,41 @@ pqPrepareAsyncResult(PGconn *conn)
return res; 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 * pqAddTuple
* add a row pointer to the PGresult structure, growing it if necessary * add a row pointer to the PGresult structure, growing it if necessary
...@@ -484,6 +514,25 @@ pqAddTuple(PGresult *res, PGresAttValue *tup) ...@@ -484,6 +514,25 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
return TRUE; 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 * pqSaveParameterStatus - remember parameter status sent by backend
...@@ -543,26 +592,6 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value) ...@@ -543,26 +592,6 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
StrNCpy(conn->sversion, value, sizeof(conn->sversion)); 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 * PQsendQuery
...@@ -574,12 +603,9 @@ pqGetParameterStatus(PGconn *conn, const char *name) ...@@ -574,12 +603,9 @@ pqGetParameterStatus(PGconn *conn, const char *name)
int int
PQsendQuery(PGconn *conn, const char *query) PQsendQuery(PGconn *conn, const char *query)
{ {
if (!conn) if (!PQsendQueryStart(conn))
return 0; return 0;
/* clear the error string */
resetPQExpBuffer(&conn->errorMessage);
if (!query) if (!query)
{ {
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
...@@ -587,25 +613,6 @@ PQsendQuery(PGconn *conn, const char *query) ...@@ -587,25 +613,6 @@ PQsendQuery(PGconn *conn, const char *query)
return 0; 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 */ /* construct the outgoing Query message */
if (pqPutMsgStart('Q', false, conn) < 0 || if (pqPutMsgStart('Q', false, conn) < 0 ||
pqPuts(query, conn) < 0 || pqPuts(query, conn) < 0 ||
...@@ -617,7 +624,7 @@ PQsendQuery(PGconn *conn, const char *query) ...@@ -617,7 +624,7 @@ PQsendQuery(PGconn *conn, const char *query)
/* /*
* Give the data a push. In nonblock mode, don't complain if we're * 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. * needed.
*/ */
if (pqFlush(conn) < 0) if (pqFlush(conn) < 0)
...@@ -631,6 +638,194 @@ PQsendQuery(PGconn *conn, const char *query) ...@@ -631,6 +638,194 @@ PQsendQuery(PGconn *conn, const char *query)
return 1; 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. * pqHandleSendFailure: try to clean up after failure to send command.
* *
...@@ -746,8 +941,24 @@ PQgetResult(PGconn *conn) ...@@ -746,8 +941,24 @@ PQgetResult(PGconn *conn)
/* If not ready to return something, block until we are. */ /* If not ready to return something, block until we are. */
while (conn->asyncStatus == PGASYNC_BUSY) 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. */ /* Wait for some more data, and load it. */
if (pqWait(TRUE, FALSE, conn) || if (flushResult ||
pqWait(TRUE, FALSE, conn) ||
pqReadData(conn) < 0) pqReadData(conn) < 0)
{ {
/* /*
...@@ -758,6 +969,7 @@ PQgetResult(PGconn *conn) ...@@ -758,6 +969,7 @@ PQgetResult(PGconn *conn)
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
return pqPrepareAsyncResult(conn); return pqPrepareAsyncResult(conn);
} }
/* Parse it. */ /* Parse it. */
parseInput(conn); parseInput(conn);
} }
...@@ -774,9 +986,15 @@ PQgetResult(PGconn *conn) ...@@ -774,9 +986,15 @@ PQgetResult(PGconn *conn)
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
break; break;
case PGASYNC_COPY_IN: case PGASYNC_COPY_IN:
if (conn->result && conn->result->resultStatus == PGRES_COPY_IN)
res = pqPrepareAsyncResult(conn);
else
res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN); res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
break; break;
case PGASYNC_COPY_OUT: case PGASYNC_COPY_OUT:
if (conn->result && conn->result->resultStatus == PGRES_COPY_OUT)
res = pqPrepareAsyncResult(conn);
else
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT); res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
break; break;
default: default:
...@@ -806,18 +1024,46 @@ PQgetResult(PGconn *conn) ...@@ -806,18 +1024,46 @@ PQgetResult(PGconn *conn)
PGresult * PGresult *
PQexec(PGconn *conn, const char *query) PQexec(PGconn *conn, const char *query)
{ {
PGresult *result; if (!PQexecStart(conn))
PGresult *lastResult; return NULL;
bool savedblocking; if (!PQsendQuery(conn, query))
return NULL;
return PQexecFinish(conn);
}
/* /*
* we assume anyone calling PQexec wants blocking behaviour, we force * PQexecParams
* the blocking status of the connection to blocking for the duration * Like PQexec, but use 3.0 protocol so we can pass parameters
* of this function and restore it on return
*/ */
savedblocking = pqIsnonblocking(conn); PGresult *
if (PQsetnonblocking(conn, FALSE) == -1) 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 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 * Silently discard any prior query result that application didn't
...@@ -832,15 +1078,23 @@ PQexec(PGconn *conn, const char *query) ...@@ -832,15 +1078,23 @@ PQexec(PGconn *conn, const char *query)
PQclear(result); PQclear(result);
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("COPY state must be terminated first\n")); libpq_gettext("COPY state must be terminated first\n"));
/* restore blocking status */ return false;
goto errout;
} }
PQclear(result); PQclear(result);
} }
/* OK to send the message */ /* OK to send a command */
if (!PQsendQuery(conn, query)) return true;
goto errout; /* restore blocking status */ }
/*
* 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 * For backwards compatibility, return the last result if there are
...@@ -848,7 +1102,7 @@ PQexec(PGconn *conn, const char *query) ...@@ -848,7 +1102,7 @@ PQexec(PGconn *conn, const char *query)
* error result. * error result.
* *
* We have to stop if we see copy in/out, however. We will resume parsing * 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; lastResult = NULL;
while ((result = PQgetResult(conn)) != NULL) while ((result = PQgetResult(conn)) != NULL)
...@@ -874,14 +1128,7 @@ PQexec(PGconn *conn, const char *query) ...@@ -874,14 +1128,7 @@ PQexec(PGconn *conn, const char *query)
break; break;
} }
if (PQsetnonblocking(conn, savedblocking) == -1)
return NULL;
return lastResult; return lastResult;
errout:
if (PQsetnonblocking(conn, savedblocking) == -1)
return NULL;
return NULL;
} }
/* /*
...@@ -894,7 +1141,6 @@ errout: ...@@ -894,7 +1141,6 @@ errout:
* *
* the CALLER is responsible for FREE'ing the structure returned * the CALLER is responsible for FREE'ing the structure returned
*/ */
PGnotify * PGnotify *
PQnotifies(PGconn *conn) PQnotifies(PGconn *conn)
{ {
...@@ -916,6 +1162,156 @@ PQnotifies(PGconn *conn) ...@@ -916,6 +1162,156 @@ PQnotifies(PGconn *conn)
return event; 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. * PQgetline - gets a newline-terminated string from the backend.
* *
...@@ -1002,11 +1398,12 @@ PQgetlineAsync(PGconn *conn, char *buffer, int bufsize) ...@@ -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. * Returns 0 if OK, EOF if not.
* *
* This exists to support "COPY <rel> from stdin". The backend will ignore * This is deprecated primarily because the return convention doesn't allow
* the string if not doing COPY. * caller to tell the difference between a hard error and a nonblock-mode
* send failure.
*/ */
int int
PQputline(PGconn *conn, const char *s) PQputline(PGconn *conn, const char *s)
...@@ -1021,27 +1418,10 @@ PQputline(PGconn *conn, const char *s) ...@@ -1021,27 +1418,10 @@ PQputline(PGconn *conn, const char *s)
int int
PQputnbytes(PGconn *conn, const char *buffer, int nbytes) PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
{ {
if (!conn || conn->sock < 0) if (PQputCopyData(conn, buffer, nbytes) > 0)
return EOF; return 0;
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 else
{
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return EOF; return EOF;
}
}
return 0;
} }
/* /*
...@@ -1049,6 +1429,11 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes) ...@@ -1049,6 +1429,11 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
* After completing the data transfer portion of a copy in/out, * After completing the data transfer portion of a copy in/out,
* the application must call this routine to finish the command protocol. * 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: * RETURNS:
* 0 on success * 0 on success
* 1 on failure * 1 on failure
...@@ -1133,7 +1518,7 @@ ExecStatusType ...@@ -1133,7 +1518,7 @@ ExecStatusType
PQresultStatus(const PGresult *res) PQresultStatus(const PGresult *res)
{ {
if (!res) if (!res)
return PGRES_NONFATAL_ERROR; return PGRES_FATAL_ERROR;
return res->resultStatus; return res->resultStatus;
} }
...@@ -1153,6 +1538,21 @@ PQresultErrorMessage(const PGresult *res) ...@@ -1153,6 +1538,21 @@ PQresultErrorMessage(const PGresult *res)
return res->errMsg; 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 int
PQntuples(const PGresult *res) PQntuples(const PGresult *res)
{ {
...@@ -1190,14 +1590,11 @@ check_field_number(const PGresult *res, int field_num) ...@@ -1190,14 +1590,11 @@ check_field_number(const PGresult *res, int field_num)
if (!res) if (!res)
return FALSE; /* no way to display error message... */ return FALSE; /* no way to display error message... */
if (field_num < 0 || field_num >= res->numAttributes) if (field_num < 0 || field_num >= res->numAttributes)
{
if (res->noticeHook)
{ {
snprintf(noticeBuf, sizeof(noticeBuf), snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d\n"), libpq_gettext("column number %d is out of range 0..%d"),
field_num, res->numAttributes - 1); field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf); PGDONOTICE(res, noticeBuf);
}
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
...@@ -1212,33 +1609,27 @@ check_tuple_field_number(const PGresult *res, ...@@ -1212,33 +1609,27 @@ check_tuple_field_number(const PGresult *res,
if (!res) if (!res)
return FALSE; /* no way to display error message... */ return FALSE; /* no way to display error message... */
if (tup_num < 0 || tup_num >= res->ntups) if (tup_num < 0 || tup_num >= res->ntups)
{
if (res->noticeHook)
{ {
snprintf(noticeBuf, sizeof(noticeBuf), snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("row number %d is out of range 0..%d\n"), libpq_gettext("row number %d is out of range 0..%d"),
tup_num, res->ntups - 1); tup_num, res->ntups - 1);
PGDONOTICE(res, noticeBuf); PGDONOTICE(res, noticeBuf);
}
return FALSE; return FALSE;
} }
if (field_num < 0 || field_num >= res->numAttributes) if (field_num < 0 || field_num >= res->numAttributes)
{
if (res->noticeHook)
{ {
snprintf(noticeBuf, sizeof(noticeBuf), snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("column number %d is out of range 0..%d\n"), libpq_gettext("column number %d is out of range 0..%d"),
field_num, res->numAttributes - 1); field_num, res->numAttributes - 1);
PGDONOTICE(res, noticeBuf); PGDONOTICE(res, noticeBuf);
}
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
/* /*
returns NULL if the field_num is invalid * returns NULL if the field_num is invalid
*/ */
char * char *
PQfname(const PGresult *res, int field_num) PQfname(const PGresult *res, int field_num)
{ {
...@@ -1251,8 +1642,8 @@ 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 int
PQfnumber(const PGresult *res, const char *field_name) PQfnumber(const PGresult *res, const char *field_name)
{ {
...@@ -1290,6 +1681,39 @@ PQfnumber(const PGresult *res, const char *field_name) ...@@ -1290,6 +1681,39 @@ PQfnumber(const PGresult *res, const char *field_name)
return -1; 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 Oid
PQftype(const PGresult *res, int field_num) PQftype(const PGresult *res, int field_num)
{ {
...@@ -1332,10 +1756,10 @@ PQcmdStatus(PGresult *res) ...@@ -1332,10 +1756,10 @@ PQcmdStatus(PGresult *res)
} }
/* /*
PQoidStatus - * PQoidStatus -
if the last command was an INSERT, return the oid string * if the last command was an INSERT, return the oid string
if not, return "" * if not, return ""
*/ */
char * char *
PQoidStatus(const PGresult *res) PQoidStatus(const PGresult *res)
{ {
...@@ -1360,10 +1784,10 @@ PQoidStatus(const PGresult *res) ...@@ -1360,10 +1784,10 @@ PQoidStatus(const PGresult *res)
} }
/* /*
PQoidValue - * PQoidValue -
a perhaps preferable form of the above which just returns * a perhaps preferable form of the above which just returns
an Oid type * an Oid type
*/ */
Oid Oid
PQoidValue(const PGresult *res) PQoidValue(const PGresult *res)
{ {
...@@ -1388,13 +1812,13 @@ PQoidValue(const PGresult *res) ...@@ -1388,13 +1812,13 @@ PQoidValue(const PGresult *res)
/* /*
PQcmdTuples - * PQcmdTuples -
If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a * If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a
string containing the number of inserted/affected tuples. If not, * string containing the number of inserted/affected tuples. If not,
return "". * return "".
*
XXX: this should probably return an int * XXX: this should probably return an int
*/ */
char * char *
PQcmdTuples(PGresult *res) PQcmdTuples(PGresult *res)
{ {
...@@ -1425,14 +1849,11 @@ PQcmdTuples(PGresult *res) ...@@ -1425,14 +1849,11 @@ PQcmdTuples(PGresult *res)
p++; p++;
if (*p == 0) if (*p == 0)
{
if (res->noticeHook)
{ {
snprintf(noticeBuf, sizeof(noticeBuf), snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("could not interpret result from server: %s\n"), libpq_gettext("could not interpret result from server: %s"),
res->cmdStatus); res->cmdStatus);
PGDONOTICE(res, noticeBuf); PGDONOTICE(res, noticeBuf);
}
return ""; return "";
} }
...@@ -1440,15 +1861,9 @@ PQcmdTuples(PGresult *res) ...@@ -1440,15 +1861,9 @@ PQcmdTuples(PGresult *res)
} }
/* /*
PQgetvalue: * PQgetvalue:
return the value of field 'field_num' of row 'tup_num' * 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.
*/
char * char *
PQgetvalue(const PGresult *res, int tup_num, int field_num) PQgetvalue(const PGresult *res, int tup_num, int field_num)
{ {
...@@ -1458,11 +1873,8 @@ 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: /* PQgetlength:
returns the length of a field value in bytes. If res is binary, * returns the actual length of a field value in bytes.
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.)
*/
int int
PQgetlength(const PGresult *res, int tup_num, int field_num) PQgetlength(const PGresult *res, int tup_num, int field_num)
{ {
...@@ -1475,8 +1887,8 @@ 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: /* PQgetisnull:
returns the null status of a field value. * returns the null status of a field value.
*/ */
int int
PQgetisnull(const PGresult *res, int tup_num, int field_num) PQgetisnull(const PGresult *res, int tup_num, int field_num)
{ {
...@@ -1489,16 +1901,17 @@ 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: /* PQsetnonblocking:
sets the PGconn's database connection non-blocking if the arg is TRUE * 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 * 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 * you from PQexec(), you'll only be safe when using the non-blocking API.
API * Needs to be called only on a connected database connection.
Needs to be called only on a connected database connection. */
*/
int int
PQsetnonblocking(PGconn *conn, int arg) PQsetnonblocking(PGconn *conn, int arg)
{ {
if (!conn || conn->status == CONNECTION_BAD)
return -1;
arg = (arg == TRUE) ? 1 : 0; arg = (arg == TRUE) ? 1 : 0;
/* early out if the socket is already in the state requested */ /* early out if the socket is already in the state requested */
if (arg == conn->nonblocking) if (arg == conn->nonblocking)
...@@ -1520,9 +1933,10 @@ PQsetnonblocking(PGconn *conn, int arg) ...@@ -1520,9 +1933,10 @@ PQsetnonblocking(PGconn *conn, int arg)
return (0); 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 int
PQisnonblocking(const PGconn *conn) PQisnonblocking(const PGconn *conn)
{ {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -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 * read a 2 or 4 byte integer and convert from network byte order
* to local byte order * to local byte order
*/ */
...@@ -226,7 +226,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn) ...@@ -226,7 +226,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
break; break;
default: default:
snprintf(noticeBuf, sizeof(noticeBuf), 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); (unsigned long) bytes);
PGDONOTICE(conn, noticeBuf); PGDONOTICE(conn, noticeBuf);
return EOF; return EOF;
...@@ -239,7 +239,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn) ...@@ -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 * write an integer of 2 or 4 bytes, converting from host byte order
* to network byte order. * to network byte order.
*/ */
...@@ -264,7 +264,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn) ...@@ -264,7 +264,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
break; break;
default: default:
snprintf(noticeBuf, sizeof(noticeBuf), 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); (unsigned long) bytes);
PGDONOTICE(conn, noticeBuf); PGDONOTICE(conn, noticeBuf);
return EOF; return EOF;
...@@ -282,7 +282,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn) ...@@ -282,7 +282,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
* *
* Returns 0 on success, EOF if failed to enlarge buffer * Returns 0 on success, EOF if failed to enlarge buffer
*/ */
static int int
pqCheckOutBufferSpace(int bytes_needed, PGconn *conn) pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
{ {
int newsize = conn->outBufSize; int newsize = conn->outBufSize;
...@@ -748,7 +748,7 @@ pqSendSome(PGconn *conn, int len) ...@@ -748,7 +748,7 @@ pqSendSome(PGconn *conn, int len)
if (sent < 0) 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 * EPIPE or ECONNRESET, assume we've lost the backend
* connection permanently. * connection permanently.
*/ */
...@@ -804,25 +804,17 @@ pqSendSome(PGconn *conn, int len) ...@@ -804,25 +804,17 @@ pqSendSome(PGconn *conn, int len)
if (len > 0) 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 * We didn't send it all, wait till we can send more.
* here and return 1 to indicate that data is still pending. *
* 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)
{
#endif
if (pqIsnonblocking(conn)) if (pqIsnonblocking(conn))
{ {
result = 1; result = 1;
break; break;
} }
#ifdef USE_SSL
}
#endif
if (pqWait(FALSE, TRUE, conn)) if (pqWait(FALSE, TRUE, conn))
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -38,6 +38,7 @@
static int getRowDescriptions(PGconn *conn); static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn, bool binary); static int getAnotherTuple(PGconn *conn, bool binary);
static int pqGetErrorNotice2(PGconn *conn, bool isError); static int pqGetErrorNotice2(PGconn *conn, bool isError);
static void checkXactStatus(PGconn *conn, const char *cmdTag);
static int getNotify(PGconn *conn); static int getNotify(PGconn *conn);
...@@ -312,7 +313,7 @@ pqSetenvPoll(PGconn *conn) ...@@ -312,7 +313,7 @@ pqSetenvPoll(PGconn *conn)
val); val);
else else
{ {
val = pqGetParameterStatus(conn, "server_encoding"); val = PQparameterStatus(conn, "server_encoding");
if (val && *val) if (val && *val)
pqSaveParameterStatus(conn, "client_encoding", pqSaveParameterStatus(conn, "client_encoding",
val); val);
...@@ -424,7 +425,7 @@ pqParseInput2(PGconn *conn) ...@@ -424,7 +425,7 @@ pqParseInput2(PGconn *conn)
else else
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), 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); id);
PGDONOTICE(conn, noticeWorkspace); PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */ /* Discard the unexpected message; good idea?? */
...@@ -447,6 +448,7 @@ pqParseInput2(PGconn *conn) ...@@ -447,6 +448,7 @@ pqParseInput2(PGconn *conn)
PGRES_COMMAND_OK); PGRES_COMMAND_OK);
strncpy(conn->result->cmdStatus, conn->workBuffer.data, strncpy(conn->result->cmdStatus, conn->workBuffer.data,
CMDSTATUS_LEN); CMDSTATUS_LEN);
checkXactStatus(conn, conn->workBuffer.data);
conn->asyncStatus = PGASYNC_READY; conn->asyncStatus = PGASYNC_READY;
break; break;
case 'E': /* error return */ case 'E': /* error return */
...@@ -464,7 +466,7 @@ pqParseInput2(PGconn *conn) ...@@ -464,7 +466,7 @@ pqParseInput2(PGconn *conn)
if (id != '\0') if (id != '\0')
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), 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); id);
PGDONOTICE(conn, noticeWorkspace); PGDONOTICE(conn, noticeWorkspace);
} }
...@@ -521,7 +523,7 @@ pqParseInput2(PGconn *conn) ...@@ -521,7 +523,7 @@ pqParseInput2(PGconn *conn)
else else
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), 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); PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */ /* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd; conn->inStart = conn->inEnd;
...@@ -538,7 +540,7 @@ pqParseInput2(PGconn *conn) ...@@ -538,7 +540,7 @@ pqParseInput2(PGconn *conn)
else else
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), 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); PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message; good idea?? */ /* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd; conn->inStart = conn->inEnd;
...@@ -628,6 +630,9 @@ getRowDescriptions(PGconn *conn) ...@@ -628,6 +630,9 @@ getRowDescriptions(PGconn *conn)
result->attDescs[i].name = pqResultStrdup(result, result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data); 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].typid = typid;
result->attDescs[i].typlen = typlen; result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod; result->attDescs[i].atttypmod = atttypmod;
...@@ -674,6 +679,15 @@ getAnotherTuple(PGconn *conn, bool binary) ...@@ -674,6 +679,15 @@ getAnotherTuple(PGconn *conn, bool binary)
if (conn->curTuple == NULL) if (conn->curTuple == NULL)
goto outOfMemory; goto outOfMemory;
MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue)); 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; tup = conn->curTuple;
...@@ -778,6 +792,8 @@ pqGetErrorNotice2(PGconn *conn, bool isError) ...@@ -778,6 +792,8 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
{ {
PGresult *res; PGresult *res;
PQExpBufferData workBuf; PQExpBufferData workBuf;
char *startp;
char *splitp;
/* /*
* Since the message might be pretty long, we create a temporary * Since the message might be pretty long, we create a temporary
...@@ -800,19 +816,63 @@ pqGetErrorNotice2(PGconn *conn, bool isError) ...@@ -800,19 +816,63 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
res->errMsg = pqResultStrdup(res, workBuf.data); 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. * 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) if (isError)
{ {
pqClearAsyncResult(conn); pqClearAsyncResult(conn);
conn->result = res; conn->result = res;
resetPQExpBuffer(&conn->errorMessage); resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, workBuf.data); appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
if (conn->xactStatus == PQTRANS_INTRANS)
conn->xactStatus = PQTRANS_INERROR;
} }
else else
{ {
PGDONOTICE(conn, workBuf.data); (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
PQclear(res); PQclear(res);
} }
...@@ -820,6 +880,37 @@ pqGetErrorNotice2(PGconn *conn, bool isError) ...@@ -820,6 +880,37 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
return 0; 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. * Attempt to read a Notify response message.
...@@ -832,6 +923,7 @@ static int ...@@ -832,6 +923,7 @@ static int
getNotify(PGconn *conn) getNotify(PGconn *conn)
{ {
int be_pid; int be_pid;
int nmlen;
PGnotify *newNotify; PGnotify *newNotify;
if (pqGetInt(&be_pid, 4, conn)) if (pqGetInt(&be_pid, 4, conn))
...@@ -844,12 +936,14 @@ getNotify(PGconn *conn) ...@@ -844,12 +936,14 @@ getNotify(PGconn *conn)
* can all be freed at once. We don't use NAMEDATALEN because we * 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. * don't want to tie this interface to a specific server name length.
*/ */
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen = strlen(conn->workBuffer.data);
strlen(conn->workBuffer.data) +1); newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
if (newNotify) if (newNotify)
{ {
newNotify->relname = (char *) newNotify + sizeof(PGnotify); newNotify->relname = (char *) newNotify + sizeof(PGnotify);
strcpy(newNotify->relname, conn->workBuffer.data); strcpy(newNotify->relname, conn->workBuffer.data);
/* fake up an empty-string extra field */
newNotify->extra = newNotify->relname + nmlen;
newNotify->be_pid = be_pid; newNotify->be_pid = be_pid;
DLAddTail(conn->notifyList, DLNewElem(newNotify)); DLAddTail(conn->notifyList, DLNewElem(newNotify));
} }
...@@ -858,6 +952,84 @@ getNotify(PGconn *conn) ...@@ -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. * PQgetline - gets a newline-terminated string from the backend.
* *
...@@ -1020,7 +1192,7 @@ pqEndcopy2(PGconn *conn) ...@@ -1020,7 +1192,7 @@ pqEndcopy2(PGconn *conn)
if (conn->errorMessage.len > 0) if (conn->errorMessage.len > 0)
PGDONOTICE(conn, conn->errorMessage.data); 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 * Users doing non-blocking connections need to handle the reset
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -40,6 +40,8 @@ static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn, int msgLength); static int getAnotherTuple(PGconn *conn, int msgLength);
static int getParameterStatus(PGconn *conn); static int getParameterStatus(PGconn *conn);
static int getNotify(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, static int build_startup_packet(const PGconn *conn, char *packet,
const PQEnvironmentOption *options); const PQEnvironmentOption *options);
...@@ -171,7 +173,7 @@ pqParseInput3(PGconn *conn) ...@@ -171,7 +173,7 @@ pqParseInput3(PGconn *conn)
else else
{ {
snprintf(noticeWorkspace, sizeof(noticeWorkspace), 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); id);
PGDONOTICE(conn, noticeWorkspace); PGDONOTICE(conn, noticeWorkspace);
/* Discard the unexpected message */ /* Discard the unexpected message */
...@@ -201,7 +203,7 @@ pqParseInput3(PGconn *conn) ...@@ -201,7 +203,7 @@ pqParseInput3(PGconn *conn)
conn->asyncStatus = PGASYNC_READY; conn->asyncStatus = PGASYNC_READY;
break; break;
case 'Z': /* backend is ready for new query */ case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn)) if (getReadyForQuery(conn))
return; return;
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
break; break;
...@@ -211,6 +213,11 @@ pqParseInput3(PGconn *conn) ...@@ -211,6 +213,11 @@ pqParseInput3(PGconn *conn)
PGRES_EMPTY_QUERY); PGRES_EMPTY_QUERY);
conn->asyncStatus = PGASYNC_READY; conn->asyncStatus = PGASYNC_READY;
break; 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 */ case 'S': /* parameter status */
if (getParameterStatus(conn)) if (getParameterStatus(conn))
return; return;
...@@ -276,17 +283,13 @@ pqParseInput3(PGconn *conn) ...@@ -276,17 +283,13 @@ pqParseInput3(PGconn *conn)
} }
break; break;
case 'G': /* Start Copy In */ case 'G': /* Start Copy In */
if (pqGetc(&conn->copy_is_binary, conn)) if (getCopyStart(conn, PGRES_COPY_IN))
return; return;
/* XXX we currently ignore the rest of the message */
conn->inCursor = conn->inStart + 5 + msgLength;
conn->asyncStatus = PGASYNC_COPY_IN; conn->asyncStatus = PGASYNC_COPY_IN;
break; break;
case 'H': /* Start Copy Out */ case 'H': /* Start Copy Out */
if (pqGetc(&conn->copy_is_binary, conn)) if (getCopyStart(conn, PGRES_COPY_OUT))
return; return;
/* XXX we currently ignore the rest of the message */
conn->inCursor = conn->inStart + 5 + msgLength;
conn->asyncStatus = PGASYNC_COPY_OUT; conn->asyncStatus = PGASYNC_COPY_OUT;
conn->copy_already_done = 0; conn->copy_already_done = 0;
break; break;
...@@ -398,6 +401,9 @@ getRowDescriptions(PGconn *conn) ...@@ -398,6 +401,9 @@ getRowDescriptions(PGconn *conn)
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc)); 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 */ /* get type info */
for (i = 0; i < nfields; i++) for (i = 0; i < nfields; i++)
{ {
...@@ -430,10 +436,15 @@ getRowDescriptions(PGconn *conn) ...@@ -430,10 +436,15 @@ getRowDescriptions(PGconn *conn)
result->attDescs[i].name = pqResultStrdup(result, result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data); 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].typid = typid;
result->attDescs[i].typlen = typlen; result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod; result->attDescs[i].atttypmod = atttypmod;
/* XXX todo: save tableid/columnid, format too */
if (format != 1)
result->binary = 0;
} }
/* Success! */ /* Success! */
...@@ -503,7 +514,9 @@ getAnotherTuple(PGconn *conn, int msgLength) ...@@ -503,7 +514,9 @@ getAnotherTuple(PGconn *conn, int msgLength)
vlen = 0; vlen = 0;
if (tup[i].value == NULL) 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) if (tup[i].value == NULL)
goto outOfMemory; goto outOfMemory;
} }
...@@ -553,6 +566,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError) ...@@ -553,6 +566,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
PGresult *res; PGresult *res;
PQExpBufferData workBuf; PQExpBufferData workBuf;
char id; char id;
const char *val;
/* /*
* Make a PGresult to hold the accumulated fields. We temporarily * Make a PGresult to hold the accumulated fields. We temporarily
...@@ -580,68 +594,63 @@ pqGetErrorNotice3(PGconn *conn, bool isError) ...@@ -580,68 +594,63 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
break; /* terminator found */ break; /* terminator found */
if (pqGets(&workBuf, conn)) if (pqGets(&workBuf, conn))
goto fail; goto fail;
switch (id) pqSaveMessageField(res, id, workBuf.data);
{
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;
}
} }
/* /*
* Now build the "overall" error message for PQresultErrorMessage. * Now build the "overall" error message for PQresultErrorMessage.
*
* XXX this should be configurable somehow.
*/ */
resetPQExpBuffer(&workBuf); resetPQExpBuffer(&workBuf);
if (res->errSeverity) val = PQresultErrorField(res, 'S'); /* Severity */
appendPQExpBuffer(&workBuf, "%s: ", res->errSeverity); if (val)
if (res->errPrimary) appendPQExpBuffer(&workBuf, "%s: ", val);
appendPQExpBufferStr(&workBuf, res->errPrimary); 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 */ /* translator: %s represents a digit string */
if (res->errPosition) appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val);
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), }
res->errPosition); appendPQExpBufferChar(&workBuf, '\n');
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'); 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);
/* /*
* Either save error as current async result, or just emit the notice. * Either save error as current async result, or just emit the notice.
...@@ -656,7 +665,9 @@ pqGetErrorNotice3(PGconn *conn, bool isError) ...@@ -656,7 +665,9 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
} }
else 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); PQclear(res);
} }
...@@ -710,35 +721,216 @@ static int ...@@ -710,35 +721,216 @@ static int
getNotify(PGconn *conn) getNotify(PGconn *conn)
{ {
int be_pid; int be_pid;
char *svname;
int nmlen;
int extralen;
PGnotify *newNotify; PGnotify *newNotify;
if (pqGetInt(&be_pid, 4, conn)) if (pqGetInt(&be_pid, 4, conn))
return EOF; return EOF;
if (pqGets(&conn->workBuffer, conn)) if (pqGets(&conn->workBuffer, conn))
return EOF; 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 * 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. * don't want to tie this interface to a specific server name length.
*/ */
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen = strlen(svname);
strlen(conn->workBuffer.data) +1); extralen = strlen(conn->workBuffer.data);
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
if (newNotify) if (newNotify)
{ {
newNotify->relname = (char *) newNotify + sizeof(PGnotify); 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; newNotify->be_pid = be_pid;
DLAddTail(conn->notifyList, DLNewElem(newNotify)); DLAddTail(conn->notifyList, DLNewElem(newNotify));
} }
/* Swallow extra string (not presently used) */ free(svname);
if (pqGets(&conn->workBuffer, conn)) 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; 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; 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. * PQgetline - gets a newline-terminated string from the backend.
...@@ -1108,7 +1300,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid, ...@@ -1108,7 +1300,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
continue; continue;
break; break;
case 'Z': /* backend is ready for new query */ case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn)) if (getReadyForQuery(conn))
continue; continue;
/* consume the message and exit */ /* consume the message and exit */
conn->inStart += 5 + msgLength; conn->inStart += 5 + msgLength;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -88,6 +88,22 @@ typedef enum
PGRES_FATAL_ERROR /* query failed */ PGRES_FATAL_ERROR /* query failed */
} ExecStatusType; } 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. /* PGconn encapsulates a connection to the backend.
* The contents of this struct are not supposed to be known to applications. * The contents of this struct are not supposed to be known to applications.
*/ */
...@@ -108,12 +124,13 @@ typedef struct pg_result PGresult; ...@@ -108,12 +124,13 @@ typedef struct pg_result PGresult;
*/ */
typedef struct pgNotify typedef struct pgNotify
{ {
char *relname; /* name of relation containing data */ char *relname; /* notification condition name */
int be_pid; /* process id of backend */ int be_pid; /* process ID of server process */
char *extra; /* notification parameter */
} PGnotify; } 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); typedef void (*PQnoticeProcessor) (void *arg, const char *message);
/* Print options for PQprint() */ /* Print options for PQprint() */
...@@ -227,6 +244,10 @@ extern char *PQport(const PGconn *conn); ...@@ -227,6 +244,10 @@ extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn); extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn); extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(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 char *PQerrorMessage(const PGconn *conn);
extern int PQsocket(const PGconn *conn); extern int PQsocket(const PGconn *conn);
extern int PQbackendPID(const PGconn *conn); extern int PQbackendPID(const PGconn *conn);
...@@ -238,42 +259,58 @@ extern int PQsetClientEncoding(PGconn *conn, const char *encoding); ...@@ -238,42 +259,58 @@ extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
extern SSL *PQgetssl(PGconn *conn); extern SSL *PQgetssl(PGconn *conn);
#endif #endif
/* Set verbosity for PQerrorMessage and PQresultErrorMessage */
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
/* Enable/disable tracing */ /* Enable/disable tracing */
extern void PQtrace(PGconn *conn, FILE *debug_port); extern void PQtrace(PGconn *conn, FILE *debug_port);
extern void PQuntrace(PGconn *conn); 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, extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc, PQnoticeProcessor proc,
void *arg); void *arg);
/* === in fe-exec.c === */ /* === 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 */ /* Simple synchronous query */
extern PGresult *PQexec(PGconn *conn, const char *query); extern PGresult *PQexec(PGconn *conn, const char *query);
extern PGnotify *PQnotifies(PGconn *conn); extern PGresult *PQexecParams(PGconn *conn,
/* Exists for backward compatibility. bjm 2003-03-24 */ const char *command,
#define PQfreeNotify(ptr) PQfreemem(ptr) int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
/* Interface for multiple-result or asynchronous queries */ /* Interface for multiple-result or asynchronous queries */
extern int PQsendQuery(PGconn *conn, const char *query); 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); extern PGresult *PQgetResult(PGconn *conn);
/* Routines for managing an asynchronous query */ /* Routines for managing an asynchronous query */
extern int PQisBusy(PGconn *conn); extern int PQisBusy(PGconn *conn);
extern int PQconsumeInput(PGconn *conn); extern int PQconsumeInput(PGconn *conn);
/* LISTEN/NOTIFY support */
extern PGnotify *PQnotifies(PGconn *conn);
/* Routines for copy in/out */ /* 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 PQgetline(PGconn *conn, char *string, int length);
extern int PQputline(PGconn *conn, const char *string); extern int PQputline(PGconn *conn, const char *string);
extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize); extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
...@@ -303,11 +340,15 @@ extern PGresult *PQfn(PGconn *conn, ...@@ -303,11 +340,15 @@ extern PGresult *PQfn(PGconn *conn,
extern ExecStatusType PQresultStatus(const PGresult *res); extern ExecStatusType PQresultStatus(const PGresult *res);
extern char *PQresStatus(ExecStatusType status); extern char *PQresStatus(ExecStatusType status);
extern char *PQresultErrorMessage(const PGresult *res); extern char *PQresultErrorMessage(const PGresult *res);
extern char *PQresultErrorField(const PGresult *res, int fieldcode);
extern int PQntuples(const PGresult *res); extern int PQntuples(const PGresult *res);
extern int PQnfields(const PGresult *res); extern int PQnfields(const PGresult *res);
extern int PQbinaryTuples(const PGresult *res); extern int PQbinaryTuples(const PGresult *res);
extern char *PQfname(const PGresult *res, int field_num); extern char *PQfname(const PGresult *res, int field_num);
extern int PQfnumber(const PGresult *res, const char *field_name); 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 Oid PQftype(const PGresult *res, int field_num);
extern int PQfsize(const PGresult *res, int field_num); extern int PQfsize(const PGresult *res, int field_num);
extern int PQfmod(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); ...@@ -322,6 +363,12 @@ extern int PQgetisnull(const PGresult *res, int tup_num, int field_num);
/* Delete a PGresult */ /* Delete a PGresult */
extern void PQclear(PGresult *res); 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 * Make an empty PGresult with given status (some apps find this
* useful). If conn is not NULL and status indicates an error, the * useful). If conn is not NULL and status indicates an error, the
...@@ -329,26 +376,33 @@ extern void PQclear(PGresult *res); ...@@ -329,26 +376,33 @@ extern void PQclear(PGresult *res);
*/ */
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status); 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 === */ /* === in fe-print.c === */
extern void extern void PQprint(FILE *fout, /* output stream */
PQprint(FILE *fout, /* output stream */
const PGresult *res, const PGresult *res,
const PQprintOpt *ps); /* option structure */ const PQprintOpt *ps); /* option structure */
/* /*
* really old printing routines * really old printing routines
*/ */
extern void extern void PQdisplayTuples(const PGresult *res,
PQdisplayTuples(const PGresult *res,
FILE *fp, /* where to send the output */ FILE *fp, /* where to send the output */
int fillAlign, /* pad the fields with spaces */ int fillAlign, /* pad the fields with spaces */
const char *fieldSep, /* field separator */ const char *fieldSep, /* field separator */
int printHeader, /* display headers? */ int printHeader, /* display headers? */
int quiet); int quiet);
extern void extern void PQprintTuples(const PGresult *res,
PQprintTuples(const PGresult *res,
FILE *fout, /* output stream */ FILE *fout, /* output stream */
int printAttName, /* print attribute names */ int printAttName, /* print attribute names */
int terseOutput, /* delimiter bars */ int terseOutput, /* delimiter bars */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -20,6 +20,9 @@
#ifndef LIBPQ_INT_H #ifndef LIBPQ_INT_H
#define LIBPQ_INT_H #define LIBPQ_INT_H
/* We assume libpq-fe.h has already been included. */
#include "postgres_fe.h"
#include <time.h> #include <time.h>
#include <sys/types.h> #include <sys/types.h>
#ifndef WIN32 #ifndef WIN32
...@@ -28,13 +31,10 @@ ...@@ -28,13 +31,10 @@
#if defined(WIN32) && (!defined(ssize_t)) #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) */ * not VC6) */
#endif #endif
/* We assume libpq-fe.h has already been included. */
#include "postgres_fe.h"
/* include stuff common to fe and be */ /* include stuff common to fe and be */
#include "getaddrinfo.h" #include "getaddrinfo.h"
#include "libpq/pqcomm.h" #include "libpq/pqcomm.h"
...@@ -78,7 +78,10 @@ union pgresult_data ...@@ -78,7 +78,10 @@ union pgresult_data
typedef struct pgresAttDesc 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 */ Oid typid; /* type id */
int typlen; /* type size */ int typlen; /* type size */
int atttypmod; /* type-specific modifier info */ int atttypmod; /* type-specific modifier info */
...@@ -91,7 +94,7 @@ typedef struct pgresAttDesc ...@@ -91,7 +94,7 @@ typedef struct pgresAttDesc
* *
* The value pointer always points to a null-terminated area; we add a * 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 * 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 * value might have embedded nulls, so the application can't use C string
* operators on it. But we add a null anyway for consistency. * operators on it. But we add a null anyway for consistency.
* Note that the value itself does not contain a length word. * Note that the value itself does not contain a length word.
...@@ -111,6 +114,23 @@ typedef struct pgresAttValue ...@@ -111,6 +114,23 @@ typedef struct pgresAttValue
* byte */ * byte */
} PGresAttValue; } 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 struct pg_result
{ {
int ntups; int ntups;
...@@ -118,10 +138,10 @@ struct pg_result ...@@ -118,10 +138,10 @@ struct pg_result
PGresAttDesc *attDescs; PGresAttDesc *attDescs;
PGresAttValue **tuples; /* each PGresTuple is an array of PGresAttValue **tuples; /* each PGresTuple is an array of
* PGresAttValue's */ * PGresAttValue's */
int tupArrSize; /* size of tuples array allocated */ int tupArrSize; /* allocated size of tuples array */
ExecStatusType resultStatus; ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
* last query */ * query */
int binary; /* binary tuple values if binary == 1, int binary; /* binary tuple values if binary == 1,
* otherwise text */ * otherwise text */
...@@ -129,35 +149,23 @@ struct pg_result ...@@ -129,35 +149,23 @@ struct pg_result
* These fields are copied from the originating PGconn, so that * These fields are copied from the originating PGconn, so that
* operations on the PGresult don't have to reference the PGconn. * operations on the PGresult don't have to reference the PGconn.
*/ */
PQnoticeProcessor noticeHook; /* notice/error message processor */ PGNoticeHooks noticeHooks;
void *noticeArg;
int client_encoding; /* encoding id */ int client_encoding; /* encoding id */
/* /*
* Error information (all NULL if not an error result). errMsg is the * Error information (all NULL if not an error result). errMsg is the
* "overall" error message returned by PQresultErrorMessage. If we * "overall" error message returned by PQresultErrorMessage. If we
* got a field-ized error from the server then the additional fields * have per-field info then it is stored in a linked list.
* may be set.
*/ */
char *errMsg; /* error message, or NULL if no error */ char *errMsg; /* error message, or NULL if no error */
PGMessageField *errFields; /* message broken into fields */
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 */
/* All NULL attributes in the query result point to this null string */ /* All NULL attributes in the query result point to this null string */
char null_field[1]; char null_field[1];
/* /*
* Space management information. Note that attDescs and errMsg, if * Space management information. Note that attDescs and error stuff,
* not null, point into allocated blocks. But tuples points to a * if not null, point into allocated blocks. But tuples points to a
* separately malloc'd block, so that we can realloc it. * separately malloc'd block, so that we can realloc it.
*/ */
PGresult_data *curBlock; /* most recently allocated block */ PGresult_data *curBlock; /* most recently allocated block */
...@@ -245,18 +253,18 @@ struct pg_conn ...@@ -245,18 +253,18 @@ struct pg_conn
/* Optional file to write trace info to */ /* Optional file to write trace info to */
FILE *Pfdebug; FILE *Pfdebug;
/* Callback procedure for notice/error message processing */ /* Callback procedures for notice message processing */
PQnoticeProcessor noticeHook; PGNoticeHooks noticeHooks;
void *noticeArg;
/* Status indicators */ /* Status indicators */
ConnStatusType status; ConnStatusType status;
PGAsyncStatusType asyncStatus; PGAsyncStatusType asyncStatus;
char xact_status; /* status flag from latest ReadyForQuery */ PGTransactionStatusType xactStatus;
char copy_is_binary; /* 1 = copy binary, 0 = copy text */ /* note: xactStatus never changes to ACTIVE */
int copy_already_done; /* # bytes already returned in COPY OUT */
int nonblocking; /* whether this connection is using a int nonblocking; /* whether this connection is using a
* blocking socket to the backend or not */ * 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 Dllist *notifyList; /* Notify msgs not yet handed to
* application */ * application */
...@@ -281,6 +289,7 @@ struct pg_conn ...@@ -281,6 +289,7 @@ struct pg_conn
char cryptSalt[2]; /* password salt received from backend */ char cryptSalt[2]; /* password salt received from backend */
pgParameterStatus *pstatus; /* ParameterStatus data */ pgParameterStatus *pstatus; /* ParameterStatus data */
int client_encoding; /* encoding id */ int client_encoding; /* encoding id */
PGVerbosity verbosity; /* error/notice message verbosity */
PGlobjfuncs *lobjfuncs; /* private state for large-object access PGlobjfuncs *lobjfuncs; /* private state for large-object access
* fns */ * fns */
...@@ -351,10 +360,12 @@ extern char *pqResultStrdup(PGresult *res, const char *str); ...@@ -351,10 +360,12 @@ extern char *pqResultStrdup(PGresult *res, const char *str);
extern void pqClearAsyncResult(PGconn *conn); extern void pqClearAsyncResult(PGconn *conn);
extern void pqSaveErrorResult(PGconn *conn); extern void pqSaveErrorResult(PGconn *conn);
extern PGresult *pqPrepareAsyncResult(PGconn *conn); extern PGresult *pqPrepareAsyncResult(PGconn *conn);
extern void pqInternalNotice(const PGNoticeHooks *hooks, const char *msgtext);
extern int pqAddTuple(PGresult *res, PGresAttValue *tup); 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, extern void pqSaveParameterStatus(PGconn *conn, const char *name,
const char *value); const char *value);
extern const char *pqGetParameterStatus(PGconn *conn, const char *name);
extern void pqHandleSendFailure(PGconn *conn); extern void pqHandleSendFailure(PGconn *conn);
/* === in fe-protocol2.c === */ /* === in fe-protocol2.c === */
...@@ -364,6 +375,7 @@ extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn); ...@@ -364,6 +375,7 @@ extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen, extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
const PQEnvironmentOption *options); const PQEnvironmentOption *options);
extern void pqParseInput2(PGconn *conn); 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 pqGetline2(PGconn *conn, char *s, int maxlen);
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize); extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy2(PGconn *conn); extern int pqEndcopy2(PGconn *conn);
...@@ -378,6 +390,7 @@ extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen, ...@@ -378,6 +390,7 @@ extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
const PQEnvironmentOption *options); const PQEnvironmentOption *options);
extern void pqParseInput3(PGconn *conn); extern void pqParseInput3(PGconn *conn);
extern int pqGetErrorNotice3(PGconn *conn, bool isError); 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 pqGetline3(PGconn *conn, char *s, int maxlen);
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize); extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy3(PGconn *conn); extern int pqEndcopy3(PGconn *conn);
...@@ -393,6 +406,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, ...@@ -393,6 +406,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
* for Get, EOF merely means the buffer is exhausted, not that there is * for Get, EOF merely means the buffer is exhausted, not that there is
* necessarily any error. * necessarily any error.
*/ */
extern int pqCheckOutBufferSpace(int bytes_needed, PGconn *conn);
extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn); extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
extern int pqGetc(char *result, PGconn *conn); extern int pqGetc(char *result, PGconn *conn);
extern int pqPutc(char c, 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); ...@@ -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 */ /* Note: PGDONOTICE macro will work if applied to either PGconn or PGresult */
#define PGDONOTICE(conn,message) \ #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 * without the overhead of a function call
*/ */
#define pqIsnonblocking(conn) ((conn)->nonblocking) #define pqIsnonblocking(conn) ((conn)->nonblocking)
......
...@@ -97,4 +97,17 @@ EXPORTS ...@@ -97,4 +97,17 @@ EXPORTS
pg_utf_mblen @ 93 pg_utf_mblen @ 93
PQunescapeBytea @ 94 PQunescapeBytea @ 94
PQfreemem @ 95 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% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment