From 523adeb1119bbc68e056c4e3a2aa2a62dcf26e9e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 3 Mar 2006 20:57:32 +0000 Subject: [PATCH] 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. --- doc/src/sgml/libpq.sgml | 11 +++++---- src/interfaces/libpq/fe-exec.c | 45 ++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 9c48948c86..ccec9c72b8 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -2127,12 +2127,13 @@ char *PQcmdTuples(PGresult *res); affected by the SQL statement that generated the PGresult. This function can only be used following the execution of an INSERT, - UPDATE, DELETE, MOVE, or - FETCH statement, or an EXECUTE of a - prepared query that contains a INSERT, + UPDATE, DELETE, MOVE, + FETCH, or COPY statement, + or an EXECUTE of a + prepared query that contains an INSERT, UPDATE, or DELETE statement. If the command that generated the PGresult was - anything else, PQcmdTuples returns the empty + anything else, PQcmdTuples returns an empty string. The caller should not free the return value directly. It will be freed when the associated PGresult handle is passed to diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 4edb065c9c..2643166df6 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,13 +8,12 @@ * * * 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 #include #include @@ -2168,8 +2167,8 @@ PQoidValue(const PGresult *res) /* * PQcmdTuples - - * If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a - * string containing the number of inserted/affected tuples. If not, + * If the last command was INSERT/UPDATE/DELETE/MOVE/FETCH/COPY, return + * a string containing the number of inserted/affected tuples. If not, * return "". * * XXX: this should probably return an int @@ -2177,40 +2176,48 @@ PQoidValue(const PGresult *res) char * PQcmdTuples(PGresult *res) { - char *p; + char *p, *c; if (!res) return ""; if (strncmp(res->cmdStatus, "INSERT ", 7) == 0) { - p = res->cmdStatus + 6; - p++; - /* INSERT: skip oid */ - while (*p != ' ' && *p) + p = res->cmdStatus + 7; + /* INSERT: skip oid and space */ + while (*p && *p != ' ') p++; + if (*p == 0) + goto interpret_error; /* no space? */ + p++; } else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 || strncmp(res->cmdStatus, "UPDATE ", 7) == 0) - p = res->cmdStatus + 6; + p = res->cmdStatus + 7; 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; - else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0) - p = res->cmdStatus + 4; else return ""; - p++; - - if (*p == 0) + /* check that we have an integer (at least one digit, nothing else) */ + for (c = p; *c; c++) { - pqInternalNotice(&res->noticeHooks, - "could not interpret result from server: %s", - res->cmdStatus); - return ""; + if (!isdigit((unsigned char) *c)) + goto interpret_error; } + if (c == p) + goto interpret_error; return p; + +interpret_error: + pqInternalNotice(&res->noticeHooks, + "could not interpret result from server: %s", + res->cmdStatus); + return ""; } /*