Commit aa7e7ae9 authored by Bruce Momjian's avatar Bruce Momjian

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
parent 346a721e
<!-- $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"> <chapter id="libpq">
<title><application>libpq</application> - C Library</title> <title><application>libpq</application> - C Library</title>
...@@ -2869,12 +2869,11 @@ typedef struct { ...@@ -2869,12 +2869,11 @@ typedef struct {
</sect2> </sect2>
<sect2 id="libpq-exec-nonselect"> <sect2 id="libpq-exec-nonselect">
<title>Retrieving Result Information for Other Commands</title> <title>Retrieving Other Result Information</title>
<para> <para>
These functions are used to extract information from These functions are used to extract other information from
<structname>PGresult</structname> objects that are not <structname>PGresult</structname> objects.
<command>SELECT</> results.
</para> </para>
<variablelist> <variablelist>
...@@ -2925,12 +2924,12 @@ typedef struct { ...@@ -2925,12 +2924,12 @@ typedef struct {
This function returns a string containing the number of rows This function returns a string containing the number of rows
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 following <structname>PGresult</>. This function can only be used following
the execution of an <command>INSERT</>, <command>UPDATE</>, the execution of a <command>SELECT</>, <command>CREATE TABLE AS</>,
<command>DELETE</>, <command>MOVE</>, <command>FETCH</>, or <command>INSERT</>, <command>UPDATE</>, <command>DELETE</>,
<command>COPY</> statement, or an <command>EXECUTE</> of a <command>MOVE</>, <command>FETCH</>, or <command>COPY</> statement,
prepared query that contains an <command>INSERT</>, or an <command>EXECUTE</> of a prepared query that contains an
<command>UPDATE</>, or <command>DELETE</> statement. If the <command>INSERT</>, <command>UPDATE</>, or <command>DELETE</> statement.
command that generated the <structname>PGresult</> was anything If the command that generated the <structname>PGresult</> was anything
else, <function>PQcmdTuples</> returns an empty string. The caller else, <function>PQcmdTuples</> returns an empty string. The caller
should not free the return value directly. It will be freed when should not free the return value directly. It will be freed when
the associated <structname>PGresult</> handle is passed to the associated <structname>PGresult</> handle is passed to
......
<!-- $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"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -2221,6 +2221,12 @@ CommandComplete (B) ...@@ -2221,6 +2221,12 @@ CommandComplete (B)
<replaceable>rows</replaceable> is the number of rows updated. <replaceable>rows</replaceable> is the number of rows updated.
</para> </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> <para>
For a <command>MOVE</command> command, the tag is For a <command>MOVE</command> command, the tag is
<literal>MOVE <replaceable>rows</replaceable></literal> where <literal>MOVE <replaceable>rows</replaceable></literal> where
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -205,7 +205,8 @@ ProcessQuery(PlannedStmt *plan,
switch (queryDesc->operation) switch (queryDesc->operation)
{ {
case CMD_SELECT: case CMD_SELECT:
strcpy(completionTag, "SELECT"); snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"SELECT %u", queryDesc->estate->es_processed);
break; break;
case CMD_INSERT: case CMD_INSERT:
if (queryDesc->estate->es_processed == 1) if (queryDesc->estate->es_processed == 1)
...@@ -714,6 +715,7 @@ PortalRun(Portal portal, long count, bool isTopLevel, ...@@ -714,6 +715,7 @@ PortalRun(Portal portal, long count, bool isTopLevel,
char *completionTag) char *completionTag)
{ {
bool result; bool result;
uint32 nprocessed;
ResourceOwner saveTopTransactionResourceOwner; ResourceOwner saveTopTransactionResourceOwner;
MemoryContext saveTopTransactionContext; MemoryContext saveTopTransactionContext;
Portal saveActivePortal; Portal saveActivePortal;
...@@ -776,39 +778,35 @@ PortalRun(Portal portal, long count, bool isTopLevel, ...@@ -776,39 +778,35 @@ PortalRun(Portal portal, long count, bool isTopLevel,
switch (portal->strategy) switch (portal->strategy)
{ {
case PORTAL_ONE_SELECT: 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_ONE_RETURNING:
case PORTAL_UTIL_SELECT: case PORTAL_UTIL_SELECT:
/* /*
* If we have not yet run the command, do so, storing its * 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); FillPortalStore(portal, isTopLevel);
/* /*
* Now fetch desired portion of results. * 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) 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 */ /* Mark portal not active */
portal->status = PORTAL_READY; portal->status = PORTAL_READY;
...@@ -1331,7 +1329,9 @@ PortalRunMulti(Portal portal, bool isTopLevel, ...@@ -1331,7 +1329,9 @@ PortalRunMulti(Portal portal, bool isTopLevel,
{ {
if (portal->commandTag) if (portal->commandTag)
strcpy(completionTag, 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"); strcpy(completionTag, "INSERT 0 0");
else if (strcmp(completionTag, "UPDATE") == 0) else if (strcmp(completionTag, "UPDATE") == 0)
strcpy(completionTag, "UPDATE 0"); strcpy(completionTag, "UPDATE 0");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2752,7 +2752,8 @@ PQcmdTuples(PGresult *res)
goto interpret_error; /* no space? */ goto interpret_error; /* no space? */
p++; 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) strncmp(res->cmdStatus, "UPDATE ", 7) == 0)
p = res->cmdStatus + 7; p = res->cmdStatus + 7;
else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0) else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment