Allow PQcmdTuples to return row counts for MOVE and FETCH.

Neil Conway
This commit is contained in:
Bruce Momjian 2003-02-19 03:59:02 +00:00
parent 1eb9fd49d1
commit 81f6db4803
4 changed files with 92 additions and 71 deletions

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.110 2003/02/14 02:21:25 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.111 2003/02/19 03:59:02 momjian Exp $
-->
<chapter id="libpq">
@ -702,12 +702,11 @@ char *PQerrorMessage(const PGconn* conn);
int PQbackendPID(const PGconn *conn);
</synopsis>
The backend <acronym>PID</acronym> is useful for debugging
purposes and for comparison
to NOTIFY messages (which include the <acronym>PID</acronym> of
the notifying backend).
Note that the <acronym>PID</acronym> belongs to a process
executing on the database
server host, not the local host!
purposes and for comparison to <command>NOTIFY</command>
messages (which include the <acronym>PID</acronym> of the
notifying backend). Note that the <acronym>PID</acronym>
belongs to a process executing on the database server host, not
the local host!
</para>
</listitem>
@ -818,13 +817,14 @@ ExecStatusType PQresultStatus(const PGresult *res)
</listitem>
</itemizedlist>
If the result status is <literal>PGRES_TUPLES_OK</literal>, then the
routines described below can be used to retrieve the
rows returned by the query. Note that a SELECT command that
happens to retrieve zero rows still shows <literal>PGRES_TUPLES_OK</literal>.
<literal>PGRES_COMMAND_OK</literal> is for commands that can never return rows
(INSERT, UPDATE, etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> often
exposes a bug in the client software.
If the result status is <literal>PGRES_TUPLES_OK</literal>, then the
routines described below can be used to retrieve the rows returned by
the query. Note that a <command>SELECT</command> command that happens
to retrieve zero rows still shows <literal>PGRES_TUPLES_OK</literal>.
<literal>PGRES_COMMAND_OK</literal> is for commands that can never
return rows (<command>INSERT</command>, <command>UPDATE</command>,
etc.). A response of <literal>PGRES_EMPTY_QUERY</literal> often
indicates a bug in the client software.
</para>
</listitem>
@ -1243,36 +1243,41 @@ char * PQcmdStatus(PGresult *res);
char * PQcmdTuples(PGresult *res);
</synopsis>
If the <acronym>SQL</acronym> command that generated the
<structname>PGresult</structname> was INSERT, UPDATE or DELETE, this returns a
string containing the number of rows affected. If the
command was anything else, it returns the empty string.
<structname>PGresult</structname> was <command>INSERT</command>,
<command>UPDATE</command>, <command>DELETE</command>,
<command>MOVE</command>, or <command>FETCH</command> this
returns a string containing the number of rows affected. If the
command was anything else, it returns the empty string.
</para>
</listitem>
<listitem>
<para>
<function>PQoidValue</function>
Returns the object ID of the inserted row, if the
<acronym>SQL</acronym> command was an INSERT
that inserted exactly one row into a table that has OIDs.
Otherwise, returns <literal>InvalidOid</literal>.
Returns the object ID of the inserted row, if the
<acronym>SQL</acronym> command was an <command>INSERT</command>
that inserted exactly one row into a table that has OIDs.
Otherwise, returns <literal>InvalidOid</literal>.
<synopsis>
Oid PQoidValue(const PGresult *res);
</synopsis>
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.
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>
<para>
<function>PQoidStatus</function>
Returns a string with the object ID of the inserted row, if the
<acronym>SQL</acronym> command was an INSERT.
(The string will be <literal>0</> if the INSERT did not insert exactly one
row, or if the target table does not have OIDs.) If the command
was not an INSERT, returns an empty string.
Returns a string with the object ID
of the inserted row, if the <acronym>SQL</acronym> command
was an <command>INSERT</command>. (The string will be
<literal>0</> if the <command>INSERT</command> did not
insert exactly one row, or if the target table does not have
OIDs.) If the command was not an <command>INSERT</command>,
returns an empty string.
<synopsis>
char * PQoidStatus(const PGresult *res);
</synopsis>
@ -1530,7 +1535,8 @@ When the main loop detects input ready, it should call
<function>PQconsumeInput</function> to read the input. It can then call
<function>PQisBusy</function>, followed by <function>PQgetResult</function>
if <function>PQisBusy</function> returns false (0). It can also call
<function>PQnotifies</function> to detect NOTIFY messages (see <xref linkend="libpq-notify">).
<function>PQnotifies</function> to detect <command>NOTIFY</command>
messages (see <xref linkend="libpq-notify">).
</para>
<para>
@ -1700,13 +1706,13 @@ of asynchronous notification.
<function>PQnotifies()</function> does not actually read backend data; it just
returns messages previously absorbed by another <application>libpq</application>
function. In prior releases of <application>libpq</application>, the only way
to ensure timely receipt of NOTIFY messages was to constantly submit queries,
to ensure timely receipt of <command>NOTIFY</command> messages was to constantly submit queries,
even empty ones, and then check <function>PQnotifies()</function> after each
<function>PQexec()</function>. While this still works, it is
deprecated as a waste of processing power.
</para>
<para>
A better way to check for NOTIFY
A better way to check for <command>NOTIFY</command>
messages when you have no useful queries to make is to call
<function>PQconsumeInput()</function>, then check
<function>PQnotifies()</function>.

View File

@ -1,4 +1,4 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.24 2002/03/22 19:20:21 petere Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.25 2003/02/19 03:59:02 momjian Exp $ -->
<chapter id="protocol">
<title>Frontend/Backend Protocol</title>
@ -1335,6 +1335,20 @@ CompletedResponse (B)
<literal>UPDATE <Replaceable>rows</Replaceable></literal> where
<Replaceable>rows</Replaceable> is the number of rows updated.
</Para>
<para>
For a <command>MOVE</command> command, the tag is
<literal>MOVE <replaceable>rows</replaceable></literal> where
<replaceable>rows</replaceable> is the number of rows the
cursor's position has been changed by.
</para>
<para>
For a <command>FETCH</command> command, the tag is
<literal>FETCH <replaceable>rows</replaceable></literal> where
<replaceable>rows</replaceable> is the number of rows that
have been retrieved from the cursor.
</para>
</ListItem>
</VarListEntry>
</VariableList>

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.192 2003/02/13 05:20:01 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.193 2003/02/19 03:59:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -254,7 +254,7 @@ ProcessUtility(Node *parsetree,
switch (nodeTag(parsetree))
{
/*
* ******************************** transactions ********************************
* ******************** transactions ********************
*/
case T_TransactionStmt:
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.124 2003/01/07 22:23:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.125 2003/02/19 03:59:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -2272,7 +2272,7 @@ PQoidStatus(const PGresult *res)
/*
PQoidValue -
a perhaps preferable form of the above which just returns
a perhaps preferable form of the above which just returns
an Oid type
*/
Oid
@ -2300,53 +2300,54 @@ PQoidValue(const PGresult *res)
/*
PQcmdTuples -
if the last command was an INSERT/UPDATE/DELETE, return number
of inserted/affected tuples, if not, return ""
If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a
string containing the number of inserted/affected tuples. If not,
return "".
XXX: this should probably return an int
*/
char *
PQcmdTuples(PGresult *res)
{
char noticeBuf[128];
char *p;
if (!res)
return "";
if (strncmp(res->cmdStatus, "INSERT", 6) == 0 ||
strncmp(res->cmdStatus, "DELETE", 6) == 0 ||
strncmp(res->cmdStatus, "UPDATE", 6) == 0)
if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)
{
char *p = res->cmdStatus + 6;
if (*p == 0)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("could not interpret result from server: %s\n"),
res->cmdStatus);
DONOTICE(res, noticeBuf);
}
return "";
}
p = res->cmdStatus + 6;
p++;
if (*(res->cmdStatus) != 'I') /* UPDATE/DELETE */
return p;
/* INSERT: skip oid */
while (*p != ' ' && *p)
p++; /* INSERT: skip oid */
if (*p == 0)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("no row count available\n"));
DONOTICE(res, noticeBuf);
}
return "";
}
p++;
return p;
p++;
}
return "";
else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||
strncmp(res->cmdStatus, "UPDATE ", 7) == 0)
p = res->cmdStatus + 6;
else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)
p = res->cmdStatus + 5;
else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0)
p = res->cmdStatus + 4;
else
return "";
p++;
if (*p == 0)
{
if (res->noticeHook)
{
snprintf(noticeBuf, sizeof(noticeBuf),
libpq_gettext("could not interpret result from server: %s\n"),
res->cmdStatus);
DONOTICE(res, noticeBuf);
}
return "";
}
return p;
}
/*