PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2024, 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_authid.h"
26#include "catalog/pg_database.h"
29#include "catalog/pg_opclass.h"
30#include "catalog/pg_opfamily.h"
32#include "catalog/pg_proc.h"
34#include "catalog/pg_trigger.h"
36#include "catalog/pg_type.h"
38#include "commands/extension.h"
39#include "commands/trigger.h"
40#include "funcapi.h"
41#include "lib/ilist.h"
42#include "miscadmin.h"
43#include "parser/parse_func.h"
44#include "pgstat.h"
45#include "storage/lmgr.h"
47#include "tcop/utility.h"
48#include "utils/acl.h"
49#include "utils/builtins.h"
50#include "utils/evtcache.h"
51#include "utils/fmgroids.h"
52#include "utils/fmgrprotos.h"
53#include "utils/lsyscache.h"
54#include "utils/memutils.h"
55#include "utils/rel.h"
56#include "utils/snapmgr.h"
57#include "utils/syscache.h"
58
60{
61 /* memory context for this state's objects */
63
64 /* sql_drop */
67
68 /* table_rewrite */
69 Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite
70 * event */
71 int table_rewrite_reason; /* AT_REWRITE reason */
72
73 /* Support for command collection */
76 List *commandList; /* list of CollectedCommand; see
77 * deparse_utility.h */
80
82
83/* GUC parameter */
84bool event_triggers = true;
85
86/* Support for dropped objects */
87typedef struct SQLDropObject
88{
90 const char *schemaname;
91 const char *objname;
92 const char *objidentity;
93 const char *objecttype;
97 bool normal;
98 bool istemp;
101
103 HeapTuple tup,
104 Oid newOwnerId);
105static void error_duplicate_filter_variable(const char *defname);
106static Datum filter_list_to_array(List *filterlist);
107static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
108 Oid evtOwner, Oid funcoid, List *taglist);
109static void validate_ddl_tags(const char *filtervar, List *taglist);
110static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
111static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
112static const char *stringify_grant_objtype(ObjectType objtype);
113static const char *stringify_adefprivs_objtype(ObjectType objtype);
114static void SetDatabaseHasLoginEventTriggers(void);
115
116/*
117 * Create an event trigger.
118 */
119Oid
121{
122 HeapTuple tuple;
123 Oid funcoid;
124 Oid funcrettype;
125 Oid evtowner = GetUserId();
126 ListCell *lc;
127 List *tags = NULL;
128
129 /*
130 * It would be nice to allow database owners or even regular users to do
131 * this, but there are obvious privilege escalation risks which would have
132 * to somehow be plugged first.
133 */
134 if (!superuser())
136 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
137 errmsg("permission denied to create event trigger \"%s\"",
138 stmt->trigname),
139 errhint("Must be superuser to create an event trigger.")));
140
141 /* Validate event name. */
142 if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
143 strcmp(stmt->eventname, "ddl_command_end") != 0 &&
144 strcmp(stmt->eventname, "sql_drop") != 0 &&
145 strcmp(stmt->eventname, "login") != 0 &&
146 strcmp(stmt->eventname, "table_rewrite") != 0)
148 (errcode(ERRCODE_SYNTAX_ERROR),
149 errmsg("unrecognized event name \"%s\"",
150 stmt->eventname)));
151
152 /* Validate filter conditions. */
153 foreach(lc, stmt->whenclause)
154 {
155 DefElem *def = (DefElem *) lfirst(lc);
156
157 if (strcmp(def->defname, "tag") == 0)
158 {
159 if (tags != NULL)
161 tags = (List *) def->arg;
162 }
163 else
165 (errcode(ERRCODE_SYNTAX_ERROR),
166 errmsg("unrecognized filter variable \"%s\"", def->defname)));
167 }
168
169 /* Validate tag list, if any. */
170 if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
171 strcmp(stmt->eventname, "ddl_command_end") == 0 ||
172 strcmp(stmt->eventname, "sql_drop") == 0)
173 && tags != NULL)
174 validate_ddl_tags("tag", tags);
175 else if (strcmp(stmt->eventname, "table_rewrite") == 0
176 && tags != NULL)
177 validate_table_rewrite_tags("tag", tags);
178 else if (strcmp(stmt->eventname, "login") == 0 && tags != NULL)
180 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
181 errmsg("tag filtering is not supported for login event triggers")));
182
183 /*
184 * Give user a nice error message if an event trigger of the same name
185 * already exists.
186 */
187 tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
188 if (HeapTupleIsValid(tuple))
191 errmsg("event trigger \"%s\" already exists",
192 stmt->trigname)));
193
194 /* Find and validate the trigger function. */
195 funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
196 funcrettype = get_func_rettype(funcoid);
197 if (funcrettype != EVENT_TRIGGEROID)
199 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
200 errmsg("function %s must return type %s",
201 NameListToString(stmt->funcname), "event_trigger")));
202
203 /* Insert catalog entries. */
204 return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
205 evtowner, funcoid, tags);
206}
207
208/*
209 * Validate DDL command tags.
210 */
211static void
212validate_ddl_tags(const char *filtervar, List *taglist)
213{
214 ListCell *lc;
215
216 foreach(lc, taglist)
217 {
218 const char *tagstr = strVal(lfirst(lc));
219 CommandTag commandTag = GetCommandTagEnum(tagstr);
220
221 if (commandTag == CMDTAG_UNKNOWN)
223 (errcode(ERRCODE_SYNTAX_ERROR),
224 errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
225 tagstr, filtervar)));
226 if (!command_tag_event_trigger_ok(commandTag))
228 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
229 /* translator: %s represents an SQL statement name */
230 errmsg("event triggers are not supported for %s",
231 tagstr)));
232 }
233}
234
235/*
236 * Validate DDL command tags for event table_rewrite.
237 */
238static void
239validate_table_rewrite_tags(const char *filtervar, List *taglist)
240{
241 ListCell *lc;
242
243 foreach(lc, taglist)
244 {
245 const char *tagstr = strVal(lfirst(lc));
246 CommandTag commandTag = GetCommandTagEnum(tagstr);
247
248 if (!command_tag_table_rewrite_ok(commandTag))
250 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
251 /* translator: %s represents an SQL statement name */
252 errmsg("event triggers are not supported for %s",
253 tagstr)));
254 }
255}
256
257/*
258 * Complain about a duplicate filter variable.
259 */
260static void
262{
264 (errcode(ERRCODE_SYNTAX_ERROR),
265 errmsg("filter variable \"%s\" specified more than once",
266 defname)));
267}
268
269/*
270 * Insert the new pg_event_trigger row and record dependencies.
271 */
272static Oid
273insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
274 Oid funcoid, List *taglist)
275{
276 Relation tgrel;
277 Oid trigoid;
278 HeapTuple tuple;
279 Datum values[Natts_pg_event_trigger];
280 bool nulls[Natts_pg_event_trigger];
281 NameData evtnamedata,
282 evteventdata;
283 ObjectAddress myself,
284 referenced;
285
286 /* Open pg_event_trigger. */
287 tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
288
289 /* Build the new pg_trigger tuple. */
290 trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId,
291 Anum_pg_event_trigger_oid);
292 values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
293 memset(nulls, false, sizeof(nulls));
294 namestrcpy(&evtnamedata, trigname);
295 values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
296 namestrcpy(&evteventdata, eventname);
297 values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
298 values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
299 values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
300 values[Anum_pg_event_trigger_evtenabled - 1] =
302 if (taglist == NIL)
303 nulls[Anum_pg_event_trigger_evttags - 1] = true;
304 else
305 values[Anum_pg_event_trigger_evttags - 1] =
306 filter_list_to_array(taglist);
307
308 /* Insert heap tuple. */
309 tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
310 CatalogTupleInsert(tgrel, tuple);
311 heap_freetuple(tuple);
312
313 /*
314 * Login event triggers have an additional flag in pg_database to enable
315 * faster lookups in hot codepaths. Set the flag unless already True.
316 */
317 if (strcmp(eventname, "login") == 0)
319
320 /* Depend on owner. */
321 recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
322
323 /* Depend on event trigger function. */
324 myself.classId = EventTriggerRelationId;
325 myself.objectId = trigoid;
326 myself.objectSubId = 0;
327 referenced.classId = ProcedureRelationId;
328 referenced.objectId = funcoid;
329 referenced.objectSubId = 0;
330 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
331
332 /* Depend on extension, if any. */
334
335 /* Post creation hook for new event trigger */
336 InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
337
338 /* Close pg_event_trigger. */
340
341 return trigoid;
342}
343
344/*
345 * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
346 * by a DefElem whose value is a List of String nodes; in the catalog, we
347 * store the list of strings as a text array. This function transforms the
348 * former representation into the latter one.
349 *
350 * For cleanliness, we store command tags in the catalog as text. It's
351 * possible (although not currently anticipated) that we might have
352 * a case-sensitive filter variable in the future, in which case this would
353 * need some further adjustment.
354 */
355static Datum
357{
358 ListCell *lc;
359 Datum *data;
360 int i = 0,
361 l = list_length(filterlist);
362
363 data = (Datum *) palloc(l * sizeof(Datum));
364
365 foreach(lc, filterlist)
366 {
367 const char *value = strVal(lfirst(lc));
368 char *result,
369 *p;
370
371 result = pstrdup(value);
372 for (p = result; *p; p++)
373 *p = pg_ascii_toupper((unsigned char) *p);
375 pfree(result);
376 }
377
378 return PointerGetDatum(construct_array_builtin(data, l, TEXTOID));
379}
380
381/*
382 * Set pg_database.dathasloginevt flag for current database indicating that
383 * current database has on login event triggers.
384 */
385void
387{
388 /* Set dathasloginevt flag in pg_database */
390 Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock);
391 ItemPointerData otid;
392 HeapTuple tuple;
393
394 /*
395 * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying
396 * to reset pg_database.dathasloginevt flag. Note, this lock doesn't
397 * effectively blocks database or other objection. It's just custom lock
398 * tag used to prevent multiple backends changing
399 * pg_database.dathasloginevt flag.
400 */
401 LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, AccessExclusiveLock);
402
404 if (!HeapTupleIsValid(tuple))
405 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
406 otid = tuple->t_self;
407 db = (Form_pg_database) GETSTRUCT(tuple);
408 if (!db->dathasloginevt)
409 {
410 db->dathasloginevt = true;
411 CatalogTupleUpdate(pg_db, &otid, tuple);
413 }
414 UnlockTuple(pg_db, &otid, InplaceUpdateTupleLock);
416 heap_freetuple(tuple);
417}
418
419/*
420 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
421 */
422Oid
424{
425 Relation tgrel;
426 HeapTuple tup;
427 Oid trigoid;
428 Form_pg_event_trigger evtForm;
429 char tgenabled = stmt->tgenabled;
430
431 tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
432
433 tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
434 CStringGetDatum(stmt->trigname));
435 if (!HeapTupleIsValid(tup))
437 (errcode(ERRCODE_UNDEFINED_OBJECT),
438 errmsg("event trigger \"%s\" does not exist",
439 stmt->trigname)));
440
441 evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
442 trigoid = evtForm->oid;
443
444 if (!object_ownercheck(EventTriggerRelationId, trigoid, GetUserId()))
446 stmt->trigname);
447
448 /* tuple is a copy, so we can modify it below */
449 evtForm->evtenabled = tgenabled;
450
451 CatalogTupleUpdate(tgrel, &tup->t_self, tup);
452
453 /*
454 * Login event triggers have an additional flag in pg_database to enable
455 * faster lookups in hot codepaths. Set the flag unless already True.
456 */
457 if (namestrcmp(&evtForm->evtevent, "login") == 0 &&
458 tgenabled != TRIGGER_DISABLED)
460
461 InvokeObjectPostAlterHook(EventTriggerRelationId,
462 trigoid, 0);
463
464 /* clean up */
465 heap_freetuple(tup);
467
468 return trigoid;
469}
470
471/*
472 * Change event trigger's owner -- by name
473 */
475AlterEventTriggerOwner(const char *name, Oid newOwnerId)
476{
477 Oid evtOid;
478 HeapTuple tup;
479 Form_pg_event_trigger evtForm;
480 Relation rel;
481 ObjectAddress address;
482
483 rel = table_open(EventTriggerRelationId, RowExclusiveLock);
484
485 tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
486
487 if (!HeapTupleIsValid(tup))
489 (errcode(ERRCODE_UNDEFINED_OBJECT),
490 errmsg("event trigger \"%s\" does not exist", name)));
491
492 evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
493 evtOid = evtForm->oid;
494
495 AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
496
497 ObjectAddressSet(address, EventTriggerRelationId, evtOid);
498
499 heap_freetuple(tup);
500
502
503 return address;
504}
505
506/*
507 * Change event trigger owner, by OID
508 */
509void
511{
512 HeapTuple tup;
513 Relation rel;
514
515 rel = table_open(EventTriggerRelationId, RowExclusiveLock);
516
517 tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
518
519 if (!HeapTupleIsValid(tup))
521 (errcode(ERRCODE_UNDEFINED_OBJECT),
522 errmsg("event trigger with OID %u does not exist", trigOid)));
523
524 AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
525
526 heap_freetuple(tup);
527
529}
530
531/*
532 * Internal workhorse for changing an event trigger's owner
533 */
534static void
536{
538
539 form = (Form_pg_event_trigger) GETSTRUCT(tup);
540
541 if (form->evtowner == newOwnerId)
542 return;
543
544 if (!object_ownercheck(EventTriggerRelationId, form->oid, GetUserId()))
546 NameStr(form->evtname));
547
548 /* New owner must be a superuser */
549 if (!superuser_arg(newOwnerId))
551 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
552 errmsg("permission denied to change owner of event trigger \"%s\"",
553 NameStr(form->evtname)),
554 errhint("The owner of an event trigger must be a superuser.")));
555
556 form->evtowner = newOwnerId;
557 CatalogTupleUpdate(rel, &tup->t_self, tup);
558
559 /* Update owner dependency reference */
560 changeDependencyOnOwner(EventTriggerRelationId,
561 form->oid,
562 newOwnerId);
563
564 InvokeObjectPostAlterHook(EventTriggerRelationId,
565 form->oid, 0);
566}
567
568/*
569 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
570 *
571 * If missing_ok is false, throw an error if trigger not found. If
572 * true, just return InvalidOid.
573 */
574Oid
575get_event_trigger_oid(const char *trigname, bool missing_ok)
576{
577 Oid oid;
578
579 oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
580 CStringGetDatum(trigname));
581 if (!OidIsValid(oid) && !missing_ok)
583 (errcode(ERRCODE_UNDEFINED_OBJECT),
584 errmsg("event trigger \"%s\" does not exist", trigname)));
585 return oid;
586}
587
588/*
589 * Return true when we want to fire given Event Trigger and false otherwise,
590 * filtering on the session replication role and the event trigger registered
591 * tags matching.
592 */
593static bool
595{
596 /*
597 * Filter by session replication role, knowing that we never see disabled
598 * items down here.
599 */
601 {
602 if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
603 return false;
604 }
605 else
606 {
608 return false;
609 }
610
611 /* Filter by tags, if any were specified. */
612 if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
613 return false;
614
615 /* if we reach that point, we're not filtering out this item */
616 return true;
617}
618
619static CommandTag
621{
622 if (event == EVT_Login)
623 return CMDTAG_LOGIN;
624 else
625 return CreateCommandTag(parsetree);
626}
627
628/*
629 * Setup for running triggers for the given event. Return value is an OID list
630 * of functions to run; if there are any, trigdata is filled with an
631 * appropriate EventTriggerData for them to receive.
632 */
633static List *
635 EventTriggerEvent event, const char *eventstr,
636 EventTriggerData *trigdata, bool unfiltered)
637{
638 CommandTag tag;
639 List *cachelist;
640 ListCell *lc;
641 List *runlist = NIL;
642
643 /*
644 * We want the list of command tags for which this procedure is actually
645 * invoked to match up exactly with the list that CREATE EVENT TRIGGER
646 * accepts. This debugging cross-check will throw an error if this
647 * function is invoked for a command tag that CREATE EVENT TRIGGER won't
648 * accept. (Unfortunately, there doesn't seem to be any simple, automated
649 * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
650 * never reaches this control point.)
651 *
652 * If this cross-check fails for you, you probably need to either adjust
653 * standard_ProcessUtility() not to invoke event triggers for the command
654 * type in question, or you need to adjust event_trigger_ok to accept the
655 * relevant command tag.
656 */
657#ifdef USE_ASSERT_CHECKING
658 {
659 CommandTag dbgtag;
660
661 dbgtag = EventTriggerGetTag(parsetree, event);
662
663 if (event == EVT_DDLCommandStart ||
664 event == EVT_DDLCommandEnd ||
665 event == EVT_SQLDrop ||
666 event == EVT_Login)
667 {
668 if (!command_tag_event_trigger_ok(dbgtag))
669 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
670 }
671 else if (event == EVT_TableRewrite)
672 {
673 if (!command_tag_table_rewrite_ok(dbgtag))
674 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
675 }
676 }
677#endif
678
679 /* Use cache to find triggers for this event; fast exit if none. */
680 cachelist = EventCacheLookup(event);
681 if (cachelist == NIL)
682 return NIL;
683
684 /* Get the command tag. */
685 tag = EventTriggerGetTag(parsetree, event);
686
687 /*
688 * Filter list of event triggers by command tag, and copy them into our
689 * memory context. Once we start running the command triggers, or indeed
690 * once we do anything at all that touches the catalogs, an invalidation
691 * might leave cachelist pointing at garbage, so we must do this before we
692 * can do much else.
693 */
694 foreach(lc, cachelist)
695 {
696 EventTriggerCacheItem *item = lfirst(lc);
697
698 if (unfiltered || filter_event_trigger(tag, item))
699 {
700 /* We must plan to fire this trigger. */
701 runlist = lappend_oid(runlist, item->fnoid);
702 }
703 }
704
705 /* Don't spend any more time on this if no functions to run */
706 if (runlist == NIL)
707 return NIL;
708
709 trigdata->type = T_EventTriggerData;
710 trigdata->event = eventstr;
711 trigdata->parsetree = parsetree;
712 trigdata->tag = tag;
713
714 return runlist;
715}
716
717/*
718 * Fire ddl_command_start triggers.
719 */
720void
722{
723 List *runlist;
724 EventTriggerData trigdata;
725
726 /*
727 * Event Triggers are completely disabled in standalone mode. There are
728 * (at least) two reasons for this:
729 *
730 * 1. A sufficiently broken event trigger might not only render the
731 * database unusable, but prevent disabling itself to fix the situation.
732 * In this scenario, restarting in standalone mode provides an escape
733 * hatch.
734 *
735 * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
736 * therefore will malfunction if pg_event_trigger's indexes are damaged.
737 * To allow recovery from a damaged index, we need some operating mode
738 * wherein event triggers are disabled. (Or we could implement
739 * heapscan-and-sort logic for that case, but having disaster recovery
740 * scenarios depend on code that's otherwise untested isn't appetizing.)
741 *
742 * Additionally, event triggers can be disabled with a superuser-only GUC
743 * to make fixing database easier as per 1 above.
744 */
746 return;
747
748 runlist = EventTriggerCommonSetup(parsetree,
750 "ddl_command_start",
751 &trigdata, false);
752 if (runlist == NIL)
753 return;
754
755 /* Run the triggers. */
756 EventTriggerInvoke(runlist, &trigdata);
757
758 /* Cleanup. */
759 list_free(runlist);
760
761 /*
762 * Make sure anything the event triggers did will be visible to the main
763 * command.
764 */
766}
767
768/*
769 * Fire ddl_command_end triggers.
770 */
771void
773{
774 List *runlist;
775 EventTriggerData trigdata;
776
777 /*
778 * See EventTriggerDDLCommandStart for a discussion about why event
779 * triggers are disabled in single user mode or via GUC.
780 */
782 return;
783
784 /*
785 * Also do nothing if our state isn't set up, which it won't be if there
786 * weren't any relevant event triggers at the start of the current DDL
787 * command. This test might therefore seem optional, but it's important
788 * because EventTriggerCommonSetup might find triggers that didn't exist
789 * at the time the command started. Although this function itself
790 * wouldn't crash, the event trigger functions would presumably call
791 * pg_event_trigger_ddl_commands which would fail. Better to do nothing
792 * until the next command.
793 */
795 return;
796
797 runlist = EventTriggerCommonSetup(parsetree,
798 EVT_DDLCommandEnd, "ddl_command_end",
799 &trigdata, false);
800 if (runlist == NIL)
801 return;
802
803 /*
804 * Make sure anything the main command did will be visible to the event
805 * triggers.
806 */
808
809 /* Run the triggers. */
810 EventTriggerInvoke(runlist, &trigdata);
811
812 /* Cleanup. */
813 list_free(runlist);
814}
815
816/*
817 * Fire sql_drop triggers.
818 */
819void
821{
822 List *runlist;
823 EventTriggerData trigdata;
824
825 /*
826 * See EventTriggerDDLCommandStart for a discussion about why event
827 * triggers are disabled in single user mode or via a GUC.
828 */
830 return;
831
832 /*
833 * Use current state to determine whether this event fires at all. If
834 * there are no triggers for the sql_drop event, then we don't have
835 * anything to do here. Note that dropped object collection is disabled
836 * if this is the case, so even if we were to try to run, the list would
837 * be empty.
838 */
841 return;
842
843 runlist = EventTriggerCommonSetup(parsetree,
844 EVT_SQLDrop, "sql_drop",
845 &trigdata, false);
846
847 /*
848 * Nothing to do if run list is empty. Note this typically can't happen,
849 * because if there are no sql_drop events, then objects-to-drop wouldn't
850 * have been collected in the first place and we would have quit above.
851 * But it could occur if event triggers were dropped partway through.
852 */
853 if (runlist == NIL)
854 return;
855
856 /*
857 * Make sure anything the main command did will be visible to the event
858 * triggers.
859 */
861
862 /*
863 * Make sure pg_event_trigger_dropped_objects only works when running
864 * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
865 * one trigger fails. (This is perhaps not necessary, as the currentState
866 * variable will be removed shortly by our caller, but it seems better to
867 * play safe.)
868 */
870
871 /* Run the triggers. */
872 PG_TRY();
873 {
874 EventTriggerInvoke(runlist, &trigdata);
875 }
876 PG_FINALLY();
877 {
879 }
880 PG_END_TRY();
881
882 /* Cleanup. */
883 list_free(runlist);
884}
885
886/*
887 * Fire login event triggers if any are present. The dathasloginevt
888 * pg_database flag is left unchanged when an event trigger is dropped to avoid
889 * complicating the codepath in the case of multiple event triggers. This
890 * function will instead unset the flag if no trigger is defined.
891 */
892void
894{
895 List *runlist;
896 EventTriggerData trigdata;
897
898 /*
899 * See EventTriggerDDLCommandStart for a discussion about why event
900 * triggers are disabled in single user mode or via a GUC. We also need a
901 * database connection (some background workers don't have it).
902 */
905 return;
906
908 runlist = EventTriggerCommonSetup(NULL,
909 EVT_Login, "login",
910 &trigdata, false);
911
912 if (runlist != NIL)
913 {
914 /*
915 * Event trigger execution may require an active snapshot.
916 */
918
919 /* Run the triggers. */
920 EventTriggerInvoke(runlist, &trigdata);
921
922 /* Cleanup. */
923 list_free(runlist);
924
926 }
927
928 /*
929 * There is no active login event trigger, but our
930 * pg_database.dathasloginevt is set. Try to unset this flag. We use the
931 * lock to prevent concurrent SetDatabaseHasLoginEventTriggers(), but we
932 * don't want to hang the connection waiting on the lock. Thus, we are
933 * just trying to acquire the lock conditionally.
934 */
935 else if (ConditionalLockSharedObject(DatabaseRelationId, MyDatabaseId,
937 {
938 /*
939 * The lock is held. Now we need to recheck that login event triggers
940 * list is still empty. Once the list is empty, we know that even if
941 * there is a backend which concurrently inserts/enables a login event
942 * trigger, it will update pg_database.dathasloginevt *afterwards*.
943 */
944 runlist = EventTriggerCommonSetup(NULL,
945 EVT_Login, "login",
946 &trigdata, true);
947
948 if (runlist == NIL)
949 {
950 Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock);
951 HeapTuple tuple;
952 void *state;
954 ScanKeyData key[1];
955
956 /* Fetch a copy of the tuple to scribble on */
957 ScanKeyInit(&key[0],
958 Anum_pg_database_oid,
959 BTEqualStrategyNumber, F_OIDEQ,
961
962 systable_inplace_update_begin(pg_db, DatabaseOidIndexId, true,
963 NULL, 1, key, &tuple, &state);
964
965 if (!HeapTupleIsValid(tuple))
966 elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
967
968 db = (Form_pg_database) GETSTRUCT(tuple);
969 if (db->dathasloginevt)
970 {
971 db->dathasloginevt = false;
972
973 /*
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.
978 */
980 }
981 else
984 heap_freetuple(tuple);
985 }
986 else
987 {
988 list_free(runlist);
989 }
990 }
992}
993
994
995/*
996 * Fire table_rewrite triggers.
997 */
998void
999EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
1000{
1001 List *runlist;
1002 EventTriggerData trigdata;
1003
1004 /*
1005 * See EventTriggerDDLCommandStart for a discussion about why event
1006 * triggers are disabled in single user mode or via a GUC.
1007 */
1009 return;
1010
1011 /*
1012 * Also do nothing if our state isn't set up, which it won't be if there
1013 * weren't any relevant event triggers at the start of the current DDL
1014 * command. This test might therefore seem optional, but it's
1015 * *necessary*, because EventTriggerCommonSetup might find triggers that
1016 * didn't exist at the time the command started.
1017 */
1019 return;
1020
1021 runlist = EventTriggerCommonSetup(parsetree,
1023 "table_rewrite",
1024 &trigdata, false);
1025 if (runlist == NIL)
1026 return;
1027
1028 /*
1029 * Make sure pg_event_trigger_table_rewrite_oid only works when running
1030 * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
1031 * when one trigger fails. (This is perhaps not necessary, as the
1032 * currentState variable will be removed shortly by our caller, but it
1033 * seems better to play safe.)
1034 */
1037
1038 /* Run the triggers. */
1039 PG_TRY();
1040 {
1041 EventTriggerInvoke(runlist, &trigdata);
1042 }
1043 PG_FINALLY();
1044 {
1047 }
1048 PG_END_TRY();
1049
1050 /* Cleanup. */
1051 list_free(runlist);
1052
1053 /*
1054 * Make sure anything the event triggers did will be visible to the main
1055 * command.
1056 */
1058}
1059
1060/*
1061 * Invoke each event trigger in a list of event triggers.
1062 */
1063static void
1065{
1067 MemoryContext oldcontext;
1068 ListCell *lc;
1069 bool first = true;
1070
1071 /* Guard against stack overflow due to recursive event trigger */
1073
1074 /*
1075 * Let's evaluate event triggers in their own memory context, so that any
1076 * leaks get cleaned up promptly.
1077 */
1079 "event trigger context",
1081 oldcontext = MemoryContextSwitchTo(context);
1082
1083 /* Call each event trigger. */
1084 foreach(lc, fn_oid_list)
1085 {
1086 LOCAL_FCINFO(fcinfo, 0);
1087 Oid fnoid = lfirst_oid(lc);
1088 FmgrInfo flinfo;
1090
1091 elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
1092
1093 /*
1094 * We want each event trigger to be able to see the results of the
1095 * previous event trigger's action. Caller is responsible for any
1096 * command-counter increment that is needed between the event trigger
1097 * and anything else in the transaction.
1098 */
1099 if (first)
1100 first = false;
1101 else
1103
1104 /* Look up the function */
1105 fmgr_info(fnoid, &flinfo);
1106
1107 /* Call the function, passing no arguments but setting a context. */
1108 InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
1109 InvalidOid, (Node *) trigdata, NULL);
1110 pgstat_init_function_usage(fcinfo, &fcusage);
1111 FunctionCallInvoke(fcinfo);
1112 pgstat_end_function_usage(&fcusage, true);
1113
1114 /* Reclaim memory. */
1116 }
1117
1118 /* Restore old memory context and delete the temporary one. */
1119 MemoryContextSwitchTo(oldcontext);
1121}
1122
1123/*
1124 * Do event triggers support this object type?
1125 *
1126 * See also event trigger documentation in event-trigger.sgml.
1127 */
1128bool
1130{
1131 switch (obtype)
1132 {
1133 case OBJECT_DATABASE:
1134 case OBJECT_TABLESPACE:
1135 case OBJECT_ROLE:
1137 /* no support for global objects (except subscriptions) */
1138 return false;
1140 /* no support for event triggers on event triggers */
1141 return false;
1142 default:
1143 return true;
1144 }
1145}
1146
1147/*
1148 * Do event triggers support this object class?
1149 *
1150 * See also event trigger documentation in event-trigger.sgml.
1151 */
1152bool
1154{
1155 switch (object->classId)
1156 {
1157 case DatabaseRelationId:
1158 case TableSpaceRelationId:
1159 case AuthIdRelationId:
1160 case AuthMemRelationId:
1161 case ParameterAclRelationId:
1162 /* no support for global objects (except subscriptions) */
1163 return false;
1164 case EventTriggerRelationId:
1165 /* no support for event triggers on event triggers */
1166 return false;
1167 default:
1168 return true;
1169 }
1170}
1171
1172/*
1173 * Prepare event trigger state for a new complete query to run, if necessary;
1174 * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1175 * be called when the query is done, regardless of whether it succeeds or fails
1176 * -- so use of a PG_TRY block is mandatory.
1177 */
1178bool
1180{
1182 MemoryContext cxt;
1183
1184 /*
1185 * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1186 * reason to have event trigger state at all; so if there are none, don't
1187 * install one.
1188 */
1190 return false;
1191
1193 "event trigger state",
1196 state->cxt = cxt;
1197 slist_init(&(state->SQLDropList));
1198 state->in_sql_drop = false;
1199 state->table_rewrite_oid = InvalidOid;
1200
1201 state->commandCollectionInhibited = currentEventTriggerState ?
1203 state->currentCommand = NULL;
1204 state->commandList = NIL;
1205 state->previous = currentEventTriggerState;
1207
1208 return true;
1209}
1210
1211/*
1212 * Query completed (or errored out) -- clean up local state, return to previous
1213 * one.
1214 *
1215 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1216 * returned false previously.
1217 *
1218 * Note: this might be called in the PG_CATCH block of a failing transaction,
1219 * so be wary of running anything unnecessary. (In particular, it's probably
1220 * unwise to try to allocate memory.)
1221 */
1222void
1224{
1225 EventTriggerQueryState *prevstate;
1226
1228
1229 /* this avoids the need for retail pfree of SQLDropList items: */
1231
1232 currentEventTriggerState = prevstate;
1233}
1234
1235/*
1236 * Do we need to keep close track of objects being dropped?
1237 *
1238 * This is useful because there is a cost to running with them enabled.
1239 */
1240bool
1242{
1243 /*
1244 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1245 * exists
1246 */
1247 return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
1250}
1251
1252/*
1253 * Support for dropped objects information on event trigger functions.
1254 *
1255 * We keep the list of objects dropped by the current command in current
1256 * state's SQLDropList (comprising SQLDropObject items). Each time a new
1257 * command is to start, a clean EventTriggerQueryState is created; commands
1258 * that drop objects do the dependency.c dance to drop objects, which
1259 * populates the current state's SQLDropList; when the event triggers are
1260 * invoked they can consume the list via pg_event_trigger_dropped_objects().
1261 * When the command finishes, the EventTriggerQueryState is cleared, and
1262 * the one from the previous command is restored (when no command is in
1263 * execution, the current state is NULL).
1264 *
1265 * All this lets us support the case that an event trigger function drops
1266 * objects "reentrantly".
1267 */
1268
1269/*
1270 * Register one object as being dropped by the current command.
1271 */
1272void
1273EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1274{
1275 SQLDropObject *obj;
1276 MemoryContext oldcxt;
1277
1279 return;
1280
1282
1283 /* don't report temp schemas except my own */
1284 if (object->classId == NamespaceRelationId &&
1285 (isAnyTempNamespace(object->objectId) &&
1286 !isTempNamespace(object->objectId)))
1287 return;
1288
1290
1291 obj = palloc0(sizeof(SQLDropObject));
1292 obj->address = *object;
1293 obj->original = original;
1294 obj->normal = normal;
1295
1296 /*
1297 * Obtain schema names from the object's catalog tuple, if one exists;
1298 * this lets us skip objects in temp schemas. We trust that
1299 * ObjectProperty contains all object classes that can be
1300 * schema-qualified.
1301 */
1302 if (is_objectclass_supported(object->classId))
1303 {
1304 Relation catalog;
1305 HeapTuple tuple;
1306
1307 catalog = table_open(obj->address.classId, AccessShareLock);
1308 tuple = get_catalog_object_by_oid(catalog,
1310 obj->address.objectId);
1311
1312 if (tuple)
1313 {
1315 Datum datum;
1316 bool isnull;
1317
1320 {
1321 datum = heap_getattr(tuple, attnum,
1322 RelationGetDescr(catalog), &isnull);
1323 if (!isnull)
1324 {
1325 Oid namespaceId;
1326
1327 namespaceId = DatumGetObjectId(datum);
1328 /* temp objects are only reported if they are my own */
1329 if (isTempNamespace(namespaceId))
1330 {
1331 obj->schemaname = "pg_temp";
1332 obj->istemp = true;
1333 }
1334 else if (isAnyTempNamespace(namespaceId))
1335 {
1336 pfree(obj);
1337 table_close(catalog, AccessShareLock);
1338 MemoryContextSwitchTo(oldcxt);
1339 return;
1340 }
1341 else
1342 {
1343 obj->schemaname = get_namespace_name(namespaceId);
1344 obj->istemp = false;
1345 }
1346 }
1347 }
1348
1350 obj->address.objectSubId == 0)
1351 {
1354 {
1355 datum = heap_getattr(tuple, attnum,
1356 RelationGetDescr(catalog), &isnull);
1357 if (!isnull)
1358 obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1359 }
1360 }
1361 }
1362
1363 table_close(catalog, AccessShareLock);
1364 }
1365 else
1366 {
1367 if (object->classId == NamespaceRelationId &&
1368 isTempNamespace(object->objectId))
1369 obj->istemp = true;
1370 }
1371
1372 /* object identity, objname and objargs */
1373 obj->objidentity =
1375 false);
1376
1377 /* object type */
1378 obj->objecttype = getObjectTypeDescription(&obj->address, false);
1379
1381
1382 MemoryContextSwitchTo(oldcxt);
1383}
1384
1385/*
1386 * pg_event_trigger_dropped_objects
1387 *
1388 * Make the list of dropped objects available to the user function run by the
1389 * Event Trigger.
1390 */
1391Datum
1393{
1394 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1395 slist_iter iter;
1396
1397 /*
1398 * Protect this function from being called out of context
1399 */
1402 ereport(ERROR,
1403 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1404 errmsg("%s can only be called in a sql_drop event trigger function",
1405 "pg_event_trigger_dropped_objects()")));
1406
1407 /* Build tuplestore to hold the result rows */
1408 InitMaterializedSRF(fcinfo, 0);
1409
1411 {
1412 SQLDropObject *obj;
1413 int i = 0;
1414 Datum values[12] = {0};
1415 bool nulls[12] = {0};
1416
1417 obj = slist_container(SQLDropObject, next, iter.cur);
1418
1419 /* classid */
1421
1422 /* objid */
1424
1425 /* objsubid */
1427
1428 /* original */
1429 values[i++] = BoolGetDatum(obj->original);
1430
1431 /* normal */
1432 values[i++] = BoolGetDatum(obj->normal);
1433
1434 /* is_temporary */
1435 values[i++] = BoolGetDatum(obj->istemp);
1436
1437 /* object_type */
1439
1440 /* schema_name */
1441 if (obj->schemaname)
1443 else
1444 nulls[i++] = true;
1445
1446 /* object_name */
1447 if (obj->objname)
1449 else
1450 nulls[i++] = true;
1451
1452 /* object_identity */
1453 if (obj->objidentity)
1455 else
1456 nulls[i++] = true;
1457
1458 /* address_names and address_args */
1459 if (obj->addrnames)
1460 {
1462
1463 if (obj->addrargs)
1465 else
1467 }
1468 else
1469 {
1470 nulls[i++] = true;
1471 nulls[i++] = true;
1472 }
1473
1474 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1475 values, nulls);
1476 }
1477
1478 return (Datum) 0;
1479}
1480
1481/*
1482 * pg_event_trigger_table_rewrite_oid
1483 *
1484 * Make the Oid of the table going to be rewritten available to the user
1485 * function run by the Event Trigger.
1486 */
1487Datum
1489{
1490 /*
1491 * Protect this function from being called out of context
1492 */
1495 ereport(ERROR,
1496 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1497 errmsg("%s can only be called in a table_rewrite event trigger function",
1498 "pg_event_trigger_table_rewrite_oid()")));
1499
1501}
1502
1503/*
1504 * pg_event_trigger_table_rewrite_reason
1505 *
1506 * Make the rewrite reason available to the user.
1507 */
1508Datum
1510{
1511 /*
1512 * Protect this function from being called out of context
1513 */
1516 ereport(ERROR,
1517 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1518 errmsg("%s can only be called in a table_rewrite event trigger function",
1519 "pg_event_trigger_table_rewrite_reason()")));
1520
1522}
1523
1524/*-------------------------------------------------------------------------
1525 * Support for DDL command deparsing
1526 *
1527 * The routines below enable an event trigger function to obtain a list of
1528 * DDL commands as they are executed. There are three main pieces to this
1529 * feature:
1530 *
1531 * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1532 * adds a struct CollectedCommand representation of itself to the command list,
1533 * using the routines below.
1534 *
1535 * 2) Some time after that, ddl_command_end fires and the command list is made
1536 * available to the event trigger function via pg_event_trigger_ddl_commands();
1537 * the complete command details are exposed as a column of type pg_ddl_command.
1538 *
1539 * 3) An extension can install a function capable of taking a value of type
1540 * pg_ddl_command and transform it into some external, user-visible and/or
1541 * -modifiable representation.
1542 *-------------------------------------------------------------------------
1543 */
1544
1545/*
1546 * Inhibit DDL command collection.
1547 */
1548void
1550{
1552 return;
1553
1555}
1556
1557/*
1558 * Re-establish DDL command collection.
1559 */
1560void
1562{
1564 return;
1565
1567}
1568
1569/*
1570 * EventTriggerCollectSimpleCommand
1571 * Save data about a simple DDL command that was just executed
1572 *
1573 * address identifies the object being operated on. secondaryObject is an
1574 * object address that was related in some way to the executed command; its
1575 * meaning is command-specific.
1576 *
1577 * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1578 * object being moved, objectId is its OID, and secondaryOid is the OID of the
1579 * old schema. (The destination schema OID can be obtained by catalog lookup
1580 * of the object.)
1581 */
1582void
1584 ObjectAddress secondaryObject,
1585 Node *parsetree)
1586{
1587 MemoryContext oldcxt;
1588 CollectedCommand *command;
1589
1590 /* ignore if event trigger context not set, or collection disabled */
1593 return;
1594
1596
1597 command = palloc(sizeof(CollectedCommand));
1598
1599 command->type = SCT_Simple;
1601
1602 command->d.simple.address = address;
1603 command->d.simple.secondaryObject = secondaryObject;
1604 command->parsetree = copyObject(parsetree);
1605
1607 command);
1608
1609 MemoryContextSwitchTo(oldcxt);
1610}
1611
1612/*
1613 * EventTriggerAlterTableStart
1614 * Prepare to receive data on an ALTER TABLE command about to be executed
1615 *
1616 * Note we don't collect the command immediately; instead we keep it in
1617 * currentCommand, and only when we're done processing the subcommands we will
1618 * add it to the command list.
1619 */
1620void
1622{
1623 MemoryContext oldcxt;
1624 CollectedCommand *command;
1625
1626 /* ignore if event trigger context not set, or collection disabled */
1629 return;
1630
1632
1633 command = palloc(sizeof(CollectedCommand));
1634
1635 command->type = SCT_AlterTable;
1637
1638 command->d.alterTable.classId = RelationRelationId;
1639 command->d.alterTable.objectId = InvalidOid;
1640 command->d.alterTable.subcmds = NIL;
1641 command->parsetree = copyObject(parsetree);
1642
1645
1646 MemoryContextSwitchTo(oldcxt);
1647}
1648
1649/*
1650 * Remember the OID of the object being affected by an ALTER TABLE.
1651 *
1652 * This is needed because in some cases we don't know the OID until later.
1653 */
1654void
1656{
1659 return;
1660
1662}
1663
1664/*
1665 * EventTriggerCollectAlterTableSubcmd
1666 * Save data about a single part of an ALTER TABLE.
1667 *
1668 * Several different commands go through this path, but apart from ALTER TABLE
1669 * itself, they are all concerned with AlterTableCmd nodes that are generated
1670 * internally, so that's all that this code needs to handle at the moment.
1671 */
1672void
1674{
1675 MemoryContext oldcxt;
1677
1678 /* ignore if event trigger context not set, or collection disabled */
1681 return;
1682
1683 Assert(IsA(subcmd, AlterTableCmd));
1686
1688
1689 newsub = palloc(sizeof(CollectedATSubcmd));
1690 newsub->address = address;
1691 newsub->parsetree = copyObject(subcmd);
1692
1695
1696 MemoryContextSwitchTo(oldcxt);
1697}
1698
1699/*
1700 * EventTriggerAlterTableEnd
1701 * Finish up saving an ALTER TABLE command, and add it to command list.
1702 *
1703 * FIXME this API isn't considering the possibility that an xact/subxact is
1704 * aborted partway through. Probably it's best to add an
1705 * AtEOSubXact_EventTriggers() to fix this.
1706 */
1707void
1709{
1710 CollectedCommand *parent;
1711
1712 /* ignore if event trigger context not set, or collection disabled */
1715 return;
1716
1718
1719 /* If no subcommands, don't collect */
1721 {
1722 MemoryContext oldcxt;
1723
1725
1729
1730 MemoryContextSwitchTo(oldcxt);
1731 }
1732 else
1734
1736}
1737
1738/*
1739 * EventTriggerCollectGrant
1740 * Save data about a GRANT/REVOKE command being executed
1741 *
1742 * This function creates a copy of the InternalGrant, as the original might
1743 * not have the right lifetime.
1744 */
1745void
1747{
1748 MemoryContext oldcxt;
1749 CollectedCommand *command;
1750 InternalGrant *icopy;
1751 ListCell *cell;
1752
1753 /* ignore if event trigger context not set, or collection disabled */
1756 return;
1757
1759
1760 /*
1761 * This is tedious, but necessary.
1762 */
1763 icopy = palloc(sizeof(InternalGrant));
1764 memcpy(icopy, istmt, sizeof(InternalGrant));
1765 icopy->objects = list_copy(istmt->objects);
1766 icopy->grantees = list_copy(istmt->grantees);
1767 icopy->col_privs = NIL;
1768 foreach(cell, istmt->col_privs)
1769 icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1770
1771 /* Now collect it, using the copied InternalGrant */
1772 command = palloc(sizeof(CollectedCommand));
1773 command->type = SCT_Grant;
1775 command->d.grant.istmt = icopy;
1776 command->parsetree = NULL;
1777
1780
1781 MemoryContextSwitchTo(oldcxt);
1782}
1783
1784/*
1785 * EventTriggerCollectAlterOpFam
1786 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1787 * executed
1788 */
1789void
1791 List *operators, List *procedures)
1792{
1793 MemoryContext oldcxt;
1794 CollectedCommand *command;
1795
1796 /* ignore if event trigger context not set, or collection disabled */
1799 return;
1800
1802
1803 command = palloc(sizeof(CollectedCommand));
1804 command->type = SCT_AlterOpFamily;
1807 OperatorFamilyRelationId, opfamoid);
1808 command->d.opfam.operators = operators;
1809 command->d.opfam.procedures = procedures;
1810 command->parsetree = (Node *) copyObject(stmt);
1811
1814
1815 MemoryContextSwitchTo(oldcxt);
1816}
1817
1818/*
1819 * EventTriggerCollectCreateOpClass
1820 * Save data about a CREATE OPERATOR CLASS command being executed
1821 */
1822void
1824 List *operators, List *procedures)
1825{
1826 MemoryContext oldcxt;
1827 CollectedCommand *command;
1828
1829 /* ignore if event trigger context not set, or collection disabled */
1832 return;
1833
1835
1836 command = palloc0(sizeof(CollectedCommand));
1837 command->type = SCT_CreateOpClass;
1840 OperatorClassRelationId, opcoid);
1841 command->d.createopc.operators = operators;
1842 command->d.createopc.procedures = procedures;
1843 command->parsetree = (Node *) copyObject(stmt);
1844
1847
1848 MemoryContextSwitchTo(oldcxt);
1849}
1850
1851/*
1852 * EventTriggerCollectAlterTSConfig
1853 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1854 * executed
1855 */
1856void
1858 Oid *dictIds, int ndicts)
1859{
1860 MemoryContext oldcxt;
1861 CollectedCommand *command;
1862
1863 /* ignore if event trigger context not set, or collection disabled */
1866 return;
1867
1869
1870 command = palloc0(sizeof(CollectedCommand));
1871 command->type = SCT_AlterTSConfig;
1874 TSConfigRelationId, cfgId);
1875 command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
1876 memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
1877 command->d.atscfg.ndicts = ndicts;
1878 command->parsetree = (Node *) copyObject(stmt);
1879
1882
1883 MemoryContextSwitchTo(oldcxt);
1884}
1885
1886/*
1887 * EventTriggerCollectAlterDefPrivs
1888 * Save data about an ALTER DEFAULT PRIVILEGES command being
1889 * executed
1890 */
1891void
1893{
1894 MemoryContext oldcxt;
1895 CollectedCommand *command;
1896
1897 /* ignore if event trigger context not set, or collection disabled */
1900 return;
1901
1903
1904 command = palloc0(sizeof(CollectedCommand));
1906 command->d.defprivs.objtype = stmt->action->objtype;
1908 command->parsetree = (Node *) copyObject(stmt);
1909
1912 MemoryContextSwitchTo(oldcxt);
1913}
1914
1915/*
1916 * In a ddl_command_end event trigger, this function reports the DDL commands
1917 * being run.
1918 */
1919Datum
1921{
1922 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1923 ListCell *lc;
1924
1925 /*
1926 * Protect this function from being called out of context
1927 */
1929 ereport(ERROR,
1930 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1931 errmsg("%s can only be called in an event trigger function",
1932 "pg_event_trigger_ddl_commands()")));
1933
1934 /* Build tuplestore to hold the result rows */
1935 InitMaterializedSRF(fcinfo, 0);
1936
1938 {
1939 CollectedCommand *cmd = lfirst(lc);
1940 Datum values[9];
1941 bool nulls[9] = {0};
1942 ObjectAddress addr;
1943 int i = 0;
1944
1945 /*
1946 * For IF NOT EXISTS commands that attempt to create an existing
1947 * object, the returned OID is Invalid. Don't return anything.
1948 *
1949 * One might think that a viable alternative would be to look up the
1950 * Oid of the existing object and run the deparse with that. But
1951 * since the parse tree might be different from the one that created
1952 * the object in the first place, we might not end up in a consistent
1953 * state anyway.
1954 */
1955 if (cmd->type == SCT_Simple &&
1957 continue;
1958
1959 switch (cmd->type)
1960 {
1961 case SCT_Simple:
1962 case SCT_AlterTable:
1963 case SCT_AlterOpFamily:
1964 case SCT_CreateOpClass:
1965 case SCT_AlterTSConfig:
1966 {
1967 char *identity;
1968 char *type;
1969 char *schema = NULL;
1970
1971 if (cmd->type == SCT_Simple)
1972 addr = cmd->d.simple.address;
1973 else if (cmd->type == SCT_AlterTable)
1974 ObjectAddressSet(addr,
1975 cmd->d.alterTable.classId,
1976 cmd->d.alterTable.objectId);
1977 else if (cmd->type == SCT_AlterOpFamily)
1978 addr = cmd->d.opfam.address;
1979 else if (cmd->type == SCT_CreateOpClass)
1980 addr = cmd->d.createopc.address;
1981 else if (cmd->type == SCT_AlterTSConfig)
1982 addr = cmd->d.atscfg.address;
1983
1984 /*
1985 * If an object was dropped in the same command we may end
1986 * up in a situation where we generated a message but can
1987 * no longer look for the object information, so skip it
1988 * rather than failing. This can happen for example with
1989 * some subcommand combinations of ALTER TABLE.
1990 */
1991 identity = getObjectIdentity(&addr, true);
1992 if (identity == NULL)
1993 continue;
1994
1995 /* The type can never be NULL. */
1996 type = getObjectTypeDescription(&addr, true);
1997
1998 /*
1999 * Obtain schema name, if any ("pg_temp" if a temp
2000 * object). If the object class is not in the supported
2001 * list here, we assume it's a schema-less object type,
2002 * and thus "schema" remains set to NULL.
2003 */
2005 {
2006 AttrNumber nspAttnum;
2007
2008 nspAttnum = get_object_attnum_namespace(addr.classId);
2009 if (nspAttnum != InvalidAttrNumber)
2010 {
2011 Relation catalog;
2012 HeapTuple objtup;
2013 Oid schema_oid;
2014 bool isnull;
2015
2016 catalog = table_open(addr.classId, AccessShareLock);
2017 objtup = get_catalog_object_by_oid(catalog,
2019 addr.objectId);
2020 if (!HeapTupleIsValid(objtup))
2021 elog(ERROR, "cache lookup failed for object %u/%u",
2022 addr.classId, addr.objectId);
2023 schema_oid =
2024 heap_getattr(objtup, nspAttnum,
2025 RelationGetDescr(catalog), &isnull);
2026 if (isnull)
2027 elog(ERROR,
2028 "invalid null namespace in object %u/%u/%d",
2029 addr.classId, addr.objectId, addr.objectSubId);
2030 schema = get_namespace_name_or_temp(schema_oid);
2031
2032 table_close(catalog, AccessShareLock);
2033 }
2034 }
2035
2036 /* classid */
2037 values[i++] = ObjectIdGetDatum(addr.classId);
2038 /* objid */
2039 values[i++] = ObjectIdGetDatum(addr.objectId);
2040 /* objsubid */
2041 values[i++] = Int32GetDatum(addr.objectSubId);
2042 /* command tag */
2044 /* object_type */
2046 /* schema */
2047 if (schema == NULL)
2048 nulls[i++] = true;
2049 else
2050 values[i++] = CStringGetTextDatum(schema);
2051 /* identity */
2052 values[i++] = CStringGetTextDatum(identity);
2053 /* in_extension */
2054 values[i++] = BoolGetDatum(cmd->in_extension);
2055 /* command */
2056 values[i++] = PointerGetDatum(cmd);
2057 }
2058 break;
2059
2061 /* classid */
2062 nulls[i++] = true;
2063 /* objid */
2064 nulls[i++] = true;
2065 /* objsubid */
2066 nulls[i++] = true;
2067 /* command tag */
2069 /* object_type */
2071 /* schema */
2072 nulls[i++] = true;
2073 /* identity */
2074 nulls[i++] = true;
2075 /* in_extension */
2076 values[i++] = BoolGetDatum(cmd->in_extension);
2077 /* command */
2078 values[i++] = PointerGetDatum(cmd);
2079 break;
2080
2081 case SCT_Grant:
2082 /* classid */
2083 nulls[i++] = true;
2084 /* objid */
2085 nulls[i++] = true;
2086 /* objsubid */
2087 nulls[i++] = true;
2088 /* command tag */
2090 "GRANT" : "REVOKE");
2091 /* object_type */
2093 /* schema */
2094 nulls[i++] = true;
2095 /* identity */
2096 nulls[i++] = true;
2097 /* in_extension */
2098 values[i++] = BoolGetDatum(cmd->in_extension);
2099 /* command */
2100 values[i++] = PointerGetDatum(cmd);
2101 break;
2102 }
2103
2104 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2105 values, nulls);
2106 }
2107
2109}
2110
2111/*
2112 * Return the ObjectType as a string, as it would appear in GRANT and
2113 * REVOKE commands.
2114 */
2115static const char *
2117{
2118 switch (objtype)
2119 {
2120 case OBJECT_COLUMN:
2121 return "COLUMN";
2122 case OBJECT_TABLE:
2123 return "TABLE";
2124 case OBJECT_SEQUENCE:
2125 return "SEQUENCE";
2126 case OBJECT_DATABASE:
2127 return "DATABASE";
2128 case OBJECT_DOMAIN:
2129 return "DOMAIN";
2130 case OBJECT_FDW:
2131 return "FOREIGN DATA WRAPPER";
2133 return "FOREIGN SERVER";
2134 case OBJECT_FUNCTION:
2135 return "FUNCTION";
2136 case OBJECT_LANGUAGE:
2137 return "LANGUAGE";
2138 case OBJECT_LARGEOBJECT:
2139 return "LARGE OBJECT";
2140 case OBJECT_SCHEMA:
2141 return "SCHEMA";
2143 return "PARAMETER";
2144 case OBJECT_PROCEDURE:
2145 return "PROCEDURE";
2146 case OBJECT_ROUTINE:
2147 return "ROUTINE";
2148 case OBJECT_TABLESPACE:
2149 return "TABLESPACE";
2150 case OBJECT_TYPE:
2151 return "TYPE";
2152 /* these currently aren't used */
2154 case OBJECT_AGGREGATE:
2155 case OBJECT_AMOP:
2156 case OBJECT_AMPROC:
2157 case OBJECT_ATTRIBUTE:
2158 case OBJECT_CAST:
2159 case OBJECT_COLLATION:
2160 case OBJECT_CONVERSION:
2161 case OBJECT_DEFAULT:
2162 case OBJECT_DEFACL:
2165 case OBJECT_EXTENSION:
2167 case OBJECT_INDEX:
2168 case OBJECT_MATVIEW:
2169 case OBJECT_OPCLASS:
2170 case OBJECT_OPERATOR:
2171 case OBJECT_OPFAMILY:
2172 case OBJECT_POLICY:
2173 case OBJECT_PUBLICATION:
2176 case OBJECT_ROLE:
2177 case OBJECT_RULE:
2181 case OBJECT_TRANSFORM:
2182 case OBJECT_TRIGGER:
2185 case OBJECT_TSPARSER:
2186 case OBJECT_TSTEMPLATE:
2188 case OBJECT_VIEW:
2189 elog(ERROR, "unsupported object type: %d", (int) objtype);
2190 }
2191
2192 return "???"; /* keep compiler quiet */
2193}
2194
2195/*
2196 * Return the ObjectType as a string; as above, but use the spelling
2197 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2198 * the plural.
2199 */
2200static const char *
2202{
2203 switch (objtype)
2204 {
2205 case OBJECT_COLUMN:
2206 return "COLUMNS";
2207 case OBJECT_TABLE:
2208 return "TABLES";
2209 case OBJECT_SEQUENCE:
2210 return "SEQUENCES";
2211 case OBJECT_DATABASE:
2212 return "DATABASES";
2213 case OBJECT_DOMAIN:
2214 return "DOMAINS";
2215 case OBJECT_FDW:
2216 return "FOREIGN DATA WRAPPERS";
2218 return "FOREIGN SERVERS";
2219 case OBJECT_FUNCTION:
2220 return "FUNCTIONS";
2221 case OBJECT_LANGUAGE:
2222 return "LANGUAGES";
2223 case OBJECT_LARGEOBJECT:
2224 return "LARGE OBJECTS";
2225 case OBJECT_SCHEMA:
2226 return "SCHEMAS";
2227 case OBJECT_PROCEDURE:
2228 return "PROCEDURES";
2229 case OBJECT_ROUTINE:
2230 return "ROUTINES";
2231 case OBJECT_TABLESPACE:
2232 return "TABLESPACES";
2233 case OBJECT_TYPE:
2234 return "TYPES";
2235 /* these currently aren't used */
2237 case OBJECT_AGGREGATE:
2238 case OBJECT_AMOP:
2239 case OBJECT_AMPROC:
2240 case OBJECT_ATTRIBUTE:
2241 case OBJECT_CAST:
2242 case OBJECT_COLLATION:
2243 case OBJECT_CONVERSION:
2244 case OBJECT_DEFAULT:
2245 case OBJECT_DEFACL:
2248 case OBJECT_EXTENSION:
2250 case OBJECT_INDEX:
2251 case OBJECT_MATVIEW:
2252 case OBJECT_OPCLASS:
2253 case OBJECT_OPERATOR:
2254 case OBJECT_OPFAMILY:
2256 case OBJECT_POLICY:
2257 case OBJECT_PUBLICATION:
2260 case OBJECT_ROLE:
2261 case OBJECT_RULE:
2265 case OBJECT_TRANSFORM:
2266 case OBJECT_TRIGGER:
2269 case OBJECT_TSPARSER:
2270 case OBJECT_TSTEMPLATE:
2272 case OBJECT_VIEW:
2273 elog(ERROR, "unsupported object type: %d", (int) objtype);
2274 }
2275
2276 return "???"; /* keep compiler quiet */
2277}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4064
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:219
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:700
#define Assert(condition)
Definition: c.h:812
#define OidIsValid(objectId)
Definition: c.h:729
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
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:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PG_FINALLY(...)
Definition: elog.h:388
#define ereport(elevel,...)
Definition: elog.h:149
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)
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:81
struct SQLDropObject SQLDropObject
void EventTriggerAlterTableEnd(void)
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
bool event_triggers
Definition: event_trigger.c:84
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:73
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_inplace_update_cancel(void *state)
Definition: genam.c:905
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:810
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition: genam.c:886
bool MyDatabaseHasLoginEventTriggers
Definition: globals.c:97
bool IsUnderPostmaster
Definition: globals.c:119
Oid MyDatabaseId
Definition: globals.c:93
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:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
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 @161 value
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
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 LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1072
bool ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1096
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:594
#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:3390
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
Oid GetUserId(void)
Definition: miscinit.c:517
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:3594
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
#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
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2144
ObjectType
Definition: parsenodes.h:2267
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2282
@ OBJECT_FDW
Definition: parsenodes.h:2284
@ OBJECT_TSPARSER
Definition: parsenodes.h:2315
@ OBJECT_COLLATION
Definition: parsenodes.h:2275
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2318
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2268
@ OBJECT_OPCLASS
Definition: parsenodes.h:2292
@ OBJECT_DEFACL
Definition: parsenodes.h:2279
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2269
@ OBJECT_MATVIEW
Definition: parsenodes.h:2291
@ OBJECT_SCHEMA
Definition: parsenodes.h:2304
@ OBJECT_POLICY
Definition: parsenodes.h:2296
@ OBJECT_OPERATOR
Definition: parsenodes.h:2293
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2286
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2313
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2294
@ OBJECT_DOMAIN
Definition: parsenodes.h:2280
@ OBJECT_COLUMN
Definition: parsenodes.h:2274
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2310
@ OBJECT_ROLE
Definition: parsenodes.h:2301
@ OBJECT_ROUTINE
Definition: parsenodes.h:2302
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2290
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2299
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2297
@ OBJECT_EXTENSION
Definition: parsenodes.h:2283
@ OBJECT_INDEX
Definition: parsenodes.h:2288
@ OBJECT_DEFAULT
Definition: parsenodes.h:2278
@ OBJECT_DATABASE
Definition: parsenodes.h:2277
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2305
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2316
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2289
@ OBJECT_AMOP
Definition: parsenodes.h:2270
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2300
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2285
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2314
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2272
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2298
@ OBJECT_RULE
Definition: parsenodes.h:2303
@ OBJECT_CONVERSION
Definition: parsenodes.h:2276
@ OBJECT_AMPROC
Definition: parsenodes.h:2271
@ OBJECT_TABLE
Definition: parsenodes.h:2309
@ OBJECT_VIEW
Definition: parsenodes.h:2319
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2295
@ OBJECT_TYPE
Definition: parsenodes.h:2317
@ OBJECT_FUNCTION
Definition: parsenodes.h:2287
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2308
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2281
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2306
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2307
@ OBJECT_CAST
Definition: parsenodes.h:2273
@ OBJECT_TRIGGER
Definition: parsenodes.h:2312
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2311
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
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
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:322
static Name DatumGetName(Datum X)
Definition: postgres.h:360
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
tree context
Definition: radixtree.h:1837
MemoryContextSwitchTo(old_ctx)
static color newsub(struct colormap *cm, color co)
Definition: regc_color.c:389
#define RelationGetDescr(relation)
Definition: rel.h:531
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:212
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:610
void PopActiveSnapshot(void)
Definition: snapmgr.c:703
void check_stack_depth(void)
Definition: stack_depth.c:95
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
CollectedCommandType type
struct CollectedCommand::@124::@128 opfam
struct CollectedCommand::@124::@131 defprivs
InternalGrant * istmt
union CollectedCommand::@124 d
struct CollectedCommand::@124::@127 grant
struct CollectedCommand::@124::@126 alterTable
struct CollectedCommand::@124::@130 atscfg
struct CollectedCommand * parent
struct CollectedCommand::@124::@125 simple
ObjectAddress secondaryObject
struct CollectedCommand::@124::@129 createopc
ObjectAddress address
char * defname
Definition: parsenodes.h:817
Node * arg
Definition: parsenodes.h:818
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:78
CollectedCommand * currentCommand
Definition: event_trigger.c:75
Definition: fmgr.h:57
ItemPointerData t_self
Definition: htup.h:65
ObjectType objtype
Definition: pg_list.h:54
Definition: nodes.h:129
TupleDesc rd_att
Definition: rel.h:112
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342
ObjectAddress address
Definition: event_trigger.c:89
const char * schemaname
Definition: event_trigger.c:90
slist_node next
Definition: event_trigger.c:99
const char * objidentity
Definition: event_trigger.c:92
const char * objecttype
Definition: event_trigger.c:93
List * addrnames
Definition: event_trigger.c:94
const char * objname
Definition: event_trigger.c:91
Definition: c.h:695
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:404
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#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:2362
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:184
const char * type
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1099
void StartTransactionCommand(void)
Definition: xact.c:3051
void CommitTransactionCommand(void)
Definition: xact.c:3149