Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
event_trigger.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * event_trigger.c
4 * PostgreSQL EVENT TRIGGER support code.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/commands/event_trigger.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
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"
24#include "catalog/pg_attrdef.h"
25#include "catalog/pg_authid.h"
27#include "catalog/pg_database.h"
30#include "catalog/pg_opclass.h"
31#include "catalog/pg_opfamily.h"
33#include "catalog/pg_policy.h"
34#include "catalog/pg_proc.h"
36#include "catalog/pg_trigger.h"
38#include "catalog/pg_type.h"
40#include "commands/extension.h"
41#include "commands/trigger.h"
42#include "funcapi.h"
43#include "lib/ilist.h"
44#include "miscadmin.h"
45#include "parser/parse_func.h"
46#include "pgstat.h"
47#include "storage/lmgr.h"
49#include "tcop/utility.h"
50#include "utils/acl.h"
51#include "utils/builtins.h"
52#include "utils/evtcache.h"
53#include "utils/fmgroids.h"
54#include "utils/fmgrprotos.h"
55#include "utils/lsyscache.h"
56#include "utils/memutils.h"
57#include "utils/rel.h"
58#include "utils/snapmgr.h"
59#include "utils/syscache.h"
60
62{
63 /* memory context for this state's objects */
65
66 /* sql_drop */
69
70 /* table_rewrite */
71 Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite
72 * event */
73 int table_rewrite_reason; /* AT_REWRITE reason */
74
75 /* Support for command collection */
78 List *commandList; /* list of CollectedCommand; see
79 * deparse_utility.h */
82
84
85/* GUC parameter */
86bool event_triggers = true;
87
88/* Support for dropped objects */
89typedef struct SQLDropObject
90{
92 const char *schemaname;
93 const char *objname;
94 const char *objidentity;
95 const char *objecttype;
99 bool normal;
100 bool istemp;
103
105 HeapTuple tup,
106 Oid newOwnerId);
107static void error_duplicate_filter_variable(const char *defname);
108static Datum filter_list_to_array(List *filterlist);
109static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
110 Oid evtOwner, Oid funcoid, List *taglist);
111static void validate_ddl_tags(const char *filtervar, List *taglist);
112static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
113static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
114static bool obtain_object_name_namespace(const ObjectAddress *object,
115 SQLDropObject *obj);
116static const char *stringify_grant_objtype(ObjectType objtype);
117static const char *stringify_adefprivs_objtype(ObjectType objtype);
118static void SetDatabaseHasLoginEventTriggers(void);
119
120/*
121 * Create an event trigger.
122 */
123Oid
125{
126 HeapTuple tuple;
127 Oid funcoid;
128 Oid funcrettype;
129 Oid evtowner = GetUserId();
130 ListCell *lc;
131 List *tags = NULL;
132
133 /*
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.
137 */
138 if (!superuser())
140 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
141 errmsg("permission denied to create event trigger \"%s\"",
142 stmt->trigname),
143 errhint("Must be superuser to create an event trigger.")));
144
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\"",
154 stmt->eventname)));
155
156 /* Validate filter conditions. */
157 foreach(lc, stmt->whenclause)
158 {
159 DefElem *def = (DefElem *) lfirst(lc);
160
161 if (strcmp(def->defname, "tag") == 0)
162 {
163 if (tags != NULL)
165 tags = (List *) def->arg;
166 }
167 else
169 (errcode(ERRCODE_SYNTAX_ERROR),
170 errmsg("unrecognized filter variable \"%s\"", def->defname)));
171 }
172
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)
177 && tags != NULL)
178 validate_ddl_tags("tag", tags);
179 else if (strcmp(stmt->eventname, "table_rewrite") == 0
180 && tags != NULL)
181 validate_table_rewrite_tags("tag", tags);
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")));
186
187 /*
188 * Give user a nice error message if an event trigger of the same name
189 * already exists.
190 */
191 tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
192 if (HeapTupleIsValid(tuple))
195 errmsg("event trigger \"%s\" already exists",
196 stmt->trigname)));
197
198 /* Find and validate the trigger function. */
199 funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
200 funcrettype = get_func_rettype(funcoid);
201 if (funcrettype != EVENT_TRIGGEROID)
203 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
204 errmsg("function %s must return type %s",
205 NameListToString(stmt->funcname), "event_trigger")));
206
207 /* Insert catalog entries. */
208 return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
209 evtowner, funcoid, tags);
210}
211
212/*
213 * Validate DDL command tags.
214 */
215static void
216validate_ddl_tags(const char *filtervar, List *taglist)
217{
218 ListCell *lc;
219
220 foreach(lc, taglist)
221 {
222 const char *tagstr = strVal(lfirst(lc));
223 CommandTag commandTag = GetCommandTagEnum(tagstr);
224
225 if (commandTag == CMDTAG_UNKNOWN)
227 (errcode(ERRCODE_SYNTAX_ERROR),
228 errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
229 tagstr, filtervar)));
230 if (!command_tag_event_trigger_ok(commandTag))
232 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
233 /* translator: %s represents an SQL statement name */
234 errmsg("event triggers are not supported for %s",
235 tagstr)));
236 }
237}
238
239/*
240 * Validate DDL command tags for event table_rewrite.
241 */
242static void
243validate_table_rewrite_tags(const char *filtervar, List *taglist)
244{
245 ListCell *lc;
246
247 foreach(lc, taglist)
248 {
249 const char *tagstr = strVal(lfirst(lc));
250 CommandTag commandTag = GetCommandTagEnum(tagstr);
251
252 if (!command_tag_table_rewrite_ok(commandTag))
254 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
255 /* translator: %s represents an SQL statement name */
256 errmsg("event triggers are not supported for %s",
257 tagstr)));
258 }
259}
260
261/*
262 * Complain about a duplicate filter variable.
263 */
264static void
266{
268 (errcode(ERRCODE_SYNTAX_ERROR),
269 errmsg("filter variable \"%s\" specified more than once",
270 defname)));
271}
272
273/*
274 * Insert the new pg_event_trigger row and record dependencies.
275 */
276static Oid
277insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
278 Oid funcoid, List *taglist)
279{
280 Relation tgrel;
281 Oid trigoid;
282 HeapTuple tuple;
283 Datum values[Natts_pg_event_trigger];
284 bool nulls[Natts_pg_event_trigger];
285 NameData evtnamedata,
286 evteventdata;
287 ObjectAddress myself,
288 referenced;
289
290 /* Open pg_event_trigger. */
291 tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
292
293 /* Build the new pg_trigger tuple. */
294 trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId,
295 Anum_pg_event_trigger_oid);
296 values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
297 memset(nulls, false, sizeof(nulls));
298 namestrcpy(&evtnamedata, trigname);
299 values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
300 namestrcpy(&evteventdata, eventname);
301 values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
302 values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
303 values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
304 values[Anum_pg_event_trigger_evtenabled - 1] =
306 if (taglist == NIL)
307 nulls[Anum_pg_event_trigger_evttags - 1] = true;
308 else
309 values[Anum_pg_event_trigger_evttags - 1] =
310 filter_list_to_array(taglist);
311
312 /* Insert heap tuple. */
313 tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
314 CatalogTupleInsert(tgrel, tuple);
315 heap_freetuple(tuple);
316
317 /*
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.
320 */
321 if (strcmp(eventname, "login") == 0)
323
324 /* Depend on owner. */
325 recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
326
327 /* Depend on event trigger function. */
328 myself.classId = EventTriggerRelationId;
329 myself.objectId = trigoid;
330 myself.objectSubId = 0;
331 referenced.classId = ProcedureRelationId;
332 referenced.objectId = funcoid;
333 referenced.objectSubId = 0;
334 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
335
336 /* Depend on extension, if any. */
338
339 /* Post creation hook for new event trigger */
340 InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
341
342 /* Close pg_event_trigger. */
344
345 return trigoid;
346}
347
348/*
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.
353 *
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.
358 */
359static Datum
361{
362 ListCell *lc;
363 Datum *data;
364 int i = 0,
365 l = list_length(filterlist);
366
367 data = (Datum *) palloc(l * sizeof(Datum));
368
369 foreach(lc, filterlist)
370 {
371 const char *value = strVal(lfirst(lc));
372 char *result,
373 *p;
374
375 result = pstrdup(value);
376 for (p = result; *p; p++)
377 *p = pg_ascii_toupper((unsigned char) *p);
379 pfree(result);
380 }
381
382 return PointerGetDatum(construct_array_builtin(data, l, TEXTOID));
383}
384
385/*
386 * Set pg_database.dathasloginevt flag for current database indicating that
387 * current database has on login event triggers.
388 */
389void
391{
392 /* Set dathasloginevt flag in pg_database */
394 Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock);
395 ItemPointerData otid;
396 HeapTuple tuple;
397
398 /*
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.
404 */
405 LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, AccessExclusiveLock);
406
408 if (!HeapTupleIsValid(tuple))
409 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
410 otid = tuple->t_self;
411 db = (Form_pg_database) GETSTRUCT(tuple);
412 if (!db->dathasloginevt)
413 {
414 db->dathasloginevt = true;
415 CatalogTupleUpdate(pg_db, &otid, tuple);
417 }
418 UnlockTuple(pg_db, &otid, InplaceUpdateTupleLock);
420 heap_freetuple(tuple);
421}
422
423/*
424 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
425 */
426Oid
428{
429 Relation tgrel;
430 HeapTuple tup;
431 Oid trigoid;
432 Form_pg_event_trigger evtForm;
433 char tgenabled = stmt->tgenabled;
434
435 tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
436
437 tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
438 CStringGetDatum(stmt->trigname));
439 if (!HeapTupleIsValid(tup))
441 (errcode(ERRCODE_UNDEFINED_OBJECT),
442 errmsg("event trigger \"%s\" does not exist",
443 stmt->trigname)));
444
445 evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
446 trigoid = evtForm->oid;
447
448 if (!object_ownercheck(EventTriggerRelationId, trigoid, GetUserId()))
450 stmt->trigname);
451
452 /* tuple is a copy, so we can modify it below */
453 evtForm->evtenabled = tgenabled;
454
455 CatalogTupleUpdate(tgrel, &tup->t_self, tup);
456
457 /*
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.
460 */
461 if (namestrcmp(&evtForm->evtevent, "login") == 0 &&
462 tgenabled != TRIGGER_DISABLED)
464
465 InvokeObjectPostAlterHook(EventTriggerRelationId,
466 trigoid, 0);
467
468 /* clean up */
469 heap_freetuple(tup);
471
472 return trigoid;
473}
474
475/*
476 * Change event trigger's owner -- by name
477 */
479AlterEventTriggerOwner(const char *name, Oid newOwnerId)
480{
481 Oid evtOid;
482 HeapTuple tup;
483 Form_pg_event_trigger evtForm;
484 Relation rel;
485 ObjectAddress address;
486
487 rel = table_open(EventTriggerRelationId, RowExclusiveLock);
488
489 tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
490
491 if (!HeapTupleIsValid(tup))
493 (errcode(ERRCODE_UNDEFINED_OBJECT),
494 errmsg("event trigger \"%s\" does not exist", name)));
495
496 evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
497 evtOid = evtForm->oid;
498
499 AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
500
501 ObjectAddressSet(address, EventTriggerRelationId, evtOid);
502
503 heap_freetuple(tup);
504
506
507 return address;
508}
509
510/*
511 * Change event trigger owner, by OID
512 */
513void
515{
516 HeapTuple tup;
517 Relation rel;
518
519 rel = table_open(EventTriggerRelationId, RowExclusiveLock);
520
521 tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
522
523 if (!HeapTupleIsValid(tup))
525 (errcode(ERRCODE_UNDEFINED_OBJECT),
526 errmsg("event trigger with OID %u does not exist", trigOid)));
527
528 AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
529
530 heap_freetuple(tup);
531
533}
534
535/*
536 * Internal workhorse for changing an event trigger's owner
537 */
538static void
540{
542
543 form = (Form_pg_event_trigger) GETSTRUCT(tup);
544
545 if (form->evtowner == newOwnerId)
546 return;
547
548 if (!object_ownercheck(EventTriggerRelationId, form->oid, GetUserId()))
550 NameStr(form->evtname));
551
552 /* New owner must be a superuser */
553 if (!superuser_arg(newOwnerId))
555 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
556 errmsg("permission denied to change owner of event trigger \"%s\"",
557 NameStr(form->evtname)),
558 errhint("The owner of an event trigger must be a superuser.")));
559
560 form->evtowner = newOwnerId;
561 CatalogTupleUpdate(rel, &tup->t_self, tup);
562
563 /* Update owner dependency reference */
564 changeDependencyOnOwner(EventTriggerRelationId,
565 form->oid,
566 newOwnerId);
567
568 InvokeObjectPostAlterHook(EventTriggerRelationId,
569 form->oid, 0);
570}
571
572/*
573 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
574 *
575 * If missing_ok is false, throw an error if trigger not found. If
576 * true, just return InvalidOid.
577 */
578Oid
579get_event_trigger_oid(const char *trigname, bool missing_ok)
580{
581 Oid oid;
582
583 oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
584 CStringGetDatum(trigname));
585 if (!OidIsValid(oid) && !missing_ok)
587 (errcode(ERRCODE_UNDEFINED_OBJECT),
588 errmsg("event trigger \"%s\" does not exist", trigname)));
589 return oid;
590}
591
592/*
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
595 * tags matching.
596 */
597static bool
599{
600 /*
601 * Filter by session replication role, knowing that we never see disabled
602 * items down here.
603 */
605 {
606 if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
607 return false;
608 }
609 else
610 {
612 return false;
613 }
614
615 /* Filter by tags, if any were specified. */
616 if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
617 return false;
618
619 /* if we reach that point, we're not filtering out this item */
620 return true;
621}
622
623static CommandTag
625{
626 if (event == EVT_Login)
627 return CMDTAG_LOGIN;
628 else
629 return CreateCommandTag(parsetree);
630}
631
632/*
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.
636 */
637static List *
639 EventTriggerEvent event, const char *eventstr,
640 EventTriggerData *trigdata, bool unfiltered)
641{
642 CommandTag tag;
643 List *cachelist;
644 ListCell *lc;
645 List *runlist = NIL;
646
647 /*
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.)
655 *
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.
660 */
661#ifdef USE_ASSERT_CHECKING
662 {
663 CommandTag dbgtag;
664
665 dbgtag = EventTriggerGetTag(parsetree, event);
666
667 if (event == EVT_DDLCommandStart ||
668 event == EVT_DDLCommandEnd ||
669 event == EVT_SQLDrop ||
670 event == EVT_Login)
671 {
672 if (!command_tag_event_trigger_ok(dbgtag))
673 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
674 }
675 else if (event == EVT_TableRewrite)
676 {
677 if (!command_tag_table_rewrite_ok(dbgtag))
678 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
679 }
680 }
681#endif
682
683 /* Use cache to find triggers for this event; fast exit if none. */
684 cachelist = EventCacheLookup(event);
685 if (cachelist == NIL)
686 return NIL;
687
688 /* Get the command tag. */
689 tag = EventTriggerGetTag(parsetree, event);
690
691 /*
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
696 * can do much else.
697 */
698 foreach(lc, cachelist)
699 {
700 EventTriggerCacheItem *item = lfirst(lc);
701
702 if (unfiltered || filter_event_trigger(tag, item))
703 {
704 /* We must plan to fire this trigger. */
705 runlist = lappend_oid(runlist, item->fnoid);
706 }
707 }
708
709 /* Don't spend any more time on this if no functions to run */
710 if (runlist == NIL)
711 return NIL;
712
713 trigdata->type = T_EventTriggerData;
714 trigdata->event = eventstr;
715 trigdata->parsetree = parsetree;
716 trigdata->tag = tag;
717
718 return runlist;
719}
720
721/*
722 * Fire ddl_command_start triggers.
723 */
724void
726{
727 List *runlist;
728 EventTriggerData trigdata;
729
730 /*
731 * Event Triggers are completely disabled in standalone mode. There are
732 * (at least) two reasons for this:
733 *
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
737 * hatch.
738 *
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.)
745 *
746 * Additionally, event triggers can be disabled with a superuser-only GUC
747 * to make fixing database easier as per 1 above.
748 */
750 return;
751
752 runlist = EventTriggerCommonSetup(parsetree,
754 "ddl_command_start",
755 &trigdata, false);
756 if (runlist == NIL)
757 return;
758
759 /* Run the triggers. */
760 EventTriggerInvoke(runlist, &trigdata);
761
762 /* Cleanup. */
763 list_free(runlist);
764
765 /*
766 * Make sure anything the event triggers did will be visible to the main
767 * command.
768 */
770}
771
772/*
773 * Fire ddl_command_end triggers.
774 */
775void
777{
778 List *runlist;
779 EventTriggerData trigdata;
780
781 /*
782 * See EventTriggerDDLCommandStart for a discussion about why event
783 * triggers are disabled in single user mode or via GUC.
784 */
786 return;
787
788 /*
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.
797 */
799 return;
800
801 runlist = EventTriggerCommonSetup(parsetree,
802 EVT_DDLCommandEnd, "ddl_command_end",
803 &trigdata, false);
804 if (runlist == NIL)
805 return;
806
807 /*
808 * Make sure anything the main command did will be visible to the event
809 * triggers.
810 */
812
813 /* Run the triggers. */
814 EventTriggerInvoke(runlist, &trigdata);
815
816 /* Cleanup. */
817 list_free(runlist);
818}
819
820/*
821 * Fire sql_drop triggers.
822 */
823void
825{
826 List *runlist;
827 EventTriggerData trigdata;
828
829 /*
830 * See EventTriggerDDLCommandStart for a discussion about why event
831 * triggers are disabled in single user mode or via a GUC.
832 */
834 return;
835
836 /*
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
841 * be empty.
842 */
845 return;
846
847 runlist = EventTriggerCommonSetup(parsetree,
848 EVT_SQLDrop, "sql_drop",
849 &trigdata, false);
850
851 /*
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.
856 */
857 if (runlist == NIL)
858 return;
859
860 /*
861 * Make sure anything the main command did will be visible to the event
862 * triggers.
863 */
865
866 /*
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
871 * play safe.)
872 */
874
875 /* Run the triggers. */
876 PG_TRY();
877 {
878 EventTriggerInvoke(runlist, &trigdata);
879 }
880 PG_FINALLY();
881 {
883 }
884 PG_END_TRY();
885
886 /* Cleanup. */
887 list_free(runlist);
888}
889
890/*
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.
895 */
896void
898{
899 List *runlist;
900 EventTriggerData trigdata;
901
902 /*
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).
906 */
909 return;
910
912 runlist = EventTriggerCommonSetup(NULL,
913 EVT_Login, "login",
914 &trigdata, false);
915
916 if (runlist != NIL)
917 {
918 /*
919 * Event trigger execution may require an active snapshot.
920 */
922
923 /* Run the triggers. */
924 EventTriggerInvoke(runlist, &trigdata);
925
926 /* Cleanup. */
927 list_free(runlist);
928
930 }
931
932 /*
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.
938 */
939 else if (ConditionalLockSharedObject(DatabaseRelationId, MyDatabaseId,
941 {
942 /*
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*.
947 */
948 runlist = EventTriggerCommonSetup(NULL,
949 EVT_Login, "login",
950 &trigdata, true);
951
952 if (runlist == NIL)
953 {
954 Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock);
955 HeapTuple tuple;
956 void *state;
958 ScanKeyData key[1];
959
960 /* Fetch a copy of the tuple to scribble on */
961 ScanKeyInit(&key[0],
962 Anum_pg_database_oid,
963 BTEqualStrategyNumber, F_OIDEQ,
965
966 systable_inplace_update_begin(pg_db, DatabaseOidIndexId, true,
967 NULL, 1, key, &tuple, &state);
968
969 if (!HeapTupleIsValid(tuple))
970 elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
971
972 db = (Form_pg_database) GETSTRUCT(tuple);
973 if (db->dathasloginevt)
974 {
975 db->dathasloginevt = false;
976
977 /*
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.
982 */
984 }
985 else
988 heap_freetuple(tuple);
989 }
990 else
991 {
992 list_free(runlist);
993 }
994 }
996}
997
998
999/*
1000 * Fire table_rewrite triggers.
1001 */
1002void
1003EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
1004{
1005 List *runlist;
1006 EventTriggerData trigdata;
1007
1008 /*
1009 * See EventTriggerDDLCommandStart for a discussion about why event
1010 * triggers are disabled in single user mode or via a GUC.
1011 */
1013 return;
1014
1015 /*
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.
1021 */
1023 return;
1024
1025 runlist = EventTriggerCommonSetup(parsetree,
1027 "table_rewrite",
1028 &trigdata, false);
1029 if (runlist == NIL)
1030 return;
1031
1032 /*
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.)
1038 */
1041
1042 /* Run the triggers. */
1043 PG_TRY();
1044 {
1045 EventTriggerInvoke(runlist, &trigdata);
1046 }
1047 PG_FINALLY();
1048 {
1051 }
1052 PG_END_TRY();
1053
1054 /* Cleanup. */
1055 list_free(runlist);
1056
1057 /*
1058 * Make sure anything the event triggers did will be visible to the main
1059 * command.
1060 */
1062}
1063
1064/*
1065 * Invoke each event trigger in a list of event triggers.
1066 */
1067static void
1069{
1070 MemoryContext context;
1071 MemoryContext oldcontext;
1072 ListCell *lc;
1073 bool first = true;
1074
1075 /* Guard against stack overflow due to recursive event trigger */
1077
1078 /*
1079 * Let's evaluate event triggers in their own memory context, so that any
1080 * leaks get cleaned up promptly.
1081 */
1083 "event trigger context",
1085 oldcontext = MemoryContextSwitchTo(context);
1086
1087 /* Call each event trigger. */
1088 foreach(lc, fn_oid_list)
1089 {
1090 LOCAL_FCINFO(fcinfo, 0);
1091 Oid fnoid = lfirst_oid(lc);
1092 FmgrInfo flinfo;
1094
1095 elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
1096
1097 /*
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.
1102 */
1103 if (first)
1104 first = false;
1105 else
1107
1108 /* Look up the function */
1109 fmgr_info(fnoid, &flinfo);
1110
1111 /* Call the function, passing no arguments but setting a context. */
1112 InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
1113 InvalidOid, (Node *) trigdata, NULL);
1114 pgstat_init_function_usage(fcinfo, &fcusage);
1115 FunctionCallInvoke(fcinfo);
1116 pgstat_end_function_usage(&fcusage, true);
1117
1118 /* Reclaim memory. */
1119 MemoryContextReset(context);
1120 }
1121
1122 /* Restore old memory context and delete the temporary one. */
1123 MemoryContextSwitchTo(oldcontext);
1124 MemoryContextDelete(context);
1125}
1126
1127/*
1128 * Do event triggers support this object type?
1129 *
1130 * See also event trigger documentation in event-trigger.sgml.
1131 */
1132bool
1134{
1135 switch (obtype)
1136 {
1137 case OBJECT_DATABASE:
1138 case OBJECT_TABLESPACE:
1139 case OBJECT_ROLE:
1141 /* no support for global objects (except subscriptions) */
1142 return false;
1144 /* no support for event triggers on event triggers */
1145 return false;
1146 default:
1147 return true;
1148 }
1149}
1150
1151/*
1152 * Do event triggers support this object class?
1153 *
1154 * See also event trigger documentation in event-trigger.sgml.
1155 */
1156bool
1158{
1159 switch (object->classId)
1160 {
1161 case DatabaseRelationId:
1162 case TableSpaceRelationId:
1163 case AuthIdRelationId:
1164 case AuthMemRelationId:
1165 case ParameterAclRelationId:
1166 /* no support for global objects (except subscriptions) */
1167 return false;
1168 case EventTriggerRelationId:
1169 /* no support for event triggers on event triggers */
1170 return false;
1171 default:
1172 return true;
1173 }
1174}
1175
1176/*
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.
1181 */
1182bool
1184{
1186 MemoryContext cxt;
1187
1188 /*
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
1191 * install one.
1192 */
1194 return false;
1195
1197 "event trigger state",
1200 state->cxt = cxt;
1201 slist_init(&(state->SQLDropList));
1202 state->in_sql_drop = false;
1203 state->table_rewrite_oid = InvalidOid;
1204
1205 state->commandCollectionInhibited = currentEventTriggerState ?
1207 state->currentCommand = NULL;
1208 state->commandList = NIL;
1209 state->previous = currentEventTriggerState;
1211
1212 return true;
1213}
1214
1215/*
1216 * Query completed (or errored out) -- clean up local state, return to previous
1217 * one.
1218 *
1219 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1220 * returned false previously.
1221 *
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.)
1225 */
1226void
1228{
1229 EventTriggerQueryState *prevstate;
1230
1232
1233 /* this avoids the need for retail pfree of SQLDropList items: */
1235
1236 currentEventTriggerState = prevstate;
1237}
1238
1239/*
1240 * Do we need to keep close track of objects being dropped?
1241 *
1242 * This is useful because there is a cost to running with them enabled.
1243 */
1244bool
1246{
1247 /*
1248 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1249 * exists
1250 */
1251 return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
1254}
1255
1256/*
1257 * Support for dropped objects information on event trigger functions.
1258 *
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).
1268 *
1269 * All this lets us support the case that an event trigger function drops
1270 * objects "reentrantly".
1271 */
1272
1273/*
1274 * Register one object as being dropped by the current command.
1275 */
1276void
1277EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1278{
1279 SQLDropObject *obj;
1280 MemoryContext oldcxt;
1281
1283 return;
1284
1286
1288
1289 obj = palloc0(sizeof(SQLDropObject));
1290 obj->address = *object;
1291 obj->original = original;
1292 obj->normal = normal;
1293
1294 if (object->classId == NamespaceRelationId)
1295 {
1296 /* Special handling is needed for temp namespaces */
1297 if (isTempNamespace(object->objectId))
1298 obj->istemp = true;
1299 else if (isAnyTempNamespace(object->objectId))
1300 {
1301 /* don't report temp schemas except my own */
1302 pfree(obj);
1303 MemoryContextSwitchTo(oldcxt);
1304 return;
1305 }
1306 obj->objname = get_namespace_name(object->objectId);
1307 }
1308 else if (object->classId == AttrDefaultRelationId)
1309 {
1310 /* We treat a column default as temp if its table is temp */
1311 ObjectAddress colobject;
1312
1313 colobject = GetAttrDefaultColumnAddress(object->objectId);
1314 if (OidIsValid(colobject.objectId))
1315 {
1316 if (!obtain_object_name_namespace(&colobject, obj))
1317 {
1318 pfree(obj);
1319 MemoryContextSwitchTo(oldcxt);
1320 return;
1321 }
1322 }
1323 }
1324 else if (object->classId == TriggerRelationId)
1325 {
1326 /* Similarly, a trigger is temp if its table is temp */
1327 /* Sadly, there's no lsyscache.c support for trigger objects */
1328 Relation pg_trigger_rel;
1329 ScanKeyData skey[1];
1330 SysScanDesc sscan;
1331 HeapTuple tuple;
1332 Oid relid;
1333
1334 /* Fetch the trigger's table OID the hard way */
1335 pg_trigger_rel = table_open(TriggerRelationId, AccessShareLock);
1336 ScanKeyInit(&skey[0],
1337 Anum_pg_trigger_oid,
1338 BTEqualStrategyNumber, F_OIDEQ,
1339 ObjectIdGetDatum(object->objectId));
1340 sscan = systable_beginscan(pg_trigger_rel, TriggerOidIndexId, true,
1341 NULL, 1, skey);
1342 tuple = systable_getnext(sscan);
1343 if (HeapTupleIsValid(tuple))
1344 relid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid;
1345 else
1346 relid = InvalidOid; /* shouldn't happen */
1347 systable_endscan(sscan);
1348 table_close(pg_trigger_rel, AccessShareLock);
1349 /* Do nothing if we didn't find the trigger */
1350 if (OidIsValid(relid))
1351 {
1352 ObjectAddress relobject;
1353
1354 relobject.classId = RelationRelationId;
1355 relobject.objectId = relid;
1356 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1357 relobject.objectSubId = 1;
1358 if (!obtain_object_name_namespace(&relobject, obj))
1359 {
1360 pfree(obj);
1361 MemoryContextSwitchTo(oldcxt);
1362 return;
1363 }
1364 }
1365 }
1366 else if (object->classId == PolicyRelationId)
1367 {
1368 /* Similarly, a policy is temp if its table is temp */
1369 /* Sadly, there's no lsyscache.c support for policy objects */
1370 Relation pg_policy_rel;
1371 ScanKeyData skey[1];
1372 SysScanDesc sscan;
1373 HeapTuple tuple;
1374 Oid relid;
1375
1376 /* Fetch the policy's table OID the hard way */
1377 pg_policy_rel = table_open(PolicyRelationId, AccessShareLock);
1378 ScanKeyInit(&skey[0],
1379 Anum_pg_policy_oid,
1380 BTEqualStrategyNumber, F_OIDEQ,
1381 ObjectIdGetDatum(object->objectId));
1382 sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
1383 NULL, 1, skey);
1384 tuple = systable_getnext(sscan);
1385 if (HeapTupleIsValid(tuple))
1386 relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
1387 else
1388 relid = InvalidOid; /* shouldn't happen */
1389 systable_endscan(sscan);
1390 table_close(pg_policy_rel, AccessShareLock);
1391 /* Do nothing if we didn't find the policy */
1392 if (OidIsValid(relid))
1393 {
1394 ObjectAddress relobject;
1395
1396 relobject.classId = RelationRelationId;
1397 relobject.objectId = relid;
1398 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1399 relobject.objectSubId = 1;
1400 if (!obtain_object_name_namespace(&relobject, obj))
1401 {
1402 pfree(obj);
1403 MemoryContextSwitchTo(oldcxt);
1404 return;
1405 }
1406 }
1407 }
1408 else
1409 {
1410 /* Generic handling for all other object classes */
1411 if (!obtain_object_name_namespace(object, obj))
1412 {
1413 /* don't report temp objects except my own */
1414 pfree(obj);
1415 MemoryContextSwitchTo(oldcxt);
1416 return;
1417 }
1418 }
1419
1420 /* object identity, objname and objargs */
1421 obj->objidentity =
1423 false);
1424
1425 /* object type */
1426 obj->objecttype = getObjectTypeDescription(&obj->address, false);
1427
1429
1430 MemoryContextSwitchTo(oldcxt);
1431}
1432
1433/*
1434 * Fill obj->objname, obj->schemaname, and obj->istemp based on object.
1435 *
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.
1438 */
1439static bool
1441{
1442 /*
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
1446 * schema-qualified.
1447 *
1448 * Currently, this function does nothing for object classes that are not
1449 * in ObjectProperty, but we might sometime add special cases for that.
1450 */
1451 if (is_objectclass_supported(object->classId))
1452 {
1453 Relation catalog;
1454 HeapTuple tuple;
1455
1456 catalog = table_open(object->classId, AccessShareLock);
1457 tuple = get_catalog_object_by_oid(catalog,
1459 object->objectId);
1460
1461 if (tuple)
1462 {
1464 Datum datum;
1465 bool isnull;
1466
1469 {
1470 datum = heap_getattr(tuple, attnum,
1471 RelationGetDescr(catalog), &isnull);
1472 if (!isnull)
1473 {
1474 Oid namespaceId;
1475
1476 namespaceId = DatumGetObjectId(datum);
1477 /* temp objects are only reported if they are my own */
1478 if (isTempNamespace(namespaceId))
1479 {
1480 obj->schemaname = "pg_temp";
1481 obj->istemp = true;
1482 }
1483 else if (isAnyTempNamespace(namespaceId))
1484 {
1485 /* no need to fill any fields of *obj */
1486 table_close(catalog, AccessShareLock);
1487 return false;
1488 }
1489 else
1490 {
1491 obj->schemaname = get_namespace_name(namespaceId);
1492 obj->istemp = false;
1493 }
1494 }
1495 }
1496
1497 if (get_object_namensp_unique(object->classId) &&
1498 object->objectSubId == 0)
1499 {
1502 {
1503 datum = heap_getattr(tuple, attnum,
1504 RelationGetDescr(catalog), &isnull);
1505 if (!isnull)
1506 obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1507 }
1508 }
1509 }
1510
1511 table_close(catalog, AccessShareLock);
1512 }
1513
1514 return true;
1515}
1516
1517/*
1518 * pg_event_trigger_dropped_objects
1519 *
1520 * Make the list of dropped objects available to the user function run by the
1521 * Event Trigger.
1522 */
1523Datum
1525{
1526 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1527 slist_iter iter;
1528
1529 /*
1530 * Protect this function from being called out of context
1531 */
1534 ereport(ERROR,
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()")));
1538
1539 /* Build tuplestore to hold the result rows */
1540 InitMaterializedSRF(fcinfo, 0);
1541
1543 {
1544 SQLDropObject *obj;
1545 int i = 0;
1546 Datum values[12] = {0};
1547 bool nulls[12] = {0};
1548
1549 obj = slist_container(SQLDropObject, next, iter.cur);
1550
1551 /* classid */
1553
1554 /* objid */
1556
1557 /* objsubid */
1559
1560 /* original */
1561 values[i++] = BoolGetDatum(obj->original);
1562
1563 /* normal */
1564 values[i++] = BoolGetDatum(obj->normal);
1565
1566 /* is_temporary */
1567 values[i++] = BoolGetDatum(obj->istemp);
1568
1569 /* object_type */
1571
1572 /* schema_name */
1573 if (obj->schemaname)
1575 else
1576 nulls[i++] = true;
1577
1578 /* object_name */
1579 if (obj->objname)
1581 else
1582 nulls[i++] = true;
1583
1584 /* object_identity */
1585 if (obj->objidentity)
1587 else
1588 nulls[i++] = true;
1589
1590 /* address_names and address_args */
1591 if (obj->addrnames)
1592 {
1594
1595 if (obj->addrargs)
1597 else
1599 }
1600 else
1601 {
1602 nulls[i++] = true;
1603 nulls[i++] = true;
1604 }
1605
1606 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1607 values, nulls);
1608 }
1609
1610 return (Datum) 0;
1611}
1612
1613/*
1614 * pg_event_trigger_table_rewrite_oid
1615 *
1616 * Make the Oid of the table going to be rewritten available to the user
1617 * function run by the Event Trigger.
1618 */
1619Datum
1621{
1622 /*
1623 * Protect this function from being called out of context
1624 */
1627 ereport(ERROR,
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()")));
1631
1633}
1634
1635/*
1636 * pg_event_trigger_table_rewrite_reason
1637 *
1638 * Make the rewrite reason available to the user.
1639 */
1640Datum
1642{
1643 /*
1644 * Protect this function from being called out of context
1645 */
1648 ereport(ERROR,
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()")));
1652
1654}
1655
1656/*-------------------------------------------------------------------------
1657 * Support for DDL command deparsing
1658 *
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
1661 * feature:
1662 *
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.
1666 *
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.
1670 *
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 *-------------------------------------------------------------------------
1675 */
1676
1677/*
1678 * Inhibit DDL command collection.
1679 */
1680void
1682{
1684 return;
1685
1687}
1688
1689/*
1690 * Re-establish DDL command collection.
1691 */
1692void
1694{
1696 return;
1697
1699}
1700
1701/*
1702 * EventTriggerCollectSimpleCommand
1703 * Save data about a simple DDL command that was just executed
1704 *
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.
1708 *
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
1712 * of the object.)
1713 */
1714void
1716 ObjectAddress secondaryObject,
1717 Node *parsetree)
1718{
1719 MemoryContext oldcxt;
1720 CollectedCommand *command;
1721
1722 /* ignore if event trigger context not set, or collection disabled */
1725 return;
1726
1728
1729 command = palloc(sizeof(CollectedCommand));
1730
1731 command->type = SCT_Simple;
1733
1734 command->d.simple.address = address;
1735 command->d.simple.secondaryObject = secondaryObject;
1736 command->parsetree = copyObject(parsetree);
1737
1739 command);
1740
1741 MemoryContextSwitchTo(oldcxt);
1742}
1743
1744/*
1745 * EventTriggerAlterTableStart
1746 * Prepare to receive data on an ALTER TABLE command about to be executed
1747 *
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.
1751 */
1752void
1754{
1755 MemoryContext oldcxt;
1756 CollectedCommand *command;
1757
1758 /* ignore if event trigger context not set, or collection disabled */
1761 return;
1762
1764
1765 command = palloc(sizeof(CollectedCommand));
1766
1767 command->type = SCT_AlterTable;
1769
1770 command->d.alterTable.classId = RelationRelationId;
1771 command->d.alterTable.objectId = InvalidOid;
1772 command->d.alterTable.subcmds = NIL;
1773 command->parsetree = copyObject(parsetree);
1774
1777
1778 MemoryContextSwitchTo(oldcxt);
1779}
1780
1781/*
1782 * Remember the OID of the object being affected by an ALTER TABLE.
1783 *
1784 * This is needed because in some cases we don't know the OID until later.
1785 */
1786void
1788{
1791 return;
1792
1794}
1795
1796/*
1797 * EventTriggerCollectAlterTableSubcmd
1798 * Save data about a single part of an ALTER TABLE.
1799 *
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.
1803 */
1804void
1806{
1807 MemoryContext oldcxt;
1809
1810 /* ignore if event trigger context not set, or collection disabled */
1813 return;
1814
1815 Assert(IsA(subcmd, AlterTableCmd));
1818
1820
1821 newsub = palloc(sizeof(CollectedATSubcmd));
1822 newsub->address = address;
1823 newsub->parsetree = copyObject(subcmd);
1824
1827
1828 MemoryContextSwitchTo(oldcxt);
1829}
1830
1831/*
1832 * EventTriggerAlterTableEnd
1833 * Finish up saving an ALTER TABLE command, and add it to command list.
1834 *
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.
1838 */
1839void
1841{
1842 CollectedCommand *parent;
1843
1844 /* ignore if event trigger context not set, or collection disabled */
1847 return;
1848
1850
1851 /* If no subcommands, don't collect */
1853 {
1854 MemoryContext oldcxt;
1855
1857
1861
1862 MemoryContextSwitchTo(oldcxt);
1863 }
1864 else
1866
1868}
1869
1870/*
1871 * EventTriggerCollectGrant
1872 * Save data about a GRANT/REVOKE command being executed
1873 *
1874 * This function creates a copy of the InternalGrant, as the original might
1875 * not have the right lifetime.
1876 */
1877void
1879{
1880 MemoryContext oldcxt;
1881 CollectedCommand *command;
1882 InternalGrant *icopy;
1883 ListCell *cell;
1884
1885 /* ignore if event trigger context not set, or collection disabled */
1888 return;
1889
1891
1892 /*
1893 * This is tedious, but necessary.
1894 */
1895 icopy = palloc(sizeof(InternalGrant));
1896 memcpy(icopy, istmt, sizeof(InternalGrant));
1897 icopy->objects = list_copy(istmt->objects);
1898 icopy->grantees = list_copy(istmt->grantees);
1899 icopy->col_privs = NIL;
1900 foreach(cell, istmt->col_privs)
1901 icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1902
1903 /* Now collect it, using the copied InternalGrant */
1904 command = palloc(sizeof(CollectedCommand));
1905 command->type = SCT_Grant;
1907 command->d.grant.istmt = icopy;
1908 command->parsetree = NULL;
1909
1912
1913 MemoryContextSwitchTo(oldcxt);
1914}
1915
1916/*
1917 * EventTriggerCollectAlterOpFam
1918 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1919 * executed
1920 */
1921void
1923 List *operators, List *procedures)
1924{
1925 MemoryContext oldcxt;
1926 CollectedCommand *command;
1927
1928 /* ignore if event trigger context not set, or collection disabled */
1931 return;
1932
1934
1935 command = palloc(sizeof(CollectedCommand));
1936 command->type = SCT_AlterOpFamily;
1939 OperatorFamilyRelationId, opfamoid);
1940 command->d.opfam.operators = operators;
1941 command->d.opfam.procedures = procedures;
1942 command->parsetree = (Node *) copyObject(stmt);
1943
1946
1947 MemoryContextSwitchTo(oldcxt);
1948}
1949
1950/*
1951 * EventTriggerCollectCreateOpClass
1952 * Save data about a CREATE OPERATOR CLASS command being executed
1953 */
1954void
1956 List *operators, List *procedures)
1957{
1958 MemoryContext oldcxt;
1959 CollectedCommand *command;
1960
1961 /* ignore if event trigger context not set, or collection disabled */
1964 return;
1965
1967
1968 command = palloc0(sizeof(CollectedCommand));
1969 command->type = SCT_CreateOpClass;
1972 OperatorClassRelationId, opcoid);
1973 command->d.createopc.operators = operators;
1974 command->d.createopc.procedures = procedures;
1975 command->parsetree = (Node *) copyObject(stmt);
1976
1979
1980 MemoryContextSwitchTo(oldcxt);
1981}
1982
1983/*
1984 * EventTriggerCollectAlterTSConfig
1985 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1986 * executed
1987 */
1988void
1990 Oid *dictIds, int ndicts)
1991{
1992 MemoryContext oldcxt;
1993 CollectedCommand *command;
1994
1995 /* ignore if event trigger context not set, or collection disabled */
1998 return;
1999
2001
2002 command = palloc0(sizeof(CollectedCommand));
2003 command->type = SCT_AlterTSConfig;
2006 TSConfigRelationId, cfgId);
2007 command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
2008 memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
2009 command->d.atscfg.ndicts = ndicts;
2010 command->parsetree = (Node *) copyObject(stmt);
2011
2014
2015 MemoryContextSwitchTo(oldcxt);
2016}
2017
2018/*
2019 * EventTriggerCollectAlterDefPrivs
2020 * Save data about an ALTER DEFAULT PRIVILEGES command being
2021 * executed
2022 */
2023void
2025{
2026 MemoryContext oldcxt;
2027 CollectedCommand *command;
2028
2029 /* ignore if event trigger context not set, or collection disabled */
2032 return;
2033
2035
2036 command = palloc0(sizeof(CollectedCommand));
2038 command->d.defprivs.objtype = stmt->action->objtype;
2040 command->parsetree = (Node *) copyObject(stmt);
2041
2044 MemoryContextSwitchTo(oldcxt);
2045}
2046
2047/*
2048 * In a ddl_command_end event trigger, this function reports the DDL commands
2049 * being run.
2050 */
2051Datum
2053{
2054 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2055 ListCell *lc;
2056
2057 /*
2058 * Protect this function from being called out of context
2059 */
2061 ereport(ERROR,
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()")));
2065
2066 /* Build tuplestore to hold the result rows */
2067 InitMaterializedSRF(fcinfo, 0);
2068
2070 {
2071 CollectedCommand *cmd = lfirst(lc);
2072 Datum values[9];
2073 bool nulls[9] = {0};
2074 ObjectAddress addr;
2075 int i = 0;
2076
2077 /*
2078 * For IF NOT EXISTS commands that attempt to create an existing
2079 * object, the returned OID is Invalid. Don't return anything.
2080 *
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
2085 * state anyway.
2086 */
2087 if (cmd->type == SCT_Simple &&
2089 continue;
2090
2091 switch (cmd->type)
2092 {
2093 case SCT_Simple:
2094 case SCT_AlterTable:
2095 case SCT_AlterOpFamily:
2096 case SCT_CreateOpClass:
2097 case SCT_AlterTSConfig:
2098 {
2099 char *identity;
2100 char *type;
2101 char *schema = NULL;
2102
2103 if (cmd->type == SCT_Simple)
2104 addr = cmd->d.simple.address;
2105 else if (cmd->type == SCT_AlterTable)
2106 ObjectAddressSet(addr,
2107 cmd->d.alterTable.classId,
2108 cmd->d.alterTable.objectId);
2109 else if (cmd->type == SCT_AlterOpFamily)
2110 addr = cmd->d.opfam.address;
2111 else if (cmd->type == SCT_CreateOpClass)
2112 addr = cmd->d.createopc.address;
2113 else if (cmd->type == SCT_AlterTSConfig)
2114 addr = cmd->d.atscfg.address;
2115
2116 /*
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.
2122 */
2123 identity = getObjectIdentity(&addr, true);
2124 if (identity == NULL)
2125 continue;
2126
2127 /* The type can never be NULL. */
2128 type = getObjectTypeDescription(&addr, true);
2129
2130 /*
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.
2135 */
2137 {
2138 AttrNumber nspAttnum;
2139
2140 nspAttnum = get_object_attnum_namespace(addr.classId);
2141 if (nspAttnum != InvalidAttrNumber)
2142 {
2143 Relation catalog;
2144 HeapTuple objtup;
2145 Oid schema_oid;
2146 bool isnull;
2147
2148 catalog = table_open(addr.classId, AccessShareLock);
2149 objtup = get_catalog_object_by_oid(catalog,
2151 addr.objectId);
2152 if (!HeapTupleIsValid(objtup))
2153 elog(ERROR, "cache lookup failed for object %u/%u",
2154 addr.classId, addr.objectId);
2155 schema_oid =
2156 DatumGetObjectId(heap_getattr(objtup, nspAttnum,
2157 RelationGetDescr(catalog), &isnull));
2158 if (isnull)
2159 elog(ERROR,
2160 "invalid null namespace in object %u/%u/%d",
2161 addr.classId, addr.objectId, addr.objectSubId);
2162 schema = get_namespace_name_or_temp(schema_oid);
2163
2164 table_close(catalog, AccessShareLock);
2165 }
2166 }
2167
2168 /* classid */
2169 values[i++] = ObjectIdGetDatum(addr.classId);
2170 /* objid */
2171 values[i++] = ObjectIdGetDatum(addr.objectId);
2172 /* objsubid */
2173 values[i++] = Int32GetDatum(addr.objectSubId);
2174 /* command tag */
2176 /* object_type */
2178 /* schema */
2179 if (schema == NULL)
2180 nulls[i++] = true;
2181 else
2182 values[i++] = CStringGetTextDatum(schema);
2183 /* identity */
2184 values[i++] = CStringGetTextDatum(identity);
2185 /* in_extension */
2186 values[i++] = BoolGetDatum(cmd->in_extension);
2187 /* command */
2188 values[i++] = PointerGetDatum(cmd);
2189 }
2190 break;
2191
2193 /* classid */
2194 nulls[i++] = true;
2195 /* objid */
2196 nulls[i++] = true;
2197 /* objsubid */
2198 nulls[i++] = true;
2199 /* command tag */
2201 /* object_type */
2203 /* schema */
2204 nulls[i++] = true;
2205 /* identity */
2206 nulls[i++] = true;
2207 /* in_extension */
2208 values[i++] = BoolGetDatum(cmd->in_extension);
2209 /* command */
2210 values[i++] = PointerGetDatum(cmd);
2211 break;
2212
2213 case SCT_Grant:
2214 /* classid */
2215 nulls[i++] = true;
2216 /* objid */
2217 nulls[i++] = true;
2218 /* objsubid */
2219 nulls[i++] = true;
2220 /* command tag */
2222 "GRANT" : "REVOKE");
2223 /* object_type */
2225 /* schema */
2226 nulls[i++] = true;
2227 /* identity */
2228 nulls[i++] = true;
2229 /* in_extension */
2230 values[i++] = BoolGetDatum(cmd->in_extension);
2231 /* command */
2232 values[i++] = PointerGetDatum(cmd);
2233 break;
2234 }
2235
2236 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2237 values, nulls);
2238 }
2239
2241}
2242
2243/*
2244 * Return the ObjectType as a string, as it would appear in GRANT and
2245 * REVOKE commands.
2246 */
2247static const char *
2249{
2250 switch (objtype)
2251 {
2252 case OBJECT_COLUMN:
2253 return "COLUMN";
2254 case OBJECT_TABLE:
2255 return "TABLE";
2256 case OBJECT_SEQUENCE:
2257 return "SEQUENCE";
2258 case OBJECT_DATABASE:
2259 return "DATABASE";
2260 case OBJECT_DOMAIN:
2261 return "DOMAIN";
2262 case OBJECT_FDW:
2263 return "FOREIGN DATA WRAPPER";
2265 return "FOREIGN SERVER";
2266 case OBJECT_FUNCTION:
2267 return "FUNCTION";
2268 case OBJECT_LANGUAGE:
2269 return "LANGUAGE";
2270 case OBJECT_LARGEOBJECT:
2271 return "LARGE OBJECT";
2272 case OBJECT_SCHEMA:
2273 return "SCHEMA";
2275 return "PARAMETER";
2276 case OBJECT_PROCEDURE:
2277 return "PROCEDURE";
2278 case OBJECT_ROUTINE:
2279 return "ROUTINE";
2280 case OBJECT_TABLESPACE:
2281 return "TABLESPACE";
2282 case OBJECT_TYPE:
2283 return "TYPE";
2284 /* these currently aren't used */
2286 case OBJECT_AGGREGATE:
2287 case OBJECT_AMOP:
2288 case OBJECT_AMPROC:
2289 case OBJECT_ATTRIBUTE:
2290 case OBJECT_CAST:
2291 case OBJECT_COLLATION:
2292 case OBJECT_CONVERSION:
2293 case OBJECT_DEFAULT:
2294 case OBJECT_DEFACL:
2297 case OBJECT_EXTENSION:
2299 case OBJECT_INDEX:
2300 case OBJECT_MATVIEW:
2301 case OBJECT_OPCLASS:
2302 case OBJECT_OPERATOR:
2303 case OBJECT_OPFAMILY:
2304 case OBJECT_POLICY:
2305 case OBJECT_PUBLICATION:
2308 case OBJECT_ROLE:
2309 case OBJECT_RULE:
2313 case OBJECT_TRANSFORM:
2314 case OBJECT_TRIGGER:
2317 case OBJECT_TSPARSER:
2318 case OBJECT_TSTEMPLATE:
2320 case OBJECT_VIEW:
2321 elog(ERROR, "unsupported object type: %d", (int) objtype);
2322 }
2323
2324 return "???"; /* keep compiler quiet */
2325}
2326
2327/*
2328 * Return the ObjectType as a string; as above, but use the spelling
2329 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2330 * the plural.
2331 */
2332static const char *
2334{
2335 switch (objtype)
2336 {
2337 case OBJECT_COLUMN:
2338 return "COLUMNS";
2339 case OBJECT_TABLE:
2340 return "TABLES";
2341 case OBJECT_SEQUENCE:
2342 return "SEQUENCES";
2343 case OBJECT_DATABASE:
2344 return "DATABASES";
2345 case OBJECT_DOMAIN:
2346 return "DOMAINS";
2347 case OBJECT_FDW:
2348 return "FOREIGN DATA WRAPPERS";
2350 return "FOREIGN SERVERS";
2351 case OBJECT_FUNCTION:
2352 return "FUNCTIONS";
2353 case OBJECT_LANGUAGE:
2354 return "LANGUAGES";
2355 case OBJECT_LARGEOBJECT:
2356 return "LARGE OBJECTS";
2357 case OBJECT_SCHEMA:
2358 return "SCHEMAS";
2359 case OBJECT_PROCEDURE:
2360 return "PROCEDURES";
2361 case OBJECT_ROUTINE:
2362 return "ROUTINES";
2363 case OBJECT_TABLESPACE:
2364 return "TABLESPACES";
2365 case OBJECT_TYPE:
2366 return "TYPES";
2367 /* these currently aren't used */
2369 case OBJECT_AGGREGATE:
2370 case OBJECT_AMOP:
2371 case OBJECT_AMPROC:
2372 case OBJECT_ATTRIBUTE:
2373 case OBJECT_CAST:
2374 case OBJECT_COLLATION:
2375 case OBJECT_CONVERSION:
2376 case OBJECT_DEFAULT:
2377 case OBJECT_DEFACL:
2380 case OBJECT_EXTENSION:
2382 case OBJECT_INDEX:
2383 case OBJECT_MATVIEW:
2384 case OBJECT_OPCLASS:
2385 case OBJECT_OPERATOR:
2386 case OBJECT_OPFAMILY:
2388 case OBJECT_POLICY:
2389 case OBJECT_PUBLICATION:
2392 case OBJECT_ROLE:
2393 case OBJECT_RULE:
2397 case OBJECT_TRANSFORM:
2398 case OBJECT_TRIGGER:
2401 case OBJECT_TSPARSER:
2402 case OBJECT_TSTEMPLATE:
2404 case OBJECT_VIEW:
2405 elog(ERROR, "unsupported object type: %d", (int) objtype);
2406 }
2407
2408 return "???"; /* keep compiler quiet */
2409}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4088
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3580
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
#define bms_is_empty(a)
Definition: bitmapset.h:118
static int32 next
Definition: blutils.c:224
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:752
#define OidIsValid(objectId)
Definition: c.h:775
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:47
CommandTag GetCommandTagEnum(const char *commandname)
Definition: cmdtag.c:83
bool command_tag_event_trigger_ok(CommandTag commandTag)
Definition: cmdtag.c:66
bool command_tag_table_rewrite_ok(CommandTag commandTag)
Definition: cmdtag.c:72
CommandTag
Definition: cmdtag.h:23
@ SCT_Simple
@ SCT_AlterTSConfig
@ SCT_AlterDefaultPrivileges
@ SCT_Grant
@ SCT_CreateOpClass
@ SCT_AlterOpFamily
@ SCT_AlterTable
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define PG_FINALLY(...)
Definition: elog.h:389
#define ereport(elevel,...)
Definition: elog.h:150
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
Definition: event_trigger.c:83
struct SQLDropObject SQLDropObject
void EventTriggerAlterTableEnd(void)
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
bool event_triggers
Definition: event_trigger.c:86
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)
Definition: evtcache.c:63
EventTriggerEvent
Definition: evtcache.h:21
@ EVT_SQLDrop
Definition: evtcache.h:24
@ EVT_Login
Definition: evtcache.h:26
@ EVT_DDLCommandEnd
Definition: evtcache.h:23
@ EVT_DDLCommandStart
Definition: evtcache.h:22
@ EVT_TableRewrite
Definition: evtcache.h:25
bool creating_extension
Definition: extension.c:77
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
void systable_inplace_update_cancel(void *state)
Definition: genam.c:902
void systable_inplace_update_begin(Relation relation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, const ScanKeyData *key, HeapTuple *oldtupcopy, void **state)
Definition: genam.c:807
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition: genam.c:883
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
bool MyDatabaseHasLoginEventTriggers
Definition: globals.c:98
bool IsUnderPostmaster
Definition: globals.c:120
Oid MyDatabaseId
Definition: globals.c:94
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
static void slist_init(slist_head *head)
Definition: ilist.h:986
static bool slist_is_empty(const slist_head *head)
Definition: ilist.h:995
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:1006
#define slist_container(type, membername, ptr)
Definition: ilist.h:1106
#define slist_foreach(iter, lhead)
Definition: ilist.h:1132
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static struct @166 value
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void list_free(List *list)
Definition: list.c:1546
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition: lmgr.c:601
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1088
bool ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1112
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3557
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1822
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void * palloc(Size size)
Definition: mcxt.c:1365
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
Oid GetUserId(void)
Definition: miscinit.c:469
int namestrcmp(Name name, const char *str)
Definition: name.c:247
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char * NameListToString(const List *names)
Definition: namespace.c:3661
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3716
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3754
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define copyObject(obj)
Definition: nodes.h:232
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
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)
Definition: objectaddress.h:40
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2260
ObjectType
Definition: parsenodes.h:2321
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2336
@ OBJECT_FDW
Definition: parsenodes.h:2338
@ OBJECT_TSPARSER
Definition: parsenodes.h:2369
@ OBJECT_COLLATION
Definition: parsenodes.h:2329
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2372
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2322
@ OBJECT_OPCLASS
Definition: parsenodes.h:2346
@ OBJECT_DEFACL
Definition: parsenodes.h:2333
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2323
@ OBJECT_MATVIEW
Definition: parsenodes.h:2345
@ OBJECT_SCHEMA
Definition: parsenodes.h:2358
@ OBJECT_POLICY
Definition: parsenodes.h:2350
@ OBJECT_OPERATOR
Definition: parsenodes.h:2347
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2340
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2367
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2348
@ OBJECT_DOMAIN
Definition: parsenodes.h:2334
@ OBJECT_COLUMN
Definition: parsenodes.h:2328
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2364
@ OBJECT_ROLE
Definition: parsenodes.h:2355
@ OBJECT_ROUTINE
Definition: parsenodes.h:2356
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2344
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2353
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2351
@ OBJECT_EXTENSION
Definition: parsenodes.h:2337
@ OBJECT_INDEX
Definition: parsenodes.h:2342
@ OBJECT_DEFAULT
Definition: parsenodes.h:2332
@ OBJECT_DATABASE
Definition: parsenodes.h:2331
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2359
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2370
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2343
@ OBJECT_AMOP
Definition: parsenodes.h:2324
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2354
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2339
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2368
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2326
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2352
@ OBJECT_RULE
Definition: parsenodes.h:2357
@ OBJECT_CONVERSION
Definition: parsenodes.h:2330
@ OBJECT_AMPROC
Definition: parsenodes.h:2325
@ OBJECT_TABLE
Definition: parsenodes.h:2363
@ OBJECT_VIEW
Definition: parsenodes.h:2373
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2349
@ OBJECT_TYPE
Definition: parsenodes.h:2371
@ OBJECT_FUNCTION
Definition: parsenodes.h:2341
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2362
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2335
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2360
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2361
@ OBJECT_CAST
Definition: parsenodes.h:2327
@ OBJECT_TRIGGER
Definition: parsenodes.h:2366
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2365
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition: pg_attrdef.c:320
int16 attnum
Definition: pg_attribute.h:74
const void * data
FormData_pg_database * Form_pg_database
Definition: pg_database.h:96
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
FormData_pg_event_trigger * Form_pg_event_trigger
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_policy * Form_pg_policy
Definition: pg_policy.h:51
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
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)
Definition: pgstrcasecmp.c:135
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Name DatumGetName(Datum X)
Definition: postgres.h:370
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:383
uint64_t Datum
Definition: postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
static Datum CharGetDatum(char X)
Definition: postgres.h:132
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
static color newsub(struct colormap *cm, color co)
Definition: regc_color.c:389
#define RelationGetDescr(relation)
Definition: rel.h:540
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:271
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:680
void PopActiveSnapshot(void)
Definition: snapmgr.c:773
void check_stack_depth(void)
Definition: stack_depth.c:95
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
struct CollectedCommand::@129::@130 simple
CollectedCommandType type
struct CollectedCommand::@129::@134 createopc
union CollectedCommand::@129 d
struct CollectedCommand::@129::@131 alterTable
InternalGrant * istmt
struct CollectedCommand::@129::@133 opfam
struct CollectedCommand::@129::@132 grant
struct CollectedCommand::@129::@135 atscfg
struct CollectedCommand * parent
ObjectAddress secondaryObject
struct CollectedCommand::@129::@136 defprivs
ObjectAddress address
char * defname
Definition: parsenodes.h:841
Node * arg
Definition: parsenodes.h:842
Bitmapset * tagset
Definition: evtcache.h:33
CommandTag tag
Definition: event_trigger.h:29
const char * event
Definition: event_trigger.h:27
struct EventTriggerQueryState * previous
Definition: event_trigger.c:80
CollectedCommand * currentCommand
Definition: event_trigger.c:77
Definition: fmgr.h:57
ItemPointerData t_self
Definition: htup.h:65
ObjectType objtype
Definition: pg_list.h:54
Definition: nodes.h:135
TupleDesc rd_att
Definition: rel.h:112
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
ObjectAddress address
Definition: event_trigger.c:91
const char * schemaname
Definition: event_trigger.c:92
slist_node next
const char * objidentity
Definition: event_trigger.c:94
const char * objecttype
Definition: event_trigger.c:95
List * addrnames
Definition: event_trigger.c:96
const char * objname
Definition: event_trigger.c:93
Definition: c.h:747
Definition: regguts.h:323
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:399
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
int SessionReplicationRole
Definition: trigger.c:63
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:141
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149
#define TRIGGER_DISABLED
Definition: trigger.h:152
#define TRIGGER_FIRES_ON_REPLICA
Definition: trigger.h:151
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2354
static const char * CreateCommandName(Node *parsetree)
Definition: utility.h:103
#define strVal(v)
Definition: value.h:82
text * cstring_to_text(const char *s)
Definition: varlena.c:181
const char * type
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1100
void StartTransactionCommand(void)
Definition: xact.c:3071
void CommitTransactionCommand(void)
Definition: xact.c:3169