diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index c7131fea4c44cdf241d3c4f3bd08ec2097bd8f6f..4972a8c2592184e95d5e3761c3cc2e4ce2eeb580 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.297 2010/02/05 03:09:04 joe Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.298 2010/02/16 20:58:13 momjian Exp $ -->
 
 <chapter id="libpq">
  <title><application>libpq</application> - C Library</title>
@@ -2869,12 +2869,11 @@ typedef struct {
   </sect2>
 
   <sect2 id="libpq-exec-nonselect">
-   <title>Retrieving Result Information for Other Commands</title>
+   <title>Retrieving Other Result Information</title>
 
    <para>
-    These functions are used to extract information from
-    <structname>PGresult</structname> objects that are not
-    <command>SELECT</> results.
+    These functions are used to extract other information from
+    <structname>PGresult</structname> objects.
    </para>
 
    <variablelist>
@@ -2925,12 +2924,12 @@ typedef struct {
        This function returns a string containing the number of rows
        affected by the <acronym>SQL</> statement that generated the
        <structname>PGresult</>. This function can only be used following
-       the execution of an <command>INSERT</>, <command>UPDATE</>,
-       <command>DELETE</>, <command>MOVE</>, <command>FETCH</>, or
-       <command>COPY</> statement, or an <command>EXECUTE</> of a
-       prepared query that contains an <command>INSERT</>,
-       <command>UPDATE</>, or <command>DELETE</> statement.  If the
-       command that generated the <structname>PGresult</> was anything
+       the execution of a <command>SELECT</>, <command>CREATE TABLE AS</>,
+       <command>INSERT</>, <command>UPDATE</>, <command>DELETE</>,
+       <command>MOVE</>, <command>FETCH</>, or <command>COPY</> statement,
+       or an <command>EXECUTE</> of a prepared query that contains an
+       <command>INSERT</>, <command>UPDATE</>, or <command>DELETE</> statement.
+       If the command that generated the <structname>PGresult</> was anything
        else, <function>PQcmdTuples</> returns an empty string. The caller
        should not free the return value directly. It will be freed when
        the associated <structname>PGresult</> handle is passed to
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 5b69f373243774f9c06a5c68de184383de2ff418..e4364ec305f1c2dcadb9315650b070526950e989 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.79 2010/02/16 20:15:14 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.80 2010/02/16 20:58:14 momjian Exp $ -->
 
 <chapter id="protocol">
  <title>Frontend/Backend Protocol</title>
@@ -2221,6 +2221,12 @@ CommandComplete (B)
         <replaceable>rows</replaceable> is the number of rows updated.
        </para>
 
+       <para>
+        For a <command>SELECT</command> or <command>CREATE TABLE AS</command>
+        command, the tag is <literal>SELECT <replaceable>rows</replaceable></literal>
+        where <replaceable>rows</replaceable> is the number of rows retrieved.
+       </para>
+
        <para>
         For a <command>MOVE</command> command, the tag is
         <literal>MOVE <replaceable>rows</replaceable></literal> where
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 42960b82250a65b2ae112e89728e6ef461e8bdae..8beb82385a6bf9798f7f8a009aeafdac08eff3d4 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 2e5551d31e5b11f3a5a71d19ab39861774a95a03..df4e8879c848e04c0bd3bc018c698d1661e10376 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)