diff options
author | Alvaro Herrera | 2020-03-02 21:19:51 +0000 |
---|---|---|
committer | Alvaro Herrera | 2020-03-02 21:19:51 +0000 |
commit | 2f9661311b83dc481fc19f6e3bda015392010a40 (patch) | |
tree | 9a1aabe1d15ac894f7badbc886ae33f16bbfc3b6 /src/backend/commands/event_trigger.c | |
parent | 7b425a5283cb2c8a452c2e79d6218e41373fd641 (diff) |
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/[email protected]
Diffstat (limited to 'src/backend/commands/event_trigger.c')
-rw-r--r-- | src/backend/commands/event_trigger.c | 160 |
1 files changed, 22 insertions, 138 deletions
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 71911d4067b..a366869369b 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -78,59 +78,6 @@ typedef struct bool supported; } event_trigger_support_data; -typedef enum -{ - EVENT_TRIGGER_COMMAND_TAG_OK, - EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED, - EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED -} event_trigger_command_tag_check_result; - -/* XXX merge this with ObjectTypeMap? */ -static const event_trigger_support_data event_trigger_support[] = { - {"ACCESS METHOD", true}, - {"AGGREGATE", true}, - {"CAST", true}, - {"CONSTRAINT", true}, - {"COLLATION", true}, - {"CONVERSION", true}, - {"DATABASE", false}, - {"DOMAIN", true}, - {"EXTENSION", true}, - {"EVENT TRIGGER", false}, - {"FOREIGN DATA WRAPPER", true}, - {"FOREIGN TABLE", true}, - {"FUNCTION", true}, - {"INDEX", true}, - {"LANGUAGE", true}, - {"MATERIALIZED VIEW", true}, - {"OPERATOR", true}, - {"OPERATOR CLASS", true}, - {"OPERATOR FAMILY", true}, - {"POLICY", true}, - {"PROCEDURE", true}, - {"PUBLICATION", true}, - {"ROLE", false}, - {"ROUTINE", true}, - {"RULE", true}, - {"SCHEMA", true}, - {"SEQUENCE", true}, - {"SERVER", true}, - {"STATISTICS", true}, - {"SUBSCRIPTION", true}, - {"TABLE", true}, - {"TABLESPACE", false}, - {"TRANSFORM", true}, - {"TRIGGER", true}, - {"TEXT SEARCH CONFIGURATION", true}, - {"TEXT SEARCH DICTIONARY", true}, - {"TEXT SEARCH PARSER", true}, - {"TEXT SEARCH TEMPLATE", true}, - {"TYPE", true}, - {"USER MAPPING", true}, - {"VIEW", true}, - {NULL, false} -}; - /* Support for dropped objects */ typedef struct SQLDropObject { @@ -150,8 +97,6 @@ typedef struct SQLDropObject static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId); -static event_trigger_command_tag_check_result check_ddl_tag(const char *tag); -static event_trigger_command_tag_check_result check_table_rewrite_ddl_tag(const char *tag); static void error_duplicate_filter_variable(const char *defname); static Datum filter_list_to_array(List *filterlist); static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname, @@ -259,71 +204,23 @@ validate_ddl_tags(const char *filtervar, List *taglist) foreach(lc, taglist) { - const char *tag = strVal(lfirst(lc)); - event_trigger_command_tag_check_result result; + const char *tagstr = strVal(lfirst(lc)); + CommandTag commandTag = GetCommandTagEnum(tagstr); - result = check_ddl_tag(tag); - if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED) + if (commandTag == CMDTAG_UNKNOWN) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filter value \"%s\" not recognized for filter variable \"%s\"", - tag, filtervar))); - if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED) + tagstr, filtervar))); + if (!command_tag_event_trigger_ok(commandTag)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s represents an SQL statement name */ errmsg("event triggers are not supported for %s", - tag))); + tagstr))); } } -static event_trigger_command_tag_check_result -check_ddl_tag(const char *tag) -{ - const char *obtypename; - const event_trigger_support_data *etsd; - - /* - * Handle some idiosyncratic special cases. - */ - if (pg_strcasecmp(tag, "CREATE TABLE AS") == 0 || - pg_strcasecmp(tag, "SELECT INTO") == 0 || - pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 || - pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 || - pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 || - pg_strcasecmp(tag, "COMMENT") == 0 || - pg_strcasecmp(tag, "GRANT") == 0 || - pg_strcasecmp(tag, "REVOKE") == 0 || - pg_strcasecmp(tag, "DROP OWNED") == 0 || - pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0 || - pg_strcasecmp(tag, "SECURITY LABEL") == 0) - return EVENT_TRIGGER_COMMAND_TAG_OK; - - /* - * Otherwise, command should be CREATE, ALTER, or DROP. - */ - if (pg_strncasecmp(tag, "CREATE ", 7) == 0) - obtypename = tag + 7; - else if (pg_strncasecmp(tag, "ALTER ", 6) == 0) - obtypename = tag + 6; - else if (pg_strncasecmp(tag, "DROP ", 5) == 0) - obtypename = tag + 5; - else - return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED; - - /* - * ...and the object type should be something recognizable. - */ - for (etsd = event_trigger_support; etsd->obtypename != NULL; etsd++) - if (pg_strcasecmp(etsd->obtypename, obtypename) == 0) - break; - if (etsd->obtypename == NULL) - return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED; - if (!etsd->supported) - return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED; - return EVENT_TRIGGER_COMMAND_TAG_OK; -} - /* * Validate DDL command tags for event table_rewrite. */ @@ -334,29 +231,18 @@ validate_table_rewrite_tags(const char *filtervar, List *taglist) foreach(lc, taglist) { - const char *tag = strVal(lfirst(lc)); - event_trigger_command_tag_check_result result; + const char *tagstr = strVal(lfirst(lc)); + CommandTag commandTag = GetCommandTagEnum(tagstr); - result = check_table_rewrite_ddl_tag(tag); - if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED) + if (!command_tag_table_rewrite_ok(commandTag)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s represents an SQL statement name */ errmsg("event triggers are not supported for %s", - tag))); + tagstr))); } } -static event_trigger_command_tag_check_result -check_table_rewrite_ddl_tag(const char *tag) -{ - if (pg_strcasecmp(tag, "ALTER TABLE") == 0 || - pg_strcasecmp(tag, "ALTER TYPE") == 0) - return EVENT_TRIGGER_COMMAND_TAG_OK; - - return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED; -} - /* * Complain about a duplicate filter variable. */ @@ -663,7 +549,7 @@ get_event_trigger_oid(const char *trigname, bool missing_ok) * tags matching. */ static bool -filter_event_trigger(const char **tag, EventTriggerCacheItem *item) +filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item) { /* * Filter by session replication role, knowing that we never see disabled @@ -681,9 +567,7 @@ filter_event_trigger(const char **tag, EventTriggerCacheItem *item) } /* Filter by tags, if any were specified. */ - if (item->ntags != 0 && bsearch(tag, item->tag, - item->ntags, sizeof(char *), - pg_qsort_strcmp) == NULL) + if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset)) return false; /* if we reach that point, we're not filtering out this item */ @@ -700,7 +584,7 @@ EventTriggerCommonSetup(Node *parsetree, EventTriggerEvent event, const char *eventstr, EventTriggerData *trigdata) { - const char *tag; + CommandTag tag; List *cachelist; ListCell *lc; List *runlist = NIL; @@ -716,25 +600,25 @@ EventTriggerCommonSetup(Node *parsetree, * * If this cross-check fails for you, you probably need to either adjust * standard_ProcessUtility() not to invoke event triggers for the command - * type in question, or you need to adjust check_ddl_tag to accept the + * type in question, or you need to adjust event_trigger_ok to accept the * relevant command tag. */ #ifdef USE_ASSERT_CHECKING { - const char *dbgtag; + CommandTag dbgtag; dbgtag = CreateCommandTag(parsetree); if (event == EVT_DDLCommandStart || event == EVT_DDLCommandEnd || event == EVT_SQLDrop) { - if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK) - elog(ERROR, "unexpected command tag \"%s\"", dbgtag); + if (!command_tag_event_trigger_ok(dbgtag)) + elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag)); } else if (event == EVT_TableRewrite) { - if (check_table_rewrite_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK) - elog(ERROR, "unexpected command tag \"%s\"", dbgtag); + if (!command_tag_table_rewrite_ok(dbgtag)) + elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag)); } } #endif @@ -758,7 +642,7 @@ EventTriggerCommonSetup(Node *parsetree, { EventTriggerCacheItem *item = lfirst(lc); - if (filter_event_trigger(&tag, item)) + if (filter_event_trigger(tag, item)) { /* We must plan to fire this trigger. */ runlist = lappend_oid(runlist, item->fnoid); @@ -2136,7 +2020,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) /* objsubid */ values[i++] = Int32GetDatum(addr.objectSubId); /* command tag */ - values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree)); + values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree)); /* object_type */ values[i++] = CStringGetTextDatum(type); /* schema */ @@ -2161,7 +2045,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) /* objsubid */ nulls[i++] = true; /* command tag */ - values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree)); + values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree)); /* object_type */ values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype)); /* schema */ |