Teach PQcmdTuples() that a COPY command tag might contain a row count,

and tighten up its sanity checking of the tag as a safety measure.
Volkan Yazici.
This commit is contained in:
Tom Lane 2006-03-03 20:57:32 +00:00
parent 502e9aefdc
commit 523adeb111
2 changed files with 32 additions and 24 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.204 2006/03/01 00:23:21 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.205 2006/03/03 20:57:32 tgl Exp $
--> -->
<chapter id="libpq"> <chapter id="libpq">
@ -2127,12 +2127,13 @@ char *PQcmdTuples(PGresult *res);
affected by the <acronym>SQL</> statement that generated the affected by the <acronym>SQL</> statement that generated the
<structname>PGresult</>. This function can only be used <structname>PGresult</>. This function can only be used
following the execution of an <command>INSERT</>, following the execution of an <command>INSERT</>,
<command>UPDATE</>, <command>DELETE</>, <command>MOVE</>, or <command>UPDATE</>, <command>DELETE</>, <command>MOVE</>,
<command>FETCH</> statement, or an <command>EXECUTE</> of a <command>FETCH</>, or <command>COPY</> statement,
prepared query that contains a <command>INSERT</>, or an <command>EXECUTE</> of a
prepared query that contains an <command>INSERT</>,
<command>UPDATE</>, or <command>DELETE</> statement. If the <command>UPDATE</>, or <command>DELETE</> statement. If the
command that generated the <structname>PGresult</> was command that generated the <structname>PGresult</> was
anything else, <function>PQcmdTuples</> returns the empty anything else, <function>PQcmdTuples</> returns an empty
string. The caller should not free the return value string. The caller should not free the return value
directly. It will be freed when the associated directly. It will be freed when the associated
<structname>PGresult</> handle is passed to <structname>PGresult</> handle is passed to

View File

@ -8,13 +8,12 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.179 2006/01/25 20:44:32 tgl Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.180 2006/03/03 20:57:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
@ -2168,8 +2167,8 @@ PQoidValue(const PGresult *res)
/* /*
* PQcmdTuples - * PQcmdTuples -
* If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a * If the last command was INSERT/UPDATE/DELETE/MOVE/FETCH/COPY, return
* string containing the number of inserted/affected tuples. If not, * a 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
@ -2177,40 +2176,48 @@ PQoidValue(const PGresult *res)
char * char *
PQcmdTuples(PGresult *res) PQcmdTuples(PGresult *res)
{ {
char *p; char *p, *c;
if (!res) if (!res)
return ""; return "";
if (strncmp(res->cmdStatus, "INSERT ", 7) == 0) if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)
{ {
p = res->cmdStatus + 6; p = res->cmdStatus + 7;
p++; /* INSERT: skip oid and space */
/* INSERT: skip oid */ while (*p && *p != ' ')
while (*p != ' ' && *p)
p++; p++;
if (*p == 0)
goto interpret_error; /* no space? */
p++;
} }
else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 || else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||
strncmp(res->cmdStatus, "UPDATE ", 7) == 0) strncmp(res->cmdStatus, "UPDATE ", 7) == 0)
p = res->cmdStatus + 6; p = res->cmdStatus + 7;
else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0) else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)
p = res->cmdStatus + 6;
else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0 ||
strncmp(res->cmdStatus, "COPY ", 5) == 0)
p = res->cmdStatus + 5; p = res->cmdStatus + 5;
else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0)
p = res->cmdStatus + 4;
else else
return ""; return "";
p++; /* check that we have an integer (at least one digit, nothing else) */
for (c = p; *c; c++)
if (*p == 0)
{ {
pqInternalNotice(&res->noticeHooks, if (!isdigit((unsigned char) *c))
"could not interpret result from server: %s", goto interpret_error;
res->cmdStatus);
return "";
} }
if (c == p)
goto interpret_error;
return p; return p;
interpret_error:
pqInternalNotice(&res->noticeHooks,
"could not interpret result from server: %s",
res->cmdStatus);
return "";
} }
/* /*