Have SELECT and CREATE TABLE AS queries return a row count. While this
authorBruce Momjian
Tue, 16 Feb 2010 20:58:14 +0000 (20:58 +0000)
committerBruce Momjian
Tue, 16 Feb 2010 20:58:14 +0000 (20:58 +0000)
is invisible in psql, other interfaces, like libpq, make this value
visible.

Boszormenyi Zoltan

doc/src/sgml/libpq.sgml
doc/src/sgml/protocol.sgml
src/backend/tcop/pquery.c
src/interfaces/libpq/fe-exec.c

index c7131fea4c44cdf241d3c4f3bd08ec2097bd8f6f..4972a8c2592184e95d5e3761c3cc2e4ce2eeb580 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  <application>libpq</application> - C Library
@@ -2869,12 +2869,11 @@ typedef struct {
   
 
   
-   Retrieving <span class="marked">Result Information for Other Commands</span>
+   Retrieving <span class="marked">Other Result Information</span>
 
    
-    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 aINSERT, 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
index 5b69f373243774f9c06a5c68de184383de2ff418..e4364ec305f1c2dcadb9315650b070526950e989 100644 (file)
@@ -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
index 42960b82250a65b2ae112e89728e6ef461e8bdae..8beb82385a6bf9798f7f8a009aeafdac08eff3d4 100644 (file)
@@ -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");
index 2e5551d31e5b11f3a5a71d19ab39861774a95a03..df4e8879c848e04c0bd3bc018c698d1661e10376 100644 (file)
@@ -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)