From aa7e7ae9a6adfd5553ed05144cf765fbf7c8f5af Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 16 Feb 2010 20:58:14 +0000 Subject: [PATCH] Have SELECT and CREATE TABLE AS queries return a row count. While this is invisible in psql, other interfaces, like libpq, make this value visible. Boszormenyi Zoltan --- doc/src/sgml/libpq.sgml | 21 ++++++++-------- doc/src/sgml/protocol.sgml | 8 +++++- src/backend/tcop/pquery.c | 46 +++++++++++++++++----------------- src/interfaces/libpq/fe-exec.c | 5 ++-- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index c7131fea4c4..4972a8c2592 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,4 +1,4 @@ - + <application>libpq</application> - C Library @@ -2869,12 +2869,11 @@ typedef struct { - Retrieving Result Information for Other Commands + Retrieving Other Result Information - These functions are used to extract information from - PGresult objects that are not - SELECT results. + These functions are used to extract other information from + PGresult objects. @@ -2925,12 +2924,12 @@ typedef struct { This function returns a string containing the number of rows affected by the SQL statement that generated the PGresult. This function can only be used following - the execution of an 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 + the execution of a SELECT, CREATE TABLE AS, + 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 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/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 5b69f373243..e4364ec305f 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1,4 +1,4 @@ - + Frontend/Backend Protocol @@ -2221,6 +2221,12 @@ CommandComplete (B) rows is the number of rows updated. + + For a SELECT or CREATE TABLE AS + command, the tag is SELECT rows + where rows is the number of rows retrieved. + + For a MOVE command, the tag is MOVE rows where diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 42960b82250..8beb82385a6 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.135 2010/02/13 22:45:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.136 2010/02/16 20:58:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -205,7 +205,8 @@ ProcessQuery(PlannedStmt *plan, switch (queryDesc->operation) { case CMD_SELECT: - strcpy(completionTag, "SELECT"); + snprintf(completionTag, COMPLETION_TAG_BUFSIZE, + "SELECT %u", queryDesc->estate->es_processed); break; case CMD_INSERT: if (queryDesc->estate->es_processed == 1) @@ -714,6 +715,7 @@ PortalRun(Portal portal, long count, bool isTopLevel, char *completionTag) { bool result; + uint32 nprocessed; ResourceOwner saveTopTransactionResourceOwner; MemoryContext saveTopTransactionContext; Portal saveActivePortal; @@ -776,39 +778,35 @@ PortalRun(Portal portal, long count, bool isTopLevel, switch (portal->strategy) { case PORTAL_ONE_SELECT: - (void) PortalRunSelect(portal, true, count, dest); - - /* we know the query is supposed to set the tag */ - if (completionTag && portal->commandTag) - strcpy(completionTag, portal->commandTag); - - /* Mark portal not active */ - portal->status = PORTAL_READY; - - /* - * Since it's a forward fetch, say DONE iff atEnd is now true. - */ - result = portal->atEnd; - break; - case PORTAL_ONE_RETURNING: case PORTAL_UTIL_SELECT: /* * If we have not yet run the command, do so, storing its - * results in the portal's tuplestore. + * results in the portal's tuplestore. Do this only for the + * PORTAL_ONE_RETURNING and PORTAL_UTIL_SELECT cases. */ - if (!portal->holdStore) + if (portal->strategy != PORTAL_ONE_SELECT && !portal->holdStore) FillPortalStore(portal, isTopLevel); /* * Now fetch desired portion of results. */ - (void) PortalRunSelect(portal, true, count, dest); + nprocessed = PortalRunSelect(portal, true, count, dest); - /* we know the query is supposed to set the tag */ + /* + * If the portal result contains a command tag and the caller + * gave us a pointer to store it, copy it. Patch the "SELECT" + * tag to also provide the rowcount. + */ if (completionTag && portal->commandTag) - strcpy(completionTag, portal->commandTag); + { + if (strcmp(portal->commandTag, "SELECT") == 0) + snprintf(completionTag, COMPLETION_TAG_BUFSIZE, + "SELECT %u", nprocessed); + else + strcpy(completionTag, portal->commandTag); + } /* Mark portal not active */ portal->status = PORTAL_READY; @@ -1331,7 +1329,9 @@ PortalRunMulti(Portal portal, bool isTopLevel, { if (portal->commandTag) strcpy(completionTag, portal->commandTag); - if (strcmp(completionTag, "INSERT") == 0) + if (strcmp(completionTag, "SELECT") == 0) + sprintf(completionTag, "SELECT 0 0"); + else if (strcmp(completionTag, "INSERT") == 0) strcpy(completionTag, "INSERT 0 0"); else if (strcmp(completionTag, "UPDATE") == 0) strcpy(completionTag, "UPDATE 0"); diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 2e5551d31e5..df4e8879c84 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.208 2010/01/21 18:43:25 rhaas Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.209 2010/02/16 20:58:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2752,7 +2752,8 @@ PQcmdTuples(PGresult *res) goto interpret_error; /* no space? */ p++; } - else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 || + else if (strncmp(res->cmdStatus, "SELECT ", 7) == 0 || + strncmp(res->cmdStatus, "DELETE ", 7) == 0 || strncmp(res->cmdStatus, "UPDATE ", 7) == 0) p = res->cmdStatus + 7; else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)