Robert Haas írta: > On Fri, Feb 12, 2010 at 1:22 PM, Boszormenyi Zoltan <z...@cybertec.at> wrote: > >> Robert Haas írta: >> >>> On Fri, Feb 12, 2010 at 10:48 AM, Boszormenyi Zoltan <z...@cybertec.at> >>> wrote: >>> >>> >>>> I added a small change to protocol.sgml for the >>>> "CommandComplete" message describing the change. >>>> Is it enough? >>>> >>>> >>> Ah, I didn't even see that that section needed to be updated. Good >>> catch. I'd suggest the following wording: >>> >>> For a <command>SELECT</command> or <command>CREATE TABLE AS</command> >>> command, the tag is SELECT rows... [and the rest as you have it] >>> >>> We should probably also retitle that section from "Retrieving Result >>> Information for Other Commands" to "Retrieving Other Result >>> Information" and adjust the text of the opening sentence similarly. >>> >>> Also I think you need to update the docs for PQcmdtuples to mention >>> that it not works for SELECT and CTAS. >>> >>> >> Ok, I will update libpq.sgml where this section resides. >> What's a CTA, btw? Do you mean CTE, a.k.a. "Common Table Expression"? >> > > Sorry, CTAS = CREATE TABLE AS SELECT. >
Okay, new patch is attached. Please read the docs changes, and comment. Thanks, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/
diff -dcrpN pgsql.orig/doc/src/sgml/libpq.sgml pgsql/doc/src/sgml/libpq.sgml *** pgsql.orig/doc/src/sgml/libpq.sgml 2010-02-05 12:20:10.000000000 +0100 --- pgsql/doc/src/sgml/libpq.sgml 2010-02-12 19:53:36.000000000 +0100 *************** typedef struct { *** 2869,2880 **** </sect2> <sect2 id="libpq-exec-nonselect"> ! <title>Retrieving Result Information for Other Commands</title> <para> ! These functions are used to extract information from ! <structname>PGresult</structname> objects that are not ! <command>SELECT</> results. </para> <variablelist> --- 2869,2879 ---- </sect2> <sect2 id="libpq-exec-nonselect"> ! <title>Retrieving Other Result Information</title> <para> ! These functions are used to extract other information from ! <structname>PGresult</structname> objects. </para> <variablelist> *************** typedef struct { *** 2925,2936 **** 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 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 --- 2924,2935 ---- 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 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 -dcrpN pgsql.orig/doc/src/sgml/protocol.sgml pgsql/doc/src/sgml/protocol.sgml *** pgsql.orig/doc/src/sgml/protocol.sgml 2010-02-03 11:12:23.000000000 +0100 --- pgsql/doc/src/sgml/protocol.sgml 2010-02-12 19:17:24.000000000 +0100 *************** CommandComplete (B) *** 2222,2227 **** --- 2222,2233 ---- </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 <replaceable>rows</replaceable> is the number of rows the diff -dcrpN pgsql.orig/src/backend/tcop/pquery.c pgsql/src/backend/tcop/pquery.c *** pgsql.orig/src/backend/tcop/pquery.c 2010-01-03 12:54:25.000000000 +0100 --- pgsql/src/backend/tcop/pquery.c 2010-02-08 11:46:33.000000000 +0100 *************** ProcessQuery(PlannedStmt *plan, *** 205,211 **** switch (queryDesc->operation) { case CMD_SELECT: ! strcpy(completionTag, "SELECT"); break; case CMD_INSERT: if (queryDesc->estate->es_processed == 1) --- 205,212 ---- switch (queryDesc->operation) { case CMD_SELECT: ! snprintf(completionTag, COMPLETION_TAG_BUFSIZE, ! "SELECT %u", queryDesc->estate->es_processed); break; case CMD_INSERT: if (queryDesc->estate->es_processed == 1) *************** PortalRun(Portal portal, long count, boo *** 714,719 **** --- 715,721 ---- char *completionTag) { bool result; + uint32 nprocessed; ResourceOwner saveTopTransactionResourceOwner; MemoryContext saveTopTransactionContext; Portal saveActivePortal; *************** PortalRun(Portal portal, long count, boo *** 776,814 **** 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. */ ! if (!portal->holdStore) FillPortalStore(portal, isTopLevel); /* * Now fetch desired portion of results. */ ! (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; --- 778,812 ---- switch (portal->strategy) { case PORTAL_ONE_SELECT: 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. Do this only for the ! * PORTAL_ONE_RETURNING and PORTAL_UTIL_SELECT cases. */ ! if ((portal->strategy != PORTAL_ONE_SELECT) && (!portal->holdStore)) FillPortalStore(portal, isTopLevel); /* * Now fetch desired portion of results. */ ! nprocessed = PortalRunSelect(portal, true, count, dest); ! /* ! * 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 (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; *************** PortalRunMulti(Portal portal, bool isTop *** 1318,1337 **** * If a command completion tag was supplied, use it. Otherwise use the * portal's commandTag as the default completion tag. * ! * Exception: clients will expect INSERT/UPDATE/DELETE tags to have ! * counts, so fake something up if necessary. (This could happen if the * original query was replaced by a DO INSTEAD rule.) */ if (completionTag && completionTag[0] == '\0') { if (portal->commandTag) strcpy(completionTag, portal->commandTag); if (strcmp(completionTag, "INSERT") == 0) ! strcpy(completionTag, "INSERT 0 0"); else if (strcmp(completionTag, "UPDATE") == 0) ! strcpy(completionTag, "UPDATE 0"); else if (strcmp(completionTag, "DELETE") == 0) ! strcpy(completionTag, "DELETE 0"); } } --- 1316,1346 ---- * If a command completion tag was supplied, use it. Otherwise use the * portal's commandTag as the default completion tag. * ! * Exception: clients will expect SELECT/INSERT/UPDATE/DELETE tags to have ! * counts, so try to provide the proper info. (This could happen if the * original query was replaced by a DO INSTEAD rule.) */ if (completionTag && completionTag[0] == '\0') { + Oid lastOid = InvalidOid; + uint32 processed = 0; + + if (portal->queryDesc && portal->queryDesc->estate) + { + lastOid = portal->queryDesc->estate->es_lastoid; + processed = portal->queryDesc->estate->es_processed; + } + if (portal->commandTag) strcpy(completionTag, portal->commandTag); if (strcmp(completionTag, "INSERT") == 0) ! sprintf(completionTag, "INSERT %u %u", lastOid, processed); else if (strcmp(completionTag, "UPDATE") == 0) ! sprintf(completionTag, "UPDATE %u", processed); else if (strcmp(completionTag, "DELETE") == 0) ! sprintf(completionTag, "DELETE %u", processed); ! else if (strcmp(completionTag, "SELECT") == 0) ! sprintf(completionTag, "SELECT %u", processed); } } diff -dcrpN pgsql.orig/src/interfaces/libpq/fe-exec.c pgsql/src/interfaces/libpq/fe-exec.c *** pgsql.orig/src/interfaces/libpq/fe-exec.c 2010-01-21 20:45:39.000000000 +0100 --- pgsql/src/interfaces/libpq/fe-exec.c 2010-02-08 10:32:25.000000000 +0100 *************** PQcmdTuples(PGresult *res) *** 2753,2758 **** --- 2753,2759 ---- p++; } else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 || + strncmp(res->cmdStatus, "SELECT ", 7) == 0 || strncmp(res->cmdStatus, "UPDATE ", 7) == 0) p = res->cmdStatus + 7; else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers