1 /*-------------------------------------------------------------------------
4 * PostgreSQL EVENT TRIGGER support code.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/commands/event_trigger.c
12 *-------------------------------------------------------------------------
16 #include "access/heapam.h"
17 #include "access/htup_details.h"
18 #include "access/table.h"
19 #include "access/xact.h"
20 #include "catalog/catalog.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/objectaccess.h"
24 #include "catalog/pg_database.h"
25 #include "catalog/pg_event_trigger.h"
26 #include "catalog/pg_namespace.h"
27 #include "catalog/pg_opclass.h"
28 #include "catalog/pg_opfamily.h"
29 #include "catalog/pg_proc.h"
30 #include "catalog/pg_trigger.h"
31 #include "catalog/pg_ts_config.h"
32 #include "catalog/pg_type.h"
33 #include "commands/event_trigger.h"
34 #include "commands/extension.h"
35 #include "commands/trigger.h"
37 #include "lib/ilist.h"
38 #include "miscadmin.h"
39 #include "parser/parse_func.h"
41 #include "storage/lmgr.h"
42 #include "tcop/deparse_utility.h"
43 #include "tcop/utility.h"
44 #include "utils/acl.h"
45 #include "utils/builtins.h"
46 #include "utils/evtcache.h"
47 #include "utils/fmgroids.h"
48 #include "utils/fmgrprotos.h"
49 #include "utils/lsyscache.h"
50 #include "utils/memutils.h"
51 #include "utils/rel.h"
52 #include "utils/snapmgr.h"
53 #include "utils/syscache.h"
55 typedef struct EventTriggerQueryState
57 /* memory context for this state's objects */
61 slist_head SQLDropList
;
65 Oid table_rewrite_oid
; /* InvalidOid, or set for table_rewrite
67 int table_rewrite_reason
; /* AT_REWRITE reason */
69 /* Support for command collection */
70 bool commandCollectionInhibited
;
71 CollectedCommand
*currentCommand
;
72 List
*commandList
; /* list of CollectedCommand; see
73 * deparse_utility.h */
74 struct EventTriggerQueryState
*previous
;
75 } EventTriggerQueryState
;
77 static EventTriggerQueryState
*currentEventTriggerState
= NULL
;
80 bool event_triggers
= true;
82 /* Support for dropped objects */
83 typedef struct SQLDropObject
85 ObjectAddress address
;
86 const char *schemaname
;
88 const char *objidentity
;
89 const char *objecttype
;
98 static void AlterEventTriggerOwner_internal(Relation rel
,
101 static void error_duplicate_filter_variable(const char *defname
);
102 static Datum
filter_list_to_array(List
*filterlist
);
103 static Oid
insert_event_trigger_tuple(const char *trigname
, const char *eventname
,
104 Oid evtOwner
, Oid funcoid
, List
*taglist
);
105 static void validate_ddl_tags(const char *filtervar
, List
*taglist
);
106 static void validate_table_rewrite_tags(const char *filtervar
, List
*taglist
);
107 static void EventTriggerInvoke(List
*fn_oid_list
, EventTriggerData
*trigdata
);
108 static const char *stringify_grant_objtype(ObjectType objtype
);
109 static const char *stringify_adefprivs_objtype(ObjectType objtype
);
110 static void SetDatatabaseHasLoginEventTriggers(void);
113 * Create an event trigger.
116 CreateEventTrigger(CreateEventTrigStmt
*stmt
)
121 Oid evtowner
= GetUserId();
126 * It would be nice to allow database owners or even regular users to do
127 * this, but there are obvious privilege escalation risks which would have
128 * to somehow be plugged first.
132 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
133 errmsg("permission denied to create event trigger \"%s\"",
135 errhint("Must be superuser to create an event trigger.")));
137 /* Validate event name. */
138 if (strcmp(stmt
->eventname
, "ddl_command_start") != 0 &&
139 strcmp(stmt
->eventname
, "ddl_command_end") != 0 &&
140 strcmp(stmt
->eventname
, "sql_drop") != 0 &&
141 strcmp(stmt
->eventname
, "login") != 0 &&
142 strcmp(stmt
->eventname
, "table_rewrite") != 0)
144 (errcode(ERRCODE_SYNTAX_ERROR
),
145 errmsg("unrecognized event name \"%s\"",
148 /* Validate filter conditions. */
149 foreach(lc
, stmt
->whenclause
)
151 DefElem
*def
= (DefElem
*) lfirst(lc
);
153 if (strcmp(def
->defname
, "tag") == 0)
156 error_duplicate_filter_variable(def
->defname
);
157 tags
= (List
*) def
->arg
;
161 (errcode(ERRCODE_SYNTAX_ERROR
),
162 errmsg("unrecognized filter variable \"%s\"", def
->defname
)));
165 /* Validate tag list, if any. */
166 if ((strcmp(stmt
->eventname
, "ddl_command_start") == 0 ||
167 strcmp(stmt
->eventname
, "ddl_command_end") == 0 ||
168 strcmp(stmt
->eventname
, "sql_drop") == 0)
170 validate_ddl_tags("tag", tags
);
171 else if (strcmp(stmt
->eventname
, "table_rewrite") == 0
173 validate_table_rewrite_tags("tag", tags
);
174 else if (strcmp(stmt
->eventname
, "login") == 0 && tags
!= NULL
)
176 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
177 errmsg("tag filtering is not supported for login event triggers")));
180 * Give user a nice error message if an event trigger of the same name
183 tuple
= SearchSysCache1(EVENTTRIGGERNAME
, CStringGetDatum(stmt
->trigname
));
184 if (HeapTupleIsValid(tuple
))
186 (errcode(ERRCODE_DUPLICATE_OBJECT
),
187 errmsg("event trigger \"%s\" already exists",
190 /* Find and validate the trigger function. */
191 funcoid
= LookupFuncName(stmt
->funcname
, 0, NULL
, false);
192 funcrettype
= get_func_rettype(funcoid
);
193 if (funcrettype
!= EVENT_TRIGGEROID
)
195 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
196 errmsg("function %s must return type %s",
197 NameListToString(stmt
->funcname
), "event_trigger")));
199 /* Insert catalog entries. */
200 return insert_event_trigger_tuple(stmt
->trigname
, stmt
->eventname
,
201 evtowner
, funcoid
, tags
);
205 * Validate DDL command tags.
208 validate_ddl_tags(const char *filtervar
, List
*taglist
)
214 const char *tagstr
= strVal(lfirst(lc
));
215 CommandTag commandTag
= GetCommandTagEnum(tagstr
);
217 if (commandTag
== CMDTAG_UNKNOWN
)
219 (errcode(ERRCODE_SYNTAX_ERROR
),
220 errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
221 tagstr
, filtervar
)));
222 if (!command_tag_event_trigger_ok(commandTag
))
224 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
225 /* translator: %s represents an SQL statement name */
226 errmsg("event triggers are not supported for %s",
232 * Validate DDL command tags for event table_rewrite.
235 validate_table_rewrite_tags(const char *filtervar
, List
*taglist
)
241 const char *tagstr
= strVal(lfirst(lc
));
242 CommandTag commandTag
= GetCommandTagEnum(tagstr
);
244 if (!command_tag_table_rewrite_ok(commandTag
))
246 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
247 /* translator: %s represents an SQL statement name */
248 errmsg("event triggers are not supported for %s",
254 * Complain about a duplicate filter variable.
257 error_duplicate_filter_variable(const char *defname
)
260 (errcode(ERRCODE_SYNTAX_ERROR
),
261 errmsg("filter variable \"%s\" specified more than once",
266 * Insert the new pg_event_trigger row and record dependencies.
269 insert_event_trigger_tuple(const char *trigname
, const char *eventname
, Oid evtOwner
,
270 Oid funcoid
, List
*taglist
)
275 Datum values
[Natts_pg_trigger
];
276 bool nulls
[Natts_pg_trigger
];
277 NameData evtnamedata
,
279 ObjectAddress myself
,
282 /* Open pg_event_trigger. */
283 tgrel
= table_open(EventTriggerRelationId
, RowExclusiveLock
);
285 /* Build the new pg_trigger tuple. */
286 trigoid
= GetNewOidWithIndex(tgrel
, EventTriggerOidIndexId
,
287 Anum_pg_event_trigger_oid
);
288 values
[Anum_pg_event_trigger_oid
- 1] = ObjectIdGetDatum(trigoid
);
289 memset(nulls
, false, sizeof(nulls
));
290 namestrcpy(&evtnamedata
, trigname
);
291 values
[Anum_pg_event_trigger_evtname
- 1] = NameGetDatum(&evtnamedata
);
292 namestrcpy(&evteventdata
, eventname
);
293 values
[Anum_pg_event_trigger_evtevent
- 1] = NameGetDatum(&evteventdata
);
294 values
[Anum_pg_event_trigger_evtowner
- 1] = ObjectIdGetDatum(evtOwner
);
295 values
[Anum_pg_event_trigger_evtfoid
- 1] = ObjectIdGetDatum(funcoid
);
296 values
[Anum_pg_event_trigger_evtenabled
- 1] =
297 CharGetDatum(TRIGGER_FIRES_ON_ORIGIN
);
299 nulls
[Anum_pg_event_trigger_evttags
- 1] = true;
301 values
[Anum_pg_event_trigger_evttags
- 1] =
302 filter_list_to_array(taglist
);
304 /* Insert heap tuple. */
305 tuple
= heap_form_tuple(tgrel
->rd_att
, values
, nulls
);
306 CatalogTupleInsert(tgrel
, tuple
);
307 heap_freetuple(tuple
);
310 * Login event triggers have an additional flag in pg_database to enable
311 * faster lookups in hot codepaths. Set the flag unless already True.
313 if (strcmp(eventname
, "login") == 0)
314 SetDatatabaseHasLoginEventTriggers();
316 /* Depend on owner. */
317 recordDependencyOnOwner(EventTriggerRelationId
, trigoid
, evtOwner
);
319 /* Depend on event trigger function. */
320 myself
.classId
= EventTriggerRelationId
;
321 myself
.objectId
= trigoid
;
322 myself
.objectSubId
= 0;
323 referenced
.classId
= ProcedureRelationId
;
324 referenced
.objectId
= funcoid
;
325 referenced
.objectSubId
= 0;
326 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_NORMAL
);
328 /* Depend on extension, if any. */
329 recordDependencyOnCurrentExtension(&myself
, false);
331 /* Post creation hook for new event trigger */
332 InvokeObjectPostCreateHook(EventTriggerRelationId
, trigoid
, 0);
334 /* Close pg_event_trigger. */
335 table_close(tgrel
, RowExclusiveLock
);
341 * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
342 * by a DefElem whose value is a List of String nodes; in the catalog, we
343 * store the list of strings as a text array. This function transforms the
344 * former representation into the latter one.
346 * For cleanliness, we store command tags in the catalog as text. It's
347 * possible (although not currently anticipated) that we might have
348 * a case-sensitive filter variable in the future, in which case this would
349 * need some further adjustment.
352 filter_list_to_array(List
*filterlist
)
357 l
= list_length(filterlist
);
359 data
= (Datum
*) palloc(l
* sizeof(Datum
));
361 foreach(lc
, filterlist
)
363 const char *value
= strVal(lfirst(lc
));
367 result
= pstrdup(value
);
368 for (p
= result
; *p
; p
++)
369 *p
= pg_ascii_toupper((unsigned char) *p
);
370 data
[i
++] = PointerGetDatum(cstring_to_text(result
));
374 return PointerGetDatum(construct_array_builtin(data
, l
, TEXTOID
));
378 * Set pg_database.dathasloginevt flag for current database indicating that
379 * current database has on login event triggers.
382 SetDatatabaseHasLoginEventTriggers(void)
384 /* Set dathasloginevt flag in pg_database */
386 Relation pg_db
= table_open(DatabaseRelationId
, RowExclusiveLock
);
390 * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying
391 * to reset pg_database.dathasloginevt flag. Note, this lock doesn't
392 * effectively blocks database or other objection. It's just custom lock
393 * tag used to prevent multiple backends changing
394 * pg_database.dathasloginevt flag.
396 LockSharedObject(DatabaseRelationId
, MyDatabaseId
, 0, AccessExclusiveLock
);
398 tuple
= SearchSysCacheCopy1(DATABASEOID
, ObjectIdGetDatum(MyDatabaseId
));
399 if (!HeapTupleIsValid(tuple
))
400 elog(ERROR
, "cache lookup failed for database %u", MyDatabaseId
);
401 db
= (Form_pg_database
) GETSTRUCT(tuple
);
402 if (!db
->dathasloginevt
)
404 db
->dathasloginevt
= true;
405 CatalogTupleUpdate(pg_db
, &tuple
->t_self
, tuple
);
406 CommandCounterIncrement();
408 table_close(pg_db
, RowExclusiveLock
);
409 heap_freetuple(tuple
);
413 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
416 AlterEventTrigger(AlterEventTrigStmt
*stmt
)
421 Form_pg_event_trigger evtForm
;
422 char tgenabled
= stmt
->tgenabled
;
424 tgrel
= table_open(EventTriggerRelationId
, RowExclusiveLock
);
426 tup
= SearchSysCacheCopy1(EVENTTRIGGERNAME
,
427 CStringGetDatum(stmt
->trigname
));
428 if (!HeapTupleIsValid(tup
))
430 (errcode(ERRCODE_UNDEFINED_OBJECT
),
431 errmsg("event trigger \"%s\" does not exist",
434 evtForm
= (Form_pg_event_trigger
) GETSTRUCT(tup
);
435 trigoid
= evtForm
->oid
;
437 if (!object_ownercheck(EventTriggerRelationId
, trigoid
, GetUserId()))
438 aclcheck_error(ACLCHECK_NOT_OWNER
, OBJECT_EVENT_TRIGGER
,
441 /* tuple is a copy, so we can modify it below */
442 evtForm
->evtenabled
= tgenabled
;
444 CatalogTupleUpdate(tgrel
, &tup
->t_self
, tup
);
447 * Login event triggers have an additional flag in pg_database to enable
448 * faster lookups in hot codepaths. Set the flag unless already True.
450 if (namestrcmp(&evtForm
->evtevent
, "login") == 0 &&
451 tgenabled
!= TRIGGER_DISABLED
)
452 SetDatatabaseHasLoginEventTriggers();
454 InvokeObjectPostAlterHook(EventTriggerRelationId
,
459 table_close(tgrel
, RowExclusiveLock
);
465 * Change event trigger's owner -- by name
468 AlterEventTriggerOwner(const char *name
, Oid newOwnerId
)
472 Form_pg_event_trigger evtForm
;
474 ObjectAddress address
;
476 rel
= table_open(EventTriggerRelationId
, RowExclusiveLock
);
478 tup
= SearchSysCacheCopy1(EVENTTRIGGERNAME
, CStringGetDatum(name
));
480 if (!HeapTupleIsValid(tup
))
482 (errcode(ERRCODE_UNDEFINED_OBJECT
),
483 errmsg("event trigger \"%s\" does not exist", name
)));
485 evtForm
= (Form_pg_event_trigger
) GETSTRUCT(tup
);
486 evtOid
= evtForm
->oid
;
488 AlterEventTriggerOwner_internal(rel
, tup
, newOwnerId
);
490 ObjectAddressSet(address
, EventTriggerRelationId
, evtOid
);
494 table_close(rel
, RowExclusiveLock
);
500 * Change event trigger owner, by OID
503 AlterEventTriggerOwner_oid(Oid trigOid
, Oid newOwnerId
)
508 rel
= table_open(EventTriggerRelationId
, RowExclusiveLock
);
510 tup
= SearchSysCacheCopy1(EVENTTRIGGEROID
, ObjectIdGetDatum(trigOid
));
512 if (!HeapTupleIsValid(tup
))
514 (errcode(ERRCODE_UNDEFINED_OBJECT
),
515 errmsg("event trigger with OID %u does not exist", trigOid
)));
517 AlterEventTriggerOwner_internal(rel
, tup
, newOwnerId
);
521 table_close(rel
, RowExclusiveLock
);
525 * Internal workhorse for changing an event trigger's owner
528 AlterEventTriggerOwner_internal(Relation rel
, HeapTuple tup
, Oid newOwnerId
)
530 Form_pg_event_trigger form
;
532 form
= (Form_pg_event_trigger
) GETSTRUCT(tup
);
534 if (form
->evtowner
== newOwnerId
)
537 if (!object_ownercheck(EventTriggerRelationId
, form
->oid
, GetUserId()))
538 aclcheck_error(ACLCHECK_NOT_OWNER
, OBJECT_EVENT_TRIGGER
,
539 NameStr(form
->evtname
));
541 /* New owner must be a superuser */
542 if (!superuser_arg(newOwnerId
))
544 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
545 errmsg("permission denied to change owner of event trigger \"%s\"",
546 NameStr(form
->evtname
)),
547 errhint("The owner of an event trigger must be a superuser.")));
549 form
->evtowner
= newOwnerId
;
550 CatalogTupleUpdate(rel
, &tup
->t_self
, tup
);
552 /* Update owner dependency reference */
553 changeDependencyOnOwner(EventTriggerRelationId
,
557 InvokeObjectPostAlterHook(EventTriggerRelationId
,
562 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
564 * If missing_ok is false, throw an error if trigger not found. If
565 * true, just return InvalidOid.
568 get_event_trigger_oid(const char *trigname
, bool missing_ok
)
572 oid
= GetSysCacheOid1(EVENTTRIGGERNAME
, Anum_pg_event_trigger_oid
,
573 CStringGetDatum(trigname
));
574 if (!OidIsValid(oid
) && !missing_ok
)
576 (errcode(ERRCODE_UNDEFINED_OBJECT
),
577 errmsg("event trigger \"%s\" does not exist", trigname
)));
582 * Return true when we want to fire given Event Trigger and false otherwise,
583 * filtering on the session replication role and the event trigger registered
587 filter_event_trigger(CommandTag tag
, EventTriggerCacheItem
*item
)
590 * Filter by session replication role, knowing that we never see disabled
593 if (SessionReplicationRole
== SESSION_REPLICATION_ROLE_REPLICA
)
595 if (item
->enabled
== TRIGGER_FIRES_ON_ORIGIN
)
600 if (item
->enabled
== TRIGGER_FIRES_ON_REPLICA
)
604 /* Filter by tags, if any were specified. */
605 if (!bms_is_empty(item
->tagset
) && !bms_is_member(tag
, item
->tagset
))
608 /* if we reach that point, we're not filtering out this item */
613 EventTriggerGetTag(Node
*parsetree
, EventTriggerEvent event
)
615 if (event
== EVT_Login
)
618 return CreateCommandTag(parsetree
);
622 * Setup for running triggers for the given event. Return value is an OID list
623 * of functions to run; if there are any, trigdata is filled with an
624 * appropriate EventTriggerData for them to receive.
627 EventTriggerCommonSetup(Node
*parsetree
,
628 EventTriggerEvent event
, const char *eventstr
,
629 EventTriggerData
*trigdata
, bool unfiltered
)
637 * We want the list of command tags for which this procedure is actually
638 * invoked to match up exactly with the list that CREATE EVENT TRIGGER
639 * accepts. This debugging cross-check will throw an error if this
640 * function is invoked for a command tag that CREATE EVENT TRIGGER won't
641 * accept. (Unfortunately, there doesn't seem to be any simple, automated
642 * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
643 * never reaches this control point.)
645 * If this cross-check fails for you, you probably need to either adjust
646 * standard_ProcessUtility() not to invoke event triggers for the command
647 * type in question, or you need to adjust event_trigger_ok to accept the
648 * relevant command tag.
650 #ifdef USE_ASSERT_CHECKING
654 dbgtag
= EventTriggerGetTag(parsetree
, event
);
656 if (event
== EVT_DDLCommandStart
||
657 event
== EVT_DDLCommandEnd
||
658 event
== EVT_SQLDrop
||
661 if (!command_tag_event_trigger_ok(dbgtag
))
662 elog(ERROR
, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag
));
664 else if (event
== EVT_TableRewrite
)
666 if (!command_tag_table_rewrite_ok(dbgtag
))
667 elog(ERROR
, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag
));
672 /* Use cache to find triggers for this event; fast exit if none. */
673 cachelist
= EventCacheLookup(event
);
674 if (cachelist
== NIL
)
677 /* Get the command tag. */
678 tag
= EventTriggerGetTag(parsetree
, event
);
681 * Filter list of event triggers by command tag, and copy them into our
682 * memory context. Once we start running the command triggers, or indeed
683 * once we do anything at all that touches the catalogs, an invalidation
684 * might leave cachelist pointing at garbage, so we must do this before we
687 foreach(lc
, cachelist
)
689 EventTriggerCacheItem
*item
= lfirst(lc
);
691 if (unfiltered
|| filter_event_trigger(tag
, item
))
693 /* We must plan to fire this trigger. */
694 runlist
= lappend_oid(runlist
, item
->fnoid
);
698 /* Don't spend any more time on this if no functions to run */
702 trigdata
->type
= T_EventTriggerData
;
703 trigdata
->event
= eventstr
;
704 trigdata
->parsetree
= parsetree
;
711 * Fire ddl_command_start triggers.
714 EventTriggerDDLCommandStart(Node
*parsetree
)
717 EventTriggerData trigdata
;
720 * Event Triggers are completely disabled in standalone mode. There are
721 * (at least) two reasons for this:
723 * 1. A sufficiently broken event trigger might not only render the
724 * database unusable, but prevent disabling itself to fix the situation.
725 * In this scenario, restarting in standalone mode provides an escape
728 * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
729 * therefore will malfunction if pg_event_trigger's indexes are damaged.
730 * To allow recovery from a damaged index, we need some operating mode
731 * wherein event triggers are disabled. (Or we could implement
732 * heapscan-and-sort logic for that case, but having disaster recovery
733 * scenarios depend on code that's otherwise untested isn't appetizing.)
735 * Additionally, event triggers can be disabled with a superuser-only GUC
736 * to make fixing database easier as per 1 above.
738 if (!IsUnderPostmaster
|| !event_triggers
)
741 runlist
= EventTriggerCommonSetup(parsetree
,
748 /* Run the triggers. */
749 EventTriggerInvoke(runlist
, &trigdata
);
755 * Make sure anything the event triggers did will be visible to the main
758 CommandCounterIncrement();
762 * Fire ddl_command_end triggers.
765 EventTriggerDDLCommandEnd(Node
*parsetree
)
768 EventTriggerData trigdata
;
771 * See EventTriggerDDLCommandStart for a discussion about why event
772 * triggers are disabled in single user mode or via GUC.
774 if (!IsUnderPostmaster
|| !event_triggers
)
778 * Also do nothing if our state isn't set up, which it won't be if there
779 * weren't any relevant event triggers at the start of the current DDL
780 * command. This test might therefore seem optional, but it's important
781 * because EventTriggerCommonSetup might find triggers that didn't exist
782 * at the time the command started. Although this function itself
783 * wouldn't crash, the event trigger functions would presumably call
784 * pg_event_trigger_ddl_commands which would fail. Better to do nothing
785 * until the next command.
787 if (!currentEventTriggerState
)
790 runlist
= EventTriggerCommonSetup(parsetree
,
791 EVT_DDLCommandEnd
, "ddl_command_end",
797 * Make sure anything the main command did will be visible to the event
800 CommandCounterIncrement();
802 /* Run the triggers. */
803 EventTriggerInvoke(runlist
, &trigdata
);
810 * Fire sql_drop triggers.
813 EventTriggerSQLDrop(Node
*parsetree
)
816 EventTriggerData trigdata
;
819 * See EventTriggerDDLCommandStart for a discussion about why event
820 * triggers are disabled in single user mode or via a GUC.
822 if (!IsUnderPostmaster
|| !event_triggers
)
826 * Use current state to determine whether this event fires at all. If
827 * there are no triggers for the sql_drop event, then we don't have
828 * anything to do here. Note that dropped object collection is disabled
829 * if this is the case, so even if we were to try to run, the list would
832 if (!currentEventTriggerState
||
833 slist_is_empty(¤tEventTriggerState
->SQLDropList
))
836 runlist
= EventTriggerCommonSetup(parsetree
,
837 EVT_SQLDrop
, "sql_drop",
841 * Nothing to do if run list is empty. Note this typically can't happen,
842 * because if there are no sql_drop events, then objects-to-drop wouldn't
843 * have been collected in the first place and we would have quit above.
844 * But it could occur if event triggers were dropped partway through.
850 * Make sure anything the main command did will be visible to the event
853 CommandCounterIncrement();
856 * Make sure pg_event_trigger_dropped_objects only works when running
857 * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
858 * one trigger fails. (This is perhaps not necessary, as the currentState
859 * variable will be removed shortly by our caller, but it seems better to
862 currentEventTriggerState
->in_sql_drop
= true;
864 /* Run the triggers. */
867 EventTriggerInvoke(runlist
, &trigdata
);
871 currentEventTriggerState
->in_sql_drop
= false;
880 * Fire login event triggers if any are present. The dathasloginevt
881 * pg_database flag is left unchanged when an event trigger is dropped to avoid
882 * complicating the codepath in the case of multiple event triggers. This
883 * function will instead unset the flag if no trigger is defined.
886 EventTriggerOnLogin(void)
889 EventTriggerData trigdata
;
892 * See EventTriggerDDLCommandStart for a discussion about why event
893 * triggers are disabled in single user mode or via a GUC. We also need a
894 * database connection (some background workers don't have it).
896 if (!IsUnderPostmaster
|| !event_triggers
||
897 !OidIsValid(MyDatabaseId
) || !MyDatabaseHasLoginEventTriggers
)
900 StartTransactionCommand();
901 runlist
= EventTriggerCommonSetup(NULL
,
908 * Event trigger execution may require an active snapshot.
910 PushActiveSnapshot(GetTransactionSnapshot());
912 /* Run the triggers. */
913 EventTriggerInvoke(runlist
, &trigdata
);
922 * There is no active login event trigger, but our
923 * pg_database.dathasloginevt is set. Try to unset this flag. We use the
924 * lock to prevent concurrent SetDatatabaseHasLoginEventTriggers(), but we
925 * don't want to hang the connection waiting on the lock. Thus, we are
926 * just trying to acquire the lock conditionally.
928 else if (ConditionalLockSharedObject(DatabaseRelationId
, MyDatabaseId
,
929 0, AccessExclusiveLock
))
932 * The lock is held. Now we need to recheck that login event triggers
933 * list is still empty. Once the list is empty, we know that even if
934 * there is a backend which concurrently inserts/enables a login event
935 * trigger, it will update pg_database.dathasloginevt *afterwards*.
937 runlist
= EventTriggerCommonSetup(NULL
,
943 Relation pg_db
= table_open(DatabaseRelationId
, RowExclusiveLock
);
950 * Get the pg_database tuple to scribble on. Note that this does
951 * not directly rely on the syscache to avoid issues with
952 * flattened toast values for the in-place update.
955 Anum_pg_database_oid
,
956 BTEqualStrategyNumber
, F_OIDEQ
,
957 ObjectIdGetDatum(MyDatabaseId
));
959 scan
= systable_beginscan(pg_db
, DatabaseOidIndexId
, true,
961 tuple
= systable_getnext(scan
);
962 tuple
= heap_copytuple(tuple
);
963 systable_endscan(scan
);
965 if (!HeapTupleIsValid(tuple
))
966 elog(ERROR
, "could not find tuple for database %u", MyDatabaseId
);
968 db
= (Form_pg_database
) GETSTRUCT(tuple
);
969 if (db
->dathasloginevt
)
971 db
->dathasloginevt
= false;
974 * Do an "in place" update of the pg_database tuple. Doing
975 * this instead of regular updates serves two purposes. First,
976 * that avoids possible waiting on the row-level lock. Second,
977 * that avoids dealing with TOAST.
979 * It's known that changes made by heap_inplace_update() may
980 * be lost due to concurrent normal updates. However, we are
981 * OK with that. The subsequent connections will still have a
982 * chance to set "dathasloginevt" to false.
984 heap_inplace_update(pg_db
, tuple
);
986 table_close(pg_db
, RowExclusiveLock
);
987 heap_freetuple(tuple
);
994 CommitTransactionCommand();
999 * Fire table_rewrite triggers.
1002 EventTriggerTableRewrite(Node
*parsetree
, Oid tableOid
, int reason
)
1005 EventTriggerData trigdata
;
1008 * See EventTriggerDDLCommandStart for a discussion about why event
1009 * triggers are disabled in single user mode or via a GUC.
1011 if (!IsUnderPostmaster
|| !event_triggers
)
1015 * Also do nothing if our state isn't set up, which it won't be if there
1016 * weren't any relevant event triggers at the start of the current DDL
1017 * command. This test might therefore seem optional, but it's
1018 * *necessary*, because EventTriggerCommonSetup might find triggers that
1019 * didn't exist at the time the command started.
1021 if (!currentEventTriggerState
)
1024 runlist
= EventTriggerCommonSetup(parsetree
,
1032 * Make sure pg_event_trigger_table_rewrite_oid only works when running
1033 * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
1034 * when one trigger fails. (This is perhaps not necessary, as the
1035 * currentState variable will be removed shortly by our caller, but it
1036 * seems better to play safe.)
1038 currentEventTriggerState
->table_rewrite_oid
= tableOid
;
1039 currentEventTriggerState
->table_rewrite_reason
= reason
;
1041 /* Run the triggers. */
1044 EventTriggerInvoke(runlist
, &trigdata
);
1048 currentEventTriggerState
->table_rewrite_oid
= InvalidOid
;
1049 currentEventTriggerState
->table_rewrite_reason
= 0;
1057 * Make sure anything the event triggers did will be visible to the main
1060 CommandCounterIncrement();
1064 * Invoke each event trigger in a list of event triggers.
1067 EventTriggerInvoke(List
*fn_oid_list
, EventTriggerData
*trigdata
)
1069 MemoryContext context
;
1070 MemoryContext oldcontext
;
1074 /* Guard against stack overflow due to recursive event trigger */
1075 check_stack_depth();
1078 * Let's evaluate event triggers in their own memory context, so that any
1079 * leaks get cleaned up promptly.
1081 context
= AllocSetContextCreate(CurrentMemoryContext
,
1082 "event trigger context",
1083 ALLOCSET_DEFAULT_SIZES
);
1084 oldcontext
= MemoryContextSwitchTo(context
);
1086 /* Call each event trigger. */
1087 foreach(lc
, fn_oid_list
)
1089 LOCAL_FCINFO(fcinfo
, 0);
1090 Oid fnoid
= lfirst_oid(lc
);
1092 PgStat_FunctionCallUsage fcusage
;
1094 elog(DEBUG1
, "EventTriggerInvoke %u", fnoid
);
1097 * We want each event trigger to be able to see the results of the
1098 * previous event trigger's action. Caller is responsible for any
1099 * command-counter increment that is needed between the event trigger
1100 * and anything else in the transaction.
1105 CommandCounterIncrement();
1107 /* Look up the function */
1108 fmgr_info(fnoid
, &flinfo
);
1110 /* Call the function, passing no arguments but setting a context. */
1111 InitFunctionCallInfoData(*fcinfo
, &flinfo
, 0,
1112 InvalidOid
, (Node
*) trigdata
, NULL
);
1113 pgstat_init_function_usage(fcinfo
, &fcusage
);
1114 FunctionCallInvoke(fcinfo
);
1115 pgstat_end_function_usage(&fcusage
, true);
1117 /* Reclaim memory. */
1118 MemoryContextReset(context
);
1121 /* Restore old memory context and delete the temporary one. */
1122 MemoryContextSwitchTo(oldcontext
);
1123 MemoryContextDelete(context
);
1127 * Do event triggers support this object type?
1130 EventTriggerSupportsObjectType(ObjectType obtype
)
1134 case OBJECT_DATABASE
:
1135 case OBJECT_TABLESPACE
:
1137 case OBJECT_PARAMETER_ACL
:
1138 /* no support for global objects */
1140 case OBJECT_EVENT_TRIGGER
:
1141 /* no support for event triggers on event triggers */
1143 case OBJECT_ACCESS_METHOD
:
1144 case OBJECT_AGGREGATE
:
1147 case OBJECT_ATTRIBUTE
:
1150 case OBJECT_COLLATION
:
1151 case OBJECT_CONVERSION
:
1153 case OBJECT_DEFAULT
:
1155 case OBJECT_DOMCONSTRAINT
:
1156 case OBJECT_EXTENSION
:
1158 case OBJECT_FOREIGN_SERVER
:
1159 case OBJECT_FOREIGN_TABLE
:
1160 case OBJECT_FUNCTION
:
1162 case OBJECT_LANGUAGE
:
1163 case OBJECT_LARGEOBJECT
:
1164 case OBJECT_MATVIEW
:
1165 case OBJECT_OPCLASS
:
1166 case OBJECT_OPERATOR
:
1167 case OBJECT_OPFAMILY
:
1169 case OBJECT_PROCEDURE
:
1170 case OBJECT_PUBLICATION
:
1171 case OBJECT_PUBLICATION_NAMESPACE
:
1172 case OBJECT_PUBLICATION_REL
:
1173 case OBJECT_ROUTINE
:
1176 case OBJECT_SEQUENCE
:
1177 case OBJECT_SUBSCRIPTION
:
1178 case OBJECT_STATISTIC_EXT
:
1179 case OBJECT_TABCONSTRAINT
:
1181 case OBJECT_TRANSFORM
:
1182 case OBJECT_TRIGGER
:
1183 case OBJECT_TSCONFIGURATION
:
1184 case OBJECT_TSDICTIONARY
:
1185 case OBJECT_TSPARSER
:
1186 case OBJECT_TSTEMPLATE
:
1188 case OBJECT_USER_MAPPING
:
1193 * There's intentionally no default: case here; we want the
1194 * compiler to warn if a new ObjectType hasn't been handled above.
1198 /* Shouldn't get here, but if we do, say "no support" */
1203 * Do event triggers support this object class?
1206 EventTriggerSupportsObjectClass(ObjectClass objclass
)
1210 case OCLASS_DATABASE
:
1211 case OCLASS_TBLSPACE
:
1213 case OCLASS_ROLE_MEMBERSHIP
:
1214 case OCLASS_PARAMETER_ACL
:
1215 /* no support for global objects */
1217 case OCLASS_EVENT_TRIGGER
:
1218 /* no support for event triggers on event triggers */
1224 case OCLASS_COLLATION
:
1225 case OCLASS_CONSTRAINT
:
1226 case OCLASS_CONVERSION
:
1227 case OCLASS_DEFAULT
:
1228 case OCLASS_LANGUAGE
:
1229 case OCLASS_LARGEOBJECT
:
1230 case OCLASS_OPERATOR
:
1231 case OCLASS_OPCLASS
:
1232 case OCLASS_OPFAMILY
:
1236 case OCLASS_REWRITE
:
1237 case OCLASS_TRIGGER
:
1239 case OCLASS_STATISTIC_EXT
:
1240 case OCLASS_TSPARSER
:
1242 case OCLASS_TSTEMPLATE
:
1243 case OCLASS_TSCONFIG
:
1245 case OCLASS_FOREIGN_SERVER
:
1246 case OCLASS_USER_MAPPING
:
1248 case OCLASS_EXTENSION
:
1250 case OCLASS_PUBLICATION
:
1251 case OCLASS_PUBLICATION_NAMESPACE
:
1252 case OCLASS_PUBLICATION_REL
:
1253 case OCLASS_SUBSCRIPTION
:
1254 case OCLASS_TRANSFORM
:
1258 * There's intentionally no default: case here; we want the
1259 * compiler to warn if a new OCLASS hasn't been handled above.
1263 /* Shouldn't get here, but if we do, say "no support" */
1268 * Prepare event trigger state for a new complete query to run, if necessary;
1269 * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1270 * be called when the query is done, regardless of whether it succeeds or fails
1271 * -- so use of a PG_TRY block is mandatory.
1274 EventTriggerBeginCompleteQuery(void)
1276 EventTriggerQueryState
*state
;
1280 * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1281 * reason to have event trigger state at all; so if there are none, don't
1284 if (!trackDroppedObjectsNeeded())
1287 cxt
= AllocSetContextCreate(TopMemoryContext
,
1288 "event trigger state",
1289 ALLOCSET_DEFAULT_SIZES
);
1290 state
= MemoryContextAlloc(cxt
, sizeof(EventTriggerQueryState
));
1292 slist_init(&(state
->SQLDropList
));
1293 state
->in_sql_drop
= false;
1294 state
->table_rewrite_oid
= InvalidOid
;
1296 state
->commandCollectionInhibited
= currentEventTriggerState
?
1297 currentEventTriggerState
->commandCollectionInhibited
: false;
1298 state
->currentCommand
= NULL
;
1299 state
->commandList
= NIL
;
1300 state
->previous
= currentEventTriggerState
;
1301 currentEventTriggerState
= state
;
1307 * Query completed (or errored out) -- clean up local state, return to previous
1310 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1311 * returned false previously.
1313 * Note: this might be called in the PG_CATCH block of a failing transaction,
1314 * so be wary of running anything unnecessary. (In particular, it's probably
1315 * unwise to try to allocate memory.)
1318 EventTriggerEndCompleteQuery(void)
1320 EventTriggerQueryState
*prevstate
;
1322 prevstate
= currentEventTriggerState
->previous
;
1324 /* this avoids the need for retail pfree of SQLDropList items: */
1325 MemoryContextDelete(currentEventTriggerState
->cxt
);
1327 currentEventTriggerState
= prevstate
;
1331 * Do we need to keep close track of objects being dropped?
1333 * This is useful because there is a cost to running with them enabled.
1336 trackDroppedObjectsNeeded(void)
1339 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1342 return (EventCacheLookup(EVT_SQLDrop
) != NIL
) ||
1343 (EventCacheLookup(EVT_TableRewrite
) != NIL
) ||
1344 (EventCacheLookup(EVT_DDLCommandEnd
) != NIL
);
1348 * Support for dropped objects information on event trigger functions.
1350 * We keep the list of objects dropped by the current command in current
1351 * state's SQLDropList (comprising SQLDropObject items). Each time a new
1352 * command is to start, a clean EventTriggerQueryState is created; commands
1353 * that drop objects do the dependency.c dance to drop objects, which
1354 * populates the current state's SQLDropList; when the event triggers are
1355 * invoked they can consume the list via pg_event_trigger_dropped_objects().
1356 * When the command finishes, the EventTriggerQueryState is cleared, and
1357 * the one from the previous command is restored (when no command is in
1358 * execution, the current state is NULL).
1360 * All this lets us support the case that an event trigger function drops
1361 * objects "reentrantly".
1365 * Register one object as being dropped by the current command.
1368 EventTriggerSQLDropAddObject(const ObjectAddress
*object
, bool original
, bool normal
)
1371 MemoryContext oldcxt
;
1373 if (!currentEventTriggerState
)
1376 Assert(EventTriggerSupportsObjectClass(getObjectClass(object
)));
1378 /* don't report temp schemas except my own */
1379 if (object
->classId
== NamespaceRelationId
&&
1380 (isAnyTempNamespace(object
->objectId
) &&
1381 !isTempNamespace(object
->objectId
)))
1384 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1386 obj
= palloc0(sizeof(SQLDropObject
));
1387 obj
->address
= *object
;
1388 obj
->original
= original
;
1389 obj
->normal
= normal
;
1392 * Obtain schema names from the object's catalog tuple, if one exists;
1393 * this lets us skip objects in temp schemas. We trust that
1394 * ObjectProperty contains all object classes that can be
1397 if (is_objectclass_supported(object
->classId
))
1402 catalog
= table_open(obj
->address
.classId
, AccessShareLock
);
1403 tuple
= get_catalog_object_by_oid(catalog
,
1404 get_object_attnum_oid(object
->classId
),
1405 obj
->address
.objectId
);
1413 attnum
= get_object_attnum_namespace(obj
->address
.classId
);
1414 if (attnum
!= InvalidAttrNumber
)
1416 datum
= heap_getattr(tuple
, attnum
,
1417 RelationGetDescr(catalog
), &isnull
);
1422 namespaceId
= DatumGetObjectId(datum
);
1423 /* temp objects are only reported if they are my own */
1424 if (isTempNamespace(namespaceId
))
1426 obj
->schemaname
= "pg_temp";
1429 else if (isAnyTempNamespace(namespaceId
))
1432 table_close(catalog
, AccessShareLock
);
1433 MemoryContextSwitchTo(oldcxt
);
1438 obj
->schemaname
= get_namespace_name(namespaceId
);
1439 obj
->istemp
= false;
1444 if (get_object_namensp_unique(obj
->address
.classId
) &&
1445 obj
->address
.objectSubId
== 0)
1447 attnum
= get_object_attnum_name(obj
->address
.classId
);
1448 if (attnum
!= InvalidAttrNumber
)
1450 datum
= heap_getattr(tuple
, attnum
,
1451 RelationGetDescr(catalog
), &isnull
);
1453 obj
->objname
= pstrdup(NameStr(*DatumGetName(datum
)));
1458 table_close(catalog
, AccessShareLock
);
1462 if (object
->classId
== NamespaceRelationId
&&
1463 isTempNamespace(object
->objectId
))
1467 /* object identity, objname and objargs */
1469 getObjectIdentityParts(&obj
->address
, &obj
->addrnames
, &obj
->addrargs
,
1473 obj
->objecttype
= getObjectTypeDescription(&obj
->address
, false);
1475 slist_push_head(&(currentEventTriggerState
->SQLDropList
), &obj
->next
);
1477 MemoryContextSwitchTo(oldcxt
);
1481 * pg_event_trigger_dropped_objects
1483 * Make the list of dropped objects available to the user function run by the
1487 pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS
)
1489 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
1493 * Protect this function from being called out of context
1495 if (!currentEventTriggerState
||
1496 !currentEventTriggerState
->in_sql_drop
)
1498 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED
),
1499 errmsg("%s can only be called in a sql_drop event trigger function",
1500 "pg_event_trigger_dropped_objects()")));
1502 /* Build tuplestore to hold the result rows */
1503 InitMaterializedSRF(fcinfo
, 0);
1505 slist_foreach(iter
, &(currentEventTriggerState
->SQLDropList
))
1509 Datum values
[12] = {0};
1510 bool nulls
[12] = {0};
1512 obj
= slist_container(SQLDropObject
, next
, iter
.cur
);
1515 values
[i
++] = ObjectIdGetDatum(obj
->address
.classId
);
1518 values
[i
++] = ObjectIdGetDatum(obj
->address
.objectId
);
1521 values
[i
++] = Int32GetDatum(obj
->address
.objectSubId
);
1524 values
[i
++] = BoolGetDatum(obj
->original
);
1527 values
[i
++] = BoolGetDatum(obj
->normal
);
1530 values
[i
++] = BoolGetDatum(obj
->istemp
);
1533 values
[i
++] = CStringGetTextDatum(obj
->objecttype
);
1536 if (obj
->schemaname
)
1537 values
[i
++] = CStringGetTextDatum(obj
->schemaname
);
1543 values
[i
++] = CStringGetTextDatum(obj
->objname
);
1547 /* object_identity */
1548 if (obj
->objidentity
)
1549 values
[i
++] = CStringGetTextDatum(obj
->objidentity
);
1553 /* address_names and address_args */
1556 values
[i
++] = PointerGetDatum(strlist_to_textarray(obj
->addrnames
));
1559 values
[i
++] = PointerGetDatum(strlist_to_textarray(obj
->addrargs
));
1561 values
[i
++] = PointerGetDatum(construct_empty_array(TEXTOID
));
1569 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
,
1577 * pg_event_trigger_table_rewrite_oid
1579 * Make the Oid of the table going to be rewritten available to the user
1580 * function run by the Event Trigger.
1583 pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS
)
1586 * Protect this function from being called out of context
1588 if (!currentEventTriggerState
||
1589 currentEventTriggerState
->table_rewrite_oid
== InvalidOid
)
1591 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED
),
1592 errmsg("%s can only be called in a table_rewrite event trigger function",
1593 "pg_event_trigger_table_rewrite_oid()")));
1595 PG_RETURN_OID(currentEventTriggerState
->table_rewrite_oid
);
1599 * pg_event_trigger_table_rewrite_reason
1601 * Make the rewrite reason available to the user.
1604 pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS
)
1607 * Protect this function from being called out of context
1609 if (!currentEventTriggerState
||
1610 currentEventTriggerState
->table_rewrite_reason
== 0)
1612 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED
),
1613 errmsg("%s can only be called in a table_rewrite event trigger function",
1614 "pg_event_trigger_table_rewrite_reason()")));
1616 PG_RETURN_INT32(currentEventTriggerState
->table_rewrite_reason
);
1619 /*-------------------------------------------------------------------------
1620 * Support for DDL command deparsing
1622 * The routines below enable an event trigger function to obtain a list of
1623 * DDL commands as they are executed. There are three main pieces to this
1626 * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1627 * adds a struct CollectedCommand representation of itself to the command list,
1628 * using the routines below.
1630 * 2) Some time after that, ddl_command_end fires and the command list is made
1631 * available to the event trigger function via pg_event_trigger_ddl_commands();
1632 * the complete command details are exposed as a column of type pg_ddl_command.
1634 * 3) An extension can install a function capable of taking a value of type
1635 * pg_ddl_command and transform it into some external, user-visible and/or
1636 * -modifiable representation.
1637 *-------------------------------------------------------------------------
1641 * Inhibit DDL command collection.
1644 EventTriggerInhibitCommandCollection(void)
1646 if (!currentEventTriggerState
)
1649 currentEventTriggerState
->commandCollectionInhibited
= true;
1653 * Re-establish DDL command collection.
1656 EventTriggerUndoInhibitCommandCollection(void)
1658 if (!currentEventTriggerState
)
1661 currentEventTriggerState
->commandCollectionInhibited
= false;
1665 * EventTriggerCollectSimpleCommand
1666 * Save data about a simple DDL command that was just executed
1668 * address identifies the object being operated on. secondaryObject is an
1669 * object address that was related in some way to the executed command; its
1670 * meaning is command-specific.
1672 * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1673 * object being moved, objectId is its OID, and secondaryOid is the OID of the
1674 * old schema. (The destination schema OID can be obtained by catalog lookup
1678 EventTriggerCollectSimpleCommand(ObjectAddress address
,
1679 ObjectAddress secondaryObject
,
1682 MemoryContext oldcxt
;
1683 CollectedCommand
*command
;
1685 /* ignore if event trigger context not set, or collection disabled */
1686 if (!currentEventTriggerState
||
1687 currentEventTriggerState
->commandCollectionInhibited
)
1690 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1692 command
= palloc(sizeof(CollectedCommand
));
1694 command
->type
= SCT_Simple
;
1695 command
->in_extension
= creating_extension
;
1697 command
->d
.simple
.address
= address
;
1698 command
->d
.simple
.secondaryObject
= secondaryObject
;
1699 command
->parsetree
= copyObject(parsetree
);
1701 currentEventTriggerState
->commandList
= lappend(currentEventTriggerState
->commandList
,
1704 MemoryContextSwitchTo(oldcxt
);
1708 * EventTriggerAlterTableStart
1709 * Prepare to receive data on an ALTER TABLE command about to be executed
1711 * Note we don't collect the command immediately; instead we keep it in
1712 * currentCommand, and only when we're done processing the subcommands we will
1713 * add it to the command list.
1716 EventTriggerAlterTableStart(Node
*parsetree
)
1718 MemoryContext oldcxt
;
1719 CollectedCommand
*command
;
1721 /* ignore if event trigger context not set, or collection disabled */
1722 if (!currentEventTriggerState
||
1723 currentEventTriggerState
->commandCollectionInhibited
)
1726 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1728 command
= palloc(sizeof(CollectedCommand
));
1730 command
->type
= SCT_AlterTable
;
1731 command
->in_extension
= creating_extension
;
1733 command
->d
.alterTable
.classId
= RelationRelationId
;
1734 command
->d
.alterTable
.objectId
= InvalidOid
;
1735 command
->d
.alterTable
.subcmds
= NIL
;
1736 command
->parsetree
= copyObject(parsetree
);
1738 command
->parent
= currentEventTriggerState
->currentCommand
;
1739 currentEventTriggerState
->currentCommand
= command
;
1741 MemoryContextSwitchTo(oldcxt
);
1745 * Remember the OID of the object being affected by an ALTER TABLE.
1747 * This is needed because in some cases we don't know the OID until later.
1750 EventTriggerAlterTableRelid(Oid objectId
)
1752 if (!currentEventTriggerState
||
1753 currentEventTriggerState
->commandCollectionInhibited
)
1756 currentEventTriggerState
->currentCommand
->d
.alterTable
.objectId
= objectId
;
1760 * EventTriggerCollectAlterTableSubcmd
1761 * Save data about a single part of an ALTER TABLE.
1763 * Several different commands go through this path, but apart from ALTER TABLE
1764 * itself, they are all concerned with AlterTableCmd nodes that are generated
1765 * internally, so that's all that this code needs to handle at the moment.
1768 EventTriggerCollectAlterTableSubcmd(Node
*subcmd
, ObjectAddress address
)
1770 MemoryContext oldcxt
;
1771 CollectedATSubcmd
*newsub
;
1773 /* ignore if event trigger context not set, or collection disabled */
1774 if (!currentEventTriggerState
||
1775 currentEventTriggerState
->commandCollectionInhibited
)
1778 Assert(IsA(subcmd
, AlterTableCmd
));
1779 Assert(currentEventTriggerState
->currentCommand
!= NULL
);
1780 Assert(OidIsValid(currentEventTriggerState
->currentCommand
->d
.alterTable
.objectId
));
1782 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1784 newsub
= palloc(sizeof(CollectedATSubcmd
));
1785 newsub
->address
= address
;
1786 newsub
->parsetree
= copyObject(subcmd
);
1788 currentEventTriggerState
->currentCommand
->d
.alterTable
.subcmds
=
1789 lappend(currentEventTriggerState
->currentCommand
->d
.alterTable
.subcmds
, newsub
);
1791 MemoryContextSwitchTo(oldcxt
);
1795 * EventTriggerAlterTableEnd
1796 * Finish up saving an ALTER TABLE command, and add it to command list.
1798 * FIXME this API isn't considering the possibility that an xact/subxact is
1799 * aborted partway through. Probably it's best to add an
1800 * AtEOSubXact_EventTriggers() to fix this.
1803 EventTriggerAlterTableEnd(void)
1805 CollectedCommand
*parent
;
1807 /* ignore if event trigger context not set, or collection disabled */
1808 if (!currentEventTriggerState
||
1809 currentEventTriggerState
->commandCollectionInhibited
)
1812 parent
= currentEventTriggerState
->currentCommand
->parent
;
1814 /* If no subcommands, don't collect */
1815 if (currentEventTriggerState
->currentCommand
->d
.alterTable
.subcmds
!= NIL
)
1817 MemoryContext oldcxt
;
1819 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1821 currentEventTriggerState
->commandList
=
1822 lappend(currentEventTriggerState
->commandList
,
1823 currentEventTriggerState
->currentCommand
);
1825 MemoryContextSwitchTo(oldcxt
);
1828 pfree(currentEventTriggerState
->currentCommand
);
1830 currentEventTriggerState
->currentCommand
= parent
;
1834 * EventTriggerCollectGrant
1835 * Save data about a GRANT/REVOKE command being executed
1837 * This function creates a copy of the InternalGrant, as the original might
1838 * not have the right lifetime.
1841 EventTriggerCollectGrant(InternalGrant
*istmt
)
1843 MemoryContext oldcxt
;
1844 CollectedCommand
*command
;
1845 InternalGrant
*icopy
;
1848 /* ignore if event trigger context not set, or collection disabled */
1849 if (!currentEventTriggerState
||
1850 currentEventTriggerState
->commandCollectionInhibited
)
1853 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1856 * This is tedious, but necessary.
1858 icopy
= palloc(sizeof(InternalGrant
));
1859 memcpy(icopy
, istmt
, sizeof(InternalGrant
));
1860 icopy
->objects
= list_copy(istmt
->objects
);
1861 icopy
->grantees
= list_copy(istmt
->grantees
);
1862 icopy
->col_privs
= NIL
;
1863 foreach(cell
, istmt
->col_privs
)
1864 icopy
->col_privs
= lappend(icopy
->col_privs
, copyObject(lfirst(cell
)));
1866 /* Now collect it, using the copied InternalGrant */
1867 command
= palloc(sizeof(CollectedCommand
));
1868 command
->type
= SCT_Grant
;
1869 command
->in_extension
= creating_extension
;
1870 command
->d
.grant
.istmt
= icopy
;
1871 command
->parsetree
= NULL
;
1873 currentEventTriggerState
->commandList
=
1874 lappend(currentEventTriggerState
->commandList
, command
);
1876 MemoryContextSwitchTo(oldcxt
);
1880 * EventTriggerCollectAlterOpFam
1881 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1885 EventTriggerCollectAlterOpFam(AlterOpFamilyStmt
*stmt
, Oid opfamoid
,
1886 List
*operators
, List
*procedures
)
1888 MemoryContext oldcxt
;
1889 CollectedCommand
*command
;
1891 /* ignore if event trigger context not set, or collection disabled */
1892 if (!currentEventTriggerState
||
1893 currentEventTriggerState
->commandCollectionInhibited
)
1896 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1898 command
= palloc(sizeof(CollectedCommand
));
1899 command
->type
= SCT_AlterOpFamily
;
1900 command
->in_extension
= creating_extension
;
1901 ObjectAddressSet(command
->d
.opfam
.address
,
1902 OperatorFamilyRelationId
, opfamoid
);
1903 command
->d
.opfam
.operators
= operators
;
1904 command
->d
.opfam
.procedures
= procedures
;
1905 command
->parsetree
= (Node
*) copyObject(stmt
);
1907 currentEventTriggerState
->commandList
=
1908 lappend(currentEventTriggerState
->commandList
, command
);
1910 MemoryContextSwitchTo(oldcxt
);
1914 * EventTriggerCollectCreateOpClass
1915 * Save data about a CREATE OPERATOR CLASS command being executed
1918 EventTriggerCollectCreateOpClass(CreateOpClassStmt
*stmt
, Oid opcoid
,
1919 List
*operators
, List
*procedures
)
1921 MemoryContext oldcxt
;
1922 CollectedCommand
*command
;
1924 /* ignore if event trigger context not set, or collection disabled */
1925 if (!currentEventTriggerState
||
1926 currentEventTriggerState
->commandCollectionInhibited
)
1929 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1931 command
= palloc0(sizeof(CollectedCommand
));
1932 command
->type
= SCT_CreateOpClass
;
1933 command
->in_extension
= creating_extension
;
1934 ObjectAddressSet(command
->d
.createopc
.address
,
1935 OperatorClassRelationId
, opcoid
);
1936 command
->d
.createopc
.operators
= operators
;
1937 command
->d
.createopc
.procedures
= procedures
;
1938 command
->parsetree
= (Node
*) copyObject(stmt
);
1940 currentEventTriggerState
->commandList
=
1941 lappend(currentEventTriggerState
->commandList
, command
);
1943 MemoryContextSwitchTo(oldcxt
);
1947 * EventTriggerCollectAlterTSConfig
1948 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1952 EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt
*stmt
, Oid cfgId
,
1953 Oid
*dictIds
, int ndicts
)
1955 MemoryContext oldcxt
;
1956 CollectedCommand
*command
;
1958 /* ignore if event trigger context not set, or collection disabled */
1959 if (!currentEventTriggerState
||
1960 currentEventTriggerState
->commandCollectionInhibited
)
1963 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1965 command
= palloc0(sizeof(CollectedCommand
));
1966 command
->type
= SCT_AlterTSConfig
;
1967 command
->in_extension
= creating_extension
;
1968 ObjectAddressSet(command
->d
.atscfg
.address
,
1969 TSConfigRelationId
, cfgId
);
1970 command
->d
.atscfg
.dictIds
= palloc(sizeof(Oid
) * ndicts
);
1971 memcpy(command
->d
.atscfg
.dictIds
, dictIds
, sizeof(Oid
) * ndicts
);
1972 command
->d
.atscfg
.ndicts
= ndicts
;
1973 command
->parsetree
= (Node
*) copyObject(stmt
);
1975 currentEventTriggerState
->commandList
=
1976 lappend(currentEventTriggerState
->commandList
, command
);
1978 MemoryContextSwitchTo(oldcxt
);
1982 * EventTriggerCollectAlterDefPrivs
1983 * Save data about an ALTER DEFAULT PRIVILEGES command being
1987 EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt
*stmt
)
1989 MemoryContext oldcxt
;
1990 CollectedCommand
*command
;
1992 /* ignore if event trigger context not set, or collection disabled */
1993 if (!currentEventTriggerState
||
1994 currentEventTriggerState
->commandCollectionInhibited
)
1997 oldcxt
= MemoryContextSwitchTo(currentEventTriggerState
->cxt
);
1999 command
= palloc0(sizeof(CollectedCommand
));
2000 command
->type
= SCT_AlterDefaultPrivileges
;
2001 command
->d
.defprivs
.objtype
= stmt
->action
->objtype
;
2002 command
->in_extension
= creating_extension
;
2003 command
->parsetree
= (Node
*) copyObject(stmt
);
2005 currentEventTriggerState
->commandList
=
2006 lappend(currentEventTriggerState
->commandList
, command
);
2007 MemoryContextSwitchTo(oldcxt
);
2011 * In a ddl_command_end event trigger, this function reports the DDL commands
2015 pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS
)
2017 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
2021 * Protect this function from being called out of context
2023 if (!currentEventTriggerState
)
2025 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED
),
2026 errmsg("%s can only be called in an event trigger function",
2027 "pg_event_trigger_ddl_commands()")));
2029 /* Build tuplestore to hold the result rows */
2030 InitMaterializedSRF(fcinfo
, 0);
2032 foreach(lc
, currentEventTriggerState
->commandList
)
2034 CollectedCommand
*cmd
= lfirst(lc
);
2036 bool nulls
[9] = {0};
2041 * For IF NOT EXISTS commands that attempt to create an existing
2042 * object, the returned OID is Invalid. Don't return anything.
2044 * One might think that a viable alternative would be to look up the
2045 * Oid of the existing object and run the deparse with that. But
2046 * since the parse tree might be different from the one that created
2047 * the object in the first place, we might not end up in a consistent
2050 if (cmd
->type
== SCT_Simple
&&
2051 !OidIsValid(cmd
->d
.simple
.address
.objectId
))
2057 case SCT_AlterTable
:
2058 case SCT_AlterOpFamily
:
2059 case SCT_CreateOpClass
:
2060 case SCT_AlterTSConfig
:
2064 char *schema
= NULL
;
2066 if (cmd
->type
== SCT_Simple
)
2067 addr
= cmd
->d
.simple
.address
;
2068 else if (cmd
->type
== SCT_AlterTable
)
2069 ObjectAddressSet(addr
,
2070 cmd
->d
.alterTable
.classId
,
2071 cmd
->d
.alterTable
.objectId
);
2072 else if (cmd
->type
== SCT_AlterOpFamily
)
2073 addr
= cmd
->d
.opfam
.address
;
2074 else if (cmd
->type
== SCT_CreateOpClass
)
2075 addr
= cmd
->d
.createopc
.address
;
2076 else if (cmd
->type
== SCT_AlterTSConfig
)
2077 addr
= cmd
->d
.atscfg
.address
;
2080 * If an object was dropped in the same command we may end
2081 * up in a situation where we generated a message but can
2082 * no longer look for the object information, so skip it
2083 * rather than failing. This can happen for example with
2084 * some subcommand combinations of ALTER TABLE.
2086 identity
= getObjectIdentity(&addr
, true);
2087 if (identity
== NULL
)
2090 /* The type can never be NULL. */
2091 type
= getObjectTypeDescription(&addr
, true);
2094 * Obtain schema name, if any ("pg_temp" if a temp
2095 * object). If the object class is not in the supported
2096 * list here, we assume it's a schema-less object type,
2097 * and thus "schema" remains set to NULL.
2099 if (is_objectclass_supported(addr
.classId
))
2101 AttrNumber nspAttnum
;
2103 nspAttnum
= get_object_attnum_namespace(addr
.classId
);
2104 if (nspAttnum
!= InvalidAttrNumber
)
2111 catalog
= table_open(addr
.classId
, AccessShareLock
);
2112 objtup
= get_catalog_object_by_oid(catalog
,
2113 get_object_attnum_oid(addr
.classId
),
2115 if (!HeapTupleIsValid(objtup
))
2116 elog(ERROR
, "cache lookup failed for object %u/%u",
2117 addr
.classId
, addr
.objectId
);
2119 heap_getattr(objtup
, nspAttnum
,
2120 RelationGetDescr(catalog
), &isnull
);
2123 "invalid null namespace in object %u/%u/%d",
2124 addr
.classId
, addr
.objectId
, addr
.objectSubId
);
2125 schema
= get_namespace_name_or_temp(schema_oid
);
2127 table_close(catalog
, AccessShareLock
);
2132 values
[i
++] = ObjectIdGetDatum(addr
.classId
);
2134 values
[i
++] = ObjectIdGetDatum(addr
.objectId
);
2136 values
[i
++] = Int32GetDatum(addr
.objectSubId
);
2138 values
[i
++] = CStringGetTextDatum(CreateCommandName(cmd
->parsetree
));
2140 values
[i
++] = CStringGetTextDatum(type
);
2145 values
[i
++] = CStringGetTextDatum(schema
);
2147 values
[i
++] = CStringGetTextDatum(identity
);
2149 values
[i
++] = BoolGetDatum(cmd
->in_extension
);
2151 values
[i
++] = PointerGetDatum(cmd
);
2155 case SCT_AlterDefaultPrivileges
:
2163 values
[i
++] = CStringGetTextDatum(CreateCommandName(cmd
->parsetree
));
2165 values
[i
++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd
->d
.defprivs
.objtype
));
2171 values
[i
++] = BoolGetDatum(cmd
->in_extension
);
2173 values
[i
++] = PointerGetDatum(cmd
);
2184 values
[i
++] = CStringGetTextDatum(cmd
->d
.grant
.istmt
->is_grant
?
2185 "GRANT" : "REVOKE");
2187 values
[i
++] = CStringGetTextDatum(stringify_grant_objtype(cmd
->d
.grant
.istmt
->objtype
));
2193 values
[i
++] = BoolGetDatum(cmd
->in_extension
);
2195 values
[i
++] = PointerGetDatum(cmd
);
2199 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
,
2207 * Return the ObjectType as a string, as it would appear in GRANT and
2211 stringify_grant_objtype(ObjectType objtype
)
2219 case OBJECT_SEQUENCE
:
2221 case OBJECT_DATABASE
:
2226 return "FOREIGN DATA WRAPPER";
2227 case OBJECT_FOREIGN_SERVER
:
2228 return "FOREIGN SERVER";
2229 case OBJECT_FUNCTION
:
2231 case OBJECT_LANGUAGE
:
2233 case OBJECT_LARGEOBJECT
:
2234 return "LARGE OBJECT";
2237 case OBJECT_PARAMETER_ACL
:
2239 case OBJECT_PROCEDURE
:
2241 case OBJECT_ROUTINE
:
2243 case OBJECT_TABLESPACE
:
2244 return "TABLESPACE";
2247 /* these currently aren't used */
2248 case OBJECT_ACCESS_METHOD
:
2249 case OBJECT_AGGREGATE
:
2252 case OBJECT_ATTRIBUTE
:
2254 case OBJECT_COLLATION
:
2255 case OBJECT_CONVERSION
:
2256 case OBJECT_DEFAULT
:
2258 case OBJECT_DOMCONSTRAINT
:
2259 case OBJECT_EVENT_TRIGGER
:
2260 case OBJECT_EXTENSION
:
2261 case OBJECT_FOREIGN_TABLE
:
2263 case OBJECT_MATVIEW
:
2264 case OBJECT_OPCLASS
:
2265 case OBJECT_OPERATOR
:
2266 case OBJECT_OPFAMILY
:
2268 case OBJECT_PUBLICATION
:
2269 case OBJECT_PUBLICATION_NAMESPACE
:
2270 case OBJECT_PUBLICATION_REL
:
2273 case OBJECT_STATISTIC_EXT
:
2274 case OBJECT_SUBSCRIPTION
:
2275 case OBJECT_TABCONSTRAINT
:
2276 case OBJECT_TRANSFORM
:
2277 case OBJECT_TRIGGER
:
2278 case OBJECT_TSCONFIGURATION
:
2279 case OBJECT_TSDICTIONARY
:
2280 case OBJECT_TSPARSER
:
2281 case OBJECT_TSTEMPLATE
:
2282 case OBJECT_USER_MAPPING
:
2284 elog(ERROR
, "unsupported object type: %d", (int) objtype
);
2287 return "???"; /* keep compiler quiet */
2291 * Return the ObjectType as a string; as above, but use the spelling
2292 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2296 stringify_adefprivs_objtype(ObjectType objtype
)
2304 case OBJECT_SEQUENCE
:
2306 case OBJECT_DATABASE
:
2311 return "FOREIGN DATA WRAPPERS";
2312 case OBJECT_FOREIGN_SERVER
:
2313 return "FOREIGN SERVERS";
2314 case OBJECT_FUNCTION
:
2316 case OBJECT_LANGUAGE
:
2318 case OBJECT_LARGEOBJECT
:
2319 return "LARGE OBJECTS";
2322 case OBJECT_PROCEDURE
:
2323 return "PROCEDURES";
2324 case OBJECT_ROUTINE
:
2326 case OBJECT_TABLESPACE
:
2327 return "TABLESPACES";
2330 /* these currently aren't used */
2331 case OBJECT_ACCESS_METHOD
:
2332 case OBJECT_AGGREGATE
:
2335 case OBJECT_ATTRIBUTE
:
2337 case OBJECT_COLLATION
:
2338 case OBJECT_CONVERSION
:
2339 case OBJECT_DEFAULT
:
2341 case OBJECT_DOMCONSTRAINT
:
2342 case OBJECT_EVENT_TRIGGER
:
2343 case OBJECT_EXTENSION
:
2344 case OBJECT_FOREIGN_TABLE
:
2346 case OBJECT_MATVIEW
:
2347 case OBJECT_OPCLASS
:
2348 case OBJECT_OPERATOR
:
2349 case OBJECT_OPFAMILY
:
2350 case OBJECT_PARAMETER_ACL
:
2352 case OBJECT_PUBLICATION
:
2353 case OBJECT_PUBLICATION_NAMESPACE
:
2354 case OBJECT_PUBLICATION_REL
:
2357 case OBJECT_STATISTIC_EXT
:
2358 case OBJECT_SUBSCRIPTION
:
2359 case OBJECT_TABCONSTRAINT
:
2360 case OBJECT_TRANSFORM
:
2361 case OBJECT_TRIGGER
:
2362 case OBJECT_TSCONFIGURATION
:
2363 case OBJECT_TSDICTIONARY
:
2364 case OBJECT_TSPARSER
:
2365 case OBJECT_TSTEMPLATE
:
2366 case OBJECT_USER_MAPPING
:
2368 elog(ERROR
, "unsupported object type: %d", (int) objtype
);
2371 return "???"; /* keep compiler quiet */