aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c20
-rw-r--r--contrib/sepgsql/hooks.c6
-rw-r--r--doc/src/sgml/event-trigger.sgml2
-rw-r--r--src/backend/commands/createas.c14
-rw-r--r--src/backend/commands/event_trigger.c160
-rw-r--r--src/backend/commands/matview.c2
-rw-r--r--src/backend/commands/portalcmds.c16
-rw-r--r--src/backend/commands/prepare.c4
-rw-r--r--src/backend/executor/execMain.c4
-rw-r--r--src/backend/executor/functions.c4
-rw-r--r--src/backend/executor/spi.c21
-rw-r--r--src/backend/replication/logical/decode.c2
-rw-r--r--src/backend/replication/walsender.c18
-rw-r--r--src/backend/tcop/Makefile1
-rw-r--r--src/backend/tcop/cmdtag.c98
-rw-r--r--src/backend/tcop/dest.c32
-rw-r--r--src/backend/tcop/postgres.c33
-rw-r--r--src/backend/tcop/pquery.c112
-rw-r--r--src/backend/tcop/utility.c561
-rw-r--r--src/backend/utils/cache/evtcache.c30
-rw-r--r--src/backend/utils/cache/plancache.c8
-rw-r--r--src/backend/utils/mmgr/portalmem.c6
-rw-r--r--src/include/commands/createas.h3
-rw-r--r--src/include/commands/event_trigger.h3
-rw-r--r--src/include/commands/matview.h2
-rw-r--r--src/include/commands/portalcmds.h2
-rw-r--r--src/include/commands/prepare.h2
-rw-r--r--src/include/tcop/cmdtag.h58
-rw-r--r--src/include/tcop/cmdtaglist.h218
-rw-r--r--src/include/tcop/dest.h6
-rw-r--r--src/include/tcop/pquery.h2
-rw-r--r--src/include/tcop/utility.h15
-rw-r--r--src/include/utils/evtcache.h3
-rw-r--r--src/include/utils/plancache.h7
-rw-r--r--src/include/utils/portal.h6
-rw-r--r--src/pl/plperl/plperl.c2
-rw-r--r--src/pl/plpgsql/src/pl_exec.c10
-rw-r--r--src/pl/tcl/pltcl.c3
-rw-r--r--src/test/modules/test_ddl_deparse/test_ddl_deparse.c2
39 files changed, 877 insertions, 621 deletions
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index e4fda4b4049..7d9a1de2e0b 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -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);
}
}
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 997a64c87e2..853b5b04ab8 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -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();
{
diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
index 18628c498ba..130f6cd886a 100644
--- a/doc/src/sgml/event-trigger.sgml
+++ b/doc/src/sgml/event-trigger.sgml
@@ -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>
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index cc02cf824ed..3a5676fb39e 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -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;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 71911d4067b..a366869369b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -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 */
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 1ee37c1aeb6..c3954f3e242 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -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;
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 7e5c805a1e3..40be5069fef 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -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);
}
/*
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index c4e4b6eaec6..f917fc9c7a7 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -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);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index ee5c3a60ff3..28130fbc2b1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -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));
}
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 5cff6c43216..9b45a8a9a0e 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -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));
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index c46764bf428..b1081688211 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -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;
}
}
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 0ddc707defa..c2e5e3abf82 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -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
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index abb533b9d03..ae4a9cbe119 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -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);
diff --git a/src/backend/tcop/Makefile b/src/backend/tcop/Makefile
index c78f1e0a05e..f662a7dd1cf 100644
--- a/src/backend/tcop/Makefile
+++ b/src/backend/tcop/Makefile
@@ -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
index 00000000000..b9fbff612f2
--- /dev/null
+++ b/src/backend/tcop/cmdtag.c
@@ -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;
+}
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 09c1dcbb537..7208751ec78 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -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:
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 23661ae15f5..9dba3b0566a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -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;
@@ -1439,11 +1438,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
* try to do parse analysis, rewrite, or planning, since all those
@@ -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
{
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 0f5801e0460..5781fb2e55c 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -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);
}
}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index bb85b5e52aa..1b460a26126 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -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;
}
diff --git a/src/backend/utils/cache/evtcache.c b/src/backend/utils/cache/evtcache.c
index 1b63048a774..b9c1a0a5adb 100644
--- a/src/backend/utils/cache/evtcache.c
+++ b/src/backend/utils/cache/evtcache.c
@@ -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;
}
/*
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index c47be0ba4cd..dbae18d68c6 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -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;
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index b675575c315..7072ce48a3e 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -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;
diff --git a/src/include/commands/createas.h b/src/include/commands/createas.h
index 7743851a380..5615b5ecac5 100644
--- a/src/include/commands/createas.h
+++ b/src/include/commands/createas.h
@@ -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);
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index faa2958b893..28b352051b9 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -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
diff --git a/src/include/commands/matview.h b/src/include/commands/matview.h
index 6bdb7ca2589..3ea4f5c80b9 100644
--- a/src/include/commands/matview.h
+++ b/src/include/commands/matview.h
@@ -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);
diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h
index 4ecc1a2ecd3..5f64b0a674f 100644
--- a/src/include/commands/portalcmds.h
+++ b/src/include/commands/portalcmds.h
@@ -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);
diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h
index a0509e1f33f..4fcf2406c18 100644
--- a/src/include/commands/prepare.h
+++ b/src/include/commands/prepare.h
@@ -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
index 00000000000..f75a91e7c8e
--- /dev/null
+++ b/src/include/tcop/cmdtag.h
@@ -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
index 00000000000..d28145a50d8
--- /dev/null
+++ b/src/include/tcop/cmdtaglist.h
@@ -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)
diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h
index 35bce731a1d..662ce8a56f8 100644
--- a/src/include/tcop/dest.h
+++ b/src/include/tcop/dest.h
@@ -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. */
diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h
index 4ad6324e2d0..437642cc72c 100644
--- a/src/include/tcop/pquery.h
+++ b/src/include/tcop/pquery.h
@@ -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,
diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
index a551e08cb84..4aec19a0087 100644
--- a/src/include/tcop/utility.h
+++ b/src/include/tcop/utility.h
@@ -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);
diff --git a/src/include/utils/evtcache.h b/src/include/utils/evtcache.h
index 6c3ff81ba37..bc8ce480615 100644
--- a/src/include/utils/evtcache.h
+++ b/src/include/utils/evtcache.h
@@ -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);
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index e48661ebec1..6a5953c7686 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -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,
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index 0b694337227..d41ff2efdad 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -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);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index f5de2332d55..a65bce07135 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -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);
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 5acf604f631..a867c2c43b8 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -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;
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index f0d170bec7b..26e76f6a512 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -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));
diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
index e1629ec6182..b7bdb88ce7f 100644
--- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
+++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
@@ -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)));
}
/*