1/*-------------------------------------------------------------------------
4 * PostgreSQL EVENT TRIGGER support code.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/commands/event_trigger.c
12 *-------------------------------------------------------------------------
53#include "utils/fmgroids.h"
54#include "utils/fmgrprotos.h"
63 /* memory context for this state's objects */
75 /* Support for command collection */
79 * deparse_utility.h */
88/* Support for dropped objects */
121 * Create an event trigger.
134 * It would be nice to allow database owners or even regular users to do
135 * this, but there are obvious privilege escalation risks which would have
136 * to somehow be plugged first.
140 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
141 errmsg(
"permission denied to create event trigger \"%s\"",
143 errhint(
"Must be superuser to create an event trigger.")));
145 /* Validate event name. */
146 if (strcmp(
stmt->eventname,
"ddl_command_start") != 0 &&
147 strcmp(
stmt->eventname,
"ddl_command_end") != 0 &&
148 strcmp(
stmt->eventname,
"sql_drop") != 0 &&
149 strcmp(
stmt->eventname,
"login") != 0 &&
150 strcmp(
stmt->eventname,
"table_rewrite") != 0)
152 (
errcode(ERRCODE_SYNTAX_ERROR),
153 errmsg(
"unrecognized event name \"%s\"",
156 /* Validate filter conditions. */
157 foreach(lc,
stmt->whenclause)
161 if (strcmp(def->
defname,
"tag") == 0)
169 (
errcode(ERRCODE_SYNTAX_ERROR),
170 errmsg(
"unrecognized filter variable \"%s\"", def->
defname)));
173 /* Validate tag list, if any. */
174 if ((strcmp(
stmt->eventname,
"ddl_command_start") == 0 ||
175 strcmp(
stmt->eventname,
"ddl_command_end") == 0 ||
176 strcmp(
stmt->eventname,
"sql_drop") == 0)
179 else if (strcmp(
stmt->eventname,
"table_rewrite") == 0
182 else if (strcmp(
stmt->eventname,
"login") == 0 && tags != NULL)
184 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
185 errmsg(
"tag filtering is not supported for login event triggers")));
188 * Give user a nice error message if an event trigger of the same name
195 errmsg(
"event trigger \"%s\" already exists",
198 /* Find and validate the trigger function. */
201 if (funcrettype != EVENT_TRIGGEROID)
203 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
204 errmsg(
"function %s must return type %s",
207 /* Insert catalog entries. */
209 evtowner, funcoid, tags);
213 * Validate DDL command tags.
225 if (commandTag == CMDTAG_UNKNOWN)
227 (
errcode(ERRCODE_SYNTAX_ERROR),
228 errmsg(
"filter value \"%s\" not recognized for filter variable \"%s\"",
229 tagstr, filtervar)));
232 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
233 /* translator: %s represents an SQL statement name */
234 errmsg(
"event triggers are not supported for %s",
240 * Validate DDL command tags for event table_rewrite.
254 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
255 /* translator: %s represents an SQL statement name */
256 errmsg(
"event triggers are not supported for %s",
262 * Complain about a duplicate filter variable.
268 (
errcode(ERRCODE_SYNTAX_ERROR),
269 errmsg(
"filter variable \"%s\" specified more than once",
274 * Insert the new pg_event_trigger row and record dependencies.
284 bool nulls[Natts_pg_event_trigger];
290 /* Open pg_event_trigger. */
293 /* Build the new pg_trigger tuple. */
295 Anum_pg_event_trigger_oid);
297 memset(nulls,
false,
sizeof(nulls));
304 values[Anum_pg_event_trigger_evtenabled - 1] =
307 nulls[Anum_pg_event_trigger_evttags - 1] =
true;
309 values[Anum_pg_event_trigger_evttags - 1] =
312 /* Insert heap tuple. */
318 * Login event triggers have an additional flag in pg_database to enable
319 * faster lookups in hot codepaths. Set the flag unless already True.
321 if (strcmp(eventname,
"login") == 0)
324 /* Depend on owner. */
327 /* Depend on event trigger function. */
328 myself.
classId = EventTriggerRelationId;
331 referenced.
classId = ProcedureRelationId;
336 /* Depend on extension, if any. */
339 /* Post creation hook for new event trigger */
342 /* Close pg_event_trigger. */
349 * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
350 * by a DefElem whose value is a List of String nodes; in the catalog, we
351 * store the list of strings as a text array. This function transforms the
352 * former representation into the latter one.
354 * For cleanliness, we store command tags in the catalog as text. It's
355 * possible (although not currently anticipated) that we might have
356 * a case-sensitive filter variable in the future, in which case this would
357 * need some further adjustment.
369 foreach(lc, filterlist)
376 for (p = result; *p; p++)
386 * Set pg_database.dathasloginevt flag for current database indicating that
387 * current database has on login event triggers.
392 /* Set dathasloginevt flag in pg_database */
399 * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying
400 * to reset pg_database.dathasloginevt flag. Note, this lock doesn't
401 * effectively blocks database or other objection. It's just custom lock
402 * tag used to prevent multiple backends changing
403 * pg_database.dathasloginevt flag.
412 if (!db->dathasloginevt)
414 db->dathasloginevt =
true;
424 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
433 char tgenabled =
stmt->tgenabled;
441 (
errcode(ERRCODE_UNDEFINED_OBJECT),
442 errmsg(
"event trigger \"%s\" does not exist",
446 trigoid = evtForm->oid;
452 /* tuple is a copy, so we can modify it below */
453 evtForm->evtenabled = tgenabled;
458 * Login event triggers have an additional flag in pg_database to enable
459 * faster lookups in hot codepaths. Set the flag unless already True.
461 if (
namestrcmp(&evtForm->evtevent,
"login") == 0 &&
476 * Change event trigger's owner -- by name
493 (
errcode(ERRCODE_UNDEFINED_OBJECT),
494 errmsg(
"event trigger \"%s\" does not exist",
name)));
497 evtOid = evtForm->oid;
511 * Change event trigger owner, by OID
525 (
errcode(ERRCODE_UNDEFINED_OBJECT),
526 errmsg(
"event trigger with OID %u does not exist", trigOid)));
536 * Internal workhorse for changing an event trigger's owner
545 if (form->evtowner == newOwnerId)
552 /* New owner must be a superuser */
555 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
556 errmsg(
"permission denied to change owner of event trigger \"%s\"",
558 errhint(
"The owner of an event trigger must be a superuser.")));
560 form->evtowner = newOwnerId;
563 /* Update owner dependency reference */
573 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
575 * If missing_ok is false, throw an error if trigger not found. If
576 * true, just return InvalidOid.
587 (
errcode(ERRCODE_UNDEFINED_OBJECT),
588 errmsg(
"event trigger \"%s\" does not exist", trigname)));
593 * Return true when we want to fire given Event Trigger and false otherwise,
594 * filtering on the session replication role and the event trigger registered
601 * Filter by session replication role, knowing that we never see disabled
615 /* Filter by tags, if any were specified. */
619 /* if we reach that point, we're not filtering out this item */
633 * Setup for running triggers for the given event. Return value is an OID list
634 * of functions to run; if there are any, trigdata is filled with an
635 * appropriate EventTriggerData for them to receive.
648 * We want the list of command tags for which this procedure is actually
649 * invoked to match up exactly with the list that CREATE EVENT TRIGGER
650 * accepts. This debugging cross-check will throw an error if this
651 * function is invoked for a command tag that CREATE EVENT TRIGGER won't
652 * accept. (Unfortunately, there doesn't seem to be any simple, automated
653 * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
654 * never reaches this control point.)
656 * If this cross-check fails for you, you probably need to either adjust
657 * standard_ProcessUtility() not to invoke event triggers for the command
658 * type in question, or you need to adjust event_trigger_ok to accept the
659 * relevant command tag.
661#ifdef USE_ASSERT_CHECKING
683 /* Use cache to find triggers for this event; fast exit if none. */
685 if (cachelist ==
NIL)
688 /* Get the command tag. */
692 * Filter list of event triggers by command tag, and copy them into our
693 * memory context. Once we start running the command triggers, or indeed
694 * once we do anything at all that touches the catalogs, an invalidation
695 * might leave cachelist pointing at garbage, so we must do this before we
698 foreach(lc, cachelist)
704 /* We must plan to fire this trigger. */
709 /* Don't spend any more time on this if no functions to run */
713 trigdata->
type = T_EventTriggerData;
714 trigdata->
event = eventstr;
722 * Fire ddl_command_start triggers.
731 * Event Triggers are completely disabled in standalone mode. There are
732 * (at least) two reasons for this:
734 * 1. A sufficiently broken event trigger might not only render the
735 * database unusable, but prevent disabling itself to fix the situation.
736 * In this scenario, restarting in standalone mode provides an escape
739 * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
740 * therefore will malfunction if pg_event_trigger's indexes are damaged.
741 * To allow recovery from a damaged index, we need some operating mode
742 * wherein event triggers are disabled. (Or we could implement
743 * heapscan-and-sort logic for that case, but having disaster recovery
744 * scenarios depend on code that's otherwise untested isn't appetizing.)
746 * Additionally, event triggers can be disabled with a superuser-only GUC
747 * to make fixing database easier as per 1 above.
759 /* Run the triggers. */
766 * Make sure anything the event triggers did will be visible to the main
773 * Fire ddl_command_end triggers.
782 * See EventTriggerDDLCommandStart for a discussion about why event
783 * triggers are disabled in single user mode or via GUC.
789 * Also do nothing if our state isn't set up, which it won't be if there
790 * weren't any relevant event triggers at the start of the current DDL
791 * command. This test might therefore seem optional, but it's important
792 * because EventTriggerCommonSetup might find triggers that didn't exist
793 * at the time the command started. Although this function itself
794 * wouldn't crash, the event trigger functions would presumably call
795 * pg_event_trigger_ddl_commands which would fail. Better to do nothing
796 * until the next command.
808 * Make sure anything the main command did will be visible to the event
813 /* Run the triggers. */
821 * Fire sql_drop triggers.
830 * See EventTriggerDDLCommandStart for a discussion about why event
831 * triggers are disabled in single user mode or via a GUC.
837 * Use current state to determine whether this event fires at all. If
838 * there are no triggers for the sql_drop event, then we don't have
839 * anything to do here. Note that dropped object collection is disabled
840 * if this is the case, so even if we were to try to run, the list would
852 * Nothing to do if run list is empty. Note this typically can't happen,
853 * because if there are no sql_drop events, then objects-to-drop wouldn't
854 * have been collected in the first place and we would have quit above.
855 * But it could occur if event triggers were dropped partway through.
861 * Make sure anything the main command did will be visible to the event
867 * Make sure pg_event_trigger_dropped_objects only works when running
868 * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
869 * one trigger fails. (This is perhaps not necessary, as the currentState
870 * variable will be removed shortly by our caller, but it seems better to
875 /* Run the triggers. */
891 * Fire login event triggers if any are present. The dathasloginevt
892 * pg_database flag is left unchanged when an event trigger is dropped to avoid
893 * complicating the codepath in the case of multiple event triggers. This
894 * function will instead unset the flag if no trigger is defined.
903 * See EventTriggerDDLCommandStart for a discussion about why event
904 * triggers are disabled in single user mode or via a GUC. We also need a
905 * database connection (some background workers don't have it).
919 * Event trigger execution may require an active snapshot.
923 /* Run the triggers. */
933 * There is no active login event trigger, but our
934 * pg_database.dathasloginevt is set. Try to unset this flag. We use the
935 * lock to prevent concurrent SetDatabaseHasLoginEventTriggers(), but we
936 * don't want to hang the connection waiting on the lock. Thus, we are
937 * just trying to acquire the lock conditionally.
943 * The lock is held. Now we need to recheck that login event triggers
944 * list is still empty. Once the list is empty, we know that even if
945 * there is a backend which concurrently inserts/enables a login event
946 * trigger, it will update pg_database.dathasloginevt *afterwards*.
960 /* Fetch a copy of the tuple to scribble on */
962 Anum_pg_database_oid,
973 if (db->dathasloginevt)
975 db->dathasloginevt =
false;
978 * Do an "in place" update of the pg_database tuple. Doing
979 * this instead of regular updates serves two purposes. First,
980 * that avoids possible waiting on the row-level lock. Second,
981 * that avoids dealing with TOAST.
1000 * Fire table_rewrite triggers.
1009 * See EventTriggerDDLCommandStart for a discussion about why event
1010 * triggers are disabled in single user mode or via a GUC.
1016 * Also do nothing if our state isn't set up, which it won't be if there
1017 * weren't any relevant event triggers at the start of the current DDL
1018 * command. This test might therefore seem optional, but it's
1019 * *necessary*, because EventTriggerCommonSetup might find triggers that
1020 * didn't exist at the time the command started.
1033 * Make sure pg_event_trigger_table_rewrite_oid only works when running
1034 * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
1035 * when one trigger fails. (This is perhaps not necessary, as the
1036 * currentState variable will be removed shortly by our caller, but it
1037 * seems better to play safe.)
1042 /* Run the triggers. */
1058 * Make sure anything the event triggers did will be visible to the main
1065 * Invoke each event trigger in a list of event triggers.
1075 /* Guard against stack overflow due to recursive event trigger */
1079 * Let's evaluate event triggers in their own memory context, so that any
1080 * leaks get cleaned up promptly.
1083 "event trigger context",
1087 /* Call each event trigger. */
1088 foreach(lc, fn_oid_list)
1095 elog(
DEBUG1,
"EventTriggerInvoke %u", fnoid);
1098 * We want each event trigger to be able to see the results of the
1099 * previous event trigger's action. Caller is responsible for any
1100 * command-counter increment that is needed between the event trigger
1101 * and anything else in the transaction.
1108 /* Look up the function */
1111 /* Call the function, passing no arguments but setting a context. */
1118 /* Reclaim memory. */
1122 /* Restore old memory context and delete the temporary one. */
1128 * Do event triggers support this object type?
1130 * See also event trigger documentation in event-trigger.sgml.
1141 /* no support for global objects (except subscriptions) */
1144 /* no support for event triggers on event triggers */
1152 * Do event triggers support this object class?
1154 * See also event trigger documentation in event-trigger.sgml.
1161 case DatabaseRelationId:
1162 case TableSpaceRelationId:
1163 case AuthIdRelationId:
1164 case AuthMemRelationId:
1165 case ParameterAclRelationId:
1166 /* no support for global objects (except subscriptions) */
1168 case EventTriggerRelationId:
1169 /* no support for event triggers on event triggers */
1177 * Prepare event trigger state for a new complete query to run, if necessary;
1178 * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1179 * be called when the query is done, regardless of whether it succeeds or fails
1180 * -- so use of a PG_TRY block is mandatory.
1189 * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1190 * reason to have event trigger state at all; so if there are none, don't
1197 "event trigger state",
1202 state->in_sql_drop =
false;
1207 state->currentCommand = NULL;
1216 * Query completed (or errored out) -- clean up local state, return to previous
1219 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1220 * returned false previously.
1222 * Note: this might be called in the PG_CATCH block of a failing transaction,
1223 * so be wary of running anything unnecessary. (In particular, it's probably
1224 * unwise to try to allocate memory.)
1233 /* this avoids the need for retail pfree of SQLDropList items: */
1240 * Do we need to keep close track of objects being dropped?
1242 * This is useful because there is a cost to running with them enabled.
1248 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1257 * Support for dropped objects information on event trigger functions.
1259 * We keep the list of objects dropped by the current command in current
1260 * state's SQLDropList (comprising SQLDropObject items). Each time a new
1261 * command is to start, a clean EventTriggerQueryState is created; commands
1262 * that drop objects do the dependency.c dance to drop objects, which
1263 * populates the current state's SQLDropList; when the event triggers are
1264 * invoked they can consume the list via pg_event_trigger_dropped_objects().
1265 * When the command finishes, the EventTriggerQueryState is cleared, and
1266 * the one from the previous command is restored (when no command is in
1267 * execution, the current state is NULL).
1269 * All this lets us support the case that an event trigger function drops
1270 * objects "reentrantly".
1274 * Register one object as being dropped by the current command.
1294 if (object->
classId == NamespaceRelationId)
1296 /* Special handling is needed for temp namespaces */
1301 /* don't report temp schemas except my own */
1308 else if (object->
classId == AttrDefaultRelationId)
1310 /* We treat a column default as temp if its table is temp */
1324 else if (object->
classId == TriggerRelationId)
1326 /* Similarly, a trigger is temp if its table is temp */
1327 /* Sadly, there's no lsyscache.c support for trigger objects */
1334 /* Fetch the trigger's table OID the hard way */
1337 Anum_pg_trigger_oid,
1349 /* Do nothing if we didn't find the trigger */
1354 relobject.
classId = RelationRelationId;
1356 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1366 else if (object->
classId == PolicyRelationId)
1368 /* Similarly, a policy is temp if its table is temp */
1369 /* Sadly, there's no lsyscache.c support for policy objects */
1376 /* Fetch the policy's table OID the hard way */
1391 /* Do nothing if we didn't find the policy */
1396 relobject.
classId = RelationRelationId;
1398 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1410 /* Generic handling for all other object classes */
1413 /* don't report temp objects except my own */
1420 /* object identity, objname and objargs */
1434 * Fill obj->objname, obj->schemaname, and obj->istemp based on object.
1436 * Returns true if this object should be reported, false if it should
1437 * be ignored because it is a temporary object of another session.
1443 * Obtain schema names from the object's catalog tuple, if one exists;
1444 * this lets us skip objects in temp schemas. We trust that
1445 * ObjectProperty contains all object classes that can be
1448 * Currently, this function does nothing for object classes that are not
1449 * in ObjectProperty, but we might sometime add special cases for that.
1477 /* temp objects are only reported if they are my own */
1485 /* no need to fill any fields of *obj */
1518 * pg_event_trigger_dropped_objects
1520 * Make the list of dropped objects available to the user function run by the
1530 * Protect this function from being called out of context
1535 (
errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1536 errmsg(
"%s can only be called in a sql_drop event trigger function",
1537 "pg_event_trigger_dropped_objects()")));
1539 /* Build tuplestore to hold the result rows */
1547 bool nulls[12] = {0};
1584 /* object_identity */
1590 /* address_names and address_args */
1614 * pg_event_trigger_table_rewrite_oid
1616 * Make the Oid of the table going to be rewritten available to the user
1617 * function run by the Event Trigger.
1623 * Protect this function from being called out of context
1628 (
errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1629 errmsg(
"%s can only be called in a table_rewrite event trigger function",
1630 "pg_event_trigger_table_rewrite_oid()")));
1636 * pg_event_trigger_table_rewrite_reason
1638 * Make the rewrite reason available to the user.
1644 * Protect this function from being called out of context
1649 (
errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1650 errmsg(
"%s can only be called in a table_rewrite event trigger function",
1651 "pg_event_trigger_table_rewrite_reason()")));
1656/*-------------------------------------------------------------------------
1657 * Support for DDL command deparsing
1659 * The routines below enable an event trigger function to obtain a list of
1660 * DDL commands as they are executed. There are three main pieces to this
1663 * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1664 * adds a struct CollectedCommand representation of itself to the command list,
1665 * using the routines below.
1667 * 2) Some time after that, ddl_command_end fires and the command list is made
1668 * available to the event trigger function via pg_event_trigger_ddl_commands();
1669 * the complete command details are exposed as a column of type pg_ddl_command.
1671 * 3) An extension can install a function capable of taking a value of type
1672 * pg_ddl_command and transform it into some external, user-visible and/or
1673 * -modifiable representation.
1674 *-------------------------------------------------------------------------
1678 * Inhibit DDL command collection.
1690 * Re-establish DDL command collection.
1702 * EventTriggerCollectSimpleCommand
1703 * Save data about a simple DDL command that was just executed
1705 * address identifies the object being operated on. secondaryObject is an
1706 * object address that was related in some way to the executed command; its
1707 * meaning is command-specific.
1709 * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1710 * object being moved, objectId is its OID, and secondaryOid is the OID of the
1711 * old schema. (The destination schema OID can be obtained by catalog lookup
1722 /* ignore if event trigger context not set, or collection disabled */
1745 * EventTriggerAlterTableStart
1746 * Prepare to receive data on an ALTER TABLE command about to be executed
1748 * Note we don't collect the command immediately; instead we keep it in
1749 * currentCommand, and only when we're done processing the subcommands we will
1750 * add it to the command list.
1758 /* ignore if event trigger context not set, or collection disabled */
1782 * Remember the OID of the object being affected by an ALTER TABLE.
1784 * This is needed because in some cases we don't know the OID until later.
1797 * EventTriggerCollectAlterTableSubcmd
1798 * Save data about a single part of an ALTER TABLE.
1800 * Several different commands go through this path, but apart from ALTER TABLE
1801 * itself, they are all concerned with AlterTableCmd nodes that are generated
1802 * internally, so that's all that this code needs to handle at the moment.
1810 /* ignore if event trigger context not set, or collection disabled */
1822 newsub->address = address;
1832 * EventTriggerAlterTableEnd
1833 * Finish up saving an ALTER TABLE command, and add it to command list.
1835 * FIXME this API isn't considering the possibility that an xact/subxact is
1836 * aborted partway through. Probably it's best to add an
1837 * AtEOSubXact_EventTriggers() to fix this.
1844 /* ignore if event trigger context not set, or collection disabled */
1851 /* If no subcommands, don't collect */
1871 * EventTriggerCollectGrant
1872 * Save data about a GRANT/REVOKE command being executed
1874 * This function creates a copy of the InternalGrant, as the original might
1875 * not have the right lifetime.
1885 /* ignore if event trigger context not set, or collection disabled */
1893 * This is tedious, but necessary.
1903 /* Now collect it, using the copied InternalGrant */
1917 * EventTriggerCollectAlterOpFam
1918 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1928 /* ignore if event trigger context not set, or collection disabled */
1939 OperatorFamilyRelationId, opfamoid);
1951 * EventTriggerCollectCreateOpClass
1952 * Save data about a CREATE OPERATOR CLASS command being executed
1961 /* ignore if event trigger context not set, or collection disabled */
1972 OperatorClassRelationId, opcoid);
1984 * EventTriggerCollectAlterTSConfig
1985 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1990 Oid *dictIds,
int ndicts)
1995 /* ignore if event trigger context not set, or collection disabled */
2006 TSConfigRelationId, cfgId);
2019 * EventTriggerCollectAlterDefPrivs
2020 * Save data about an ALTER DEFAULT PRIVILEGES command being
2029 /* ignore if event trigger context not set, or collection disabled */
2048 * In a ddl_command_end event trigger, this function reports the DDL commands
2058 * Protect this function from being called out of context
2062 (
errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
2063 errmsg(
"%s can only be called in an event trigger function",
2064 "pg_event_trigger_ddl_commands()")));
2066 /* Build tuplestore to hold the result rows */
2073 bool nulls[9] = {0};
2078 * For IF NOT EXISTS commands that attempt to create an existing
2079 * object, the returned OID is Invalid. Don't return anything.
2081 * One might think that a viable alternative would be to look up the
2082 * Oid of the existing object and run the deparse with that. But
2083 * since the parse tree might be different from the one that created
2084 * the object in the first place, we might not end up in a consistent
2101 char *schema = NULL;
2117 * If an object was dropped in the same command we may end
2118 * up in a situation where we generated a message but can
2119 * no longer look for the object information, so skip it
2120 * rather than failing. This can happen for example with
2121 * some subcommand combinations of ALTER TABLE.
2124 if (identity == NULL)
2127 /* The type can never be NULL. */
2131 * Obtain schema name, if any ("pg_temp" if a temp
2132 * object). If the object class is not in the supported
2133 * list here, we assume it's a schema-less object type,
2134 * and thus "schema" remains set to NULL.
2153 elog(
ERROR,
"cache lookup failed for object %u/%u",
2160 "invalid null namespace in object %u/%u/%d",
2222 "GRANT" :
"REVOKE");
2244 * Return the ObjectType as a string, as it would appear in GRANT and
2263 return "FOREIGN DATA WRAPPER";
2265 return "FOREIGN SERVER";
2271 return "LARGE OBJECT";
2281 return "TABLESPACE";
2284 /* these currently aren't used */
2321 elog(
ERROR,
"unsupported object type: %d", (
int) objtype);
2324 return "???";
/* keep compiler quiet */
2328 * Return the ObjectType as a string; as above, but use the spelling
2329 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2348 return "FOREIGN DATA WRAPPERS";
2350 return "FOREIGN SERVERS";
2356 return "LARGE OBJECTS";
2360 return "PROCEDURES";
2364 return "TABLESPACES";
2367 /* these currently aren't used */
2405 elog(
ERROR,
"unsupported object type: %d", (
int) objtype);
2408 return "???";
/* keep compiler quiet */
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
ArrayType * construct_empty_array(Oid elmtype)
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
#define InvalidAttrNumber
bool bms_is_member(int x, const Bitmapset *a)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define OidIsValid(objectId)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
const char * GetCommandTagName(CommandTag commandTag)
CommandTag GetCommandTagEnum(const char *commandname)
bool command_tag_event_trigger_ok(CommandTag commandTag)
bool command_tag_table_rewrite_ok(CommandTag commandTag)
@ SCT_AlterDefaultPrivileges
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void EventTriggerUndoInhibitCommandCollection(void)
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerOnLogin(void)
void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
bool trackDroppedObjectsNeeded(void)
Datum pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
void EventTriggerDDLCommandStart(Node *parsetree)
void EventTriggerInhibitCommandCollection(void)
bool EventTriggerBeginCompleteQuery(void)
static bool filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item)
void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
static bool obtain_object_name_namespace(const ObjectAddress *object, SQLDropObject *obj)
bool EventTriggerSupportsObject(const ObjectAddress *object)
bool EventTriggerSupportsObjectType(ObjectType obtype)
Oid CreateEventTrigger(CreateEventTrigStmt *stmt)
static void validate_table_rewrite_tags(const char *filtervar, List *taglist)
Oid AlterEventTrigger(AlterEventTrigStmt *stmt)
static const char * stringify_adefprivs_objtype(ObjectType objtype)
void EventTriggerCollectGrant(InternalGrant *istmt)
struct EventTriggerQueryState EventTriggerQueryState
Datum pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
void EventTriggerSQLDrop(Node *parsetree)
Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
static CommandTag EventTriggerGetTag(Node *parsetree, EventTriggerEvent event)
void EventTriggerEndCompleteQuery(void)
Datum pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
static void validate_ddl_tags(const char *filtervar, List *taglist)
void AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
void EventTriggerAlterTableRelid(Oid objectId)
void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId, Oid *dictIds, int ndicts)
static EventTriggerQueryState * currentEventTriggerState
struct SQLDropObject SQLDropObject
void EventTriggerAlterTableEnd(void)
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void SetDatabaseHasLoginEventTriggers(void)
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
static void error_duplicate_filter_variable(const char *defname)
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
static const char * stringify_grant_objtype(ObjectType objtype)
void EventTriggerDDLCommandEnd(Node *parsetree)
static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner, Oid funcoid, List *taglist)
static List * EventTriggerCommonSetup(Node *parsetree, EventTriggerEvent event, const char *eventstr, EventTriggerData *trigdata, bool unfiltered)
void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
Oid get_event_trigger_oid(const char *trigname, bool missing_ok)
ObjectAddress AlterEventTriggerOwner(const char *name, Oid newOwnerId)
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
static Datum filter_list_to_array(List *filterlist)
List * EventCacheLookup(EventTriggerEvent event)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
#define LOCAL_FCINFO(name, nargs)
#define FunctionCallInvoke(fcinfo)
#define PG_RETURN_INT32(x)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
void systable_endscan(SysScanDesc sysscan)
void systable_inplace_update_cancel(void *state)
void systable_inplace_update_begin(Relation relation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, const ScanKeyData *key, HeapTuple *oldtupcopy, void **state)
void systable_inplace_update_finish(void *state, HeapTuple tuple)
HeapTuple systable_getnext(SysScanDesc sysscan)
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
bool MyDatabaseHasLoginEventTriggers
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
static void slist_init(slist_head *head)
static bool slist_is_empty(const slist_head *head)
static void slist_push_head(slist_head *head, slist_node *node)
#define slist_container(type, membername, ptr)
#define slist_foreach(iter, lhead)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
if(TABLE==NULL||TABLE_index==NULL)
List * lappend(List *list, void *datum)
List * list_copy(const List *oldlist)
List * lappend_oid(List *list, Oid datum)
void list_free(List *list)
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
bool ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
#define AccessExclusiveLock
#define InplaceUpdateTupleLock
char * get_namespace_name_or_temp(Oid nspid)
char * get_namespace_name(Oid nspid)
Oid get_func_rettype(Oid funcid)
void * MemoryContextAlloc(MemoryContext context, Size size)
void MemoryContextReset(MemoryContext context)
char * pstrdup(const char *in)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext TopMemoryContext
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
int namestrcmp(Name name, const char *str)
void namestrcpy(Name name, const char *str)
char * NameListToString(const List *names)
bool isTempNamespace(Oid namespaceId)
bool isAnyTempNamespace(Oid namespaceId)
#define IsA(nodeptr, _type_)
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
char * getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
ArrayType * strlist_to_textarray(List *list)
bool get_object_namensp_unique(Oid class_id)
HeapTuple get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
AttrNumber get_object_attnum_oid(Oid class_id)
AttrNumber get_object_attnum_namespace(Oid class_id)
char * getObjectIdentityParts(const ObjectAddress *object, List **objname, List **objargs, bool missing_ok)
AttrNumber get_object_attnum_name(Oid class_id)
char * getObjectIdentity(const ObjectAddress *object, bool missing_ok)
bool is_objectclass_supported(Oid class_id)
#define ObjectAddressSet(addr, class_id, object_id)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
@ OBJECT_PUBLICATION_NAMESPACE
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
FormData_pg_database * Form_pg_database
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
FormData_pg_event_trigger * Form_pg_event_trigger
static int list_length(const List *l)
FormData_pg_policy * Form_pg_policy
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
FormData_pg_trigger * Form_pg_trigger
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
unsigned char pg_ascii_toupper(unsigned char ch)
static Datum PointerGetDatum(const void *X)
static Name DatumGetName(Datum X)
static Oid DatumGetObjectId(Datum X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static Datum NameGetDatum(const NameData *X)
static Datum CStringGetDatum(const char *X)
static Datum Int32GetDatum(int32 X)
static Datum CharGetDatum(char X)
static color newsub(struct colormap *cm, color co)
#define RelationGetDescr(relation)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Snapshot GetTransactionSnapshot(void)
void PushActiveSnapshot(Snapshot snapshot)
void PopActiveSnapshot(void)
void check_stack_depth(void)
#define BTEqualStrategyNumber
#define ERRCODE_DUPLICATE_OBJECT
struct CollectedCommand::@131::@136 createopc
CollectedCommandType type
struct CollectedCommand::@131::@133 alterTable
union CollectedCommand::@131 d
struct CollectedCommand::@131::@135 opfam
struct CollectedCommand * parent
struct CollectedCommand::@131::@138 defprivs
ObjectAddress secondaryObject
struct CollectedCommand::@131::@132 simple
struct CollectedCommand::@131::@134 grant
struct CollectedCommand::@131::@137 atscfg
struct EventTriggerQueryState * previous
CollectedCommand * currentCommand
bool commandCollectionInhibited
Tuplestorestate * setResult
bool superuser_arg(Oid roleid)
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheCopy1(cacheId, key1)
#define GetSysCacheOid1(cacheId, oidcol, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
int SessionReplicationRole
#define SESSION_REPLICATION_ROLE_REPLICA
#define TRIGGER_FIRES_ON_ORIGIN
#define TRIGGER_FIRES_ON_REPLICA
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
CommandTag CreateCommandTag(Node *parsetree)
static const char * CreateCommandName(Node *parsetree)
text * cstring_to_text(const char *s)
void CommandCounterIncrement(void)
void StartTransactionCommand(void)
void CommitTransactionCommand(void)