Represent command completion tags as structs
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 2 Mar 2020 21:19:51 +0000 (18:19 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 2 Mar 2020 21:19:51 +0000 (18:19 -0300)
The backend was using strings to represent command tags and doing string
comparisons in multiple places, but that's slow and unhelpful.  Create a
new command list with a supporting structure to use instead; this is
stored in a tag-list-file that can be tailored to specific purposes with
a caller-definable C macro, similar to what we do for WAL resource
managers.  The first first such uses are a new CommandTag enum and a
CommandTagBehavior struct.

Replace numerous occurrences of char *completionTag with a
QueryCompletion struct so that the code no longer stores information
about completed queries in a cstring.  Only at the last moment, in
EndCommand(), does this get converted to a string.

EventTriggerCacheItem no longer holds an array of palloc’d tag strings
in sorted order, but rather just a Bitmapset over the CommandTags.

Author: Mark Dilger, with unsolicited help from Álvaro Herrera
Reviewed-by: John Naylor, Tom Lane
Discussion: https://postgr.es/m/981A9DB4-3F0C-4DA5-88AD-CB9CFF4D6CAD@enterprisedb.com

39 files changed:
contrib/pg_stat_statements/pg_stat_statements.c
contrib/sepgsql/hooks.c
doc/src/sgml/event-trigger.sgml
src/backend/commands/createas.c
src/backend/commands/event_trigger.c
src/backend/commands/matview.c
src/backend/commands/portalcmds.c
src/backend/commands/prepare.c
src/backend/executor/execMain.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/replication/logical/decode.c
src/backend/replication/walsender.c
src/backend/tcop/Makefile
src/backend/tcop/cmdtag.c [new file with mode: 0644]
src/backend/tcop/dest.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/tcop/utility.c
src/backend/utils/cache/evtcache.c
src/backend/utils/cache/plancache.c
src/backend/utils/mmgr/portalmem.c
src/include/commands/createas.h
src/include/commands/event_trigger.h
src/include/commands/matview.h
src/include/commands/portalcmds.h
src/include/commands/prepare.h
src/include/tcop/cmdtag.h [new file with mode: 0644]
src/include/tcop/cmdtaglist.h [new file with mode: 0644]
src/include/tcop/dest.h
src/include/tcop/pquery.h
src/include/tcop/utility.h
src/include/utils/evtcache.h
src/include/utils/plancache.h
src/include/utils/portal.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/tcl/pltcl.c
src/test/modules/test_ddl_deparse/test_ddl_deparse.c

index e4fda4b4049fae4b6e93733679ac78c95e9f3103..7d9a1de2e0b5d9b302c296a177a7c0535ad2d4a1 100644 (file)
@@ -307,7 +307,7 @@ static void pgss_ExecutorEnd(QueryDesc *queryDesc);
 static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                                                                ProcessUtilityContext context, ParamListInfo params,
                                                                QueryEnvironment *queryEnv,
-                                                               DestReceiver *dest, char *completionTag);
+                                                               DestReceiver *dest, QueryCompletion *qc);
 static uint64 pgss_hash_string(const char *str, int len);
 static void pgss_store(const char *query, uint64 queryId,
                                           int query_location, int query_len,
@@ -960,7 +960,7 @@ static void
 pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                                        ProcessUtilityContext context,
                                        ParamListInfo params, QueryEnvironment *queryEnv,
-                                       DestReceiver *dest, char *completionTag)
+                                       DestReceiver *dest, QueryCompletion *qc)
 {
        Node       *parsetree = pstmt->utilityStmt;
 
@@ -998,11 +998,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                        if (prev_ProcessUtility)
                                prev_ProcessUtility(pstmt, queryString,
                                                                        context, params, queryEnv,
-                                                                       dest, completionTag);
+                                                                       dest, qc);
                        else
                                standard_ProcessUtility(pstmt, queryString,
                                                                                context, params, queryEnv,
-                                                                               dest, completionTag);
+                                                                               dest, qc);
                }
                PG_FINALLY();
                {
@@ -1013,12 +1013,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                INSTR_TIME_SET_CURRENT(duration);
                INSTR_TIME_SUBTRACT(duration, start);
 
-               /* parse command tag to retrieve the number of affected rows. */
-               if (completionTag &&
-                       strncmp(completionTag, "COPY ", 5) == 0)
-                       rows = pg_strtouint64(completionTag + 5, NULL, 10);
-               else
-                       rows = 0;
+               if (qc)
+                       rows = qc->commandTag == CMDTAG_COPY ? qc->nprocessed : 0;
 
                /* calc differences of buffer counters. */
                bufusage.shared_blks_hit =
@@ -1060,11 +1056,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                if (prev_ProcessUtility)
                        prev_ProcessUtility(pstmt, queryString,
                                                                context, params, queryEnv,
-                                                               dest, completionTag);
+                                                               dest, qc);
                else
                        standard_ProcessUtility(pstmt, queryString,
                                                                        context, params, queryEnv,
-                                                                       dest, completionTag);
+                                                                       dest, qc);
        }
 }
 
index 997a64c87e2b91991b21fddd791aea27459d04fd..853b5b04ab8b17f96523d1081c842bbb683b4181 100644 (file)
@@ -317,7 +317,7 @@ sepgsql_utility_command(PlannedStmt *pstmt,
                                                ParamListInfo params,
                                                QueryEnvironment *queryEnv,
                                                DestReceiver *dest,
-                                               char *completionTag)
+                                               QueryCompletion *qc)
 {
        Node       *parsetree = pstmt->utilityStmt;
        sepgsql_context_info_t saved_context_info = sepgsql_context_info;
@@ -380,11 +380,11 @@ sepgsql_utility_command(PlannedStmt *pstmt,
                if (next_ProcessUtility_hook)
                        (*next_ProcessUtility_hook) (pstmt, queryString,
                                                                                 context, params, queryEnv,
-                                                                                dest, completionTag);
+                                                                                dest, qc);
                else
                        standard_ProcessUtility(pstmt, queryString,
                                                                        context, params, queryEnv,
-                                                                       dest, completionTag);
+                                                                       dest, qc);
        }
        PG_FINALLY();
        {
index 18628c498ba20265ccc5e14ab1588b743b6bd4b2..130f6cd886a593c26a5a0e61024981a924b86b99 100644 (file)
@@ -1074,7 +1074,7 @@ typedef struct EventTriggerData
     NodeTag     type;
     const char *event;      /* event name */
     Node       *parsetree;  /* parse tree */
-    const char *tag;        /* command tag */
+    CommandTag  tag;        /* command tag */
 } EventTriggerData;
 </programlisting>
 
index cc02cf824ed9795775babbb09887ed2e27034d4d..3a5676fb39e0051a649a8592cb1e843658703fec 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Formerly, CTAS was implemented as a variant of SELECT, which led
  * to assorted legacy behaviors that we still try to preserve, notably that
- * we must return a tuples-processed count in the completionTag.  (We no
+ * we must return a tuples-processed count in the QueryCompletion.  (We no
  * longer do that for CTAS ... WITH NO DATA, however.)
  *
  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
@@ -225,7 +225,7 @@ create_ctas_nodata(List *tlist, IntoClause *into)
 ObjectAddress
 ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
                                  ParamListInfo params, QueryEnvironment *queryEnv,
-                                 char *completionTag)
+                                 QueryCompletion *qc)
 {
        Query      *query = castNode(Query, stmt->query);
        IntoClause *into = stmt->into;
@@ -270,7 +270,7 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
                ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
 
                Assert(!is_matview);    /* excluded by syntax */
-               ExecuteQuery(pstate, estmt, into, params, dest, completionTag);
+               ExecuteQuery(pstate, estmt, into, params, dest, qc);
 
                /* get object address that intorel_startup saved for us */
                address = ((DR_intorel *) dest)->reladdr;
@@ -352,11 +352,9 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
                /* run the plan to completion */
                ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
 
-               /* save the rowcount if we're given a completionTag to fill */
-               if (completionTag)
-                       snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                        "SELECT " UINT64_FORMAT,
-                                        queryDesc->estate->es_processed);
+               /* save the rowcount if we're given a qc to fill */
+               if (qc)
+                       SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
 
                /* get object address that intorel_startup saved for us */
                address = ((DR_intorel *) dest)->reladdr;
index 71911d4067bda0379249e261dce696da708e9364..a366869369b3cd32cf291eea4aaf332a7ac7c5a4 100644 (file)
@@ -78,59 +78,6 @@ typedef struct
        bool            supported;
 } event_trigger_support_data;
 
-typedef enum
-{
-       EVENT_TRIGGER_COMMAND_TAG_OK,
-       EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED,
-       EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED
-} event_trigger_command_tag_check_result;
-
-/* XXX merge this with ObjectTypeMap? */
-static const event_trigger_support_data event_trigger_support[] = {
-       {"ACCESS METHOD", true},
-       {"AGGREGATE", true},
-       {"CAST", true},
-       {"CONSTRAINT", true},
-       {"COLLATION", true},
-       {"CONVERSION", true},
-       {"DATABASE", false},
-       {"DOMAIN", true},
-       {"EXTENSION", true},
-       {"EVENT TRIGGER", false},
-       {"FOREIGN DATA WRAPPER", true},
-       {"FOREIGN TABLE", true},
-       {"FUNCTION", true},
-       {"INDEX", true},
-       {"LANGUAGE", true},
-       {"MATERIALIZED VIEW", true},
-       {"OPERATOR", true},
-       {"OPERATOR CLASS", true},
-       {"OPERATOR FAMILY", true},
-       {"POLICY", true},
-       {"PROCEDURE", true},
-       {"PUBLICATION", true},
-       {"ROLE", false},
-       {"ROUTINE", true},
-       {"RULE", true},
-       {"SCHEMA", true},
-       {"SEQUENCE", true},
-       {"SERVER", true},
-       {"STATISTICS", true},
-       {"SUBSCRIPTION", true},
-       {"TABLE", true},
-       {"TABLESPACE", false},
-       {"TRANSFORM", true},
-       {"TRIGGER", true},
-       {"TEXT SEARCH CONFIGURATION", true},
-       {"TEXT SEARCH DICTIONARY", true},
-       {"TEXT SEARCH PARSER", true},
-       {"TEXT SEARCH TEMPLATE", true},
-       {"TYPE", true},
-       {"USER MAPPING", true},
-       {"VIEW", true},
-       {NULL, false}
-};
-
 /* Support for dropped objects */
 typedef struct SQLDropObject
 {
@@ -150,8 +97,6 @@ typedef struct SQLDropObject
 static void AlterEventTriggerOwner_internal(Relation rel,
                                                                                        HeapTuple tup,
                                                                                        Oid newOwnerId);
-static event_trigger_command_tag_check_result check_ddl_tag(const char *tag);
-static event_trigger_command_tag_check_result check_table_rewrite_ddl_tag(const char *tag);
 static void error_duplicate_filter_variable(const char *defname);
 static Datum filter_list_to_array(List *filterlist);
 static Oid     insert_event_trigger_tuple(const char *trigname, const char *eventname,
@@ -259,71 +204,23 @@ validate_ddl_tags(const char *filtervar, List *taglist)
 
        foreach(lc, taglist)
        {
-               const char *tag = strVal(lfirst(lc));
-               event_trigger_command_tag_check_result result;
+               const char *tagstr = strVal(lfirst(lc));
+               CommandTag      commandTag = GetCommandTagEnum(tagstr);
 
-               result = check_ddl_tag(tag);
-               if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED)
+               if (commandTag == CMDTAG_UNKNOWN)
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
                                         errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
-                                                       tag, filtervar)));
-               if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
+                                                       tagstr, filtervar)));
+               if (!command_tag_event_trigger_ok(commandTag))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        /* translator: %s represents an SQL statement name */
                                         errmsg("event triggers are not supported for %s",
-                                                       tag)));
+                                                       tagstr)));
        }
 }
 
-static event_trigger_command_tag_check_result
-check_ddl_tag(const char *tag)
-{
-       const char *obtypename;
-       const event_trigger_support_data *etsd;
-
-       /*
-        * Handle some idiosyncratic special cases.
-        */
-       if (pg_strcasecmp(tag, "CREATE TABLE AS") == 0 ||
-               pg_strcasecmp(tag, "SELECT INTO") == 0 ||
-               pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
-               pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
-               pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
-               pg_strcasecmp(tag, "COMMENT") == 0 ||
-               pg_strcasecmp(tag, "GRANT") == 0 ||
-               pg_strcasecmp(tag, "REVOKE") == 0 ||
-               pg_strcasecmp(tag, "DROP OWNED") == 0 ||
-               pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0 ||
-               pg_strcasecmp(tag, "SECURITY LABEL") == 0)
-               return EVENT_TRIGGER_COMMAND_TAG_OK;
-
-       /*
-        * Otherwise, command should be CREATE, ALTER, or DROP.
-        */
-       if (pg_strncasecmp(tag, "CREATE ", 7) == 0)
-               obtypename = tag + 7;
-       else if (pg_strncasecmp(tag, "ALTER ", 6) == 0)
-               obtypename = tag + 6;
-       else if (pg_strncasecmp(tag, "DROP ", 5) == 0)
-               obtypename = tag + 5;
-       else
-               return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
-
-       /*
-        * ...and the object type should be something recognizable.
-        */
-       for (etsd = event_trigger_support; etsd->obtypename != NULL; etsd++)
-               if (pg_strcasecmp(etsd->obtypename, obtypename) == 0)
-                       break;
-       if (etsd->obtypename == NULL)
-               return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
-       if (!etsd->supported)
-               return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
-       return EVENT_TRIGGER_COMMAND_TAG_OK;
-}
-
 /*
  * Validate DDL command tags for event table_rewrite.
  */
@@ -334,29 +231,18 @@ validate_table_rewrite_tags(const char *filtervar, List *taglist)
 
        foreach(lc, taglist)
        {
-               const char *tag = strVal(lfirst(lc));
-               event_trigger_command_tag_check_result result;
+               const char *tagstr = strVal(lfirst(lc));
+               CommandTag      commandTag = GetCommandTagEnum(tagstr);
 
-               result = check_table_rewrite_ddl_tag(tag);
-               if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
+               if (!command_tag_table_rewrite_ok(commandTag))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        /* translator: %s represents an SQL statement name */
                                         errmsg("event triggers are not supported for %s",
-                                                       tag)));
+                                                       tagstr)));
        }
 }
 
-static event_trigger_command_tag_check_result
-check_table_rewrite_ddl_tag(const char *tag)
-{
-       if (pg_strcasecmp(tag, "ALTER TABLE") == 0 ||
-               pg_strcasecmp(tag, "ALTER TYPE") == 0)
-               return EVENT_TRIGGER_COMMAND_TAG_OK;
-
-       return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
-}
-
 /*
  * Complain about a duplicate filter variable.
  */
@@ -663,7 +549,7 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
  * tags matching.
  */
 static bool
-filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
+filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item)
 {
        /*
         * Filter by session replication role, knowing that we never see disabled
@@ -681,9 +567,7 @@ filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
        }
 
        /* Filter by tags, if any were specified. */
-       if (item->ntags != 0 && bsearch(tag, item->tag,
-                                                                       item->ntags, sizeof(char *),
-                                                                       pg_qsort_strcmp) == NULL)
+       if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
                return false;
 
        /* if we reach that point, we're not filtering out this item */
@@ -700,7 +584,7 @@ EventTriggerCommonSetup(Node *parsetree,
                                                EventTriggerEvent event, const char *eventstr,
                                                EventTriggerData *trigdata)
 {
-       const char *tag;
+       CommandTag      tag;
        List       *cachelist;
        ListCell   *lc;
        List       *runlist = NIL;
@@ -716,25 +600,25 @@ EventTriggerCommonSetup(Node *parsetree,
         *
         * If this cross-check fails for you, you probably need to either adjust
         * standard_ProcessUtility() not to invoke event triggers for the command
-        * type in question, or you need to adjust check_ddl_tag to accept the
+        * type in question, or you need to adjust event_trigger_ok to accept the
         * relevant command tag.
         */
 #ifdef USE_ASSERT_CHECKING
        {
-               const char *dbgtag;
+               CommandTag      dbgtag;
 
                dbgtag = CreateCommandTag(parsetree);
                if (event == EVT_DDLCommandStart ||
                        event == EVT_DDLCommandEnd ||
                        event == EVT_SQLDrop)
                {
-                       if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
-                               elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
+                       if (!command_tag_event_trigger_ok(dbgtag))
+                               elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
                }
                else if (event == EVT_TableRewrite)
                {
-                       if (check_table_rewrite_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
-                               elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
+                       if (!command_tag_table_rewrite_ok(dbgtag))
+                               elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
                }
        }
 #endif
@@ -758,7 +642,7 @@ EventTriggerCommonSetup(Node *parsetree,
        {
                EventTriggerCacheItem *item = lfirst(lc);
 
-               if (filter_event_trigger(&tag, item))
+               if (filter_event_trigger(tag, item))
                {
                        /* We must plan to fire this trigger. */
                        runlist = lappend_oid(runlist, item->fnoid);
@@ -2136,7 +2020,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
                                        /* objsubid */
                                        values[i++] = Int32GetDatum(addr.objectSubId);
                                        /* command tag */
-                                       values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
+                                       values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
                                        /* object_type */
                                        values[i++] = CStringGetTextDatum(type);
                                        /* schema */
@@ -2161,7 +2045,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
                                /* objsubid */
                                nulls[i++] = true;
                                /* command tag */
-                               values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
+                               values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
                                /* object_type */
                                values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
                                /* schema */
index 1ee37c1aeb6c759a07e04747cbe3c6fc371edba2..c3954f3e242c28acb6b7d0e3f4a396555d19f124 100644 (file)
@@ -136,7 +136,7 @@ SetMatViewPopulatedState(Relation relation, bool newstate)
  */
 ObjectAddress
 ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
-                                  ParamListInfo params, char *completionTag)
+                                  ParamListInfo params, QueryCompletion *qc)
 {
        Oid                     matviewOid;
        Relation        matviewRel;
index 7e5c805a1e305cbc5ec98776f4e8c2e18f51f188..40be5069fefa10f99b123f1a1c351f3c0c68b322 100644 (file)
@@ -106,7 +106,7 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
        PortalDefineQuery(portal,
                                          NULL,
                                          queryString,
-                                         "SELECT", /* cursor's query is always a SELECT */
+                                         CMDTAG_SELECT,        /* cursor's query is always a SELECT */
                                          list_make1(plan),
                                          NULL);
 
@@ -160,15 +160,14 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
  *
  *     stmt: parsetree node for command
  *     dest: where to send results
- *     completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
- *             in which to store a command completion status string.
+ *     qc: where to store a command completion status data.
  *
- * completionTag may be NULL if caller doesn't want a status string.
+ * qc may be NULL if caller doesn't want status data.
  */
 void
 PerformPortalFetch(FetchStmt *stmt,
                                   DestReceiver *dest,
-                                  char *completionTag)
+                                  QueryCompletion *qc)
 {
        Portal          portal;
        uint64          nprocessed;
@@ -203,10 +202,9 @@ PerformPortalFetch(FetchStmt *stmt,
                                                                dest);
 
        /* Return command status if wanted */
-       if (completionTag)
-               snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s " UINT64_FORMAT,
-                                stmt->ismove ? "MOVE" : "FETCH",
-                                nprocessed);
+       if (qc)
+               SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
+                                                  nprocessed);
 }
 
 /*
index c4e4b6eaec6aaf4480b16112542ba74c1429b33d..f917fc9c7a770f775a07743dac566fa6de7151ec 100644 (file)
@@ -187,7 +187,7 @@ void
 ExecuteQuery(ParseState *pstate,
                         ExecuteStmt *stmt, IntoClause *intoClause,
                         ParamListInfo params,
-                        DestReceiver *dest, char *completionTag)
+                        DestReceiver *dest, QueryCompletion *qc)
 {
        PreparedStatement *entry;
        CachedPlan *cplan;
@@ -288,7 +288,7 @@ ExecuteQuery(ParseState *pstate,
         */
        PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
 
-       (void) PortalRun(portal, count, false, true, dest, dest, completionTag);
+       (void) PortalRun(portal, count, false, true, dest, dest, qc);
 
        PortalDrop(portal, false);
 
index ee5c3a60ff324094e794abc5a8108de35bc2881b..28130fbc2b19d60d9664beabb0f9c8f69a15610b 100644 (file)
@@ -787,11 +787,11 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
                if (isTempNamespace(get_rel_namespace(rte->relid)))
                        continue;
 
-               PreventCommandIfReadOnly(CreateCommandTag((Node *) plannedstmt));
+               PreventCommandIfReadOnly(CreateCommandName((Node *) plannedstmt));
        }
 
        if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
-               PreventCommandIfParallelMode(CreateCommandTag((Node *) plannedstmt));
+               PreventCommandIfParallelMode(CreateCommandName((Node *) plannedstmt));
 }
 
 
index 5cff6c43216400cff9e02f71748b38b6bc37fb8a..9b45a8a9a0eb85ca9ca8a6d5ab9ed3385b6f64e6 100644 (file)
@@ -530,7 +530,7 @@ init_execution_state(List *queryTree_list,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                        /* translator: %s is a SQL statement name */
                                                         errmsg("%s is not allowed in a SQL function",
-                                                                       CreateCommandTag(stmt->utilityStmt))));
+                                                                       CreateCommandName(stmt->utilityStmt))));
                        }
 
                        if (fcache->readonly_func && !CommandIsReadOnly(stmt))
@@ -538,7 +538,7 @@ init_execution_state(List *queryTree_list,
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                /* translator: %s is a SQL statement name */
                                                 errmsg("%s is not allowed in a non-volatile function",
-                                                               CreateCommandTag((Node *) stmt))));
+                                                               CreateCommandName((Node *) stmt))));
 
                        /* OK, build the execution_state for this query */
                        newes = (execution_state *) palloc(sizeof(execution_state));
index c46764bf4288e02d1126dea7339f7841459fc221..b1081688211c7c760c2d4798ed5d1778856c130e 100644 (file)
@@ -1338,7 +1338,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
                                (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
                /* translator: %s is name of a SQL command, eg INSERT */
                                 errmsg("cannot open %s query as cursor",
-                                               plansource->commandTag)));
+                                               GetCommandTagName(plansource->commandTag))));
        }
 
        Assert(list_length(plan->plancache_list) == 1);
@@ -1469,7 +1469,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                /* translator: %s is a SQL statement name */
                                                 errmsg("%s is not allowed in a non-volatile function",
-                                                               CreateCommandTag((Node *) pstmt))));
+                                                               CreateCommandName((Node *) pstmt))));
                }
        }
 
@@ -2255,7 +2255,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                /* translator: %s is a SQL statement name */
                                                 errmsg("%s is not allowed in a non-volatile function",
-                                                               CreateCommandTag((Node *) stmt))));
+                                                               CreateCommandName((Node *) stmt))));
 
                        /*
                         * If not read-only mode, advance the command counter before each
@@ -2291,8 +2291,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                        }
                        else
                        {
-                               char            completionTag[COMPLETION_TAG_BUFSIZE];
                                ProcessUtilityContext context;
+                               QueryCompletion qc;
 
                                /*
                                 * If the SPI context is atomic, or we are asked to manage
@@ -2306,13 +2306,14 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                else
                                        context = PROCESS_UTILITY_QUERY_NONATOMIC;
 
+                               InitializeQueryCompletion(&qc);
                                ProcessUtility(stmt,
                                                           plansource->query_string,
                                                           context,
                                                           paramLI,
                                                           _SPI_current->queryEnv,
                                                           dest,
-                                                          completionTag);
+                                                          &qc);
 
                                /* Update "processed" if stmt returned tuples */
                                if (_SPI_current->tuptable)
@@ -2328,9 +2329,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                {
                                        CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
 
-                                       if (strncmp(completionTag, "SELECT ", 7) == 0)
-                                               _SPI_current->processed =
-                                                       pg_strtouint64(completionTag + 7, NULL, 10);
+                                       if (qc.commandTag == CMDTAG_SELECT)
+                                               _SPI_current->processed = qc.nprocessed;
                                        else
                                        {
                                                /*
@@ -2351,9 +2351,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                }
                                else if (IsA(stmt->utilityStmt, CopyStmt))
                                {
-                                       Assert(strncmp(completionTag, "COPY ", 5) == 0);
-                                       _SPI_current->processed = pg_strtouint64(completionTag + 5,
-                                                                                                                        NULL, 10);
+                                       Assert(qc.commandTag == CMDTAG_COPY);
+                                       _SPI_current->processed = qc.nprocessed;
                                }
                        }
 
index 0ddc707defa37483c627c06a45c440ffbc42c704..c2e5e3abf82eab84a9ec4986addac45728d285bf 100644 (file)
@@ -100,7 +100,7 @@ LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *recor
        buf.record = record;
 
        /* cast so we get a warning when new rmgrs are added */
-       switch ((RmgrIds) XLogRecGetRmid(record))
+       switch ((RmgrId) XLogRecGetRmid(record))
        {
                        /*
                         * Rmgrs we care about for logical decoding. Add new rmgrs in
index abb533b9d036e5a53baf51d172ffd58ae3d62672..ae4a9cbe119ea09254c9b1c56679e9036636b8be 100644 (file)
@@ -1074,8 +1074,11 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
 static void
 DropReplicationSlot(DropReplicationSlotCmd *cmd)
 {
+       QueryCompletion qc;
+
        ReplicationSlotDrop(cmd->slotname, !cmd->wait);
-       EndCommand("DROP_REPLICATION_SLOT", DestRemote);
+       SetQueryCompletion(&qc, CMDTAG_DROP_REPLICATION_SLOT, 0);
+       EndCommand(&qc, DestRemote, false);
 }
 
 /*
@@ -1086,6 +1089,7 @@ static void
 StartLogicalReplication(StartReplicationCmd *cmd)
 {
        StringInfoData buf;
+       QueryCompletion qc;
 
        /* make sure that our requirements are still fulfilled */
        CheckLogicalDecodingRequirements();
@@ -1160,7 +1164,8 @@ StartLogicalReplication(StartReplicationCmd *cmd)
        WalSndSetState(WALSNDSTATE_STARTUP);
 
        /* Get out of COPY mode (CommandComplete). */
-       EndCommand("COPY 0", DestRemote);
+       SetQueryCompletion(&qc, CMDTAG_COPY, 0);
+       EndCommand(&qc, DestRemote, false);
 }
 
 /*
@@ -1464,6 +1469,7 @@ exec_replication_command(const char *cmd_string)
        Node       *cmd_node;
        MemoryContext cmd_context;
        MemoryContext old_context;
+       QueryCompletion qc;
 
        /*
         * If WAL sender has been told that shutdown is getting close, switch its
@@ -1614,7 +1620,8 @@ exec_replication_command(const char *cmd_string)
        MemoryContextDelete(cmd_context);
 
        /* Send CommandComplete message */
-       EndCommand("SELECT", DestRemote);
+       SetQueryCompletion(&qc, CMDTAG_SELECT, 0);
+       EndCommand(&qc, DestRemote, true);
 
        /* Report to pgstat that this process is now idle */
        pgstat_report_activity(STATE_IDLE, NULL);
@@ -2867,8 +2874,11 @@ WalSndDone(WalSndSendDataCallback send_data)
        if (WalSndCaughtUp && sentPtr == replicatedPtr &&
                !pq_is_send_pending())
        {
+               QueryCompletion qc;
+
                /* Inform the standby that XLOG streaming is done */
-               EndCommand("COPY 0", DestRemote);
+               SetQueryCompletion(&qc, CMDTAG_COPY, 0);
+               EndCommand(&qc, DestRemote, false);
                pq_flush();
 
                proc_exit(0);
index c78f1e0a05e5abfd0cb104f8221053f0bed66c8d..f662a7dd1cfd1022a1fcf039f762026405349468 100644 (file)
@@ -13,6 +13,7 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = \
+       cmdtag.o \
        dest.o \
        fastpath.o \
        postgres.o \
diff --git a/src/backend/tcop/cmdtag.c b/src/backend/tcop/cmdtag.c
new file mode 100644 (file)
index 0000000..b9fbff6
--- /dev/null
@@ -0,0 +1,98 @@
+/*-------------------------------------------------------------------------
+ *
+ * cmdtag.c
+ *       Data and routines for commandtag names and enumeration.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *       src/backend/tcop/cmdtag.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "tcop/cmdtag.h"
+
+
+typedef struct CommandTagBehavior
+{
+       const char *name;
+       const bool      event_trigger_ok;
+       const bool      table_rewrite_ok;
+       const bool      display_rowcount;
+} CommandTagBehavior;
+
+#define PG_CMDTAG(tag, name, evtrgok, rwrok, rowcnt) \
+       { name, evtrgok, rwrok, rowcnt },
+
+const CommandTagBehavior tag_behavior[COMMAND_TAG_NEXTTAG] = {
+#include "tcop/cmdtaglist.h"
+};
+
+#undef PG_CMDTAG
+
+void
+InitializeQueryCompletion(QueryCompletion *qc)
+{
+       qc->commandTag = CMDTAG_UNKNOWN;
+       qc->nprocessed = 0;
+}
+
+const char *
+GetCommandTagName(CommandTag commandTag)
+{
+       return tag_behavior[commandTag].name;
+}
+
+bool
+command_tag_display_rowcount(CommandTag commandTag)
+{
+       return tag_behavior[commandTag].display_rowcount;
+}
+
+bool
+command_tag_event_trigger_ok(CommandTag commandTag)
+{
+       return tag_behavior[commandTag].event_trigger_ok;
+}
+
+bool
+command_tag_table_rewrite_ok(CommandTag commandTag)
+{
+       return tag_behavior[commandTag].table_rewrite_ok;
+}
+
+/*
+ * Search CommandTag by name
+ *
+ * Returns CommandTag, or CMDTAG_UNKNOWN if not recognized
+ */
+CommandTag
+GetCommandTagEnum(const char *commandname)
+{
+       const CommandTagBehavior *base,
+                          *last,
+                          *position;
+       int                     result;
+
+       if (commandname == NULL || *commandname == '\0')
+               return CMDTAG_UNKNOWN;
+
+       base = tag_behavior;
+       last = tag_behavior + lengthof(tag_behavior) - 1;
+       while (last >= base)
+       {
+               position = base + ((last - base) >> 1);
+               result = pg_strcasecmp(commandname, position->name);
+               if (result == 0)
+                       return (CommandTag) (position - tag_behavior);
+               else if (result < 0)
+                       last = position - 1;
+               else
+                       base = position + 1;
+       }
+       return CMDTAG_UNKNOWN;
+}
index 09c1dcbb537796641de05d4b075e04f678e846bc..7208751ec781cd04ee0589f80701c05c688eee1f 100644 (file)
@@ -100,7 +100,7 @@ DestReceiver *None_Receiver = (DestReceiver *) &donothingDR;
  * ----------------
  */
 void
-BeginCommand(const char *commandTag, CommandDest dest)
+BeginCommand(CommandTag commandTag, CommandDest dest)
 {
        /* Nothing to do at present */
 }
@@ -163,8 +163,12 @@ CreateDestReceiver(CommandDest dest)
  * ----------------
  */
 void
-EndCommand(const char *commandTag, CommandDest dest)
+EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_output)
 {
+       char            completionTag[COMPLETION_TAG_BUFSIZE];
+       CommandTag      tag;
+       const char *tagname;
+
        switch (dest)
        {
                case DestRemote:
@@ -172,11 +176,27 @@ EndCommand(const char *commandTag, CommandDest dest)
                case DestRemoteSimple:
 
                        /*
-                        * We assume the commandTag is plain ASCII and therefore requires
-                        * no encoding conversion.
+                        * We assume the tagname is plain ASCII and therefore requires no
+                        * encoding conversion.
+                        *
+                        * We no longer display LastOid, but to preserve the wire
+                        * protocol, we write InvalidOid where the LastOid used to be
+                        * written.
+                        *
+                        * All cases where LastOid was written also write nprocessed
+                        * count, so just Assert that rather than having an extra test.
                         */
-                       pq_putmessage('C', commandTag, strlen(commandTag) + 1);
-                       break;
+                       tag = qc->commandTag;
+                       tagname = GetCommandTagName(tag);
+
+                       if (command_tag_display_rowcount(tag) && !force_undecorated_output)
+                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+                                                tag == CMDTAG_INSERT ?
+                                                "%s 0 " UINT64_FORMAT : "%s " UINT64_FORMAT,
+                                                tagname, qc->nprocessed);
+                       else
+                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s", tagname);
+                       pq_putmessage('C', completionTag, strlen(completionTag) + 1);
 
                case DestNone:
                case DestDebug:
index 23661ae15f5c6b56b5bcfcb0f82b0b88edcdf10e..9dba3b0566a403fc23ecb9a01ead2273835bd605 100644 (file)
@@ -1064,8 +1064,8 @@ exec_simple_query(const char *query_string)
        {
                RawStmt    *parsetree = lfirst_node(RawStmt, parsetree_item);
                bool            snapshot_set = false;
-               const char *commandTag;
-               char            completionTag[COMPLETION_TAG_BUFSIZE];
+               CommandTag      commandTag;
+               QueryCompletion qc;
                MemoryContext per_parsetree_context = NULL;
                List       *querytree_list,
                                   *plantree_list;
@@ -1081,7 +1081,7 @@ exec_simple_query(const char *query_string)
                 */
                commandTag = CreateCommandTag(parsetree->stmt);
 
-               set_ps_display(commandTag, false);
+               set_ps_display(GetCommandTagName(commandTag), false);
 
                BeginCommand(commandTag, dest);
 
@@ -1239,7 +1239,7 @@ exec_simple_query(const char *query_string)
                                                 true,
                                                 receiver,
                                                 receiver,
-                                                completionTag);
+                                                &qc);
 
                receiver->rDestroy(receiver);
 
@@ -1290,7 +1290,7 @@ exec_simple_query(const char *query_string)
                 * command the client sent, regardless of rewriting. (But a command
                 * aborted by error will not send an EndCommand report at all.)
                 */
-               EndCommand(completionTag, dest);
+               EndCommand(&qc, dest, false);
 
                /* Now we may drop the per-parsetree context, if one was created. */
                if (per_parsetree_context)
@@ -1352,7 +1352,6 @@ exec_parse_message(const char *query_string,      /* string to execute */
        MemoryContext oldcontext;
        List       *parsetree_list;
        RawStmt    *raw_parse_tree;
-       const char *commandTag;
        List       *querytree_list;
        CachedPlanSource *psrc;
        bool            is_named;
@@ -1438,11 +1437,6 @@ exec_parse_message(const char *query_string,     /* string to execute */
 
                raw_parse_tree = linitial_node(RawStmt, parsetree_list);
 
-               /*
-                * Get the command name for possible use in status display.
-                */
-               commandTag = CreateCommandTag(raw_parse_tree->stmt);
-
                /*
                 * If we are in an aborted transaction, reject all commands except
                 * COMMIT/ROLLBACK.  It is important that this test occur before we
@@ -1463,7 +1457,8 @@ exec_parse_message(const char *query_string,      /* string to execute */
                 * Create the CachedPlanSource before we do parse analysis, since it
                 * needs to see the unmodified raw parse tree.
                 */
-               psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag);
+               psrc = CreateCachedPlan(raw_parse_tree, query_string,
+                                                               CreateCommandTag(raw_parse_tree->stmt));
 
                /*
                 * Set up a snapshot if parse analysis will need one.
@@ -1514,8 +1509,8 @@ exec_parse_message(const char *query_string,      /* string to execute */
        {
                /* Empty input string.  This is legal. */
                raw_parse_tree = NULL;
-               commandTag = NULL;
-               psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag);
+               psrc = CreateCachedPlan(raw_parse_tree, query_string,
+                                                               CMDTAG_UNKNOWN);
                querytree_list = NIL;
        }
 
@@ -2031,7 +2026,7 @@ exec_execute_message(const char *portal_name, long max_rows)
        DestReceiver *receiver;
        Portal          portal;
        bool            completed;
-       char            completionTag[COMPLETION_TAG_BUFSIZE];
+       QueryCompletion qc;
        const char *sourceText;
        const char *prepStmtName;
        ParamListInfo portalParams;
@@ -2058,7 +2053,7 @@ exec_execute_message(const char *portal_name, long max_rows)
         * If the original query was a null string, just return
         * EmptyQueryResponse.
         */
-       if (portal->commandTag == NULL)
+       if (portal->commandTag == CMDTAG_UNKNOWN)
        {
                Assert(portal->stmts == NIL);
                NullCommand(dest);
@@ -2104,7 +2099,7 @@ exec_execute_message(const char *portal_name, long max_rows)
 
        pgstat_report_activity(STATE_RUNNING, sourceText);
 
-       set_ps_display(portal->commandTag, false);
+       set_ps_display(GetCommandTagName(portal->commandTag), false);
 
        if (save_log_statement_stats)
                ResetUsage();
@@ -2185,7 +2180,7 @@ exec_execute_message(const char *portal_name, long max_rows)
                                                  !execute_is_fetch && max_rows == FETCH_ALL,
                                                  receiver,
                                                  receiver,
-                                                 completionTag);
+                                                 &qc);
 
        receiver->rDestroy(receiver);
 
@@ -2218,7 +2213,7 @@ exec_execute_message(const char *portal_name, long max_rows)
                }
 
                /* Send appropriate CommandComplete to client */
-               EndCommand(completionTag, dest);
+               EndCommand(&qc, dest, false);
        }
        else
        {
index 0f5801e0460de89f2ad378afaec1dad0fa5e57cb..5781fb2e55ca56a02c94c336f75833f22a93b355 100644 (file)
@@ -40,7 +40,7 @@ static void ProcessQuery(PlannedStmt *plan,
                                                 ParamListInfo params,
                                                 QueryEnvironment *queryEnv,
                                                 DestReceiver *dest,
-                                                char *completionTag);
+                                                QueryCompletion *qc);
 static void FillPortalStore(Portal portal, bool isTopLevel);
 static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count,
                                                   DestReceiver *dest);
@@ -48,11 +48,11 @@ static uint64 PortalRunSelect(Portal portal, bool forward, long count,
                                                          DestReceiver *dest);
 static void PortalRunUtility(Portal portal, PlannedStmt *pstmt,
                                                         bool isTopLevel, bool setHoldSnapshot,
-                                                        DestReceiver *dest, char *completionTag);
+                                                        DestReceiver *dest, QueryCompletion *qc);
 static void PortalRunMulti(Portal portal,
                                                   bool isTopLevel, bool setHoldSnapshot,
                                                   DestReceiver *dest, DestReceiver *altdest,
-                                                  char *completionTag);
+                                                  QueryCompletion *qc);
 static uint64 DoPortalRunFetch(Portal portal,
                                                           FetchDirection fdirection,
                                                           long count,
@@ -125,10 +125,9 @@ FreeQueryDesc(QueryDesc *qdesc)
  *     sourceText: the source text of the query
  *     params: any parameters needed
  *     dest: where to send results
- *     completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
- *             in which to store a command completion status string.
+ *     qc: where to store the command completion status data.
  *
- * completionTag may be NULL if caller doesn't want a status string.
+ * qc may be NULL if caller doesn't want a status string.
  *
  * Must be called in a memory context that will be reset or deleted on
  * error; otherwise the executor's memory usage will be leaked.
@@ -139,7 +138,7 @@ ProcessQuery(PlannedStmt *plan,
                         ParamListInfo params,
                         QueryEnvironment *queryEnv,
                         DestReceiver *dest,
-                        char *completionTag)
+                        QueryCompletion *qc)
 {
        QueryDesc  *queryDesc;
 
@@ -161,38 +160,26 @@ ProcessQuery(PlannedStmt *plan,
        ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
 
        /*
-        * Build command completion status string, if caller wants one.
+        * Build command completion status data, if caller wants one.
         */
-       if (completionTag)
+       if (qc)
        {
-               Oid                     lastOid;
-
                switch (queryDesc->operation)
                {
                        case CMD_SELECT:
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                "SELECT " UINT64_FORMAT,
-                                                queryDesc->estate->es_processed);
+                               SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
                                break;
                        case CMD_INSERT:
-                               /* lastoid doesn't exist anymore */
-                               lastOid = InvalidOid;
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                "INSERT %u " UINT64_FORMAT,
-                                                lastOid, queryDesc->estate->es_processed);
+                               SetQueryCompletion(qc, CMDTAG_INSERT, queryDesc->estate->es_processed);
                                break;
                        case CMD_UPDATE:
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                "UPDATE " UINT64_FORMAT,
-                                                queryDesc->estate->es_processed);
+                               SetQueryCompletion(qc, CMDTAG_UPDATE, queryDesc->estate->es_processed);
                                break;
                        case CMD_DELETE:
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                "DELETE " UINT64_FORMAT,
-                                                queryDesc->estate->es_processed);
+                               SetQueryCompletion(qc, CMDTAG_DELETE, queryDesc->estate->es_processed);
                                break;
                        default:
-                               strcpy(completionTag, "???");
+                               SetQueryCompletion(qc, CMDTAG_UNKNOWN, queryDesc->estate->es_processed);
                                break;
                }
        }
@@ -675,9 +662,8 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
  *
  * altdest: where to send output of non-primary queries
  *
- * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
- *             in which to store a command completion status string.
- *             May be NULL if caller doesn't want a status string.
+ * qc: where to store command completion status data.
+ *             May be NULL if caller doesn't want status data.
  *
  * Returns true if the portal's execution is complete, false if it was
  * suspended due to exhaustion of the count parameter.
@@ -685,7 +671,7 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
 bool
 PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
                  DestReceiver *dest, DestReceiver *altdest,
-                 char *completionTag)
+                 QueryCompletion *qc)
 {
        bool            result;
        uint64          nprocessed;
@@ -700,9 +686,9 @@ PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
 
        TRACE_POSTGRESQL_QUERY_EXECUTE_START();
 
-       /* Initialize completion tag to empty string */
-       if (completionTag)
-               completionTag[0] = '\0';
+       /* Initialize empty completion data */
+       if (qc)
+               InitializeQueryCompletion(qc);
 
        if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
        {
@@ -771,16 +757,13 @@ PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
 
                                /*
                                 * 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.
+                                * gave us a pointer to store it, copy it and update the
+                                * rowcount.
                                 */
-                               if (completionTag && portal->commandTag)
+                               if (qc && portal->qc.commandTag != CMDTAG_UNKNOWN)
                                {
-                                       if (strcmp(portal->commandTag, "SELECT") == 0)
-                                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                                "SELECT " UINT64_FORMAT, nprocessed);
-                                       else
-                                               strcpy(completionTag, portal->commandTag);
+                                       CopyQueryCompletion(qc, &portal->qc);
+                                       qc->nprocessed = nprocessed;
                                }
 
                                /* Mark portal not active */
@@ -794,7 +777,7 @@ PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
 
                        case PORTAL_MULTI_QUERY:
                                PortalRunMulti(portal, isTopLevel, false,
-                                                          dest, altdest, completionTag);
+                                                          dest, altdest, qc);
 
                                /* Prevent portal's commands from being re-executed */
                                MarkPortalDone(portal);
@@ -1005,8 +988,9 @@ static void
 FillPortalStore(Portal portal, bool isTopLevel)
 {
        DestReceiver *treceiver;
-       char            completionTag[COMPLETION_TAG_BUFSIZE];
+       QueryCompletion qc;
 
+       InitializeQueryCompletion(&qc);
        PortalCreateHoldStore(portal);
        treceiver = CreateDestReceiver(DestTuplestore);
        SetTuplestoreDestReceiverParams(treceiver,
@@ -1014,8 +998,6 @@ FillPortalStore(Portal portal, bool isTopLevel)
                                                                        portal->holdContext,
                                                                        false);
 
-       completionTag[0] = '\0';
-
        switch (portal->strategy)
        {
                case PORTAL_ONE_RETURNING:
@@ -1028,12 +1010,12 @@ FillPortalStore(Portal portal, bool isTopLevel)
                         * portal's holdSnapshot to the snapshot used (or a copy of it).
                         */
                        PortalRunMulti(portal, isTopLevel, true,
-                                                  treceiver, None_Receiver, completionTag);
+                                                  treceiver, None_Receiver, &qc);
                        break;
 
                case PORTAL_UTIL_SELECT:
                        PortalRunUtility(portal, linitial_node(PlannedStmt, portal->stmts),
-                                                        isTopLevel, true, treceiver, completionTag);
+                                                        isTopLevel, true, treceiver, &qc);
                        break;
 
                default:
@@ -1042,9 +1024,9 @@ FillPortalStore(Portal portal, bool isTopLevel)
                        break;
        }
 
-       /* Override default completion tag with actual command result */
-       if (completionTag[0] != '\0')
-               portal->commandTag = pstrdup(completionTag);
+       /* Override portal completion data with actual command results */
+       if (qc.commandTag != CMDTAG_UNKNOWN)
+               CopyQueryCompletion(&portal->qc, &qc);
 
        treceiver->rDestroy(treceiver);
 }
@@ -1130,7 +1112,7 @@ RunFromStore(Portal portal, ScanDirection direction, uint64 count,
 static void
 PortalRunUtility(Portal portal, PlannedStmt *pstmt,
                                 bool isTopLevel, bool setHoldSnapshot,
-                                DestReceiver *dest, char *completionTag)
+                                DestReceiver *dest, QueryCompletion *qc)
 {
        Node       *utilityStmt = pstmt->utilityStmt;
        Snapshot        snapshot;
@@ -1178,7 +1160,7 @@ PortalRunUtility(Portal portal, PlannedStmt *pstmt,
                                   portal->portalParams,
                                   portal->queryEnv,
                                   dest,
-                                  completionTag);
+                                  qc);
 
        /* Some utility statements may change context on us */
        MemoryContextSwitchTo(portal->portalContext);
@@ -1202,7 +1184,7 @@ static void
 PortalRunMulti(Portal portal,
                           bool isTopLevel, bool setHoldSnapshot,
                           DestReceiver *dest, DestReceiver *altdest,
-                          char *completionTag)
+                          QueryCompletion *qc)
 {
        bool            active_snapshot_set = false;
        ListCell   *stmtlist_item;
@@ -1284,7 +1266,7 @@ PortalRunMulti(Portal portal,
                                                         portal->sourceText,
                                                         portal->portalParams,
                                                         portal->queryEnv,
-                                                        dest, completionTag);
+                                                        dest, qc);
                        }
                        else
                        {
@@ -1319,7 +1301,7 @@ PortalRunMulti(Portal portal,
                                Assert(!active_snapshot_set);
                                /* statement can set tag string */
                                PortalRunUtility(portal, pstmt, isTopLevel, false,
-                                                                dest, completionTag);
+                                                                dest, qc);
                        }
                        else
                        {
@@ -1350,8 +1332,8 @@ PortalRunMulti(Portal portal,
                PopActiveSnapshot();
 
        /*
-        * If a command completion tag was supplied, use it.  Otherwise use the
-        * portal's commandTag as the default completion tag.
+        * If a query completion data was supplied, use it.  Otherwise use the
+        * portal's query completion data.
         *
         * Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so
         * fake them with zeros.  This can happen with DO INSTEAD rules if there
@@ -1361,18 +1343,12 @@ PortalRunMulti(Portal portal,
         * e.g.  an INSERT that does an UPDATE instead should not print "0 1" if
         * one row was updated.  See QueryRewrite(), step 3, for details.
         */
-       if (completionTag && completionTag[0] == '\0')
+       if (qc && qc->commandTag == CMDTAG_UNKNOWN)
        {
-               if (portal->commandTag)
-                       strcpy(completionTag, portal->commandTag);
-               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");
-               else if (strcmp(completionTag, "DELETE") == 0)
-                       strcpy(completionTag, "DELETE 0");
+               if (portal->qc.commandTag != CMDTAG_UNKNOWN)
+                       CopyQueryCompletion(qc, &portal->qc);
+               /* If the caller supplied a qc, we should have set it by now. */
+               Assert(qc->commandTag != CMDTAG_UNKNOWN);
        }
 }
 
index bb85b5e52aade72fe80e9882d8b12dde955b39a6..1b460a2612602f998fe82717d9135f8fdafa4c29 100644 (file)
@@ -75,7 +75,7 @@
 ProcessUtility_hook_type ProcessUtility_hook = NULL;
 
 /* local function declarations */
-static int ClassifyUtilityCommandAsReadOnly(Node *parsetree);
+static int     ClassifyUtilityCommandAsReadOnly(Node *parsetree);
 static void ProcessUtilitySlow(ParseState *pstate,
                                                           PlannedStmt *pstmt,
                                                           const char *queryString,
@@ -83,10 +83,9 @@ static void ProcessUtilitySlow(ParseState *pstate,
                                                           ParamListInfo params,
                                                           QueryEnvironment *queryEnv,
                                                           DestReceiver *dest,
-                                                          char *completionTag);
+                                                          QueryCompletion *qc);
 static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
 
-
 /*
  * CommandIsReadOnly: is an executable query read-only?
  *
@@ -467,7 +466,6 @@ CheckRestrictedOperation(const char *cmdname)
                                                cmdname)));
 }
 
-
 /*
  * ProcessUtility
  *             general utility function invoker
@@ -480,17 +478,13 @@ CheckRestrictedOperation(const char *cmdname)
  *     queryEnv: environment for parse through execution (e.g., ephemeral named
  *             tables like trigger transition tables).  May be NULL.
  *     dest: where to send results
- *     completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
- *             in which to store a command completion status string.
+ *     qc: where to store command completion status data.  May be NULL,
+ *             but if not, then caller must have initialized it.
  *
  * Caller MUST supply a queryString; it is not allowed (anymore) to pass NULL.
  * If you really don't have source text, you can pass a constant string,
  * perhaps "(query not available)".
  *
- * completionTag is only set nonempty if we want to return a nondefault status.
- *
- * completionTag may be NULL if caller doesn't want a status string.
- *
  * Note for users of ProcessUtility_hook: the same queryString may be passed
  * to multiple invocations of ProcessUtility when processing a query string
  * containing multiple semicolon-separated statements.  One should use
@@ -507,11 +501,12 @@ ProcessUtility(PlannedStmt *pstmt,
                           ParamListInfo params,
                           QueryEnvironment *queryEnv,
                           DestReceiver *dest,
-                          char *completionTag)
+                          QueryCompletion *qc)
 {
        Assert(IsA(pstmt, PlannedStmt));
        Assert(pstmt->commandType == CMD_UTILITY);
        Assert(queryString != NULL);    /* required as of 8.4 */
+       Assert(qc == NULL || qc->commandTag == CMDTAG_UNKNOWN);
 
        /*
         * We provide a function hook variable that lets loadable plugins get
@@ -521,11 +516,11 @@ ProcessUtility(PlannedStmt *pstmt,
        if (ProcessUtility_hook)
                (*ProcessUtility_hook) (pstmt, queryString,
                                                                context, params, queryEnv,
-                                                               dest, completionTag);
+                                                               dest, qc);
        else
                standard_ProcessUtility(pstmt, queryString,
                                                                context, params, queryEnv,
-                                                               dest, completionTag);
+                                                               dest, qc);
 }
 
 /*
@@ -546,7 +541,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                                ParamListInfo params,
                                                QueryEnvironment *queryEnv,
                                                DestReceiver *dest,
-                                               char *completionTag)
+                                               QueryCompletion *qc)
 {
        Node       *parsetree = pstmt->utilityStmt;
        bool            isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
@@ -562,19 +557,16 @@ standard_ProcessUtility(PlannedStmt *pstmt,
        if (readonly_flags != COMMAND_IS_STRICTLY_READ_ONLY &&
                (XactReadOnly || IsInParallelMode()))
        {
-               const char *commandtag = CreateCommandTag(parsetree);
+               CommandTag      commandtag = CreateCommandTag(parsetree);
 
                if ((readonly_flags & COMMAND_OK_IN_READ_ONLY_TXN) == 0)
-                       PreventCommandIfReadOnly(commandtag);
+                       PreventCommandIfReadOnly(GetCommandTagName(commandtag));
                if ((readonly_flags & COMMAND_OK_IN_PARALLEL_MODE) == 0)
-                       PreventCommandIfParallelMode(commandtag);
+                       PreventCommandIfParallelMode(GetCommandTagName(commandtag));
                if ((readonly_flags & COMMAND_OK_IN_RECOVERY) == 0)
-                       PreventCommandDuringRecovery(commandtag);
+                       PreventCommandDuringRecovery(GetCommandTagName(commandtag));
        }
 
-       if (completionTag)
-               completionTag[0] = '\0';
-
        pstate = make_parsestate(NULL);
        pstate->p_sourcetext = queryString;
        pstate->p_queryEnv = queryEnv;
@@ -623,18 +615,18 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                        case TRANS_STMT_COMMIT:
                                                if (!EndTransactionBlock(stmt->chain))
                                                {
-                                                       /* report unsuccessful commit in completionTag */
-                                                       if (completionTag)
-                                                               strcpy(completionTag, "ROLLBACK");
+                                                       /* report unsuccessful commit in qc */
+                                                       if (qc)
+                                                               SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0);
                                                }
                                                break;
 
                                        case TRANS_STMT_PREPARE:
                                                if (!PrepareTransactionBlock(stmt->gid))
                                                {
-                                                       /* report unsuccessful commit in completionTag */
-                                                       if (completionTag)
-                                                               strcpy(completionTag, "ROLLBACK");
+                                                       /* report unsuccessful commit in qc */
+                                                       if (qc)
+                                                               SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0);
                                                }
                                                break;
 
@@ -693,8 +685,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                        break;
 
                case T_FetchStmt:
-                       PerformPortalFetch((FetchStmt *) parsetree, dest,
-                                                          completionTag);
+                       PerformPortalFetch((FetchStmt *) parsetree, dest, qc);
                        break;
 
                case T_DoStmt:
@@ -729,9 +720,8 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                DoCopy(pstate, (CopyStmt *) parsetree,
                                           pstmt->stmt_location, pstmt->stmt_len,
                                           &processed);
-                               if (completionTag)
-                                       snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                        "COPY " UINT64_FORMAT, processed);
+                               if (qc)
+                                       SetQueryCompletion(qc, CMDTAG_COPY, processed);
                        }
                        break;
 
@@ -745,7 +735,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                        ExecuteQuery(pstate,
                                                 (ExecuteStmt *) parsetree, NULL,
                                                 params,
-                                                dest, completionTag);
+                                                dest, qc);
                        break;
 
                case T_DeallocateStmt:
@@ -974,7 +964,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objtype))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecuteGrantStmt(stmt);
                        }
@@ -987,7 +977,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->removeType))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecDropStmt(stmt, isTopLevel);
                        }
@@ -1000,7 +990,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->renameType))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecRenameStmt(stmt);
                        }
@@ -1013,7 +1003,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objectType))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecAlterObjectDependsStmt(stmt, NULL);
                        }
@@ -1026,7 +1016,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objectType))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecAlterObjectSchemaStmt(stmt, NULL);
                        }
@@ -1039,7 +1029,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objectType))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecAlterOwnerStmt(stmt);
                        }
@@ -1052,7 +1042,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objtype))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        CommentObject(stmt);
                                break;
@@ -1065,7 +1055,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                if (EventTriggerSupportsObjectType(stmt->objtype))
                                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                                           context, params, queryEnv,
-                                                                          dest, completionTag);
+                                                                          dest, qc);
                                else
                                        ExecSecLabelStmt(stmt);
                                break;
@@ -1075,7 +1065,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                        /* All other statement types have event trigger support */
                        ProcessUtilitySlow(pstate, pstmt, queryString,
                                                           context, params, queryEnv,
-                                                          dest, completionTag);
+                                                          dest, qc);
                        break;
        }
 
@@ -1102,7 +1092,7 @@ ProcessUtilitySlow(ParseState *pstate,
                                   ParamListInfo params,
                                   QueryEnvironment *queryEnv,
                                   DestReceiver *dest,
-                                  char *completionTag)
+                                  QueryCompletion *qc)
 {
        Node       *parsetree = pstmt->utilityStmt;
        bool            isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
@@ -1605,7 +1595,7 @@ ProcessUtilitySlow(ParseState *pstate,
 
                        case T_CreateTableAsStmt:
                                address = ExecCreateTableAs(pstate, (CreateTableAsStmt *) parsetree,
-                                                                                       params, queryEnv, completionTag);
+                                                                                       params, queryEnv, qc);
                                break;
 
                        case T_RefreshMatViewStmt:
@@ -1620,7 +1610,7 @@ ProcessUtilitySlow(ParseState *pstate,
                                PG_TRY();
                                {
                                        address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
-                                                                                                queryString, params, completionTag);
+                                                                                                queryString, params, qc);
                                }
                                PG_FINALLY();
                                {
@@ -2099,137 +2089,137 @@ UtilityContainsQuery(Node *parsetree)
  *
  * This covers most cases where ALTER is used with an ObjectType enum.
  */
-static const char *
+static CommandTag
 AlterObjectTypeCommandTag(ObjectType objtype)
 {
-       const char *tag;
+       CommandTag      tag;
 
        switch (objtype)
        {
                case OBJECT_AGGREGATE:
-                       tag = "ALTER AGGREGATE";
+                       tag = CMDTAG_ALTER_AGGREGATE;
                        break;
                case OBJECT_ATTRIBUTE:
-                       tag = "ALTER TYPE";
+                       tag = CMDTAG_ALTER_TYPE;
                        break;
                case OBJECT_CAST:
-                       tag = "ALTER CAST";
+                       tag = CMDTAG_ALTER_CAST;
                        break;
                case OBJECT_COLLATION:
-                       tag = "ALTER COLLATION";
+                       tag = CMDTAG_ALTER_COLLATION;
                        break;
                case OBJECT_COLUMN:
-                       tag = "ALTER TABLE";
+                       tag = CMDTAG_ALTER_TABLE;
                        break;
                case OBJECT_CONVERSION:
-                       tag = "ALTER CONVERSION";
+                       tag = CMDTAG_ALTER_CONVERSION;
                        break;
                case OBJECT_DATABASE:
-                       tag = "ALTER DATABASE";
+                       tag = CMDTAG_ALTER_DATABASE;
                        break;
                case OBJECT_DOMAIN:
                case OBJECT_DOMCONSTRAINT:
-                       tag = "ALTER DOMAIN";
+                       tag = CMDTAG_ALTER_DOMAIN;
                        break;
                case OBJECT_EXTENSION:
-                       tag = "ALTER EXTENSION";
+                       tag = CMDTAG_ALTER_EXTENSION;
                        break;
                case OBJECT_FDW:
-                       tag = "ALTER FOREIGN DATA WRAPPER";
+                       tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER;
                        break;
                case OBJECT_FOREIGN_SERVER:
-                       tag = "ALTER SERVER";
+                       tag = CMDTAG_ALTER_SERVER;
                        break;
                case OBJECT_FOREIGN_TABLE:
-                       tag = "ALTER FOREIGN TABLE";
+                       tag = CMDTAG_ALTER_FOREIGN_TABLE;
                        break;
                case OBJECT_FUNCTION:
-                       tag = "ALTER FUNCTION";
+                       tag = CMDTAG_ALTER_FUNCTION;
                        break;
                case OBJECT_INDEX:
-                       tag = "ALTER INDEX";
+                       tag = CMDTAG_ALTER_INDEX;
                        break;
                case OBJECT_LANGUAGE:
-                       tag = "ALTER LANGUAGE";
+                       tag = CMDTAG_ALTER_LANGUAGE;
                        break;
                case OBJECT_LARGEOBJECT:
-                       tag = "ALTER LARGE OBJECT";
+                       tag = CMDTAG_ALTER_LARGE_OBJECT;
                        break;
                case OBJECT_OPCLASS:
-                       tag = "ALTER OPERATOR CLASS";
+                       tag = CMDTAG_ALTER_OPERATOR_CLASS;
                        break;
                case OBJECT_OPERATOR:
-                       tag = "ALTER OPERATOR";
+                       tag = CMDTAG_ALTER_OPERATOR;
                        break;
                case OBJECT_OPFAMILY:
-                       tag = "ALTER OPERATOR FAMILY";
+                       tag = CMDTAG_ALTER_OPERATOR_FAMILY;
                        break;
                case OBJECT_POLICY:
-                       tag = "ALTER POLICY";
+                       tag = CMDTAG_ALTER_POLICY;
                        break;
                case OBJECT_PROCEDURE:
-                       tag = "ALTER PROCEDURE";
+                       tag = CMDTAG_ALTER_PROCEDURE;
                        break;
                case OBJECT_ROLE:
-                       tag = "ALTER ROLE";
+                       tag = CMDTAG_ALTER_ROLE;
                        break;
                case OBJECT_ROUTINE:
-                       tag = "ALTER ROUTINE";
+                       tag = CMDTAG_ALTER_ROUTINE;
                        break;
                case OBJECT_RULE:
-                       tag = "ALTER RULE";
+                       tag = CMDTAG_ALTER_RULE;
                        break;
                case OBJECT_SCHEMA:
-                       tag = "ALTER SCHEMA";
+                       tag = CMDTAG_ALTER_SCHEMA;
                        break;
                case OBJECT_SEQUENCE:
-                       tag = "ALTER SEQUENCE";
+                       tag = CMDTAG_ALTER_SEQUENCE;
                        break;
                case OBJECT_TABLE:
                case OBJECT_TABCONSTRAINT:
-                       tag = "ALTER TABLE";
+                       tag = CMDTAG_ALTER_TABLE;
                        break;
                case OBJECT_TABLESPACE:
-                       tag = "ALTER TABLESPACE";
+                       tag = CMDTAG_ALTER_TABLESPACE;
                        break;
                case OBJECT_TRIGGER:
-                       tag = "ALTER TRIGGER";
+                       tag = CMDTAG_ALTER_TRIGGER;
                        break;
                case OBJECT_EVENT_TRIGGER:
-                       tag = "ALTER EVENT TRIGGER";
+                       tag = CMDTAG_ALTER_EVENT_TRIGGER;
                        break;
                case OBJECT_TSCONFIGURATION:
-                       tag = "ALTER TEXT SEARCH CONFIGURATION";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION;
                        break;
                case OBJECT_TSDICTIONARY:
-                       tag = "ALTER TEXT SEARCH DICTIONARY";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY;
                        break;
                case OBJECT_TSPARSER:
-                       tag = "ALTER TEXT SEARCH PARSER";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_PARSER;
                        break;
                case OBJECT_TSTEMPLATE:
-                       tag = "ALTER TEXT SEARCH TEMPLATE";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE;
                        break;
                case OBJECT_TYPE:
-                       tag = "ALTER TYPE";
+                       tag = CMDTAG_ALTER_TYPE;
                        break;
                case OBJECT_VIEW:
-                       tag = "ALTER VIEW";
+                       tag = CMDTAG_ALTER_VIEW;
                        break;
                case OBJECT_MATVIEW:
-                       tag = "ALTER MATERIALIZED VIEW";
+                       tag = CMDTAG_ALTER_MATERIALIZED_VIEW;
                        break;
                case OBJECT_PUBLICATION:
-                       tag = "ALTER PUBLICATION";
+                       tag = CMDTAG_ALTER_PUBLICATION;
                        break;
                case OBJECT_SUBSCRIPTION:
-                       tag = "ALTER SUBSCRIPTION";
+                       tag = CMDTAG_ALTER_SUBSCRIPTION;
                        break;
                case OBJECT_STATISTIC_EXT:
-                       tag = "ALTER STATISTICS";
+                       tag = CMDTAG_ALTER_STATISTICS;
                        break;
                default:
-                       tag = "???";
+                       tag = CMDTAG_UNKNOWN;
                        break;
        }
 
@@ -2238,20 +2228,17 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 
 /*
  * CreateCommandTag
- *             utility to get a string representation of the command operation,
+ *             utility to get a CommandTag for the command operation,
  *             given either a raw (un-analyzed) parsetree, an analyzed Query,
  *             or a PlannedStmt.
  *
  * This must handle all command types, but since the vast majority
  * of 'em are utility commands, it seems sensible to keep it here.
- *
- * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
- * Also, the result must point at a true constant (permanent storage).
  */
-const char *
+CommandTag
 CreateCommandTag(Node *parsetree)
 {
-       const char *tag;
+       CommandTag      tag;
 
        switch (nodeTag(parsetree))
        {
@@ -2262,19 +2249,19 @@ CreateCommandTag(Node *parsetree)
 
                        /* raw plannable queries */
                case T_InsertStmt:
-                       tag = "INSERT";
+                       tag = CMDTAG_INSERT;
                        break;
 
                case T_DeleteStmt:
-                       tag = "DELETE";
+                       tag = CMDTAG_DELETE;
                        break;
 
                case T_UpdateStmt:
-                       tag = "UPDATE";
+                       tag = CMDTAG_UPDATE;
                        break;
 
                case T_SelectStmt:
-                       tag = "SELECT";
+                       tag = CMDTAG_SELECT;
                        break;
 
                        /* utility statements --- same whether raw or cooked */
@@ -2285,51 +2272,51 @@ CreateCommandTag(Node *parsetree)
                                switch (stmt->kind)
                                {
                                        case TRANS_STMT_BEGIN:
-                                               tag = "BEGIN";
+                                               tag = CMDTAG_BEGIN;
                                                break;
 
                                        case TRANS_STMT_START:
-                                               tag = "START TRANSACTION";
+                                               tag = CMDTAG_START_TRANSACTION;
                                                break;
 
                                        case TRANS_STMT_COMMIT:
-                                               tag = "COMMIT";
+                                               tag = CMDTAG_COMMIT;
                                                break;
 
                                        case TRANS_STMT_ROLLBACK:
                                        case TRANS_STMT_ROLLBACK_TO:
-                                               tag = "ROLLBACK";
+                                               tag = CMDTAG_ROLLBACK;
                                                break;
 
                                        case TRANS_STMT_SAVEPOINT:
-                                               tag = "SAVEPOINT";
+                                               tag = CMDTAG_SAVEPOINT;
                                                break;
 
                                        case TRANS_STMT_RELEASE:
-                                               tag = "RELEASE";
+                                               tag = CMDTAG_RELEASE;
                                                break;
 
                                        case TRANS_STMT_PREPARE:
-                                               tag = "PREPARE TRANSACTION";
+                                               tag = CMDTAG_PREPARE_TRANSACTION;
                                                break;
 
                                        case TRANS_STMT_COMMIT_PREPARED:
-                                               tag = "COMMIT PREPARED";
+                                               tag = CMDTAG_COMMIT_PREPARED;
                                                break;
 
                                        case TRANS_STMT_ROLLBACK_PREPARED:
-                                               tag = "ROLLBACK PREPARED";
+                                               tag = CMDTAG_ROLLBACK_PREPARED;
                                                break;
 
                                        default:
-                                               tag = "???";
+                                               tag = CMDTAG_UNKNOWN;
                                                break;
                                }
                        }
                        break;
 
                case T_DeclareCursorStmt:
-                       tag = "DECLARE CURSOR";
+                       tag = CMDTAG_DECLARE_CURSOR;
                        break;
 
                case T_ClosePortalStmt:
@@ -2337,9 +2324,9 @@ CreateCommandTag(Node *parsetree)
                                ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
 
                                if (stmt->portalname == NULL)
-                                       tag = "CLOSE CURSOR ALL";
+                                       tag = CMDTAG_CLOSE_CURSOR_ALL;
                                else
-                                       tag = "CLOSE CURSOR";
+                                       tag = CMDTAG_CLOSE_CURSOR;
                        }
                        break;
 
@@ -2347,209 +2334,209 @@ CreateCommandTag(Node *parsetree)
                        {
                                FetchStmt  *stmt = (FetchStmt *) parsetree;
 
-                               tag = (stmt->ismove) ? "MOVE" : "FETCH";
+                               tag = (stmt->ismove) ? CMDTAG_MOVE : CMDTAG_FETCH;
                        }
                        break;
 
                case T_CreateDomainStmt:
-                       tag = "CREATE DOMAIN";
+                       tag = CMDTAG_CREATE_DOMAIN;
                        break;
 
                case T_CreateSchemaStmt:
-                       tag = "CREATE SCHEMA";
+                       tag = CMDTAG_CREATE_SCHEMA;
                        break;
 
                case T_CreateStmt:
-                       tag = "CREATE TABLE";
+                       tag = CMDTAG_CREATE_TABLE;
                        break;
 
                case T_CreateTableSpaceStmt:
-                       tag = "CREATE TABLESPACE";
+                       tag = CMDTAG_CREATE_TABLESPACE;
                        break;
 
                case T_DropTableSpaceStmt:
-                       tag = "DROP TABLESPACE";
+                       tag = CMDTAG_DROP_TABLESPACE;
                        break;
 
                case T_AlterTableSpaceOptionsStmt:
-                       tag = "ALTER TABLESPACE";
+                       tag = CMDTAG_ALTER_TABLESPACE;
                        break;
 
                case T_CreateExtensionStmt:
-                       tag = "CREATE EXTENSION";
+                       tag = CMDTAG_CREATE_EXTENSION;
                        break;
 
                case T_AlterExtensionStmt:
-                       tag = "ALTER EXTENSION";
+                       tag = CMDTAG_ALTER_EXTENSION;
                        break;
 
                case T_AlterExtensionContentsStmt:
-                       tag = "ALTER EXTENSION";
+                       tag = CMDTAG_ALTER_EXTENSION;
                        break;
 
                case T_CreateFdwStmt:
-                       tag = "CREATE FOREIGN DATA WRAPPER";
+                       tag = CMDTAG_CREATE_FOREIGN_DATA_WRAPPER;
                        break;
 
                case T_AlterFdwStmt:
-                       tag = "ALTER FOREIGN DATA WRAPPER";
+                       tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER;
                        break;
 
                case T_CreateForeignServerStmt:
-                       tag = "CREATE SERVER";
+                       tag = CMDTAG_CREATE_SERVER;
                        break;
 
                case T_AlterForeignServerStmt:
-                       tag = "ALTER SERVER";
+                       tag = CMDTAG_ALTER_SERVER;
                        break;
 
                case T_CreateUserMappingStmt:
-                       tag = "CREATE USER MAPPING";
+                       tag = CMDTAG_CREATE_USER_MAPPING;
                        break;
 
                case T_AlterUserMappingStmt:
-                       tag = "ALTER USER MAPPING";
+                       tag = CMDTAG_ALTER_USER_MAPPING;
                        break;
 
                case T_DropUserMappingStmt:
-                       tag = "DROP USER MAPPING";
+                       tag = CMDTAG_DROP_USER_MAPPING;
                        break;
 
                case T_CreateForeignTableStmt:
-                       tag = "CREATE FOREIGN TABLE";
+                       tag = CMDTAG_CREATE_FOREIGN_TABLE;
                        break;
 
                case T_ImportForeignSchemaStmt:
-                       tag = "IMPORT FOREIGN SCHEMA";
+                       tag = CMDTAG_IMPORT_FOREIGN_SCHEMA;
                        break;
 
                case T_DropStmt:
                        switch (((DropStmt *) parsetree)->removeType)
                        {
                                case OBJECT_TABLE:
-                                       tag = "DROP TABLE";
+                                       tag = CMDTAG_DROP_TABLE;
                                        break;
                                case OBJECT_SEQUENCE:
-                                       tag = "DROP SEQUENCE";
+                                       tag = CMDTAG_DROP_SEQUENCE;
                                        break;
                                case OBJECT_VIEW:
-                                       tag = "DROP VIEW";
+                                       tag = CMDTAG_DROP_VIEW;
                                        break;
                                case OBJECT_MATVIEW:
-                                       tag = "DROP MATERIALIZED VIEW";
+                                       tag = CMDTAG_DROP_MATERIALIZED_VIEW;
                                        break;
                                case OBJECT_INDEX:
-                                       tag = "DROP INDEX";
+                                       tag = CMDTAG_DROP_INDEX;
                                        break;
                                case OBJECT_TYPE:
-                                       tag = "DROP TYPE";
+                                       tag = CMDTAG_DROP_TYPE;
                                        break;
                                case OBJECT_DOMAIN:
-                                       tag = "DROP DOMAIN";
+                                       tag = CMDTAG_DROP_DOMAIN;
                                        break;
                                case OBJECT_COLLATION:
-                                       tag = "DROP COLLATION";
+                                       tag = CMDTAG_DROP_COLLATION;
                                        break;
                                case OBJECT_CONVERSION:
-                                       tag = "DROP CONVERSION";
+                                       tag = CMDTAG_DROP_CONVERSION;
                                        break;
                                case OBJECT_SCHEMA:
-                                       tag = "DROP SCHEMA";
+                                       tag = CMDTAG_DROP_SCHEMA;
                                        break;
                                case OBJECT_TSPARSER:
-                                       tag = "DROP TEXT SEARCH PARSER";
+                                       tag = CMDTAG_DROP_TEXT_SEARCH_PARSER;
                                        break;
                                case OBJECT_TSDICTIONARY:
-                                       tag = "DROP TEXT SEARCH DICTIONARY";
+                                       tag = CMDTAG_DROP_TEXT_SEARCH_DICTIONARY;
                                        break;
                                case OBJECT_TSTEMPLATE:
-                                       tag = "DROP TEXT SEARCH TEMPLATE";
+                                       tag = CMDTAG_DROP_TEXT_SEARCH_TEMPLATE;
                                        break;
                                case OBJECT_TSCONFIGURATION:
-                                       tag = "DROP TEXT SEARCH CONFIGURATION";
+                                       tag = CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION;
                                        break;
                                case OBJECT_FOREIGN_TABLE:
-                                       tag = "DROP FOREIGN TABLE";
+                                       tag = CMDTAG_DROP_FOREIGN_TABLE;
                                        break;
                                case OBJECT_EXTENSION:
-                                       tag = "DROP EXTENSION";
+                                       tag = CMDTAG_DROP_EXTENSION;
                                        break;
                                case OBJECT_FUNCTION:
-                                       tag = "DROP FUNCTION";
+                                       tag = CMDTAG_DROP_FUNCTION;
                                        break;
                                case OBJECT_PROCEDURE:
-                                       tag = "DROP PROCEDURE";
+                                       tag = CMDTAG_DROP_PROCEDURE;
                                        break;
                                case OBJECT_ROUTINE:
-                                       tag = "DROP ROUTINE";
+                                       tag = CMDTAG_DROP_ROUTINE;
                                        break;
                                case OBJECT_AGGREGATE:
-                                       tag = "DROP AGGREGATE";
+                                       tag = CMDTAG_DROP_AGGREGATE;
                                        break;
                                case OBJECT_OPERATOR:
-                                       tag = "DROP OPERATOR";
+                                       tag = CMDTAG_DROP_OPERATOR;
                                        break;
                                case OBJECT_LANGUAGE:
-                                       tag = "DROP LANGUAGE";
+                                       tag = CMDTAG_DROP_LANGUAGE;
                                        break;
                                case OBJECT_CAST:
-                                       tag = "DROP CAST";
+                                       tag = CMDTAG_DROP_CAST;
                                        break;
                                case OBJECT_TRIGGER:
-                                       tag = "DROP TRIGGER";
+                                       tag = CMDTAG_DROP_TRIGGER;
                                        break;
                                case OBJECT_EVENT_TRIGGER:
-                                       tag = "DROP EVENT TRIGGER";
+                                       tag = CMDTAG_DROP_EVENT_TRIGGER;
                                        break;
                                case OBJECT_RULE:
-                                       tag = "DROP RULE";
+                                       tag = CMDTAG_DROP_RULE;
                                        break;
                                case OBJECT_FDW:
-                                       tag = "DROP FOREIGN DATA WRAPPER";
+                                       tag = CMDTAG_DROP_FOREIGN_DATA_WRAPPER;
                                        break;
                                case OBJECT_FOREIGN_SERVER:
-                                       tag = "DROP SERVER";
+                                       tag = CMDTAG_DROP_SERVER;
                                        break;
                                case OBJECT_OPCLASS:
-                                       tag = "DROP OPERATOR CLASS";
+                                       tag = CMDTAG_DROP_OPERATOR_CLASS;
                                        break;
                                case OBJECT_OPFAMILY:
-                                       tag = "DROP OPERATOR FAMILY";
+                                       tag = CMDTAG_DROP_OPERATOR_FAMILY;
                                        break;
                                case OBJECT_POLICY:
-                                       tag = "DROP POLICY";
+                                       tag = CMDTAG_DROP_POLICY;
                                        break;
                                case OBJECT_TRANSFORM:
-                                       tag = "DROP TRANSFORM";
+                                       tag = CMDTAG_DROP_TRANSFORM;
                                        break;
                                case OBJECT_ACCESS_METHOD:
-                                       tag = "DROP ACCESS METHOD";
+                                       tag = CMDTAG_DROP_ACCESS_METHOD;
                                        break;
                                case OBJECT_PUBLICATION:
-                                       tag = "DROP PUBLICATION";
+                                       tag = CMDTAG_DROP_PUBLICATION;
                                        break;
                                case OBJECT_STATISTIC_EXT:
-                                       tag = "DROP STATISTICS";
+                                       tag = CMDTAG_DROP_STATISTICS;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
                case T_TruncateStmt:
-                       tag = "TRUNCATE TABLE";
+                       tag = CMDTAG_TRUNCATE_TABLE;
                        break;
 
                case T_CommentStmt:
-                       tag = "COMMENT";
+                       tag = CMDTAG_COMMENT;
                        break;
 
                case T_SecLabelStmt:
-                       tag = "SECURITY LABEL";
+                       tag = CMDTAG_SECURITY_LABEL;
                        break;
 
                case T_CopyStmt:
-                       tag = "COPY";
+                       tag = CMDTAG_COPY;
                        break;
 
                case T_RenameStmt:
@@ -2584,23 +2571,23 @@ CreateCommandTag(Node *parsetree)
                        break;
 
                case T_AlterDomainStmt:
-                       tag = "ALTER DOMAIN";
+                       tag = CMDTAG_ALTER_DOMAIN;
                        break;
 
                case T_AlterFunctionStmt:
                        switch (((AlterFunctionStmt *) parsetree)->objtype)
                        {
                                case OBJECT_FUNCTION:
-                                       tag = "ALTER FUNCTION";
+                                       tag = CMDTAG_ALTER_FUNCTION;
                                        break;
                                case OBJECT_PROCEDURE:
-                                       tag = "ALTER PROCEDURE";
+                                       tag = CMDTAG_ALTER_PROCEDURE;
                                        break;
                                case OBJECT_ROUTINE:
-                                       tag = "ALTER ROUTINE";
+                                       tag = CMDTAG_ALTER_ROUTINE;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
@@ -2608,7 +2595,7 @@ CreateCommandTag(Node *parsetree)
                        {
                                GrantStmt  *stmt = (GrantStmt *) parsetree;
 
-                               tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
+                               tag = (stmt->is_grant) ? CMDTAG_GRANT : CMDTAG_REVOKE;
                        }
                        break;
 
@@ -2616,145 +2603,145 @@ CreateCommandTag(Node *parsetree)
                        {
                                GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
 
-                               tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
+                               tag = (stmt->is_grant) ? CMDTAG_GRANT_ROLE : CMDTAG_REVOKE_ROLE;
                        }
                        break;
 
                case T_AlterDefaultPrivilegesStmt:
-                       tag = "ALTER DEFAULT PRIVILEGES";
+                       tag = CMDTAG_ALTER_DEFAULT_PRIVILEGES;
                        break;
 
                case T_DefineStmt:
                        switch (((DefineStmt *) parsetree)->kind)
                        {
                                case OBJECT_AGGREGATE:
-                                       tag = "CREATE AGGREGATE";
+                                       tag = CMDTAG_CREATE_AGGREGATE;
                                        break;
                                case OBJECT_OPERATOR:
-                                       tag = "CREATE OPERATOR";
+                                       tag = CMDTAG_CREATE_OPERATOR;
                                        break;
                                case OBJECT_TYPE:
-                                       tag = "CREATE TYPE";
+                                       tag = CMDTAG_CREATE_TYPE;
                                        break;
                                case OBJECT_TSPARSER:
-                                       tag = "CREATE TEXT SEARCH PARSER";
+                                       tag = CMDTAG_CREATE_TEXT_SEARCH_PARSER;
                                        break;
                                case OBJECT_TSDICTIONARY:
-                                       tag = "CREATE TEXT SEARCH DICTIONARY";
+                                       tag = CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY;
                                        break;
                                case OBJECT_TSTEMPLATE:
-                                       tag = "CREATE TEXT SEARCH TEMPLATE";
+                                       tag = CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE;
                                        break;
                                case OBJECT_TSCONFIGURATION:
-                                       tag = "CREATE TEXT SEARCH CONFIGURATION";
+                                       tag = CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION;
                                        break;
                                case OBJECT_COLLATION:
-                                       tag = "CREATE COLLATION";
+                                       tag = CMDTAG_CREATE_COLLATION;
                                        break;
                                case OBJECT_ACCESS_METHOD:
-                                       tag = "CREATE ACCESS METHOD";
+                                       tag = CMDTAG_CREATE_ACCESS_METHOD;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
                case T_CompositeTypeStmt:
-                       tag = "CREATE TYPE";
+                       tag = CMDTAG_CREATE_TYPE;
                        break;
 
                case T_CreateEnumStmt:
-                       tag = "CREATE TYPE";
+                       tag = CMDTAG_CREATE_TYPE;
                        break;
 
                case T_CreateRangeStmt:
-                       tag = "CREATE TYPE";
+                       tag = CMDTAG_CREATE_TYPE;
                        break;
 
                case T_AlterEnumStmt:
-                       tag = "ALTER TYPE";
+                       tag = CMDTAG_ALTER_TYPE;
                        break;
 
                case T_ViewStmt:
-                       tag = "CREATE VIEW";
+                       tag = CMDTAG_CREATE_VIEW;
                        break;
 
                case T_CreateFunctionStmt:
                        if (((CreateFunctionStmt *) parsetree)->is_procedure)
-                               tag = "CREATE PROCEDURE";
+                               tag = CMDTAG_CREATE_PROCEDURE;
                        else
-                               tag = "CREATE FUNCTION";
+                               tag = CMDTAG_CREATE_FUNCTION;
                        break;
 
                case T_IndexStmt:
-                       tag = "CREATE INDEX";
+                       tag = CMDTAG_CREATE_INDEX;
                        break;
 
                case T_RuleStmt:
-                       tag = "CREATE RULE";
+                       tag = CMDTAG_CREATE_RULE;
                        break;
 
                case T_CreateSeqStmt:
-                       tag = "CREATE SEQUENCE";
+                       tag = CMDTAG_CREATE_SEQUENCE;
                        break;
 
                case T_AlterSeqStmt:
-                       tag = "ALTER SEQUENCE";
+                       tag = CMDTAG_ALTER_SEQUENCE;
                        break;
 
                case T_DoStmt:
-                       tag = "DO";
+                       tag = CMDTAG_DO;
                        break;
 
                case T_CreatedbStmt:
-                       tag = "CREATE DATABASE";
+                       tag = CMDTAG_CREATE_DATABASE;
                        break;
 
                case T_AlterDatabaseStmt:
-                       tag = "ALTER DATABASE";
+                       tag = CMDTAG_ALTER_DATABASE;
                        break;
 
                case T_AlterDatabaseSetStmt:
-                       tag = "ALTER DATABASE";
+                       tag = CMDTAG_ALTER_DATABASE;
                        break;
 
                case T_DropdbStmt:
-                       tag = "DROP DATABASE";
+                       tag = CMDTAG_DROP_DATABASE;
                        break;
 
                case T_NotifyStmt:
-                       tag = "NOTIFY";
+                       tag = CMDTAG_NOTIFY;
                        break;
 
                case T_ListenStmt:
-                       tag = "LISTEN";
+                       tag = CMDTAG_LISTEN;
                        break;
 
                case T_UnlistenStmt:
-                       tag = "UNLISTEN";
+                       tag = CMDTAG_UNLISTEN;
                        break;
 
                case T_LoadStmt:
-                       tag = "LOAD";
+                       tag = CMDTAG_LOAD;
                        break;
 
                case T_CallStmt:
-                       tag = "CALL";
+                       tag = CMDTAG_CALL;
                        break;
 
                case T_ClusterStmt:
-                       tag = "CLUSTER";
+                       tag = CMDTAG_CLUSTER;
                        break;
 
                case T_VacuumStmt:
                        if (((VacuumStmt *) parsetree)->is_vacuumcmd)
-                               tag = "VACUUM";
+                               tag = CMDTAG_VACUUM;
                        else
-                               tag = "ANALYZE";
+                               tag = CMDTAG_ANALYZE;
                        break;
 
                case T_ExplainStmt:
-                       tag = "EXPLAIN";
+                       tag = CMDTAG_EXPLAIN;
                        break;
 
                case T_CreateTableAsStmt:
@@ -2762,24 +2749,24 @@ CreateCommandTag(Node *parsetree)
                        {
                                case OBJECT_TABLE:
                                        if (((CreateTableAsStmt *) parsetree)->is_select_into)
-                                               tag = "SELECT INTO";
+                                               tag = CMDTAG_SELECT_INTO;
                                        else
-                                               tag = "CREATE TABLE AS";
+                                               tag = CMDTAG_CREATE_TABLE_AS;
                                        break;
                                case OBJECT_MATVIEW:
-                                       tag = "CREATE MATERIALIZED VIEW";
+                                       tag = CMDTAG_CREATE_MATERIALIZED_VIEW;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
                case T_RefreshMatViewStmt:
-                       tag = "REFRESH MATERIALIZED VIEW";
+                       tag = CMDTAG_REFRESH_MATERIALIZED_VIEW;
                        break;
 
                case T_AlterSystemStmt:
-                       tag = "ALTER SYSTEM";
+                       tag = CMDTAG_ALTER_SYSTEM;
                        break;
 
                case T_VariableSetStmt:
@@ -2789,183 +2776,183 @@ CreateCommandTag(Node *parsetree)
                                case VAR_SET_CURRENT:
                                case VAR_SET_DEFAULT:
                                case VAR_SET_MULTI:
-                                       tag = "SET";
+                                       tag = CMDTAG_SET;
                                        break;
                                case VAR_RESET:
                                case VAR_RESET_ALL:
-                                       tag = "RESET";
+                                       tag = CMDTAG_RESET;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
                case T_VariableShowStmt:
-                       tag = "SHOW";
+                       tag = CMDTAG_SHOW;
                        break;
 
                case T_DiscardStmt:
                        switch (((DiscardStmt *) parsetree)->target)
                        {
                                case DISCARD_ALL:
-                                       tag = "DISCARD ALL";
+                                       tag = CMDTAG_DISCARD_ALL;
                                        break;
                                case DISCARD_PLANS:
-                                       tag = "DISCARD PLANS";
+                                       tag = CMDTAG_DISCARD_PLANS;
                                        break;
                                case DISCARD_TEMP:
-                                       tag = "DISCARD TEMP";
+                                       tag = CMDTAG_DISCARD_TEMP;
                                        break;
                                case DISCARD_SEQUENCES:
-                                       tag = "DISCARD SEQUENCES";
+                                       tag = CMDTAG_DISCARD_SEQUENCES;
                                        break;
                                default:
-                                       tag = "???";
+                                       tag = CMDTAG_UNKNOWN;
                        }
                        break;
 
                case T_CreateTransformStmt:
-                       tag = "CREATE TRANSFORM";
+                       tag = CMDTAG_CREATE_TRANSFORM;
                        break;
 
                case T_CreateTrigStmt:
-                       tag = "CREATE TRIGGER";
+                       tag = CMDTAG_CREATE_TRIGGER;
                        break;
 
                case T_CreateEventTrigStmt:
-                       tag = "CREATE EVENT TRIGGER";
+                       tag = CMDTAG_CREATE_EVENT_TRIGGER;
                        break;
 
                case T_AlterEventTrigStmt:
-                       tag = "ALTER EVENT TRIGGER";
+                       tag = CMDTAG_ALTER_EVENT_TRIGGER;
                        break;
 
                case T_CreatePLangStmt:
-                       tag = "CREATE LANGUAGE";
+                       tag = CMDTAG_CREATE_LANGUAGE;
                        break;
 
                case T_CreateRoleStmt:
-                       tag = "CREATE ROLE";
+                       tag = CMDTAG_CREATE_ROLE;
                        break;
 
                case T_AlterRoleStmt:
-                       tag = "ALTER ROLE";
+                       tag = CMDTAG_ALTER_ROLE;
                        break;
 
                case T_AlterRoleSetStmt:
-                       tag = "ALTER ROLE";
+                       tag = CMDTAG_ALTER_ROLE;
                        break;
 
                case T_DropRoleStmt:
-                       tag = "DROP ROLE";
+                       tag = CMDTAG_DROP_ROLE;
                        break;
 
                case T_DropOwnedStmt:
-                       tag = "DROP OWNED";
+                       tag = CMDTAG_DROP_OWNED;
                        break;
 
                case T_ReassignOwnedStmt:
-                       tag = "REASSIGN OWNED";
+                       tag = CMDTAG_REASSIGN_OWNED;
                        break;
 
                case T_LockStmt:
-                       tag = "LOCK TABLE";
+                       tag = CMDTAG_LOCK_TABLE;
                        break;
 
                case T_ConstraintsSetStmt:
-                       tag = "SET CONSTRAINTS";
+                       tag = CMDTAG_SET_CONSTRAINTS;
                        break;
 
                case T_CheckPointStmt:
-                       tag = "CHECKPOINT";
+                       tag = CMDTAG_CHECKPOINT;
                        break;
 
                case T_ReindexStmt:
-                       tag = "REINDEX";
+                       tag = CMDTAG_REINDEX;
                        break;
 
                case T_CreateConversionStmt:
-                       tag = "CREATE CONVERSION";
+                       tag = CMDTAG_CREATE_CONVERSION;
                        break;
 
                case T_CreateCastStmt:
-                       tag = "CREATE CAST";
+                       tag = CMDTAG_CREATE_CAST;
                        break;
 
                case T_CreateOpClassStmt:
-                       tag = "CREATE OPERATOR CLASS";
+                       tag = CMDTAG_CREATE_OPERATOR_CLASS;
                        break;
 
                case T_CreateOpFamilyStmt:
-                       tag = "CREATE OPERATOR FAMILY";
+                       tag = CMDTAG_CREATE_OPERATOR_FAMILY;
                        break;
 
                case T_AlterOpFamilyStmt:
-                       tag = "ALTER OPERATOR FAMILY";
+                       tag = CMDTAG_ALTER_OPERATOR_FAMILY;
                        break;
 
                case T_AlterOperatorStmt:
-                       tag = "ALTER OPERATOR";
+                       tag = CMDTAG_ALTER_OPERATOR;
                        break;
 
                case T_AlterTSDictionaryStmt:
-                       tag = "ALTER TEXT SEARCH DICTIONARY";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY;
                        break;
 
                case T_AlterTSConfigurationStmt:
-                       tag = "ALTER TEXT SEARCH CONFIGURATION";
+                       tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION;
                        break;
 
                case T_CreatePolicyStmt:
-                       tag = "CREATE POLICY";
+                       tag = CMDTAG_CREATE_POLICY;
                        break;
 
                case T_AlterPolicyStmt:
-                       tag = "ALTER POLICY";
+                       tag = CMDTAG_ALTER_POLICY;
                        break;
 
                case T_CreateAmStmt:
-                       tag = "CREATE ACCESS METHOD";
+                       tag = CMDTAG_CREATE_ACCESS_METHOD;
                        break;
 
                case T_CreatePublicationStmt:
-                       tag = "CREATE PUBLICATION";
+                       tag = CMDTAG_CREATE_PUBLICATION;
                        break;
 
                case T_AlterPublicationStmt:
-                       tag = "ALTER PUBLICATION";
+                       tag = CMDTAG_ALTER_PUBLICATION;
                        break;
 
                case T_CreateSubscriptionStmt:
-                       tag = "CREATE SUBSCRIPTION";
+                       tag = CMDTAG_CREATE_SUBSCRIPTION;
                        break;
 
                case T_AlterSubscriptionStmt:
-                       tag = "ALTER SUBSCRIPTION";
+                       tag = CMDTAG_ALTER_SUBSCRIPTION;
                        break;
 
                case T_DropSubscriptionStmt:
-                       tag = "DROP SUBSCRIPTION";
+                       tag = CMDTAG_DROP_SUBSCRIPTION;
                        break;
 
                case T_AlterCollationStmt:
-                       tag = "ALTER COLLATION";
+                       tag = CMDTAG_ALTER_COLLATION;
                        break;
 
                case T_PrepareStmt:
-                       tag = "PREPARE";
+                       tag = CMDTAG_PREPARE;
                        break;
 
                case T_ExecuteStmt:
-                       tag = "EXECUTE";
+                       tag = CMDTAG_EXECUTE;
                        break;
 
                case T_CreateStatsStmt:
-                       tag = "CREATE STATISTICS";
+                       tag = CMDTAG_CREATE_STATISTICS;
                        break;
 
                case T_AlterStatsStmt:
-                       tag = "ALTER STATISTICS";
+                       tag = CMDTAG_ALTER_STATISTICS;
                        break;
 
                case T_DeallocateStmt:
@@ -2973,9 +2960,9 @@ CreateCommandTag(Node *parsetree)
                                DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
 
                                if (stmt->name == NULL)
-                                       tag = "DEALLOCATE ALL";
+                                       tag = CMDTAG_DEALLOCATE_ALL;
                                else
-                                       tag = "DEALLOCATE";
+                                       tag = CMDTAG_DEALLOCATE;
                        }
                        break;
 
@@ -2999,33 +2986,33 @@ CreateCommandTag(Node *parsetree)
                                                        switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
                                                        {
                                                                case LCS_FORKEYSHARE:
-                                                                       tag = "SELECT FOR KEY SHARE";
+                                                                       tag = CMDTAG_SELECT_FOR_KEY_SHARE;
                                                                        break;
                                                                case LCS_FORSHARE:
-                                                                       tag = "SELECT FOR SHARE";
+                                                                       tag = CMDTAG_SELECT_FOR_SHARE;
                                                                        break;
                                                                case LCS_FORNOKEYUPDATE:
-                                                                       tag = "SELECT FOR NO KEY UPDATE";
+                                                                       tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE;
                                                                        break;
                                                                case LCS_FORUPDATE:
-                                                                       tag = "SELECT FOR UPDATE";
+                                                                       tag = CMDTAG_SELECT_FOR_UPDATE;
                                                                        break;
                                                                default:
-                                                                       tag = "SELECT";
+                                                                       tag = CMDTAG_SELECT;
                                                                        break;
                                                        }
                                                }
                                                else
-                                                       tag = "SELECT";
+                                                       tag = CMDTAG_SELECT;
                                                break;
                                        case CMD_UPDATE:
-                                               tag = "UPDATE";
+                                               tag = CMDTAG_UPDATE;
                                                break;
                                        case CMD_INSERT:
-                                               tag = "INSERT";
+                                               tag = CMDTAG_INSERT;
                                                break;
                                        case CMD_DELETE:
-                                               tag = "DELETE";
+                                               tag = CMDTAG_DELETE;
                                                break;
                                        case CMD_UTILITY:
                                                tag = CreateCommandTag(stmt->utilityStmt);
@@ -3033,7 +3020,7 @@ CreateCommandTag(Node *parsetree)
                                        default:
                                                elog(WARNING, "unrecognized commandType: %d",
                                                         (int) stmt->commandType);
-                                               tag = "???";
+                                               tag = CMDTAG_UNKNOWN;
                                                break;
                                }
                        }
@@ -3059,33 +3046,33 @@ CreateCommandTag(Node *parsetree)
                                                        switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
                                                        {
                                                                case LCS_FORKEYSHARE:
-                                                                       tag = "SELECT FOR KEY SHARE";
+                                                                       tag = CMDTAG_SELECT_FOR_KEY_SHARE;
                                                                        break;
                                                                case LCS_FORSHARE:
-                                                                       tag = "SELECT FOR SHARE";
+                                                                       tag = CMDTAG_SELECT_FOR_SHARE;
                                                                        break;
                                                                case LCS_FORNOKEYUPDATE:
-                                                                       tag = "SELECT FOR NO KEY UPDATE";
+                                                                       tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE;
                                                                        break;
                                                                case LCS_FORUPDATE:
-                                                                       tag = "SELECT FOR UPDATE";
+                                                                       tag = CMDTAG_SELECT_FOR_UPDATE;
                                                                        break;
                                                                default:
-                                                                       tag = "???";
+                                                                       tag = CMDTAG_UNKNOWN;
                                                                        break;
                                                        }
                                                }
                                                else
-                                                       tag = "SELECT";
+                                                       tag = CMDTAG_SELECT;
                                                break;
                                        case CMD_UPDATE:
-                                               tag = "UPDATE";
+                                               tag = CMDTAG_UPDATE;
                                                break;
                                        case CMD_INSERT:
-                                               tag = "INSERT";
+                                               tag = CMDTAG_INSERT;
                                                break;
                                        case CMD_DELETE:
-                                               tag = "DELETE";
+                                               tag = CMDTAG_DELETE;
                                                break;
                                        case CMD_UTILITY:
                                                tag = CreateCommandTag(stmt->utilityStmt);
@@ -3093,7 +3080,7 @@ CreateCommandTag(Node *parsetree)
                                        default:
                                                elog(WARNING, "unrecognized commandType: %d",
                                                         (int) stmt->commandType);
-                                               tag = "???";
+                                               tag = CMDTAG_UNKNOWN;
                                                break;
                                }
                        }
@@ -3102,7 +3089,7 @@ CreateCommandTag(Node *parsetree)
                default:
                        elog(WARNING, "unrecognized node type: %d",
                                 (int) nodeTag(parsetree));
-                       tag = "???";
+                       tag = CMDTAG_UNKNOWN;
                        break;
        }
 
index 1b63048a774fd2ed473eaec76428b2551d3b86ab..b9c1a0a5adbc8c5c3e26da5c697057c0cacd9b1e 100644 (file)
@@ -20,6 +20,7 @@
 #include "catalog/pg_event_trigger.h"
 #include "catalog/pg_type.h"
 #include "commands/trigger.h"
+#include "tcop/cmdtag.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
@@ -51,7 +52,7 @@ static EventTriggerCacheStateType EventTriggerCacheState = ETCS_NEEDS_REBUILD;
 static void BuildEventTriggerCache(void);
 static void InvalidateEventCacheCallback(Datum arg,
                                                                                 int cacheid, uint32 hashvalue);
-static int     DecodeTextArrayToCString(Datum array, char ***cstringp);
+static Bitmapset *DecodeTextArrayToBitmapset(Datum array);
 
 /*
  * Search the event cache by trigger event.
@@ -180,10 +181,7 @@ BuildEventTriggerCache(void)
                evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
                                                           RelationGetDescr(rel), &evttags_isnull);
                if (!evttags_isnull)
-               {
-                       item->ntags = DecodeTextArrayToCString(evttags, &item->tag);
-                       qsort(item->tag, item->ntags, sizeof(char *), pg_qsort_strcmp);
-               }
+                       item->tagset = DecodeTextArrayToBitmapset(evttags);
 
                /* Add to cache entry. */
                entry = hash_search(cache, &event, HASH_ENTER, &found);
@@ -215,18 +213,18 @@ BuildEventTriggerCache(void)
 }
 
 /*
- * Decode text[] to an array of C strings.
+ * Decode text[] to a Bitmapset of CommandTags.
  *
  * We could avoid a bit of overhead here if we were willing to duplicate some
  * of the logic from deconstruct_array, but it doesn't seem worth the code
  * complexity.
  */
-static int
-DecodeTextArrayToCString(Datum array, char ***cstringp)
+static Bitmapset *
+DecodeTextArrayToBitmapset(Datum array)
 {
        ArrayType  *arr = DatumGetArrayTypeP(array);
        Datum      *elems;
-       char      **cstring;
+       Bitmapset  *bms;
        int                     i;
        int                     nelems;
 
@@ -234,13 +232,17 @@ DecodeTextArrayToCString(Datum array, char ***cstringp)
                elog(ERROR, "expected 1-D text array");
        deconstruct_array(arr, TEXTOID, -1, false, 'i', &elems, NULL, &nelems);
 
-       cstring = palloc(nelems * sizeof(char *));
-       for (i = 0; i < nelems; ++i)
-               cstring[i] = TextDatumGetCString(elems[i]);
+       for (bms = NULL, i = 0; i < nelems; ++i)
+       {
+               char       *str = TextDatumGetCString(elems[i]);
+
+               bms = bms_add_member(bms, GetCommandTagEnum(str));
+               pfree(str);
+       }
 
        pfree(elems);
-       *cstringp = cstring;
-       return nelems;
+
+       return bms;
 }
 
 /*
index c47be0ba4cd39f6f2b9ab386afcb21dfcb00f318..dbae18d68c64b5a4853c397ef8a42ba73ade3cc7 100644 (file)
@@ -158,12 +158,12 @@ InitPlanCache(void)
  *
  * raw_parse_tree: output of raw_parser(), or NULL if empty query
  * query_string: original query text
- * commandTag: compile-time-constant tag for query, or NULL if empty query
+ * commandTag: command tag for query, or UNKNOWN if empty query
  */
 CachedPlanSource *
 CreateCachedPlan(RawStmt *raw_parse_tree,
                                 const char *query_string,
-                                const char *commandTag)
+                                CommandTag commandTag)
 {
        CachedPlanSource *plansource;
        MemoryContext source_context;
@@ -241,12 +241,12 @@ CreateCachedPlan(RawStmt *raw_parse_tree,
  *
  * raw_parse_tree: output of raw_parser(), or NULL if empty query
  * query_string: original query text
- * commandTag: compile-time-constant tag for query, or NULL if empty query
+ * commandTag: command tag for query, or NULL if empty query
  */
 CachedPlanSource *
 CreateOneShotCachedPlan(RawStmt *raw_parse_tree,
                                                const char *query_string,
-                                               const char *commandTag)
+                                               CommandTag commandTag)
 {
        CachedPlanSource *plansource;
 
index b675575c3150fb86ddf9a470348d4db333270cbd..7072ce48a3ec88dcdee176f78160b96fb4c126de 100644 (file)
@@ -281,7 +281,7 @@ void
 PortalDefineQuery(Portal portal,
                                  const char *prepStmtName,
                                  const char *sourceText,
-                                 const char *commandTag,
+                                 CommandTag commandTag,
                                  List *stmts,
                                  CachedPlan *cplan)
 {
@@ -289,10 +289,12 @@ PortalDefineQuery(Portal portal,
        AssertState(portal->status == PORTAL_NEW);
 
        AssertArg(sourceText != NULL);
-       AssertArg(commandTag != NULL || stmts == NIL);
+       AssertArg(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
 
        portal->prepStmtName = prepStmtName;
        portal->sourceText = sourceText;
+       portal->qc.commandTag = commandTag;
+       portal->qc.nprocessed = 0;
        portal->commandTag = commandTag;
        portal->stmts = stmts;
        portal->cplan = cplan;
index 7743851a380bf3072872473a0e4162825d92749b..5615b5ecac50b69aa8f4f16964601b740c30138a 100644 (file)
@@ -22,7 +22,8 @@
 
 
 extern ObjectAddress ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
-                                                                          ParamListInfo params, QueryEnvironment *queryEnv, char *completionTag);
+                                                                          ParamListInfo params, QueryEnvironment *queryEnv,
+                                                                          QueryCompletion *qc);
 
 extern int     GetIntoRelEFlags(IntoClause *intoClause);
 
index faa2958b8932e7de12e88d881fa4629bed827461..28b352051b994a938f2cdf26a2545872247dc139 100644 (file)
@@ -17,6 +17,7 @@
 #include "catalog/objectaddress.h"
 #include "catalog/pg_event_trigger.h"
 #include "nodes/parsenodes.h"
+#include "tcop/cmdtag.h"
 #include "tcop/deparse_utility.h"
 #include "utils/aclchk_internal.h"
 
@@ -25,7 +26,7 @@ typedef struct EventTriggerData
        NodeTag         type;
        const char *event;                      /* event name */
        Node       *parsetree;          /* parse tree */
-       const char *tag;                        /* command tag */
+       CommandTag      tag;
 } EventTriggerData;
 
 #define AT_REWRITE_ALTER_PERSISTENCE   0x01
index 6bdb7ca258969eecca62e7b099497b1e061ad028..3ea4f5c80b96378e04eb2e2f42d569bfbabb5d05 100644 (file)
@@ -24,7 +24,7 @@
 extern void SetMatViewPopulatedState(Relation relation, bool newstate);
 
 extern ObjectAddress ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
-                                                                               ParamListInfo params, char *completionTag);
+                                                                               ParamListInfo params, QueryCompletion *qc);
 
 extern DestReceiver *CreateTransientRelDestReceiver(Oid oid);
 
index 4ecc1a2ecd37d4b0a970bc3e0e8cf5a2bd57a4d2..5f64b0a674f1a55a6f44a192c8e10e70734115e6 100644 (file)
@@ -23,7 +23,7 @@ extern void PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, Para
                                                          bool isTopLevel);
 
 extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
-                                                          char *completionTag);
+                                                          QueryCompletion *qc);
 
 extern void PerformPortalClose(const char *name);
 
index a0509e1f33f0d980577b690faa19b4ce509d6e87..4fcf2406c1806b57c66f4ef0b51b0f5be4c62d63 100644 (file)
@@ -40,7 +40,7 @@ extern void PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
 extern void ExecuteQuery(ParseState *pstate,
                                                 ExecuteStmt *stmt, IntoClause *intoClause,
                                                 ParamListInfo params,
-                                                DestReceiver *dest, char *completionTag);
+                                                DestReceiver *dest, QueryCompletion *qc);
 extern void DeallocateQuery(DeallocateStmt *stmt);
 extern void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into,
                                                                ExplainState *es, const char *queryString,
diff --git a/src/include/tcop/cmdtag.h b/src/include/tcop/cmdtag.h
new file mode 100644 (file)
index 0000000..f75a91e
--- /dev/null
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * cmdtag.h
+ *       Declarations for commandtag names and enumeration.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/tcop/cmdtag.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef CMDTAG_H
+#define CMDTAG_H
+
+
+#define PG_CMDTAG(tag, name, evtrgok, rwrok, rowcnt) \
+       tag,
+
+typedef enum CommandTag
+{
+#include "tcop/cmdtaglist.h"
+       COMMAND_TAG_NEXTTAG
+} CommandTag;
+
+#undef PG_CMDTAG
+
+typedef struct QueryCompletion
+{
+       CommandTag      commandTag;
+       uint64          nprocessed;
+} QueryCompletion;
+
+
+static inline void
+SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag,
+                                  uint64 nprocessed)
+{
+       qc->commandTag = commandTag;
+       qc->nprocessed = nprocessed;
+}
+
+static inline void
+CopyQueryCompletion(QueryCompletion *dst, const QueryCompletion *src)
+{
+       dst->commandTag = src->commandTag;
+       dst->nprocessed = src->nprocessed;
+}
+
+
+extern void InitializeQueryCompletion(QueryCompletion *qc);
+extern const char *GetCommandTagName(CommandTag commandTag);
+extern bool command_tag_display_rowcount(CommandTag commandTag);
+extern bool command_tag_event_trigger_ok(CommandTag commandTag);
+extern bool command_tag_table_rewrite_ok(CommandTag commandTag);
+extern CommandTag GetCommandTagEnum(const char *tagname);
+
+#endif                                                 /* CMDTAG_H */
diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h
new file mode 100644 (file)
index 0000000..d28145a
--- /dev/null
@@ -0,0 +1,218 @@
+/*----------------------------------------------------------------------
+ *
+ * cmdtaglist.h
+ *    Command tags
+ *
+ * The command tag list is kept in its own source file for possible use
+ * by automatic tools.  The exact representation of a command tag is
+ * determined by the PG_CMDTAG macro, which is not defined in this file;
+ * it can be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/backend/tcop/cmdtaglist.h
+ *
+ *----------------------------------------------------------------------
+ */
+
+/* there is deliberately not an #ifndef CMDTAGLIST_H here */
+
+/*
+ * List of command tags.  The entries must be sorted alphabetically on their
+ * textual name, so that we can bsearch on it; see GetCommandTagEnum().
+ */
+
+/* symbol name, textual name, event_trigger_ok, table_rewrite_ok, rowcount, last_oid */
+PG_CMDTAG(CMDTAG_UNKNOWN, "???", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_ACCESS_METHOD, "ALTER ACCESS METHOD", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_AGGREGATE, "ALTER AGGREGATE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_CAST, "ALTER CAST", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_COLLATION, "ALTER COLLATION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_CONSTRAINT, "ALTER CONSTRAINT", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_CONVERSION, "ALTER CONVERSION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_DATABASE, "ALTER DATABASE", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_DEFAULT_PRIVILEGES, "ALTER DEFAULT PRIVILEGES", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_DOMAIN, "ALTER DOMAIN", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_EVENT_TRIGGER, "ALTER EVENT TRIGGER", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_EXTENSION, "ALTER EXTENSION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_FOREIGN_DATA_WRAPPER, "ALTER FOREIGN DATA WRAPPER", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_FOREIGN_TABLE, "ALTER FOREIGN TABLE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_FUNCTION, "ALTER FUNCTION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_INDEX, "ALTER INDEX", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_LANGUAGE, "ALTER LANGUAGE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_LARGE_OBJECT, "ALTER LARGE OBJECT", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_MATERIALIZED_VIEW, "ALTER MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_OPERATOR, "ALTER OPERATOR", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_OPERATOR_CLASS, "ALTER OPERATOR CLASS", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_OPERATOR_FAMILY, "ALTER OPERATOR FAMILY", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_POLICY, "ALTER POLICY", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_PROCEDURE, "ALTER PROCEDURE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_PUBLICATION, "ALTER PUBLICATION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_ROLE, "ALTER ROLE", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_ROUTINE, "ALTER ROUTINE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_RULE, "ALTER RULE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_SCHEMA, "ALTER SCHEMA", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_SEQUENCE, "ALTER SEQUENCE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_SERVER, "ALTER SERVER", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_STATISTICS, "ALTER STATISTICS", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_SUBSCRIPTION, "ALTER SUBSCRIPTION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_SYSTEM, "ALTER SYSTEM", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TABLE, "ALTER TABLE", true, true, false)
+PG_CMDTAG(CMDTAG_ALTER_TABLESPACE, "ALTER TABLESPACE", false, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION, "ALTER TEXT SEARCH CONFIGURATION", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY, "ALTER TEXT SEARCH DICTIONARY", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_PARSER, "ALTER TEXT SEARCH PARSER", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE, "ALTER TEXT SEARCH TEMPLATE", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TRANSFORM, "ALTER TRANSFORM", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TRIGGER, "ALTER TRIGGER", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_TYPE, "ALTER TYPE", true, true, false)
+PG_CMDTAG(CMDTAG_ALTER_USER_MAPPING, "ALTER USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_VIEW, "ALTER VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_ANALYZE, "ANALYZE", false, false, false)
+PG_CMDTAG(CMDTAG_BEGIN, "BEGIN", false, false, false)
+PG_CMDTAG(CMDTAG_CALL, "CALL", false, false, false)
+PG_CMDTAG(CMDTAG_CHECKPOINT, "CHECKPOINT", false, false, false)
+PG_CMDTAG(CMDTAG_CLOSE, "CLOSE", false, false, false)
+PG_CMDTAG(CMDTAG_CLOSE_CURSOR, "CLOSE CURSOR", false, false, false)
+PG_CMDTAG(CMDTAG_CLOSE_CURSOR_ALL, "CLOSE CURSOR ALL", false, false, false)
+PG_CMDTAG(CMDTAG_CLUSTER, "CLUSTER", false, false, false)
+PG_CMDTAG(CMDTAG_COMMENT, "COMMENT", true, false, false)
+PG_CMDTAG(CMDTAG_COMMIT, "COMMIT", false, false, false)
+PG_CMDTAG(CMDTAG_COMMIT_PREPARED, "COMMIT PREPARED", false, false, false)
+PG_CMDTAG(CMDTAG_COPY, "COPY", false, false, true)
+PG_CMDTAG(CMDTAG_COPY_FROM, "COPY FROM", false, false, false)
+PG_CMDTAG(CMDTAG_CREATE_ACCESS_METHOD, "CREATE ACCESS METHOD", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_AGGREGATE, "CREATE AGGREGATE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_CAST, "CREATE CAST", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_COLLATION, "CREATE COLLATION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_CONSTRAINT, "CREATE CONSTRAINT", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_CONVERSION, "CREATE CONVERSION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_DATABASE, "CREATE DATABASE", false, false, false)
+PG_CMDTAG(CMDTAG_CREATE_DOMAIN, "CREATE DOMAIN", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_EVENT_TRIGGER, "CREATE EVENT TRIGGER", false, false, false)
+PG_CMDTAG(CMDTAG_CREATE_EXTENSION, "CREATE EXTENSION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_FOREIGN_DATA_WRAPPER, "CREATE FOREIGN DATA WRAPPER", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_FOREIGN_TABLE, "CREATE FOREIGN TABLE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_FUNCTION, "CREATE FUNCTION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_INDEX, "CREATE INDEX", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_LANGUAGE, "CREATE LANGUAGE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_MATERIALIZED_VIEW, "CREATE MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_OPERATOR, "CREATE OPERATOR", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_OPERATOR_CLASS, "CREATE OPERATOR CLASS", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_OPERATOR_FAMILY, "CREATE OPERATOR FAMILY", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_POLICY, "CREATE POLICY", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_PROCEDURE, "CREATE PROCEDURE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_PUBLICATION, "CREATE PUBLICATION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_ROLE, "CREATE ROLE", false, false, false)
+PG_CMDTAG(CMDTAG_CREATE_ROUTINE, "CREATE ROUTINE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_RULE, "CREATE RULE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_SCHEMA, "CREATE SCHEMA", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_SEQUENCE, "CREATE SEQUENCE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_SERVER, "CREATE SERVER", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_STATISTICS, "CREATE STATISTICS", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_SUBSCRIPTION, "CREATE SUBSCRIPTION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TABLE, "CREATE TABLE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TABLE_AS, "CREATE TABLE AS", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TABLESPACE, "CREATE TABLESPACE", false, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION, "CREATE TEXT SEARCH CONFIGURATION", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY, "CREATE TEXT SEARCH DICTIONARY", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_PARSER, "CREATE TEXT SEARCH PARSER", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE, "CREATE TEXT SEARCH TEMPLATE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TRANSFORM, "CREATE TRANSFORM", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TRIGGER, "CREATE TRIGGER", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_TYPE, "CREATE TYPE", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_USER_MAPPING, "CREATE USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_VIEW, "CREATE VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_DEALLOCATE, "DEALLOCATE", false, false, false)
+PG_CMDTAG(CMDTAG_DEALLOCATE_ALL, "DEALLOCATE ALL", false, false, false)
+PG_CMDTAG(CMDTAG_DECLARE_CURSOR, "DECLARE CURSOR", false, false, false)
+PG_CMDTAG(CMDTAG_DELETE, "DELETE", false, false, true)
+PG_CMDTAG(CMDTAG_DISCARD, "DISCARD", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_ALL, "DISCARD ALL", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_PLANS, "DISCARD PLANS", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_SEQUENCES, "DISCARD SEQUENCES", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_TEMP, "DISCARD TEMP", false, false, false)
+PG_CMDTAG(CMDTAG_DO, "DO", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_ACCESS_METHOD, "DROP ACCESS METHOD", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_AGGREGATE, "DROP AGGREGATE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_CAST, "DROP CAST", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_COLLATION, "DROP COLLATION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_CONSTRAINT, "DROP CONSTRAINT", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_CONVERSION, "DROP CONVERSION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_DATABASE, "DROP DATABASE", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_DOMAIN, "DROP DOMAIN", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_EVENT_TRIGGER, "DROP EVENT TRIGGER", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_EXTENSION, "DROP EXTENSION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_FOREIGN_DATA_WRAPPER, "DROP FOREIGN DATA WRAPPER", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_FOREIGN_TABLE, "DROP FOREIGN TABLE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_FUNCTION, "DROP FUNCTION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_INDEX, "DROP INDEX", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_LANGUAGE, "DROP LANGUAGE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_MATERIALIZED_VIEW, "DROP MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_OPERATOR, "DROP OPERATOR", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_OPERATOR_CLASS, "DROP OPERATOR CLASS", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_OPERATOR_FAMILY, "DROP OPERATOR FAMILY", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_OWNED, "DROP OWNED", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_POLICY, "DROP POLICY", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_PROCEDURE, "DROP PROCEDURE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_PUBLICATION, "DROP PUBLICATION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_REPLICATION_SLOT, "DROP REPLICATION SLOT", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_ROLE, "DROP ROLE", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_ROUTINE, "DROP ROUTINE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_RULE, "DROP RULE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_SCHEMA, "DROP SCHEMA", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_SEQUENCE, "DROP SEQUENCE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_SERVER, "DROP SERVER", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_STATISTICS, "DROP STATISTICS", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_SUBSCRIPTION, "DROP SUBSCRIPTION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TABLE, "DROP TABLE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TABLESPACE, "DROP TABLESPACE", false, false, false)
+PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION, "DROP TEXT SEARCH CONFIGURATION", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_DICTIONARY, "DROP TEXT SEARCH DICTIONARY", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_PARSER, "DROP TEXT SEARCH PARSER", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_TEMPLATE, "DROP TEXT SEARCH TEMPLATE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TRANSFORM, "DROP TRANSFORM", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TRIGGER, "DROP TRIGGER", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_TYPE, "DROP TYPE", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_USER_MAPPING, "DROP USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_VIEW, "DROP VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_EXECUTE, "EXECUTE", false, false, false)
+PG_CMDTAG(CMDTAG_EXPLAIN, "EXPLAIN", false, false, false)
+PG_CMDTAG(CMDTAG_FETCH, "FETCH", false, false, true)
+PG_CMDTAG(CMDTAG_GRANT, "GRANT", true, false, false)
+PG_CMDTAG(CMDTAG_GRANT_ROLE, "GRANT ROLE", false, false, false)
+PG_CMDTAG(CMDTAG_IMPORT_FOREIGN_SCHEMA, "IMPORT FOREIGN SCHEMA", true, false, false)
+PG_CMDTAG(CMDTAG_INSERT, "INSERT", false, false, true)
+PG_CMDTAG(CMDTAG_LISTEN, "LISTEN", false, false, false)
+PG_CMDTAG(CMDTAG_LOAD, "LOAD", false, false, false)
+PG_CMDTAG(CMDTAG_LOCK_TABLE, "LOCK TABLE", false, false, false)
+PG_CMDTAG(CMDTAG_MOVE, "MOVE", false, false, true)
+PG_CMDTAG(CMDTAG_NOTIFY, "NOTIFY", false, false, false)
+PG_CMDTAG(CMDTAG_PREPARE, "PREPARE", false, false, false)
+PG_CMDTAG(CMDTAG_PREPARE_TRANSACTION, "PREPARE TRANSACTION", false, false, false)
+PG_CMDTAG(CMDTAG_REASSIGN_OWNED, "REASSIGN OWNED", false, false, false)
+PG_CMDTAG(CMDTAG_REFRESH_MATERIALIZED_VIEW, "REFRESH MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_REINDEX, "REINDEX", false, false, false)
+PG_CMDTAG(CMDTAG_RELEASE, "RELEASE", false, false, false)
+PG_CMDTAG(CMDTAG_RESET, "RESET", false, false, false)
+PG_CMDTAG(CMDTAG_REVOKE, "REVOKE", true, false, false)
+PG_CMDTAG(CMDTAG_REVOKE_ROLE, "REVOKE ROLE", false, false, false)
+PG_CMDTAG(CMDTAG_ROLLBACK, "ROLLBACK", false, false, false)
+PG_CMDTAG(CMDTAG_ROLLBACK_PREPARED, "ROLLBACK PREPARED", false, false, false)
+PG_CMDTAG(CMDTAG_SAVEPOINT, "SAVEPOINT", false, false, false)
+PG_CMDTAG(CMDTAG_SECURITY_LABEL, "SECURITY LABEL", true, false, false)
+PG_CMDTAG(CMDTAG_SELECT, "SELECT", false, false, true)
+PG_CMDTAG(CMDTAG_SELECT_FOR_KEY_SHARE, "SELECT FOR KEY SHARE", false, false, false)
+PG_CMDTAG(CMDTAG_SELECT_FOR_NO_KEY_UPDATE, "SELECT FOR NO KEY UPDATE", false, false, false)
+PG_CMDTAG(CMDTAG_SELECT_FOR_SHARE, "SELECT FOR SHARE", false, false, false)
+PG_CMDTAG(CMDTAG_SELECT_FOR_UPDATE, "SELECT FOR UPDATE", false, false, false)
+PG_CMDTAG(CMDTAG_SELECT_INTO, "SELECT INTO", true, false, false)
+PG_CMDTAG(CMDTAG_SET, "SET", false, false, false)
+PG_CMDTAG(CMDTAG_SET_CONSTRAINTS, "SET CONSTRAINTS", false, false, false)
+PG_CMDTAG(CMDTAG_SHOW, "SHOW", false, false, false)
+PG_CMDTAG(CMDTAG_START_TRANSACTION, "START TRANSACTION", false, false, false)
+PG_CMDTAG(CMDTAG_TRUNCATE_TABLE, "TRUNCATE TABLE", false, false, false)
+PG_CMDTAG(CMDTAG_UNLISTEN, "UNLISTEN", false, false, false)
+PG_CMDTAG(CMDTAG_UPDATE, "UPDATE", false, false, true)
+PG_CMDTAG(CMDTAG_VACUUM, "VACUUM", false, false, false)
index 35bce731a1d63f535d736c01185b6f815315ae1a..662ce8a56f806b4ba81acdd182276715b4b73e0f 100644 (file)
@@ -68,6 +68,7 @@
 #define DEST_H
 
 #include "executor/tuptable.h"
+#include "tcop/cmdtag.h"
 
 
 /* buffer size to use for command completion tags */
@@ -134,9 +135,10 @@ extern PGDLLIMPORT DestReceiver *None_Receiver; /* permanent receiver for
 
 /* The primary destination management functions */
 
-extern void BeginCommand(const char *commandTag, CommandDest dest);
+extern void BeginCommand(CommandTag commandTag, CommandDest dest);
 extern DestReceiver *CreateDestReceiver(CommandDest dest);
-extern void EndCommand(const char *commandTag, CommandDest dest);
+extern void EndCommand(const QueryCompletion *qc, CommandDest dest,
+                                          bool force_undecorated_output);
 
 /* Additional functions that go with destination management, more or less. */
 
index 4ad6324e2d0b3712ad5c80c0d52901462ee21bda..437642cc72c6828569013c60fd55f64c7153151c 100644 (file)
@@ -35,7 +35,7 @@ extern void PortalSetResultFormat(Portal portal, int nFormats,
 
 extern bool PortalRun(Portal portal, long count, bool isTopLevel,
                                          bool run_once, DestReceiver *dest, DestReceiver *altdest,
-                                         char *completionTag);
+                                         QueryCompletion *qc);
 
 extern uint64 PortalRunFetch(Portal portal,
                                                         FetchDirection fdirection,
index a551e08cb84c4bacba3294cf140da7cf72654f19..4aec19a0087399ab01b36604b1271f575ed5e6bf 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef UTILITY_H
 #define UTILITY_H
 
+#include "tcop/cmdtag.h"
 #include "tcop/tcopprot.h"
 
 typedef enum
@@ -71,17 +72,17 @@ typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt,
                                                                                  const char *queryString, ProcessUtilityContext context,
                                                                                  ParamListInfo params,
                                                                                  QueryEnvironment *queryEnv,
-                                                                                 DestReceiver *dest, char *completionTag);
+                                                                                 DestReceiver *dest, QueryCompletion *qc);
 extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
 
 extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                                                   ProcessUtilityContext context, ParamListInfo params,
                                                   QueryEnvironment *queryEnv,
-                                                  DestReceiver *dest, char *completionTag);
+                                                  DestReceiver *dest, QueryCompletion *qc);
 extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
                                                                        ProcessUtilityContext context, ParamListInfo params,
                                                                        QueryEnvironment *queryEnv,
-                                                                       DestReceiver *dest, char *completionTag);
+                                                                       DestReceiver *dest, QueryCompletion *qc);
 
 extern void ProcessUtilityForAlterTable(Node *stmt,
                                                                                AlterTableUtilityContext *context);
@@ -92,7 +93,13 @@ extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
 
 extern Query *UtilityContainsQuery(Node *parsetree);
 
-extern const char *CreateCommandTag(Node *parsetree);
+extern CommandTag CreateCommandTag(Node *parsetree);
+
+static inline const char *
+CreateCommandName(Node *parsetree)
+{
+       return GetCommandTagName(CreateCommandTag(parsetree));
+}
 
 extern LogStmtLevel GetCommandLogLevel(Node *parsetree);
 
index 6c3ff81ba375d5641a818bbf06998e3e24c513ca..bc8ce480615d90d030a4fa136d28a8f86e4c714d 100644 (file)
@@ -28,8 +28,7 @@ typedef struct
 {
        Oid                     fnoid;                  /* function to be called */
        char            enabled;                /* as SESSION_REPLICATION_ROLE_* */
-       int                     ntags;                  /* number of command tags */
-       char      **tag;                        /* command tags in SORTED order */
+       Bitmapset  *tagset;                     /* command tags, or NULL if empty */
 } EventTriggerCacheItem;
 
 extern List *EventCacheLookup(EventTriggerEvent event);
index e48661ebec18f6b5ed50f93572421f78aad81ac2..6a5953c76865a1ea6359040838e8a7da803caf0f 100644 (file)
@@ -18,6 +18,7 @@
 #include "access/tupdesc.h"
 #include "lib/ilist.h"
 #include "nodes/params.h"
+#include "tcop/cmdtag.h"
 #include "utils/queryenvironment.h"
 
 /* Forward declaration, to avoid including parsenodes.h here */
@@ -95,7 +96,7 @@ typedef struct CachedPlanSource
        int                     magic;                  /* should equal CACHEDPLANSOURCE_MAGIC */
        struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
        const char *query_string;       /* source text of query */
-       const char *commandTag;         /* command tag (a constant!), or NULL */
+       CommandTag      commandTag;             /* 'nuff said */
        Oid                *param_types;        /* array of parameter type OIDs, or NULL */
        int                     num_params;             /* length of param_types array */
        ParserSetupHook parserSetup;    /* alternative parameter spec method */
@@ -186,10 +187,10 @@ extern void ResetPlanCache(void);
 
 extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree,
                                                                                  const char *query_string,
-                                                                                 const char *commandTag);
+                                                                                 CommandTag commandTag);
 extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree,
                                                                                                 const char *query_string,
-                                                                                                const char *commandTag);
+                                                                                                CommandTag commandTag);
 extern void CompleteCachedPlan(CachedPlanSource *plansource,
                                                           List *querytree_list,
                                                           MemoryContext querytree_context,
index 0b694337227a29c9e4cf4e355bd73fdd3cf068b1..d41ff2efdad9e021029acd845f149d311146928e 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "datatype/timestamp.h"
 #include "executor/execdesc.h"
+#include "tcop/cmdtag.h"
 #include "utils/plancache.h"
 #include "utils/resowner.h"
 
@@ -132,7 +133,8 @@ typedef struct PortalData
 
        /* The query or queries the portal will execute */
        const char *sourceText;         /* text of query (as of 8.4, never NULL) */
-       const char *commandTag;         /* command tag for original query */
+       CommandTag      commandTag;             /* command tag for original query */
+       QueryCompletion qc;                     /* command completion data for executed query */
        List       *stmts;                      /* list of PlannedStmts */
        CachedPlan *cplan;                      /* CachedPlan, if stmts are from one */
 
@@ -227,7 +229,7 @@ extern Portal GetPortalByName(const char *name);
 extern void PortalDefineQuery(Portal portal,
                                                          const char *prepStmtName,
                                                          const char *sourceText,
-                                                         const char *commandTag,
+                                                         CommandTag commandTag,
                                                          List *stmts,
                                                          CachedPlan *cplan);
 extern PlannedStmt *PortalGetPrimaryStmt(Portal portal);
index f5de2332d5599f5528de8c60a4e57b2ed36fbfe2..a65bce07135e5303a2d749b1f06f734b068ef62b 100644 (file)
@@ -1737,7 +1737,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
        tdata = (EventTriggerData *) fcinfo->context;
 
        hv_store_string(hv, "event", cstr2sv(tdata->event));
-       hv_store_string(hv, "tag", cstr2sv(tdata->tag));
+       hv_store_string(hv, "tag", cstr2sv(GetCommandTagName(tdata->tag)));
 
        return newRV_noinc((SV *) hv);
 }
index 5acf604f631951f76ec34bcea6e44bb7107c9cf9..a867c2c43b83fc93fc166b48c60140b897afc596 100644 (file)
@@ -37,6 +37,7 @@
 #include "parser/scansup.h"
 #include "plpgsql.h"
 #include "storage/proc.h"
+#include "tcop/cmdtag.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
 #include "utils/array.h"
@@ -1473,7 +1474,7 @@ plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
                case PLPGSQL_PROMISE_TG_TAG:
                        if (estate->evtrigdata == NULL)
                                elog(ERROR, "event trigger promise is not in an event trigger function");
-                       assign_text_var(estate, var, estate->evtrigdata->tag);
+                       assign_text_var(estate, var, GetCommandTagName(estate->evtrigdata->tag));
                        break;
 
                default:
@@ -4115,10 +4116,9 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
                         * tree(s), since those are the result of rewriting and could have
                         * been transmogrified into something else entirely.
                         */
-                       if (plansource->commandTag &&
-                               (strcmp(plansource->commandTag, "INSERT") == 0 ||
-                                strcmp(plansource->commandTag, "UPDATE") == 0 ||
-                                strcmp(plansource->commandTag, "DELETE") == 0))
+                       if (plansource->commandTag == CMDTAG_INSERT ||
+                               plansource->commandTag == CMDTAG_UPDATE ||
+                               plansource->commandTag == CMDTAG_DELETE)
                        {
                                stmt->mod_stmt = true;
                                break;
index f0d170bec7b0e4be03a6cb84b3c93ced922650a3..26e76f6a5124300aea1c7eedf109d40c2c94bd1c 100644 (file)
@@ -1329,7 +1329,8 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
        Tcl_ListObjAppendElement(NULL, tcl_cmd,
                                                         Tcl_NewStringObj(utf_e2u(tdata->event), -1));
        Tcl_ListObjAppendElement(NULL, tcl_cmd,
-                                                        Tcl_NewStringObj(utf_e2u(tdata->tag), -1));
+                                                        Tcl_NewStringObj(utf_e2u(GetCommandTagName(tdata->tag)),
+                                                                                         -1));
 
        tcl_rc = Tcl_EvalObjEx(interp, tcl_cmd, (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL));
 
index e1629ec618267d7dd305afebd769c3ad0050beca..b7bdb88ce7f7c21a03921b6020f91f370efbf065 100644 (file)
@@ -74,7 +74,7 @@ get_command_tag(PG_FUNCTION_ARGS)
        if (!cmd->parsetree)
                PG_RETURN_NULL();
 
-       PG_RETURN_TEXT_P(cstring_to_text(CreateCommandTag(cmd->parsetree)));
+       PG_RETURN_TEXT_P(cstring_to_text(CreateCommandName(cmd->parsetree)));
 }
 
 /*