Represent command completion tags as structs
The backend was using strings to represent command tags and doing string comparisons in multiple places, but that's slow and unhelpful. Create a new command list with a supporting structure to use instead; this is stored in a tag-list-file that can be tailored to specific purposes with a caller-definable C macro, similar to what we do for WAL resource managers. The first first such uses are a new CommandTag enum and a CommandTagBehavior struct. Replace numerous occurrences of char *completionTag with a QueryCompletion struct so that the code no longer stores information about completed queries in a cstring. Only at the last moment, in EndCommand(), does this get converted to a string. EventTriggerCacheItem no longer holds an array of palloc’d tag strings in sorted order, but rather just a Bitmapset over the CommandTags. Author: Mark Dilger, with unsolicited help from Álvaro Herrera Reviewed-by: John Naylor, Tom Lane Discussion: https://postgr.es/m/981A9DB4-3F0C-4DA5-88AD-CB9CFF4D6CAD@enterprisedb.com
This commit is contained in:
parent
7b425a5283
commit
2f9661311b
@ -307,7 +307,7 @@ static void pgss_ExecutorEnd(QueryDesc *queryDesc);
|
|||||||
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||||
ProcessUtilityContext context, ParamListInfo params,
|
ProcessUtilityContext context, ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
static uint64 pgss_hash_string(const char *str, int len);
|
static uint64 pgss_hash_string(const char *str, int len);
|
||||||
static void pgss_store(const char *query, uint64 queryId,
|
static void pgss_store(const char *query, uint64 queryId,
|
||||||
int query_location, int query_len,
|
int query_location, int query_len,
|
||||||
@ -960,7 +960,7 @@ static void
|
|||||||
pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||||
ProcessUtilityContext context,
|
ProcessUtilityContext context,
|
||||||
ParamListInfo params, QueryEnvironment *queryEnv,
|
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest, char *completionTag)
|
DestReceiver *dest, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Node *parsetree = pstmt->utilityStmt;
|
Node *parsetree = pstmt->utilityStmt;
|
||||||
|
|
||||||
@ -998,11 +998,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||||||
if (prev_ProcessUtility)
|
if (prev_ProcessUtility)
|
||||||
prev_ProcessUtility(pstmt, queryString,
|
prev_ProcessUtility(pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
else
|
else
|
||||||
standard_ProcessUtility(pstmt, queryString,
|
standard_ProcessUtility(pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
}
|
}
|
||||||
PG_FINALLY();
|
PG_FINALLY();
|
||||||
{
|
{
|
||||||
@ -1013,12 +1013,8 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||||||
INSTR_TIME_SET_CURRENT(duration);
|
INSTR_TIME_SET_CURRENT(duration);
|
||||||
INSTR_TIME_SUBTRACT(duration, start);
|
INSTR_TIME_SUBTRACT(duration, start);
|
||||||
|
|
||||||
/* parse command tag to retrieve the number of affected rows. */
|
if (qc)
|
||||||
if (completionTag &&
|
rows = qc->commandTag == CMDTAG_COPY ? qc->nprocessed : 0;
|
||||||
strncmp(completionTag, "COPY ", 5) == 0)
|
|
||||||
rows = pg_strtouint64(completionTag + 5, NULL, 10);
|
|
||||||
else
|
|
||||||
rows = 0;
|
|
||||||
|
|
||||||
/* calc differences of buffer counters. */
|
/* calc differences of buffer counters. */
|
||||||
bufusage.shared_blks_hit =
|
bufusage.shared_blks_hit =
|
||||||
@ -1060,11 +1056,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
|||||||
if (prev_ProcessUtility)
|
if (prev_ProcessUtility)
|
||||||
prev_ProcessUtility(pstmt, queryString,
|
prev_ProcessUtility(pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
else
|
else
|
||||||
standard_ProcessUtility(pstmt, queryString,
|
standard_ProcessUtility(pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ sepgsql_utility_command(PlannedStmt *pstmt,
|
|||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest,
|
DestReceiver *dest,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Node *parsetree = pstmt->utilityStmt;
|
Node *parsetree = pstmt->utilityStmt;
|
||||||
sepgsql_context_info_t saved_context_info = sepgsql_context_info;
|
sepgsql_context_info_t saved_context_info = sepgsql_context_info;
|
||||||
@ -380,11 +380,11 @@ sepgsql_utility_command(PlannedStmt *pstmt,
|
|||||||
if (next_ProcessUtility_hook)
|
if (next_ProcessUtility_hook)
|
||||||
(*next_ProcessUtility_hook) (pstmt, queryString,
|
(*next_ProcessUtility_hook) (pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
else
|
else
|
||||||
standard_ProcessUtility(pstmt, queryString,
|
standard_ProcessUtility(pstmt, queryString,
|
||||||
context, params, queryEnv,
|
context, params, queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
}
|
}
|
||||||
PG_FINALLY();
|
PG_FINALLY();
|
||||||
{
|
{
|
||||||
|
@ -1074,7 +1074,7 @@ typedef struct EventTriggerData
|
|||||||
NodeTag type;
|
NodeTag type;
|
||||||
const char *event; /* event name */
|
const char *event; /* event name */
|
||||||
Node *parsetree; /* parse tree */
|
Node *parsetree; /* parse tree */
|
||||||
const char *tag; /* command tag */
|
CommandTag tag; /* command tag */
|
||||||
} EventTriggerData;
|
} EventTriggerData;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* Formerly, CTAS was implemented as a variant of SELECT, which led
|
* Formerly, CTAS was implemented as a variant of SELECT, which led
|
||||||
* to assorted legacy behaviors that we still try to preserve, notably that
|
* 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.)
|
* longer do that for CTAS ... WITH NO DATA, however.)
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
||||||
@ -225,7 +225,7 @@ create_ctas_nodata(List *tlist, IntoClause *into)
|
|||||||
ObjectAddress
|
ObjectAddress
|
||||||
ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
ParamListInfo params, QueryEnvironment *queryEnv,
|
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Query *query = castNode(Query, stmt->query);
|
Query *query = castNode(Query, stmt->query);
|
||||||
IntoClause *into = stmt->into;
|
IntoClause *into = stmt->into;
|
||||||
@ -270,7 +270,7 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||||||
ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
|
ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
|
||||||
|
|
||||||
Assert(!is_matview); /* excluded by syntax */
|
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 */
|
/* get object address that intorel_startup saved for us */
|
||||||
address = ((DR_intorel *) dest)->reladdr;
|
address = ((DR_intorel *) dest)->reladdr;
|
||||||
@ -352,11 +352,9 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
|||||||
/* run the plan to completion */
|
/* run the plan to completion */
|
||||||
ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
|
ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
|
||||||
|
|
||||||
/* save the rowcount if we're given a completionTag to fill */
|
/* save the rowcount if we're given a qc to fill */
|
||||||
if (completionTag)
|
if (qc)
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
|
||||||
"SELECT " UINT64_FORMAT,
|
|
||||||
queryDesc->estate->es_processed);
|
|
||||||
|
|
||||||
/* get object address that intorel_startup saved for us */
|
/* get object address that intorel_startup saved for us */
|
||||||
address = ((DR_intorel *) dest)->reladdr;
|
address = ((DR_intorel *) dest)->reladdr;
|
||||||
|
@ -78,59 +78,6 @@ typedef struct
|
|||||||
bool supported;
|
bool supported;
|
||||||
} event_trigger_support_data;
|
} 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 */
|
/* Support for dropped objects */
|
||||||
typedef struct SQLDropObject
|
typedef struct SQLDropObject
|
||||||
{
|
{
|
||||||
@ -150,8 +97,6 @@ typedef struct SQLDropObject
|
|||||||
static void AlterEventTriggerOwner_internal(Relation rel,
|
static void AlterEventTriggerOwner_internal(Relation rel,
|
||||||
HeapTuple tup,
|
HeapTuple tup,
|
||||||
Oid newOwnerId);
|
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 void error_duplicate_filter_variable(const char *defname);
|
||||||
static Datum filter_list_to_array(List *filterlist);
|
static Datum filter_list_to_array(List *filterlist);
|
||||||
static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
|
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)
|
foreach(lc, taglist)
|
||||||
{
|
{
|
||||||
const char *tag = strVal(lfirst(lc));
|
const char *tagstr = strVal(lfirst(lc));
|
||||||
event_trigger_command_tag_check_result result;
|
CommandTag commandTag = GetCommandTagEnum(tagstr);
|
||||||
|
|
||||||
result = check_ddl_tag(tag);
|
if (commandTag == CMDTAG_UNKNOWN)
|
||||||
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
|
errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
|
||||||
tag, filtervar)));
|
tagstr, filtervar)));
|
||||||
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
|
if (!command_tag_event_trigger_ok(commandTag))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s represents an SQL statement name */
|
/* translator: %s represents an SQL statement name */
|
||||||
errmsg("event triggers are not supported for %s",
|
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.
|
* Validate DDL command tags for event table_rewrite.
|
||||||
*/
|
*/
|
||||||
@ -334,29 +231,18 @@ validate_table_rewrite_tags(const char *filtervar, List *taglist)
|
|||||||
|
|
||||||
foreach(lc, taglist)
|
foreach(lc, taglist)
|
||||||
{
|
{
|
||||||
const char *tag = strVal(lfirst(lc));
|
const char *tagstr = strVal(lfirst(lc));
|
||||||
event_trigger_command_tag_check_result result;
|
CommandTag commandTag = GetCommandTagEnum(tagstr);
|
||||||
|
|
||||||
result = check_table_rewrite_ddl_tag(tag);
|
if (!command_tag_table_rewrite_ok(commandTag))
|
||||||
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s represents an SQL statement name */
|
/* translator: %s represents an SQL statement name */
|
||||||
errmsg("event triggers are not supported for %s",
|
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.
|
* Complain about a duplicate filter variable.
|
||||||
*/
|
*/
|
||||||
@ -663,7 +549,7 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
|
|||||||
* tags matching.
|
* tags matching.
|
||||||
*/
|
*/
|
||||||
static bool
|
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
|
* 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. */
|
/* Filter by tags, if any were specified. */
|
||||||
if (item->ntags != 0 && bsearch(tag, item->tag,
|
if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
|
||||||
item->ntags, sizeof(char *),
|
|
||||||
pg_qsort_strcmp) == NULL)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* if we reach that point, we're not filtering out this item */
|
/* if we reach that point, we're not filtering out this item */
|
||||||
@ -700,7 +584,7 @@ EventTriggerCommonSetup(Node *parsetree,
|
|||||||
EventTriggerEvent event, const char *eventstr,
|
EventTriggerEvent event, const char *eventstr,
|
||||||
EventTriggerData *trigdata)
|
EventTriggerData *trigdata)
|
||||||
{
|
{
|
||||||
const char *tag;
|
CommandTag tag;
|
||||||
List *cachelist;
|
List *cachelist;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
List *runlist = NIL;
|
List *runlist = NIL;
|
||||||
@ -716,25 +600,25 @@ EventTriggerCommonSetup(Node *parsetree,
|
|||||||
*
|
*
|
||||||
* If this cross-check fails for you, you probably need to either adjust
|
* If this cross-check fails for you, you probably need to either adjust
|
||||||
* standard_ProcessUtility() not to invoke event triggers for the command
|
* 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.
|
* relevant command tag.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_ASSERT_CHECKING
|
#ifdef USE_ASSERT_CHECKING
|
||||||
{
|
{
|
||||||
const char *dbgtag;
|
CommandTag dbgtag;
|
||||||
|
|
||||||
dbgtag = CreateCommandTag(parsetree);
|
dbgtag = CreateCommandTag(parsetree);
|
||||||
if (event == EVT_DDLCommandStart ||
|
if (event == EVT_DDLCommandStart ||
|
||||||
event == EVT_DDLCommandEnd ||
|
event == EVT_DDLCommandEnd ||
|
||||||
event == EVT_SQLDrop)
|
event == EVT_SQLDrop)
|
||||||
{
|
{
|
||||||
if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
if (!command_tag_event_trigger_ok(dbgtag))
|
||||||
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
|
||||||
}
|
}
|
||||||
else if (event == EVT_TableRewrite)
|
else if (event == EVT_TableRewrite)
|
||||||
{
|
{
|
||||||
if (check_table_rewrite_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
if (!command_tag_table_rewrite_ok(dbgtag))
|
||||||
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -758,7 +642,7 @@ EventTriggerCommonSetup(Node *parsetree,
|
|||||||
{
|
{
|
||||||
EventTriggerCacheItem *item = lfirst(lc);
|
EventTriggerCacheItem *item = lfirst(lc);
|
||||||
|
|
||||||
if (filter_event_trigger(&tag, item))
|
if (filter_event_trigger(tag, item))
|
||||||
{
|
{
|
||||||
/* We must plan to fire this trigger. */
|
/* We must plan to fire this trigger. */
|
||||||
runlist = lappend_oid(runlist, item->fnoid);
|
runlist = lappend_oid(runlist, item->fnoid);
|
||||||
@ -2136,7 +2020,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
|
|||||||
/* objsubid */
|
/* objsubid */
|
||||||
values[i++] = Int32GetDatum(addr.objectSubId);
|
values[i++] = Int32GetDatum(addr.objectSubId);
|
||||||
/* command tag */
|
/* command tag */
|
||||||
values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
|
values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
|
||||||
/* object_type */
|
/* object_type */
|
||||||
values[i++] = CStringGetTextDatum(type);
|
values[i++] = CStringGetTextDatum(type);
|
||||||
/* schema */
|
/* schema */
|
||||||
@ -2161,7 +2045,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
|
|||||||
/* objsubid */
|
/* objsubid */
|
||||||
nulls[i++] = true;
|
nulls[i++] = true;
|
||||||
/* command tag */
|
/* command tag */
|
||||||
values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
|
values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
|
||||||
/* object_type */
|
/* object_type */
|
||||||
values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
|
values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
|
||||||
/* schema */
|
/* schema */
|
||||||
|
@ -136,7 +136,7 @@ SetMatViewPopulatedState(Relation relation, bool newstate)
|
|||||||
*/
|
*/
|
||||||
ObjectAddress
|
ObjectAddress
|
||||||
ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
||||||
ParamListInfo params, char *completionTag)
|
ParamListInfo params, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Oid matviewOid;
|
Oid matviewOid;
|
||||||
Relation matviewRel;
|
Relation matviewRel;
|
||||||
|
@ -106,7 +106,7 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
|
|||||||
PortalDefineQuery(portal,
|
PortalDefineQuery(portal,
|
||||||
NULL,
|
NULL,
|
||||||
queryString,
|
queryString,
|
||||||
"SELECT", /* cursor's query is always a SELECT */
|
CMDTAG_SELECT, /* cursor's query is always a SELECT */
|
||||||
list_make1(plan),
|
list_make1(plan),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -160,15 +160,14 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
|
|||||||
*
|
*
|
||||||
* stmt: parsetree node for command
|
* stmt: parsetree node for command
|
||||||
* dest: where to send results
|
* dest: where to send results
|
||||||
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
* qc: where to store a command completion status data.
|
||||||
* in which to store a command completion status string.
|
|
||||||
*
|
*
|
||||||
* completionTag may be NULL if caller doesn't want a status string.
|
* qc may be NULL if caller doesn't want status data.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PerformPortalFetch(FetchStmt *stmt,
|
PerformPortalFetch(FetchStmt *stmt,
|
||||||
DestReceiver *dest,
|
DestReceiver *dest,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
uint64 nprocessed;
|
uint64 nprocessed;
|
||||||
@ -203,10 +202,9 @@ PerformPortalFetch(FetchStmt *stmt,
|
|||||||
dest);
|
dest);
|
||||||
|
|
||||||
/* Return command status if wanted */
|
/* Return command status if wanted */
|
||||||
if (completionTag)
|
if (qc)
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s " UINT64_FORMAT,
|
SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
|
||||||
stmt->ismove ? "MOVE" : "FETCH",
|
nprocessed);
|
||||||
nprocessed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -187,7 +187,7 @@ void
|
|||||||
ExecuteQuery(ParseState *pstate,
|
ExecuteQuery(ParseState *pstate,
|
||||||
ExecuteStmt *stmt, IntoClause *intoClause,
|
ExecuteStmt *stmt, IntoClause *intoClause,
|
||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
DestReceiver *dest, char *completionTag)
|
DestReceiver *dest, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
PreparedStatement *entry;
|
PreparedStatement *entry;
|
||||||
CachedPlan *cplan;
|
CachedPlan *cplan;
|
||||||
@ -288,7 +288,7 @@ ExecuteQuery(ParseState *pstate,
|
|||||||
*/
|
*/
|
||||||
PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
|
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);
|
PortalDrop(portal, false);
|
||||||
|
|
||||||
|
@ -787,11 +787,11 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
|
|||||||
if (isTempNamespace(get_rel_namespace(rte->relid)))
|
if (isTempNamespace(get_rel_namespace(rte->relid)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PreventCommandIfReadOnly(CreateCommandTag((Node *) plannedstmt));
|
PreventCommandIfReadOnly(CreateCommandName((Node *) plannedstmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
|
if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
|
||||||
PreventCommandIfParallelMode(CreateCommandTag((Node *) plannedstmt));
|
PreventCommandIfParallelMode(CreateCommandName((Node *) plannedstmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ init_execution_state(List *queryTree_list,
|
|||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL statement name */
|
/* translator: %s is a SQL statement name */
|
||||||
errmsg("%s is not allowed in a SQL function",
|
errmsg("%s is not allowed in a SQL function",
|
||||||
CreateCommandTag(stmt->utilityStmt))));
|
CreateCommandName(stmt->utilityStmt))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcache->readonly_func && !CommandIsReadOnly(stmt))
|
if (fcache->readonly_func && !CommandIsReadOnly(stmt))
|
||||||
@ -538,7 +538,7 @@ init_execution_state(List *queryTree_list,
|
|||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL statement name */
|
/* translator: %s is a SQL statement name */
|
||||||
errmsg("%s is not allowed in a non-volatile function",
|
errmsg("%s is not allowed in a non-volatile function",
|
||||||
CreateCommandTag((Node *) stmt))));
|
CreateCommandName((Node *) stmt))));
|
||||||
|
|
||||||
/* OK, build the execution_state for this query */
|
/* OK, build the execution_state for this query */
|
||||||
newes = (execution_state *) palloc(sizeof(execution_state));
|
newes = (execution_state *) palloc(sizeof(execution_state));
|
||||||
|
@ -1338,7 +1338,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
|
|||||||
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
|
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
|
||||||
/* translator: %s is name of a SQL command, eg INSERT */
|
/* translator: %s is name of a SQL command, eg INSERT */
|
||||||
errmsg("cannot open %s query as cursor",
|
errmsg("cannot open %s query as cursor",
|
||||||
plansource->commandTag)));
|
GetCommandTagName(plansource->commandTag))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(list_length(plan->plancache_list) == 1);
|
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),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL statement name */
|
/* translator: %s is a SQL statement name */
|
||||||
errmsg("%s is not allowed in a non-volatile function",
|
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),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
/* translator: %s is a SQL statement name */
|
/* translator: %s is a SQL statement name */
|
||||||
errmsg("%s is not allowed in a non-volatile function",
|
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
|
* If not read-only mode, advance the command counter before each
|
||||||
@ -2291,8 +2291,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char completionTag[COMPLETION_TAG_BUFSIZE];
|
|
||||||
ProcessUtilityContext context;
|
ProcessUtilityContext context;
|
||||||
|
QueryCompletion qc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the SPI context is atomic, or we are asked to manage
|
* If the SPI context is atomic, or we are asked to manage
|
||||||
@ -2306,13 +2306,14 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
|
|||||||
else
|
else
|
||||||
context = PROCESS_UTILITY_QUERY_NONATOMIC;
|
context = PROCESS_UTILITY_QUERY_NONATOMIC;
|
||||||
|
|
||||||
|
InitializeQueryCompletion(&qc);
|
||||||
ProcessUtility(stmt,
|
ProcessUtility(stmt,
|
||||||
plansource->query_string,
|
plansource->query_string,
|
||||||
context,
|
context,
|
||||||
paramLI,
|
paramLI,
|
||||||
_SPI_current->queryEnv,
|
_SPI_current->queryEnv,
|
||||||
dest,
|
dest,
|
||||||
completionTag);
|
&qc);
|
||||||
|
|
||||||
/* Update "processed" if stmt returned tuples */
|
/* Update "processed" if stmt returned tuples */
|
||||||
if (_SPI_current->tuptable)
|
if (_SPI_current->tuptable)
|
||||||
@ -2328,9 +2329,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
|
|||||||
{
|
{
|
||||||
CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
|
CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
|
||||||
|
|
||||||
if (strncmp(completionTag, "SELECT ", 7) == 0)
|
if (qc.commandTag == CMDTAG_SELECT)
|
||||||
_SPI_current->processed =
|
_SPI_current->processed = qc.nprocessed;
|
||||||
pg_strtouint64(completionTag + 7, NULL, 10);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2351,9 +2351,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
|
|||||||
}
|
}
|
||||||
else if (IsA(stmt->utilityStmt, CopyStmt))
|
else if (IsA(stmt->utilityStmt, CopyStmt))
|
||||||
{
|
{
|
||||||
Assert(strncmp(completionTag, "COPY ", 5) == 0);
|
Assert(qc.commandTag == CMDTAG_COPY);
|
||||||
_SPI_current->processed = pg_strtouint64(completionTag + 5,
|
_SPI_current->processed = qc.nprocessed;
|
||||||
NULL, 10);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *recor
|
|||||||
buf.record = record;
|
buf.record = record;
|
||||||
|
|
||||||
/* cast so we get a warning when new rmgrs are added */
|
/* 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
|
* Rmgrs we care about for logical decoding. Add new rmgrs in
|
||||||
|
@ -1074,8 +1074,11 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
|
|||||||
static void
|
static void
|
||||||
DropReplicationSlot(DropReplicationSlotCmd *cmd)
|
DropReplicationSlot(DropReplicationSlotCmd *cmd)
|
||||||
{
|
{
|
||||||
|
QueryCompletion qc;
|
||||||
|
|
||||||
ReplicationSlotDrop(cmd->slotname, !cmd->wait);
|
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)
|
StartLogicalReplication(StartReplicationCmd *cmd)
|
||||||
{
|
{
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
|
QueryCompletion qc;
|
||||||
|
|
||||||
/* make sure that our requirements are still fulfilled */
|
/* make sure that our requirements are still fulfilled */
|
||||||
CheckLogicalDecodingRequirements();
|
CheckLogicalDecodingRequirements();
|
||||||
@ -1160,7 +1164,8 @@ StartLogicalReplication(StartReplicationCmd *cmd)
|
|||||||
WalSndSetState(WALSNDSTATE_STARTUP);
|
WalSndSetState(WALSNDSTATE_STARTUP);
|
||||||
|
|
||||||
/* Get out of COPY mode (CommandComplete). */
|
/* 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;
|
Node *cmd_node;
|
||||||
MemoryContext cmd_context;
|
MemoryContext cmd_context;
|
||||||
MemoryContext old_context;
|
MemoryContext old_context;
|
||||||
|
QueryCompletion qc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If WAL sender has been told that shutdown is getting close, switch its
|
* 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);
|
MemoryContextDelete(cmd_context);
|
||||||
|
|
||||||
/* Send CommandComplete message */
|
/* Send CommandComplete message */
|
||||||
EndCommand("SELECT", DestRemote);
|
SetQueryCompletion(&qc, CMDTAG_SELECT, 0);
|
||||||
|
EndCommand(&qc, DestRemote, true);
|
||||||
|
|
||||||
/* Report to pgstat that this process is now idle */
|
/* Report to pgstat that this process is now idle */
|
||||||
pgstat_report_activity(STATE_IDLE, NULL);
|
pgstat_report_activity(STATE_IDLE, NULL);
|
||||||
@ -2867,8 +2874,11 @@ WalSndDone(WalSndSendDataCallback send_data)
|
|||||||
if (WalSndCaughtUp && sentPtr == replicatedPtr &&
|
if (WalSndCaughtUp && sentPtr == replicatedPtr &&
|
||||||
!pq_is_send_pending())
|
!pq_is_send_pending())
|
||||||
{
|
{
|
||||||
|
QueryCompletion qc;
|
||||||
|
|
||||||
/* Inform the standby that XLOG streaming is done */
|
/* Inform the standby that XLOG streaming is done */
|
||||||
EndCommand("COPY 0", DestRemote);
|
SetQueryCompletion(&qc, CMDTAG_COPY, 0);
|
||||||
|
EndCommand(&qc, DestRemote, false);
|
||||||
pq_flush();
|
pq_flush();
|
||||||
|
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
|
@ -13,6 +13,7 @@ top_builddir = ../../..
|
|||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
|
cmdtag.o \
|
||||||
dest.o \
|
dest.o \
|
||||||
fastpath.o \
|
fastpath.o \
|
||||||
postgres.o \
|
postgres.o \
|
||||||
|
98
src/backend/tcop/cmdtag.c
Normal file
98
src/backend/tcop/cmdtag.c
Normal file
@ -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;
|
||||||
|
}
|
@ -100,7 +100,7 @@ DestReceiver *None_Receiver = (DestReceiver *) &donothingDR;
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BeginCommand(const char *commandTag, CommandDest dest)
|
BeginCommand(CommandTag commandTag, CommandDest dest)
|
||||||
{
|
{
|
||||||
/* Nothing to do at present */
|
/* Nothing to do at present */
|
||||||
}
|
}
|
||||||
@ -163,8 +163,12 @@ CreateDestReceiver(CommandDest dest)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
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)
|
switch (dest)
|
||||||
{
|
{
|
||||||
case DestRemote:
|
case DestRemote:
|
||||||
@ -172,11 +176,27 @@ EndCommand(const char *commandTag, CommandDest dest)
|
|||||||
case DestRemoteSimple:
|
case DestRemoteSimple:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume the commandTag is plain ASCII and therefore requires
|
* We assume the tagname is plain ASCII and therefore requires no
|
||||||
* no encoding conversion.
|
* 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);
|
tag = qc->commandTag;
|
||||||
break;
|
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 DestNone:
|
||||||
case DestDebug:
|
case DestDebug:
|
||||||
|
@ -1064,8 +1064,8 @@ exec_simple_query(const char *query_string)
|
|||||||
{
|
{
|
||||||
RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);
|
RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);
|
||||||
bool snapshot_set = false;
|
bool snapshot_set = false;
|
||||||
const char *commandTag;
|
CommandTag commandTag;
|
||||||
char completionTag[COMPLETION_TAG_BUFSIZE];
|
QueryCompletion qc;
|
||||||
MemoryContext per_parsetree_context = NULL;
|
MemoryContext per_parsetree_context = NULL;
|
||||||
List *querytree_list,
|
List *querytree_list,
|
||||||
*plantree_list;
|
*plantree_list;
|
||||||
@ -1081,7 +1081,7 @@ exec_simple_query(const char *query_string)
|
|||||||
*/
|
*/
|
||||||
commandTag = CreateCommandTag(parsetree->stmt);
|
commandTag = CreateCommandTag(parsetree->stmt);
|
||||||
|
|
||||||
set_ps_display(commandTag, false);
|
set_ps_display(GetCommandTagName(commandTag), false);
|
||||||
|
|
||||||
BeginCommand(commandTag, dest);
|
BeginCommand(commandTag, dest);
|
||||||
|
|
||||||
@ -1239,7 +1239,7 @@ exec_simple_query(const char *query_string)
|
|||||||
true,
|
true,
|
||||||
receiver,
|
receiver,
|
||||||
receiver,
|
receiver,
|
||||||
completionTag);
|
&qc);
|
||||||
|
|
||||||
receiver->rDestroy(receiver);
|
receiver->rDestroy(receiver);
|
||||||
|
|
||||||
@ -1290,7 +1290,7 @@ exec_simple_query(const char *query_string)
|
|||||||
* command the client sent, regardless of rewriting. (But a command
|
* command the client sent, regardless of rewriting. (But a command
|
||||||
* aborted by error will not send an EndCommand report at all.)
|
* 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. */
|
/* Now we may drop the per-parsetree context, if one was created. */
|
||||||
if (per_parsetree_context)
|
if (per_parsetree_context)
|
||||||
@ -1352,7 +1352,6 @@ exec_parse_message(const char *query_string, /* string to execute */
|
|||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
List *parsetree_list;
|
List *parsetree_list;
|
||||||
RawStmt *raw_parse_tree;
|
RawStmt *raw_parse_tree;
|
||||||
const char *commandTag;
|
|
||||||
List *querytree_list;
|
List *querytree_list;
|
||||||
CachedPlanSource *psrc;
|
CachedPlanSource *psrc;
|
||||||
bool is_named;
|
bool is_named;
|
||||||
@ -1438,11 +1437,6 @@ exec_parse_message(const char *query_string, /* string to execute */
|
|||||||
|
|
||||||
raw_parse_tree = linitial_node(RawStmt, parsetree_list);
|
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
|
* If we are in an aborted transaction, reject all commands except
|
||||||
* COMMIT/ROLLBACK. It is important that this test occur before we
|
* COMMIT/ROLLBACK. It is important that this test occur before we
|
||||||
@ -1463,7 +1457,8 @@ exec_parse_message(const char *query_string, /* string to execute */
|
|||||||
* Create the CachedPlanSource before we do parse analysis, since it
|
* Create the CachedPlanSource before we do parse analysis, since it
|
||||||
* needs to see the unmodified raw parse tree.
|
* 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.
|
* 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. */
|
/* Empty input string. This is legal. */
|
||||||
raw_parse_tree = NULL;
|
raw_parse_tree = NULL;
|
||||||
commandTag = NULL;
|
psrc = CreateCachedPlan(raw_parse_tree, query_string,
|
||||||
psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag);
|
CMDTAG_UNKNOWN);
|
||||||
querytree_list = NIL;
|
querytree_list = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2031,7 +2026,7 @@ exec_execute_message(const char *portal_name, long max_rows)
|
|||||||
DestReceiver *receiver;
|
DestReceiver *receiver;
|
||||||
Portal portal;
|
Portal portal;
|
||||||
bool completed;
|
bool completed;
|
||||||
char completionTag[COMPLETION_TAG_BUFSIZE];
|
QueryCompletion qc;
|
||||||
const char *sourceText;
|
const char *sourceText;
|
||||||
const char *prepStmtName;
|
const char *prepStmtName;
|
||||||
ParamListInfo portalParams;
|
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
|
* If the original query was a null string, just return
|
||||||
* EmptyQueryResponse.
|
* EmptyQueryResponse.
|
||||||
*/
|
*/
|
||||||
if (portal->commandTag == NULL)
|
if (portal->commandTag == CMDTAG_UNKNOWN)
|
||||||
{
|
{
|
||||||
Assert(portal->stmts == NIL);
|
Assert(portal->stmts == NIL);
|
||||||
NullCommand(dest);
|
NullCommand(dest);
|
||||||
@ -2104,7 +2099,7 @@ exec_execute_message(const char *portal_name, long max_rows)
|
|||||||
|
|
||||||
pgstat_report_activity(STATE_RUNNING, sourceText);
|
pgstat_report_activity(STATE_RUNNING, sourceText);
|
||||||
|
|
||||||
set_ps_display(portal->commandTag, false);
|
set_ps_display(GetCommandTagName(portal->commandTag), false);
|
||||||
|
|
||||||
if (save_log_statement_stats)
|
if (save_log_statement_stats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
@ -2185,7 +2180,7 @@ exec_execute_message(const char *portal_name, long max_rows)
|
|||||||
!execute_is_fetch && max_rows == FETCH_ALL,
|
!execute_is_fetch && max_rows == FETCH_ALL,
|
||||||
receiver,
|
receiver,
|
||||||
receiver,
|
receiver,
|
||||||
completionTag);
|
&qc);
|
||||||
|
|
||||||
receiver->rDestroy(receiver);
|
receiver->rDestroy(receiver);
|
||||||
|
|
||||||
@ -2218,7 +2213,7 @@ exec_execute_message(const char *portal_name, long max_rows)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send appropriate CommandComplete to client */
|
/* Send appropriate CommandComplete to client */
|
||||||
EndCommand(completionTag, dest);
|
EndCommand(&qc, dest, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@ static void ProcessQuery(PlannedStmt *plan,
|
|||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest,
|
DestReceiver *dest,
|
||||||
char *completionTag);
|
QueryCompletion *qc);
|
||||||
static void FillPortalStore(Portal portal, bool isTopLevel);
|
static void FillPortalStore(Portal portal, bool isTopLevel);
|
||||||
static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count,
|
static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count,
|
||||||
DestReceiver *dest);
|
DestReceiver *dest);
|
||||||
@ -48,11 +48,11 @@ static uint64 PortalRunSelect(Portal portal, bool forward, long count,
|
|||||||
DestReceiver *dest);
|
DestReceiver *dest);
|
||||||
static void PortalRunUtility(Portal portal, PlannedStmt *pstmt,
|
static void PortalRunUtility(Portal portal, PlannedStmt *pstmt,
|
||||||
bool isTopLevel, bool setHoldSnapshot,
|
bool isTopLevel, bool setHoldSnapshot,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
static void PortalRunMulti(Portal portal,
|
static void PortalRunMulti(Portal portal,
|
||||||
bool isTopLevel, bool setHoldSnapshot,
|
bool isTopLevel, bool setHoldSnapshot,
|
||||||
DestReceiver *dest, DestReceiver *altdest,
|
DestReceiver *dest, DestReceiver *altdest,
|
||||||
char *completionTag);
|
QueryCompletion *qc);
|
||||||
static uint64 DoPortalRunFetch(Portal portal,
|
static uint64 DoPortalRunFetch(Portal portal,
|
||||||
FetchDirection fdirection,
|
FetchDirection fdirection,
|
||||||
long count,
|
long count,
|
||||||
@ -125,10 +125,9 @@ FreeQueryDesc(QueryDesc *qdesc)
|
|||||||
* sourceText: the source text of the query
|
* sourceText: the source text of the query
|
||||||
* params: any parameters needed
|
* params: any parameters needed
|
||||||
* dest: where to send results
|
* dest: where to send results
|
||||||
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
* qc: where to store the command completion status data.
|
||||||
* in which to store a command completion status string.
|
|
||||||
*
|
*
|
||||||
* 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
|
* Must be called in a memory context that will be reset or deleted on
|
||||||
* error; otherwise the executor's memory usage will be leaked.
|
* error; otherwise the executor's memory usage will be leaked.
|
||||||
@ -139,7 +138,7 @@ ProcessQuery(PlannedStmt *plan,
|
|||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest,
|
DestReceiver *dest,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
|
|
||||||
@ -161,38 +160,26 @@ ProcessQuery(PlannedStmt *plan,
|
|||||||
ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
|
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)
|
switch (queryDesc->operation)
|
||||||
{
|
{
|
||||||
case CMD_SELECT:
|
case CMD_SELECT:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
|
||||||
"SELECT " UINT64_FORMAT,
|
|
||||||
queryDesc->estate->es_processed);
|
|
||||||
break;
|
break;
|
||||||
case CMD_INSERT:
|
case CMD_INSERT:
|
||||||
/* lastoid doesn't exist anymore */
|
SetQueryCompletion(qc, CMDTAG_INSERT, queryDesc->estate->es_processed);
|
||||||
lastOid = InvalidOid;
|
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
|
||||||
"INSERT %u " UINT64_FORMAT,
|
|
||||||
lastOid, queryDesc->estate->es_processed);
|
|
||||||
break;
|
break;
|
||||||
case CMD_UPDATE:
|
case CMD_UPDATE:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
SetQueryCompletion(qc, CMDTAG_UPDATE, queryDesc->estate->es_processed);
|
||||||
"UPDATE " UINT64_FORMAT,
|
|
||||||
queryDesc->estate->es_processed);
|
|
||||||
break;
|
break;
|
||||||
case CMD_DELETE:
|
case CMD_DELETE:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
SetQueryCompletion(qc, CMDTAG_DELETE, queryDesc->estate->es_processed);
|
||||||
"DELETE " UINT64_FORMAT,
|
|
||||||
queryDesc->estate->es_processed);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(completionTag, "???");
|
SetQueryCompletion(qc, CMDTAG_UNKNOWN, queryDesc->estate->es_processed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,9 +662,8 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
|
|||||||
*
|
*
|
||||||
* altdest: where to send output of non-primary queries
|
* altdest: where to send output of non-primary queries
|
||||||
*
|
*
|
||||||
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
* qc: where to store command completion status data.
|
||||||
* in which to store a command completion status string.
|
* May be NULL if caller doesn't want status data.
|
||||||
* May be NULL if caller doesn't want a status string.
|
|
||||||
*
|
*
|
||||||
* Returns true if the portal's execution is complete, false if it was
|
* Returns true if the portal's execution is complete, false if it was
|
||||||
* suspended due to exhaustion of the count parameter.
|
* suspended due to exhaustion of the count parameter.
|
||||||
@ -685,7 +671,7 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
|
|||||||
bool
|
bool
|
||||||
PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
|
PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
|
||||||
DestReceiver *dest, DestReceiver *altdest,
|
DestReceiver *dest, DestReceiver *altdest,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
uint64 nprocessed;
|
uint64 nprocessed;
|
||||||
@ -700,9 +686,9 @@ PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
|
|||||||
|
|
||||||
TRACE_POSTGRESQL_QUERY_EXECUTE_START();
|
TRACE_POSTGRESQL_QUERY_EXECUTE_START();
|
||||||
|
|
||||||
/* Initialize completion tag to empty string */
|
/* Initialize empty completion data */
|
||||||
if (completionTag)
|
if (qc)
|
||||||
completionTag[0] = '\0';
|
InitializeQueryCompletion(qc);
|
||||||
|
|
||||||
if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
|
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
|
* If the portal result contains a command tag and the caller
|
||||||
* gave us a pointer to store it, copy it. Patch the "SELECT"
|
* gave us a pointer to store it, copy it and update the
|
||||||
* tag to also provide the rowcount.
|
* rowcount.
|
||||||
*/
|
*/
|
||||||
if (completionTag && portal->commandTag)
|
if (qc && portal->qc.commandTag != CMDTAG_UNKNOWN)
|
||||||
{
|
{
|
||||||
if (strcmp(portal->commandTag, "SELECT") == 0)
|
CopyQueryCompletion(qc, &portal->qc);
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
qc->nprocessed = nprocessed;
|
||||||
"SELECT " UINT64_FORMAT, nprocessed);
|
|
||||||
else
|
|
||||||
strcpy(completionTag, portal->commandTag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark portal not active */
|
/* Mark portal not active */
|
||||||
@ -794,7 +777,7 @@ PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
|
|||||||
|
|
||||||
case PORTAL_MULTI_QUERY:
|
case PORTAL_MULTI_QUERY:
|
||||||
PortalRunMulti(portal, isTopLevel, false,
|
PortalRunMulti(portal, isTopLevel, false,
|
||||||
dest, altdest, completionTag);
|
dest, altdest, qc);
|
||||||
|
|
||||||
/* Prevent portal's commands from being re-executed */
|
/* Prevent portal's commands from being re-executed */
|
||||||
MarkPortalDone(portal);
|
MarkPortalDone(portal);
|
||||||
@ -1005,8 +988,9 @@ static void
|
|||||||
FillPortalStore(Portal portal, bool isTopLevel)
|
FillPortalStore(Portal portal, bool isTopLevel)
|
||||||
{
|
{
|
||||||
DestReceiver *treceiver;
|
DestReceiver *treceiver;
|
||||||
char completionTag[COMPLETION_TAG_BUFSIZE];
|
QueryCompletion qc;
|
||||||
|
|
||||||
|
InitializeQueryCompletion(&qc);
|
||||||
PortalCreateHoldStore(portal);
|
PortalCreateHoldStore(portal);
|
||||||
treceiver = CreateDestReceiver(DestTuplestore);
|
treceiver = CreateDestReceiver(DestTuplestore);
|
||||||
SetTuplestoreDestReceiverParams(treceiver,
|
SetTuplestoreDestReceiverParams(treceiver,
|
||||||
@ -1014,8 +998,6 @@ FillPortalStore(Portal portal, bool isTopLevel)
|
|||||||
portal->holdContext,
|
portal->holdContext,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
completionTag[0] = '\0';
|
|
||||||
|
|
||||||
switch (portal->strategy)
|
switch (portal->strategy)
|
||||||
{
|
{
|
||||||
case PORTAL_ONE_RETURNING:
|
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).
|
* portal's holdSnapshot to the snapshot used (or a copy of it).
|
||||||
*/
|
*/
|
||||||
PortalRunMulti(portal, isTopLevel, true,
|
PortalRunMulti(portal, isTopLevel, true,
|
||||||
treceiver, None_Receiver, completionTag);
|
treceiver, None_Receiver, &qc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PORTAL_UTIL_SELECT:
|
case PORTAL_UTIL_SELECT:
|
||||||
PortalRunUtility(portal, linitial_node(PlannedStmt, portal->stmts),
|
PortalRunUtility(portal, linitial_node(PlannedStmt, portal->stmts),
|
||||||
isTopLevel, true, treceiver, completionTag);
|
isTopLevel, true, treceiver, &qc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1042,9 +1024,9 @@ FillPortalStore(Portal portal, bool isTopLevel)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Override default completion tag with actual command result */
|
/* Override portal completion data with actual command results */
|
||||||
if (completionTag[0] != '\0')
|
if (qc.commandTag != CMDTAG_UNKNOWN)
|
||||||
portal->commandTag = pstrdup(completionTag);
|
CopyQueryCompletion(&portal->qc, &qc);
|
||||||
|
|
||||||
treceiver->rDestroy(treceiver);
|
treceiver->rDestroy(treceiver);
|
||||||
}
|
}
|
||||||
@ -1130,7 +1112,7 @@ RunFromStore(Portal portal, ScanDirection direction, uint64 count,
|
|||||||
static void
|
static void
|
||||||
PortalRunUtility(Portal portal, PlannedStmt *pstmt,
|
PortalRunUtility(Portal portal, PlannedStmt *pstmt,
|
||||||
bool isTopLevel, bool setHoldSnapshot,
|
bool isTopLevel, bool setHoldSnapshot,
|
||||||
DestReceiver *dest, char *completionTag)
|
DestReceiver *dest, QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
Node *utilityStmt = pstmt->utilityStmt;
|
Node *utilityStmt = pstmt->utilityStmt;
|
||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
@ -1178,7 +1160,7 @@ PortalRunUtility(Portal portal, PlannedStmt *pstmt,
|
|||||||
portal->portalParams,
|
portal->portalParams,
|
||||||
portal->queryEnv,
|
portal->queryEnv,
|
||||||
dest,
|
dest,
|
||||||
completionTag);
|
qc);
|
||||||
|
|
||||||
/* Some utility statements may change context on us */
|
/* Some utility statements may change context on us */
|
||||||
MemoryContextSwitchTo(portal->portalContext);
|
MemoryContextSwitchTo(portal->portalContext);
|
||||||
@ -1202,7 +1184,7 @@ static void
|
|||||||
PortalRunMulti(Portal portal,
|
PortalRunMulti(Portal portal,
|
||||||
bool isTopLevel, bool setHoldSnapshot,
|
bool isTopLevel, bool setHoldSnapshot,
|
||||||
DestReceiver *dest, DestReceiver *altdest,
|
DestReceiver *dest, DestReceiver *altdest,
|
||||||
char *completionTag)
|
QueryCompletion *qc)
|
||||||
{
|
{
|
||||||
bool active_snapshot_set = false;
|
bool active_snapshot_set = false;
|
||||||
ListCell *stmtlist_item;
|
ListCell *stmtlist_item;
|
||||||
@ -1284,7 +1266,7 @@ PortalRunMulti(Portal portal,
|
|||||||
portal->sourceText,
|
portal->sourceText,
|
||||||
portal->portalParams,
|
portal->portalParams,
|
||||||
portal->queryEnv,
|
portal->queryEnv,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1319,7 +1301,7 @@ PortalRunMulti(Portal portal,
|
|||||||
Assert(!active_snapshot_set);
|
Assert(!active_snapshot_set);
|
||||||
/* statement can set tag string */
|
/* statement can set tag string */
|
||||||
PortalRunUtility(portal, pstmt, isTopLevel, false,
|
PortalRunUtility(portal, pstmt, isTopLevel, false,
|
||||||
dest, completionTag);
|
dest, qc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1350,8 +1332,8 @@ PortalRunMulti(Portal portal,
|
|||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a command completion tag was supplied, use it. Otherwise use the
|
* If a query completion data was supplied, use it. Otherwise use the
|
||||||
* portal's commandTag as the default completion tag.
|
* portal's query completion data.
|
||||||
*
|
*
|
||||||
* Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so
|
* Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so
|
||||||
* fake them with zeros. This can happen with DO INSTEAD rules if there
|
* 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
|
* 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.
|
* one row was updated. See QueryRewrite(), step 3, for details.
|
||||||
*/
|
*/
|
||||||
if (completionTag && completionTag[0] == '\0')
|
if (qc && qc->commandTag == CMDTAG_UNKNOWN)
|
||||||
{
|
{
|
||||||
if (portal->commandTag)
|
if (portal->qc.commandTag != CMDTAG_UNKNOWN)
|
||||||
strcpy(completionTag, portal->commandTag);
|
CopyQueryCompletion(qc, &portal->qc);
|
||||||
if (strcmp(completionTag, "SELECT") == 0)
|
/* If the caller supplied a qc, we should have set it by now. */
|
||||||
sprintf(completionTag, "SELECT 0 0");
|
Assert(qc->commandTag != CMDTAG_UNKNOWN);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
30
src/backend/utils/cache/evtcache.c
vendored
30
src/backend/utils/cache/evtcache.c
vendored
@ -20,6 +20,7 @@
|
|||||||
#include "catalog/pg_event_trigger.h"
|
#include "catalog/pg_event_trigger.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/catcache.h"
|
#include "utils/catcache.h"
|
||||||
@ -51,7 +52,7 @@ static EventTriggerCacheStateType EventTriggerCacheState = ETCS_NEEDS_REBUILD;
|
|||||||
static void BuildEventTriggerCache(void);
|
static void BuildEventTriggerCache(void);
|
||||||
static void InvalidateEventCacheCallback(Datum arg,
|
static void InvalidateEventCacheCallback(Datum arg,
|
||||||
int cacheid, uint32 hashvalue);
|
int cacheid, uint32 hashvalue);
|
||||||
static int DecodeTextArrayToCString(Datum array, char ***cstringp);
|
static Bitmapset *DecodeTextArrayToBitmapset(Datum array);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search the event cache by trigger event.
|
* Search the event cache by trigger event.
|
||||||
@ -180,10 +181,7 @@ BuildEventTriggerCache(void)
|
|||||||
evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
|
evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
|
||||||
RelationGetDescr(rel), &evttags_isnull);
|
RelationGetDescr(rel), &evttags_isnull);
|
||||||
if (!evttags_isnull)
|
if (!evttags_isnull)
|
||||||
{
|
item->tagset = DecodeTextArrayToBitmapset(evttags);
|
||||||
item->ntags = DecodeTextArrayToCString(evttags, &item->tag);
|
|
||||||
qsort(item->tag, item->ntags, sizeof(char *), pg_qsort_strcmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add to cache entry. */
|
/* Add to cache entry. */
|
||||||
entry = hash_search(cache, &event, HASH_ENTER, &found);
|
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
|
* 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
|
* of the logic from deconstruct_array, but it doesn't seem worth the code
|
||||||
* complexity.
|
* complexity.
|
||||||
*/
|
*/
|
||||||
static int
|
static Bitmapset *
|
||||||
DecodeTextArrayToCString(Datum array, char ***cstringp)
|
DecodeTextArrayToBitmapset(Datum array)
|
||||||
{
|
{
|
||||||
ArrayType *arr = DatumGetArrayTypeP(array);
|
ArrayType *arr = DatumGetArrayTypeP(array);
|
||||||
Datum *elems;
|
Datum *elems;
|
||||||
char **cstring;
|
Bitmapset *bms;
|
||||||
int i;
|
int i;
|
||||||
int nelems;
|
int nelems;
|
||||||
|
|
||||||
@ -234,13 +232,17 @@ DecodeTextArrayToCString(Datum array, char ***cstringp)
|
|||||||
elog(ERROR, "expected 1-D text array");
|
elog(ERROR, "expected 1-D text array");
|
||||||
deconstruct_array(arr, TEXTOID, -1, false, 'i', &elems, NULL, &nelems);
|
deconstruct_array(arr, TEXTOID, -1, false, 'i', &elems, NULL, &nelems);
|
||||||
|
|
||||||
cstring = palloc(nelems * sizeof(char *));
|
for (bms = NULL, i = 0; i < nelems; ++i)
|
||||||
for (i = 0; i < nelems; ++i)
|
{
|
||||||
cstring[i] = TextDatumGetCString(elems[i]);
|
char *str = TextDatumGetCString(elems[i]);
|
||||||
|
|
||||||
|
bms = bms_add_member(bms, GetCommandTagEnum(str));
|
||||||
|
pfree(str);
|
||||||
|
}
|
||||||
|
|
||||||
pfree(elems);
|
pfree(elems);
|
||||||
*cstringp = cstring;
|
|
||||||
return nelems;
|
return bms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
8
src/backend/utils/cache/plancache.c
vendored
8
src/backend/utils/cache/plancache.c
vendored
@ -158,12 +158,12 @@ InitPlanCache(void)
|
|||||||
*
|
*
|
||||||
* raw_parse_tree: output of raw_parser(), or NULL if empty query
|
* raw_parse_tree: output of raw_parser(), or NULL if empty query
|
||||||
* query_string: original query text
|
* 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 *
|
CachedPlanSource *
|
||||||
CreateCachedPlan(RawStmt *raw_parse_tree,
|
CreateCachedPlan(RawStmt *raw_parse_tree,
|
||||||
const char *query_string,
|
const char *query_string,
|
||||||
const char *commandTag)
|
CommandTag commandTag)
|
||||||
{
|
{
|
||||||
CachedPlanSource *plansource;
|
CachedPlanSource *plansource;
|
||||||
MemoryContext source_context;
|
MemoryContext source_context;
|
||||||
@ -241,12 +241,12 @@ CreateCachedPlan(RawStmt *raw_parse_tree,
|
|||||||
*
|
*
|
||||||
* raw_parse_tree: output of raw_parser(), or NULL if empty query
|
* raw_parse_tree: output of raw_parser(), or NULL if empty query
|
||||||
* query_string: original query text
|
* 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 *
|
CachedPlanSource *
|
||||||
CreateOneShotCachedPlan(RawStmt *raw_parse_tree,
|
CreateOneShotCachedPlan(RawStmt *raw_parse_tree,
|
||||||
const char *query_string,
|
const char *query_string,
|
||||||
const char *commandTag)
|
CommandTag commandTag)
|
||||||
{
|
{
|
||||||
CachedPlanSource *plansource;
|
CachedPlanSource *plansource;
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ void
|
|||||||
PortalDefineQuery(Portal portal,
|
PortalDefineQuery(Portal portal,
|
||||||
const char *prepStmtName,
|
const char *prepStmtName,
|
||||||
const char *sourceText,
|
const char *sourceText,
|
||||||
const char *commandTag,
|
CommandTag commandTag,
|
||||||
List *stmts,
|
List *stmts,
|
||||||
CachedPlan *cplan)
|
CachedPlan *cplan)
|
||||||
{
|
{
|
||||||
@ -289,10 +289,12 @@ PortalDefineQuery(Portal portal,
|
|||||||
AssertState(portal->status == PORTAL_NEW);
|
AssertState(portal->status == PORTAL_NEW);
|
||||||
|
|
||||||
AssertArg(sourceText != NULL);
|
AssertArg(sourceText != NULL);
|
||||||
AssertArg(commandTag != NULL || stmts == NIL);
|
AssertArg(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
|
||||||
|
|
||||||
portal->prepStmtName = prepStmtName;
|
portal->prepStmtName = prepStmtName;
|
||||||
portal->sourceText = sourceText;
|
portal->sourceText = sourceText;
|
||||||
|
portal->qc.commandTag = commandTag;
|
||||||
|
portal->qc.nprocessed = 0;
|
||||||
portal->commandTag = commandTag;
|
portal->commandTag = commandTag;
|
||||||
portal->stmts = stmts;
|
portal->stmts = stmts;
|
||||||
portal->cplan = cplan;
|
portal->cplan = cplan;
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
|
|
||||||
|
|
||||||
extern ObjectAddress ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
extern ObjectAddress ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
ParamListInfo params, QueryEnvironment *queryEnv, char *completionTag);
|
ParamListInfo params, QueryEnvironment *queryEnv,
|
||||||
|
QueryCompletion *qc);
|
||||||
|
|
||||||
extern int GetIntoRelEFlags(IntoClause *intoClause);
|
extern int GetIntoRelEFlags(IntoClause *intoClause);
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "catalog/objectaddress.h"
|
#include "catalog/objectaddress.h"
|
||||||
#include "catalog/pg_event_trigger.h"
|
#include "catalog/pg_event_trigger.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "tcop/deparse_utility.h"
|
#include "tcop/deparse_utility.h"
|
||||||
#include "utils/aclchk_internal.h"
|
#include "utils/aclchk_internal.h"
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ typedef struct EventTriggerData
|
|||||||
NodeTag type;
|
NodeTag type;
|
||||||
const char *event; /* event name */
|
const char *event; /* event name */
|
||||||
Node *parsetree; /* parse tree */
|
Node *parsetree; /* parse tree */
|
||||||
const char *tag; /* command tag */
|
CommandTag tag;
|
||||||
} EventTriggerData;
|
} EventTriggerData;
|
||||||
|
|
||||||
#define AT_REWRITE_ALTER_PERSISTENCE 0x01
|
#define AT_REWRITE_ALTER_PERSISTENCE 0x01
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
extern void SetMatViewPopulatedState(Relation relation, bool newstate);
|
extern void SetMatViewPopulatedState(Relation relation, bool newstate);
|
||||||
|
|
||||||
extern ObjectAddress ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
extern ObjectAddress ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
||||||
ParamListInfo params, char *completionTag);
|
ParamListInfo params, QueryCompletion *qc);
|
||||||
|
|
||||||
extern DestReceiver *CreateTransientRelDestReceiver(Oid oid);
|
extern DestReceiver *CreateTransientRelDestReceiver(Oid oid);
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ extern void PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, Para
|
|||||||
bool isTopLevel);
|
bool isTopLevel);
|
||||||
|
|
||||||
extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
|
extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
|
||||||
char *completionTag);
|
QueryCompletion *qc);
|
||||||
|
|
||||||
extern void PerformPortalClose(const char *name);
|
extern void PerformPortalClose(const char *name);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ extern void PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
|
|||||||
extern void ExecuteQuery(ParseState *pstate,
|
extern void ExecuteQuery(ParseState *pstate,
|
||||||
ExecuteStmt *stmt, IntoClause *intoClause,
|
ExecuteStmt *stmt, IntoClause *intoClause,
|
||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
extern void DeallocateQuery(DeallocateStmt *stmt);
|
extern void DeallocateQuery(DeallocateStmt *stmt);
|
||||||
extern void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into,
|
extern void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into,
|
||||||
ExplainState *es, const char *queryString,
|
ExplainState *es, const char *queryString,
|
||||||
|
58
src/include/tcop/cmdtag.h
Normal file
58
src/include/tcop/cmdtag.h
Normal file
@ -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 */
|
218
src/include/tcop/cmdtaglist.h
Normal file
218
src/include/tcop/cmdtaglist.h
Normal file
@ -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)
|
@ -68,6 +68,7 @@
|
|||||||
#define DEST_H
|
#define DEST_H
|
||||||
|
|
||||||
#include "executor/tuptable.h"
|
#include "executor/tuptable.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
|
|
||||||
|
|
||||||
/* buffer size to use for command completion tags */
|
/* 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 */
|
/* 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 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. */
|
/* Additional functions that go with destination management, more or less. */
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ extern void PortalSetResultFormat(Portal portal, int nFormats,
|
|||||||
|
|
||||||
extern bool PortalRun(Portal portal, long count, bool isTopLevel,
|
extern bool PortalRun(Portal portal, long count, bool isTopLevel,
|
||||||
bool run_once, DestReceiver *dest, DestReceiver *altdest,
|
bool run_once, DestReceiver *dest, DestReceiver *altdest,
|
||||||
char *completionTag);
|
QueryCompletion *qc);
|
||||||
|
|
||||||
extern uint64 PortalRunFetch(Portal portal,
|
extern uint64 PortalRunFetch(Portal portal,
|
||||||
FetchDirection fdirection,
|
FetchDirection fdirection,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#ifndef UTILITY_H
|
#ifndef UTILITY_H
|
||||||
#define UTILITY_H
|
#define UTILITY_H
|
||||||
|
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -71,17 +72,17 @@ typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt,
|
|||||||
const char *queryString, ProcessUtilityContext context,
|
const char *queryString, ProcessUtilityContext context,
|
||||||
ParamListInfo params,
|
ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
|
extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
|
||||||
|
|
||||||
extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||||
ProcessUtilityContext context, ParamListInfo params,
|
ProcessUtilityContext context, ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||||
ProcessUtilityContext context, ParamListInfo params,
|
ProcessUtilityContext context, ParamListInfo params,
|
||||||
QueryEnvironment *queryEnv,
|
QueryEnvironment *queryEnv,
|
||||||
DestReceiver *dest, char *completionTag);
|
DestReceiver *dest, QueryCompletion *qc);
|
||||||
|
|
||||||
extern void ProcessUtilityForAlterTable(Node *stmt,
|
extern void ProcessUtilityForAlterTable(Node *stmt,
|
||||||
AlterTableUtilityContext *context);
|
AlterTableUtilityContext *context);
|
||||||
@ -92,7 +93,13 @@ extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
|
|||||||
|
|
||||||
extern Query *UtilityContainsQuery(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);
|
extern LogStmtLevel GetCommandLogLevel(Node *parsetree);
|
||||||
|
|
||||||
|
@ -28,8 +28,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
Oid fnoid; /* function to be called */
|
Oid fnoid; /* function to be called */
|
||||||
char enabled; /* as SESSION_REPLICATION_ROLE_* */
|
char enabled; /* as SESSION_REPLICATION_ROLE_* */
|
||||||
int ntags; /* number of command tags */
|
Bitmapset *tagset; /* command tags, or NULL if empty */
|
||||||
char **tag; /* command tags in SORTED order */
|
|
||||||
} EventTriggerCacheItem;
|
} EventTriggerCacheItem;
|
||||||
|
|
||||||
extern List *EventCacheLookup(EventTriggerEvent event);
|
extern List *EventCacheLookup(EventTriggerEvent event);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "access/tupdesc.h"
|
#include "access/tupdesc.h"
|
||||||
#include "lib/ilist.h"
|
#include "lib/ilist.h"
|
||||||
#include "nodes/params.h"
|
#include "nodes/params.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "utils/queryenvironment.h"
|
#include "utils/queryenvironment.h"
|
||||||
|
|
||||||
/* Forward declaration, to avoid including parsenodes.h here */
|
/* Forward declaration, to avoid including parsenodes.h here */
|
||||||
@ -95,7 +96,7 @@ typedef struct CachedPlanSource
|
|||||||
int magic; /* should equal CACHEDPLANSOURCE_MAGIC */
|
int magic; /* should equal CACHEDPLANSOURCE_MAGIC */
|
||||||
struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
|
struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
|
||||||
const char *query_string; /* source text of query */
|
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 */
|
Oid *param_types; /* array of parameter type OIDs, or NULL */
|
||||||
int num_params; /* length of param_types array */
|
int num_params; /* length of param_types array */
|
||||||
ParserSetupHook parserSetup; /* alternative parameter spec method */
|
ParserSetupHook parserSetup; /* alternative parameter spec method */
|
||||||
@ -186,10 +187,10 @@ extern void ResetPlanCache(void);
|
|||||||
|
|
||||||
extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree,
|
extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree,
|
||||||
const char *query_string,
|
const char *query_string,
|
||||||
const char *commandTag);
|
CommandTag commandTag);
|
||||||
extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree,
|
extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree,
|
||||||
const char *query_string,
|
const char *query_string,
|
||||||
const char *commandTag);
|
CommandTag commandTag);
|
||||||
extern void CompleteCachedPlan(CachedPlanSource *plansource,
|
extern void CompleteCachedPlan(CachedPlanSource *plansource,
|
||||||
List *querytree_list,
|
List *querytree_list,
|
||||||
MemoryContext querytree_context,
|
MemoryContext querytree_context,
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
#include "datatype/timestamp.h"
|
#include "datatype/timestamp.h"
|
||||||
#include "executor/execdesc.h"
|
#include "executor/execdesc.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "utils/plancache.h"
|
#include "utils/plancache.h"
|
||||||
#include "utils/resowner.h"
|
#include "utils/resowner.h"
|
||||||
|
|
||||||
@ -132,7 +133,8 @@ typedef struct PortalData
|
|||||||
|
|
||||||
/* The query or queries the portal will execute */
|
/* The query or queries the portal will execute */
|
||||||
const char *sourceText; /* text of query (as of 8.4, never NULL) */
|
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 */
|
List *stmts; /* list of PlannedStmts */
|
||||||
CachedPlan *cplan; /* CachedPlan, if stmts are from one */
|
CachedPlan *cplan; /* CachedPlan, if stmts are from one */
|
||||||
|
|
||||||
@ -227,7 +229,7 @@ extern Portal GetPortalByName(const char *name);
|
|||||||
extern void PortalDefineQuery(Portal portal,
|
extern void PortalDefineQuery(Portal portal,
|
||||||
const char *prepStmtName,
|
const char *prepStmtName,
|
||||||
const char *sourceText,
|
const char *sourceText,
|
||||||
const char *commandTag,
|
CommandTag commandTag,
|
||||||
List *stmts,
|
List *stmts,
|
||||||
CachedPlan *cplan);
|
CachedPlan *cplan);
|
||||||
extern PlannedStmt *PortalGetPrimaryStmt(Portal portal);
|
extern PlannedStmt *PortalGetPrimaryStmt(Portal portal);
|
||||||
|
@ -1737,7 +1737,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
|
|||||||
tdata = (EventTriggerData *) fcinfo->context;
|
tdata = (EventTriggerData *) fcinfo->context;
|
||||||
|
|
||||||
hv_store_string(hv, "event", cstr2sv(tdata->event));
|
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);
|
return newRV_noinc((SV *) hv);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "parser/scansup.h"
|
#include "parser/scansup.h"
|
||||||
#include "plpgsql.h"
|
#include "plpgsql.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
|
#include "tcop/cmdtag.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "tcop/utility.h"
|
#include "tcop/utility.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
@ -1473,7 +1474,7 @@ plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
|
|||||||
case PLPGSQL_PROMISE_TG_TAG:
|
case PLPGSQL_PROMISE_TG_TAG:
|
||||||
if (estate->evtrigdata == NULL)
|
if (estate->evtrigdata == NULL)
|
||||||
elog(ERROR, "event trigger promise is not in an event trigger function");
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -4115,10 +4116,9 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
|
|||||||
* tree(s), since those are the result of rewriting and could have
|
* tree(s), since those are the result of rewriting and could have
|
||||||
* been transmogrified into something else entirely.
|
* been transmogrified into something else entirely.
|
||||||
*/
|
*/
|
||||||
if (plansource->commandTag &&
|
if (plansource->commandTag == CMDTAG_INSERT ||
|
||||||
(strcmp(plansource->commandTag, "INSERT") == 0 ||
|
plansource->commandTag == CMDTAG_UPDATE ||
|
||||||
strcmp(plansource->commandTag, "UPDATE") == 0 ||
|
plansource->commandTag == CMDTAG_DELETE)
|
||||||
strcmp(plansource->commandTag, "DELETE") == 0))
|
|
||||||
{
|
{
|
||||||
stmt->mod_stmt = true;
|
stmt->mod_stmt = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1329,7 +1329,8 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
Tcl_ListObjAppendElement(NULL, tcl_cmd,
|
Tcl_ListObjAppendElement(NULL, tcl_cmd,
|
||||||
Tcl_NewStringObj(utf_e2u(tdata->event), -1));
|
Tcl_NewStringObj(utf_e2u(tdata->event), -1));
|
||||||
Tcl_ListObjAppendElement(NULL, tcl_cmd,
|
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));
|
tcl_rc = Tcl_EvalObjEx(interp, tcl_cmd, (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL));
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ get_command_tag(PG_FUNCTION_ARGS)
|
|||||||
if (!cmd->parsetree)
|
if (!cmd->parsetree)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
PG_RETURN_TEXT_P(cstring_to_text(CreateCommandTag(cmd->parsetree)));
|
PG_RETURN_TEXT_P(cstring_to_text(CreateCommandName(cmd->parsetree)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user