PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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/genam.h"
17#include "access/heapam.h"
18#include "access/htup_details.h"
19#include "access/table.h"
20#include "access/xact.h"
21#include "catalog/catalog.h"
22#include "catalog/dependency.h"
23#include "catalog/indexing.h"
25#include "catalog/pg_attrdef.h"
26#include "catalog/pg_authid.h"
28#include "catalog/pg_database.h"
31#include "catalog/pg_opclass.h"
32#include "catalog/pg_opfamily.h"
34#include "catalog/pg_policy.h"
35#include "catalog/pg_proc.h"
37#include "catalog/pg_trigger.h"
39#include "catalog/pg_type.h"
41#include "commands/extension.h"
42#include "commands/trigger.h"
43#include "funcapi.h"
44#include "lib/ilist.h"
45#include "miscadmin.h"
46#include "parser/parse_func.h"
47#include "pgstat.h"
48#include "storage/lmgr.h"
50#include "tcop/utility.h"
51#include "utils/acl.h"
52#include "utils/builtins.h"
53#include "utils/evtcache.h"
54#include "utils/fmgroids.h"
55#include "utils/fmgrprotos.h"
56#include "utils/lsyscache.h"
57#include "utils/memutils.h"
58#include "utils/rel.h"
59#include "utils/snapmgr.h"
60#include "utils/syscache.h"
61#include "utils/tuplestore.h"
62
64{
65 /* memory context for this state's objects */
67
68 /* sql_drop */
71
72 /* table_rewrite */
73 Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite
74 * event */
75 int table_rewrite_reason; /* AT_REWRITE reason */
76
77 /* Support for command collection */
80 List *commandList; /* list of CollectedCommand; see
81 * deparse_utility.h */
84
86
87/* GUC parameter */
88bool event_triggers = true;
89
90/* Support for dropped objects */
105
109static void error_duplicate_filter_variable(const char *defname);
111static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
113static void validate_ddl_tags(const char *filtervar, List *taglist);
114static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
115static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
116static bool obtain_object_name_namespace(const ObjectAddress *object,
117 SQLDropObject *obj);
118static const char *stringify_grant_objtype(ObjectType objtype);
119static const char *stringify_adefprivs_objtype(ObjectType objtype);
120static void SetDatabaseHasLoginEventTriggers(void);
121
122/*
123 * Create an event trigger.
124 */
125Oid
127{
128 HeapTuple tuple;
129 Oid funcoid;
131 Oid evtowner = GetUserId();
132 ListCell *lc;
133 List *tags = NULL;
134
135 /*
136 * It would be nice to allow database owners or even regular users to do
137 * this, but there are obvious privilege escalation risks which would have
138 * to somehow be plugged first.
139 */
140 if (!superuser())
143 errmsg("permission denied to create event trigger \"%s\"",
144 stmt->trigname),
145 errhint("Must be superuser to create an event trigger.")));
146
147 /* Validate event name. */
148 if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
149 strcmp(stmt->eventname, "ddl_command_end") != 0 &&
150 strcmp(stmt->eventname, "sql_drop") != 0 &&
151 strcmp(stmt->eventname, "login") != 0 &&
152 strcmp(stmt->eventname, "table_rewrite") != 0)
155 errmsg("unrecognized event name \"%s\"",
156 stmt->eventname)));
157
158 /* Validate filter conditions. */
159 foreach(lc, stmt->whenclause)
160 {
161 DefElem *def = (DefElem *) lfirst(lc);
162
163 if (strcmp(def->defname, "tag") == 0)
164 {
165 if (tags != NULL)
167 tags = (List *) def->arg;
168 }
169 else
172 errmsg("unrecognized filter variable \"%s\"", def->defname)));
173 }
174
175 /* Validate tag list, if any. */
176 if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
177 strcmp(stmt->eventname, "ddl_command_end") == 0 ||
178 strcmp(stmt->eventname, "sql_drop") == 0)
179 && tags != NULL)
180 validate_ddl_tags("tag", tags);
181 else if (strcmp(stmt->eventname, "table_rewrite") == 0
182 && tags != NULL)
184 else if (strcmp(stmt->eventname, "login") == 0 && tags != NULL)
187 errmsg("tag filtering is not supported for login event triggers")));
188
189 /*
190 * Give user a nice error message if an event trigger of the same name
191 * already exists.
192 */
194 if (HeapTupleIsValid(tuple))
197 errmsg("event trigger \"%s\" already exists",
198 stmt->trigname)));
199
200 /* Find and validate the trigger function. */
201 funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
206 errmsg("function %s must return type %s",
207 NameListToString(stmt->funcname), "event_trigger")));
208
209 /* Insert catalog entries. */
210 return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
211 evtowner, funcoid, tags);
212}
213
214/*
215 * Validate DDL command tags.
216 */
217static void
219{
220 ListCell *lc;
221
222 foreach(lc, taglist)
223 {
224 const char *tagstr = strVal(lfirst(lc));
225 CommandTag commandTag = GetCommandTagEnum(tagstr);
226
227 if (commandTag == CMDTAG_UNKNOWN)
230 errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
231 tagstr, filtervar)));
232 if (!command_tag_event_trigger_ok(commandTag))
235 /* translator: %s represents an SQL statement name */
236 errmsg("event triggers are not supported for %s",
237 tagstr)));
238 }
239}
240
241/*
242 * Validate DDL command tags for event table_rewrite.
243 */
244static void
246{
247 ListCell *lc;
248
249 foreach(lc, taglist)
250 {
251 const char *tagstr = strVal(lfirst(lc));
252 CommandTag commandTag = GetCommandTagEnum(tagstr);
253
254 if (!command_tag_table_rewrite_ok(commandTag))
257 /* translator: %s represents an SQL statement name */
258 errmsg("event triggers are not supported for %s",
259 tagstr)));
260 }
261}
262
263/*
264 * Complain about a duplicate filter variable.
265 */
266static void
268{
271 errmsg("filter variable \"%s\" specified more than once",
272 defname)));
273}
274
275/*
276 * Insert the new pg_event_trigger row and record dependencies.
277 */
278static Oid
279insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
281{
283 Oid trigoid;
284 HeapTuple tuple;
286 bool nulls[Natts_pg_event_trigger];
291
292 /* Open pg_event_trigger. */
294
295 /* Build the new pg_trigger tuple. */
299 memset(nulls, false, sizeof(nulls));
300 namestrcpy(&evtnamedata, trigname);
302 namestrcpy(&evteventdata, eventname);
308 if (taglist == NIL)
309 nulls[Anum_pg_event_trigger_evttags - 1] = true;
310 else
313
314 /* Insert heap tuple. */
315 tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
317 heap_freetuple(tuple);
318
319 /*
320 * Login event triggers have an additional flag in pg_database to enable
321 * faster lookups in hot codepaths. Set the flag unless already True.
322 */
323 if (strcmp(eventname, "login") == 0)
325
326 /* Depend on owner. */
328
329 /* Depend on event trigger function. */
331 myself.objectId = trigoid;
332 myself.objectSubId = 0;
334 referenced.objectId = funcoid;
335 referenced.objectSubId = 0;
337
338 /* Depend on extension, if any. */
340
341 /* Post creation hook for new event trigger */
343
344 /* Close pg_event_trigger. */
346
347 return trigoid;
348}
349
350/*
351 * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
352 * by a DefElem whose value is a List of String nodes; in the catalog, we
353 * store the list of strings as a text array. This function transforms the
354 * former representation into the latter one.
355 *
356 * For cleanliness, we store command tags in the catalog as text. It's
357 * possible (although not currently anticipated) that we might have
358 * a case-sensitive filter variable in the future, in which case this would
359 * need some further adjustment.
360 */
361static Datum
363{
364 ListCell *lc;
365 Datum *data;
366 int i = 0,
368
369 data = palloc_array(Datum, l);
370
371 foreach(lc, filterlist)
372 {
373 const char *value = strVal(lfirst(lc));
374 char *result,
375 *p;
376
378 for (p = result; *p; p++)
379 *p = pg_ascii_toupper((unsigned char) *p);
381 pfree(result);
382 }
383
385}
386
387/*
388 * Set pg_database.dathasloginevt flag for current database indicating that
389 * current database has on login event triggers.
390 */
391void
393{
394 /* Set dathasloginevt flag in pg_database */
398 HeapTuple tuple;
399
400 /*
401 * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying
402 * to reset pg_database.dathasloginevt flag. Note, this lock doesn't
403 * effectively blocks database or other objection. It's just custom lock
404 * tag used to prevent multiple backends changing
405 * pg_database.dathasloginevt flag.
406 */
408
410 if (!HeapTupleIsValid(tuple))
411 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
412 otid = tuple->t_self;
413 db = (Form_pg_database) GETSTRUCT(tuple);
414 if (!db->dathasloginevt)
415 {
416 db->dathasloginevt = true;
417 CatalogTupleUpdate(pg_db, &otid, tuple);
419 }
422 heap_freetuple(tuple);
423}
424
425/*
426 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
427 */
428Oid
430{
433 Oid trigoid;
435 char tgenabled = stmt->tgenabled;
436
438
440 CStringGetDatum(stmt->trigname));
441 if (!HeapTupleIsValid(tup))
444 errmsg("event trigger \"%s\" does not exist",
445 stmt->trigname)));
446
448 trigoid = evtForm->oid;
449
452 stmt->trigname);
453
454 /* tuple is a copy, so we can modify it below */
455 evtForm->evtenabled = tgenabled;
456
457 CatalogTupleUpdate(tgrel, &tup->t_self, tup);
458
459 /*
460 * Login event triggers have an additional flag in pg_database to enable
461 * faster lookups in hot codepaths. Set the flag unless already True.
462 */
463 if (namestrcmp(&evtForm->evtevent, "login") == 0 &&
464 tgenabled != TRIGGER_DISABLED)
466
468 trigoid, 0);
469
470 /* clean up */
473
474 return trigoid;
475}
476
477/*
478 * Change event trigger's owner -- by name
479 */
482{
483 Oid evtOid;
486 Relation rel;
487 ObjectAddress address;
488
490
492
493 if (!HeapTupleIsValid(tup))
496 errmsg("event trigger \"%s\" does not exist", name)));
497
499 evtOid = evtForm->oid;
500
502
504
506
508
509 return address;
510}
511
512/*
513 * Change event trigger owner, by OID
514 */
515void
517{
519 Relation rel;
520
522
524
525 if (!HeapTupleIsValid(tup))
528 errmsg("event trigger with OID %u does not exist", trigOid)));
529
531
533
535}
536
537/*
538 * Internal workhorse for changing an event trigger's owner
539 */
540static void
542{
544
546
547 if (form->evtowner == newOwnerId)
548 return;
549
552 NameStr(form->evtname));
553
554 /* New owner must be a superuser */
558 errmsg("permission denied to change owner of event trigger \"%s\"",
559 NameStr(form->evtname)),
560 errhint("The owner of an event trigger must be a superuser.")));
561
562 form->evtowner = newOwnerId;
563 CatalogTupleUpdate(rel, &tup->t_self, tup);
564
565 /* Update owner dependency reference */
567 form->oid,
568 newOwnerId);
569
571 form->oid, 0);
572}
573
574/*
575 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
576 *
577 * If missing_ok is false, throw an error if trigger not found. If
578 * true, just return InvalidOid.
579 */
580Oid
581get_event_trigger_oid(const char *trigname, bool missing_ok)
582{
583 Oid oid;
584
586 CStringGetDatum(trigname));
587 if (!OidIsValid(oid) && !missing_ok)
590 errmsg("event trigger \"%s\" does not exist", trigname)));
591 return oid;
592}
593
594/*
595 * Return true when we want to fire given Event Trigger and false otherwise,
596 * filtering on the session replication role and the event trigger registered
597 * tags matching.
598 */
599static bool
601{
602 /*
603 * Filter by session replication role, knowing that we never see disabled
604 * items down here.
605 */
607 {
608 if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
609 return false;
610 }
611 else
612 {
614 return false;
615 }
616
617 /* Filter by tags, if any were specified. */
618 if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
619 return false;
620
621 /* if we reach that point, we're not filtering out this item */
622 return true;
623}
624
625static CommandTag
627{
628 if (event == EVT_Login)
629 return CMDTAG_LOGIN;
630 else
631 return CreateCommandTag(parsetree);
632}
633
634/*
635 * Setup for running triggers for the given event. Return value is an OID list
636 * of functions to run; if there are any, trigdata is filled with an
637 * appropriate EventTriggerData for them to receive.
638 */
639static List *
641 EventTriggerEvent event, const char *eventstr,
642 EventTriggerData *trigdata, bool unfiltered)
643{
644 CommandTag tag;
646 ListCell *lc;
647 List *runlist = NIL;
648
649 /*
650 * We want the list of command tags for which this procedure is actually
651 * invoked to match up exactly with the list that CREATE EVENT TRIGGER
652 * accepts. This debugging cross-check will throw an error if this
653 * function is invoked for a command tag that CREATE EVENT TRIGGER won't
654 * accept. (Unfortunately, there doesn't seem to be any simple, automated
655 * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
656 * never reaches this control point.)
657 *
658 * If this cross-check fails for you, you probably need to either adjust
659 * standard_ProcessUtility() not to invoke event triggers for the command
660 * type in question, or you need to adjust event_trigger_ok to accept the
661 * relevant command tag.
662 */
663#ifdef USE_ASSERT_CHECKING
664 {
666
667 dbgtag = EventTriggerGetTag(parsetree, event);
668
669 if (event == EVT_DDLCommandStart ||
670 event == EVT_DDLCommandEnd ||
671 event == EVT_SQLDrop ||
672 event == EVT_Login)
673 {
675 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
676 }
677 else if (event == EVT_TableRewrite)
678 {
680 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
681 }
682 }
683#endif
684
685 /* Use cache to find triggers for this event; fast exit if none. */
687 if (cachelist == NIL)
688 return NIL;
689
690 /* Get the command tag. */
691 tag = EventTriggerGetTag(parsetree, event);
692
693 /*
694 * Filter list of event triggers by command tag, and copy them into our
695 * memory context. Once we start running the command triggers, or indeed
696 * once we do anything at all that touches the catalogs, an invalidation
697 * might leave cachelist pointing at garbage, so we must do this before we
698 * can do much else.
699 */
700 foreach(lc, cachelist)
701 {
703
704 if (unfiltered || filter_event_trigger(tag, item))
705 {
706 /* We must plan to fire this trigger. */
708 }
709 }
710
711 /* Don't spend any more time on this if no functions to run */
712 if (runlist == NIL)
713 return NIL;
714
715 trigdata->type = T_EventTriggerData;
716 trigdata->event = eventstr;
717 trigdata->parsetree = parsetree;
718 trigdata->tag = tag;
719
720 return runlist;
721}
722
723/*
724 * Fire ddl_command_start triggers.
725 */
726void
728{
729 List *runlist;
730 EventTriggerData trigdata;
731
732 /*
733 * Event Triggers are completely disabled in standalone mode. There are
734 * (at least) two reasons for this:
735 *
736 * 1. A sufficiently broken event trigger might not only render the
737 * database unusable, but prevent disabling itself to fix the situation.
738 * In this scenario, restarting in standalone mode provides an escape
739 * hatch.
740 *
741 * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
742 * therefore will malfunction if pg_event_trigger's indexes are damaged.
743 * To allow recovery from a damaged index, we need some operating mode
744 * wherein event triggers are disabled. (Or we could implement
745 * heapscan-and-sort logic for that case, but having disaster recovery
746 * scenarios depend on code that's otherwise untested isn't appetizing.)
747 *
748 * Additionally, event triggers can be disabled with a superuser-only GUC
749 * to make fixing database easier as per 1 above.
750 */
752 return;
753
756 "ddl_command_start",
757 &trigdata, false);
758 if (runlist == NIL)
759 return;
760
761 /* Run the triggers. */
762 EventTriggerInvoke(runlist, &trigdata);
763
764 /* Cleanup. */
766
767 /*
768 * Make sure anything the event triggers did will be visible to the main
769 * command.
770 */
772}
773
774/*
775 * Fire ddl_command_end triggers.
776 */
777void
779{
780 List *runlist;
781 EventTriggerData trigdata;
782
783 /*
784 * See EventTriggerDDLCommandStart for a discussion about why event
785 * triggers are disabled in single user mode or via GUC.
786 */
788 return;
789
790 /*
791 * Also do nothing if our state isn't set up, which it won't be if there
792 * weren't any relevant event triggers at the start of the current DDL
793 * command. This test might therefore seem optional, but it's important
794 * because EventTriggerCommonSetup might find triggers that didn't exist
795 * at the time the command started. Although this function itself
796 * wouldn't crash, the event trigger functions would presumably call
797 * pg_event_trigger_ddl_commands which would fail. Better to do nothing
798 * until the next command.
799 */
801 return;
802
804 EVT_DDLCommandEnd, "ddl_command_end",
805 &trigdata, false);
806 if (runlist == NIL)
807 return;
808
809 /*
810 * Make sure anything the main command did will be visible to the event
811 * triggers.
812 */
814
815 /* Run the triggers. */
816 EventTriggerInvoke(runlist, &trigdata);
817
818 /* Cleanup. */
820}
821
822/*
823 * Fire sql_drop triggers.
824 */
825void
827{
828 List *runlist;
829 EventTriggerData trigdata;
830
831 /*
832 * See EventTriggerDDLCommandStart for a discussion about why event
833 * triggers are disabled in single user mode or via a GUC.
834 */
836 return;
837
838 /*
839 * Use current state to determine whether this event fires at all. If
840 * there are no triggers for the sql_drop event, then we don't have
841 * anything to do here. Note that dropped object collection is disabled
842 * if this is the case, so even if we were to try to run, the list would
843 * be empty.
844 */
847 return;
848
850 EVT_SQLDrop, "sql_drop",
851 &trigdata, false);
852
853 /*
854 * Nothing to do if run list is empty. Note this typically can't happen,
855 * because if there are no sql_drop events, then objects-to-drop wouldn't
856 * have been collected in the first place and we would have quit above.
857 * But it could occur if event triggers were dropped partway through.
858 */
859 if (runlist == NIL)
860 return;
861
862 /*
863 * Make sure anything the main command did will be visible to the event
864 * triggers.
865 */
867
868 /*
869 * Make sure pg_event_trigger_dropped_objects only works when running
870 * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
871 * one trigger fails. (This is perhaps not necessary, as the currentState
872 * variable will be removed shortly by our caller, but it seems better to
873 * play safe.)
874 */
876
877 /* Run the triggers. */
878 PG_TRY();
879 {
880 EventTriggerInvoke(runlist, &trigdata);
881 }
882 PG_FINALLY();
883 {
885 }
886 PG_END_TRY();
887
888 /* Cleanup. */
890}
891
892/*
893 * Fire login event triggers if any are present. The dathasloginevt
894 * pg_database flag is left unchanged when an event trigger is dropped to avoid
895 * complicating the codepath in the case of multiple event triggers. This
896 * function will instead unset the flag if no trigger is defined.
897 */
898void
900{
901 List *runlist;
902 EventTriggerData trigdata;
903
904 /*
905 * See EventTriggerDDLCommandStart for a discussion about why event
906 * triggers are disabled in single user mode or via a GUC. We also need a
907 * database connection (some background workers don't have it).
908 */
911 return;
912
915 EVT_Login, "login",
916 &trigdata, false);
917
918 if (runlist != NIL)
919 {
920 /*
921 * Event trigger execution may require an active snapshot.
922 */
924
925 /* Run the triggers. */
926 EventTriggerInvoke(runlist, &trigdata);
927
928 /* Cleanup. */
930
932 }
933
934 /*
935 * There is no active login event trigger, but our
936 * pg_database.dathasloginevt is set. Try to unset this flag. We use the
937 * lock to prevent concurrent SetDatabaseHasLoginEventTriggers(), but we
938 * don't want to hang the connection waiting on the lock. Thus, we are
939 * just trying to acquire the lock conditionally.
940 *
941 * Skip this on a hot standby: the conditional AccessExclusiveLock on the
942 * database object would fail with "cannot acquire lock mode ... while
943 * recovery is in progress", which the caller would surface as a FATAL
944 * connection error. On a standby, we cannot (and must not) clear the
945 * pg_database flag ourselves; it will be cleared via WAL replay once the
946 * primary's next login event trigger run clears it on the primary.
947 */
948 else if (!RecoveryInProgress() &&
951 {
952 /*
953 * The lock is held. Now we need to recheck that login event triggers
954 * list is still empty. Once the list is empty, we know that even if
955 * there is a backend which concurrently inserts/enables a login event
956 * trigger, it will update pg_database.dathasloginevt *afterwards*.
957 */
959 EVT_Login, "login",
960 &trigdata, true);
961
962 if (runlist == NIL)
963 {
965 HeapTuple tuple;
966 void *state;
968 ScanKeyData key[1];
969
970 /* Fetch a copy of the tuple to scribble on */
971 ScanKeyInit(&key[0],
975
977 NULL, 1, key, &tuple, &state);
978
979 if (!HeapTupleIsValid(tuple))
980 elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
981
982 db = (Form_pg_database) GETSTRUCT(tuple);
983 if (db->dathasloginevt)
984 {
985 db->dathasloginevt = false;
986
987 /*
988 * Do an "in place" update of the pg_database tuple. Doing
989 * this instead of regular updates serves two purposes. First,
990 * that avoids possible waiting on the row-level lock. Second,
991 * that avoids dealing with TOAST.
992 */
994 }
995 else
998 heap_freetuple(tuple);
999 }
1000 else
1001 {
1003 }
1004 }
1006}
1007
1008
1009/*
1010 * Fire table_rewrite triggers.
1011 */
1012void
1013EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
1014{
1015 List *runlist;
1016 EventTriggerData trigdata;
1017
1018 /*
1019 * See EventTriggerDDLCommandStart for a discussion about why event
1020 * triggers are disabled in single user mode or via a GUC.
1021 */
1023 return;
1024
1025 /*
1026 * Also do nothing if our state isn't set up, which it won't be if there
1027 * weren't any relevant event triggers at the start of the current DDL
1028 * command. This test might therefore seem optional, but it's
1029 * *necessary*, because EventTriggerCommonSetup might find triggers that
1030 * didn't exist at the time the command started.
1031 */
1033 return;
1034
1035 runlist = EventTriggerCommonSetup(parsetree,
1037 "table_rewrite",
1038 &trigdata, false);
1039 if (runlist == NIL)
1040 return;
1041
1042 /*
1043 * Make sure pg_event_trigger_table_rewrite_oid only works when running
1044 * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
1045 * when one trigger fails. (This is perhaps not necessary, as the
1046 * currentState variable will be removed shortly by our caller, but it
1047 * seems better to play safe.)
1048 */
1051
1052 /* Run the triggers. */
1053 PG_TRY();
1054 {
1055 EventTriggerInvoke(runlist, &trigdata);
1056 }
1057 PG_FINALLY();
1058 {
1061 }
1062 PG_END_TRY();
1063
1064 /* Cleanup. */
1066
1067 /*
1068 * Make sure anything the event triggers did will be visible to the main
1069 * command.
1070 */
1072}
1073
1074/*
1075 * Invoke each event trigger in a list of event triggers.
1076 */
1077static void
1079{
1080 MemoryContext context;
1081 MemoryContext oldcontext;
1082 ListCell *lc;
1083 bool first = true;
1084
1085 /* Guard against stack overflow due to recursive event trigger */
1087
1088 /*
1089 * Let's evaluate event triggers in their own memory context, so that any
1090 * leaks get cleaned up promptly.
1091 */
1093 "event trigger context",
1095 oldcontext = MemoryContextSwitchTo(context);
1096
1097 /* Call each event trigger. */
1098 foreach(lc, fn_oid_list)
1099 {
1100 LOCAL_FCINFO(fcinfo, 0);
1101 Oid fnoid = lfirst_oid(lc);
1102 FmgrInfo flinfo;
1104
1105 elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
1106
1107 /*
1108 * We want each event trigger to be able to see the results of the
1109 * previous event trigger's action. Caller is responsible for any
1110 * command-counter increment that is needed between the event trigger
1111 * and anything else in the transaction.
1112 */
1113 if (first)
1114 first = false;
1115 else
1117
1118 /* Look up the function */
1119 fmgr_info(fnoid, &flinfo);
1120
1121 /* Call the function, passing no arguments but setting a context. */
1122 InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
1123 InvalidOid, (Node *) trigdata, NULL);
1125 FunctionCallInvoke(fcinfo);
1127
1128 /* Reclaim memory. */
1129 MemoryContextReset(context);
1130 }
1131
1132 /* Restore old memory context and delete the temporary one. */
1133 MemoryContextSwitchTo(oldcontext);
1134 MemoryContextDelete(context);
1135}
1136
1137/*
1138 * Do event triggers support this object type?
1139 *
1140 * See also event trigger documentation in event-trigger.sgml.
1141 */
1142bool
1144{
1145 switch (obtype)
1146 {
1147 case OBJECT_DATABASE:
1148 case OBJECT_TABLESPACE:
1149 case OBJECT_ROLE:
1151 /* no support for global objects (except subscriptions) */
1152 return false;
1154 /* no support for event triggers on event triggers */
1155 return false;
1156 default:
1157 return true;
1158 }
1159}
1160
1161/*
1162 * Do event triggers support this object class?
1163 *
1164 * See also event trigger documentation in event-trigger.sgml.
1165 */
1166bool
1168{
1169 switch (object->classId)
1170 {
1171 case DatabaseRelationId:
1173 case AuthIdRelationId:
1174 case AuthMemRelationId:
1176 /* no support for global objects (except subscriptions) */
1177 return false;
1179 /* no support for event triggers on event triggers */
1180 return false;
1181 default:
1182 return true;
1183 }
1184}
1185
1186/*
1187 * Prepare event trigger state for a new complete query to run, if necessary;
1188 * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1189 * be called when the query is done, regardless of whether it succeeds or fails
1190 * -- so use of a PG_TRY block is mandatory.
1191 */
1192bool
1194{
1196 MemoryContext cxt;
1197
1198 /*
1199 * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1200 * reason to have event trigger state at all; so if there are none, don't
1201 * install one.
1202 */
1204 return false;
1205
1207 "event trigger state",
1210 state->cxt = cxt;
1211 slist_init(&(state->SQLDropList));
1212 state->in_sql_drop = false;
1213 state->table_rewrite_oid = InvalidOid;
1214
1215 state->commandCollectionInhibited = currentEventTriggerState ?
1217 state->currentCommand = NULL;
1218 state->commandList = NIL;
1219 state->previous = currentEventTriggerState;
1221
1222 return true;
1223}
1224
1225/*
1226 * Query completed (or errored out) -- clean up local state, return to previous
1227 * one.
1228 *
1229 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1230 * returned false previously.
1231 *
1232 * Note: this might be called in the PG_CATCH block of a failing transaction,
1233 * so be wary of running anything unnecessary. (In particular, it's probably
1234 * unwise to try to allocate memory.)
1235 */
1236void
1238{
1240
1242
1243 /* this avoids the need for retail pfree of SQLDropList items: */
1245
1247}
1248
1249/*
1250 * Do we need to keep close track of objects being dropped?
1251 *
1252 * This is useful because there is a cost to running with them enabled.
1253 */
1254bool
1256{
1257 /*
1258 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1259 * exists
1260 */
1261 return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
1264}
1265
1266/*
1267 * Support for dropped objects information on event trigger functions.
1268 *
1269 * We keep the list of objects dropped by the current command in current
1270 * state's SQLDropList (comprising SQLDropObject items). Each time a new
1271 * command is to start, a clean EventTriggerQueryState is created; commands
1272 * that drop objects do the dependency.c dance to drop objects, which
1273 * populates the current state's SQLDropList; when the event triggers are
1274 * invoked they can consume the list via pg_event_trigger_dropped_objects().
1275 * When the command finishes, the EventTriggerQueryState is cleared, and
1276 * the one from the previous command is restored (when no command is in
1277 * execution, the current state is NULL).
1278 *
1279 * All this lets us support the case that an event trigger function drops
1280 * objects "reentrantly".
1281 */
1282
1283/*
1284 * Register one object as being dropped by the current command.
1285 */
1286void
1287EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1288{
1289 SQLDropObject *obj;
1291
1293 return;
1294
1296
1298
1300 obj->address = *object;
1301 obj->original = original;
1302 obj->normal = normal;
1303
1304 if (object->classId == NamespaceRelationId)
1305 {
1306 /* Special handling is needed for temp namespaces */
1307 if (isTempNamespace(object->objectId))
1308 obj->istemp = true;
1309 else if (isAnyTempNamespace(object->objectId))
1310 {
1311 /* don't report temp schemas except my own */
1312 pfree(obj);
1314 return;
1315 }
1316 obj->objname = get_namespace_name(object->objectId);
1317 }
1318 else if (object->classId == AttrDefaultRelationId)
1319 {
1320 /* We treat a column default as temp if its table is temp */
1322
1324 if (OidIsValid(colobject.objectId))
1325 {
1327 {
1328 pfree(obj);
1330 return;
1331 }
1332 }
1333 }
1334 else if (object->classId == TriggerRelationId)
1335 {
1336 /* Similarly, a trigger is temp if its table is temp */
1337 /* Sadly, there's no lsyscache.c support for trigger objects */
1339 ScanKeyData skey[1];
1341 HeapTuple tuple;
1342 Oid relid;
1343
1344 /* Fetch the trigger's table OID the hard way */
1346 ScanKeyInit(&skey[0],
1349 ObjectIdGetDatum(object->objectId));
1351 NULL, 1, skey);
1352 tuple = systable_getnext(sscan);
1353 if (HeapTupleIsValid(tuple))
1354 relid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid;
1355 else
1356 relid = InvalidOid; /* shouldn't happen */
1359 /* Do nothing if we didn't find the trigger */
1360 if (OidIsValid(relid))
1361 {
1363
1365 relobject.objectId = relid;
1366 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1367 relobject.objectSubId = 1;
1369 {
1370 pfree(obj);
1372 return;
1373 }
1374 }
1375 }
1376 else if (object->classId == PolicyRelationId)
1377 {
1378 /* Similarly, a policy is temp if its table is temp */
1379 /* Sadly, there's no lsyscache.c support for policy objects */
1381 ScanKeyData skey[1];
1383 HeapTuple tuple;
1384 Oid relid;
1385
1386 /* Fetch the policy's table OID the hard way */
1388 ScanKeyInit(&skey[0],
1391 ObjectIdGetDatum(object->objectId));
1393 NULL, 1, skey);
1394 tuple = systable_getnext(sscan);
1395 if (HeapTupleIsValid(tuple))
1396 relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
1397 else
1398 relid = InvalidOid; /* shouldn't happen */
1401 /* Do nothing if we didn't find the policy */
1402 if (OidIsValid(relid))
1403 {
1405
1407 relobject.objectId = relid;
1408 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1409 relobject.objectSubId = 1;
1411 {
1412 pfree(obj);
1414 return;
1415 }
1416 }
1417 }
1418 else
1419 {
1420 /* Generic handling for all other object classes */
1421 if (!obtain_object_name_namespace(object, obj))
1422 {
1423 /* don't report temp objects except my own */
1424 pfree(obj);
1426 return;
1427 }
1428 }
1429
1430 /* object identity, objname and objargs */
1431 obj->objidentity =
1433 false);
1434
1435 /* object type */
1436 obj->objecttype = getObjectTypeDescription(&obj->address, false);
1437
1439
1441}
1442
1443/*
1444 * Fill obj->objname, obj->schemaname, and obj->istemp based on object.
1445 *
1446 * Returns true if this object should be reported, false if it should
1447 * be ignored because it is a temporary object of another session.
1448 */
1449static bool
1451{
1452 /*
1453 * Obtain schema names from the object's catalog tuple, if one exists;
1454 * this lets us skip objects in temp schemas. We trust that
1455 * ObjectProperty contains all object classes that can be
1456 * schema-qualified.
1457 *
1458 * Currently, this function does nothing for object classes that are not
1459 * in ObjectProperty, but we might sometime add special cases for that.
1460 */
1461 if (is_objectclass_supported(object->classId))
1462 {
1464 HeapTuple tuple;
1465
1469 object->objectId);
1470
1471 if (tuple)
1472 {
1474 Datum datum;
1475 bool isnull;
1476
1479 {
1480 datum = heap_getattr(tuple, attnum,
1481 RelationGetDescr(catalog), &isnull);
1482 if (!isnull)
1483 {
1485
1487 /* temp objects are only reported if they are my own */
1489 {
1490 obj->schemaname = "pg_temp";
1491 obj->istemp = true;
1492 }
1494 {
1495 /* no need to fill any fields of *obj */
1497 return false;
1498 }
1499 else
1500 {
1502 obj->istemp = false;
1503 }
1504 }
1505 }
1506
1507 if (get_object_namensp_unique(object->classId) &&
1508 object->objectSubId == 0)
1509 {
1512 {
1513 datum = heap_getattr(tuple, attnum,
1514 RelationGetDescr(catalog), &isnull);
1515 if (!isnull)
1516 obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1517 }
1518 }
1519 }
1520
1522 }
1523
1524 return true;
1525}
1526
1527/*
1528 * pg_event_trigger_dropped_objects
1529 *
1530 * Make the list of dropped objects available to the user function run by the
1531 * Event Trigger.
1532 */
1533Datum
1535{
1536 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1537 slist_iter iter;
1538
1539 /*
1540 * Protect this function from being called out of context
1541 */
1544 ereport(ERROR,
1546 errmsg("%s can only be called in a sql_drop event trigger function",
1547 "pg_event_trigger_dropped_objects()")));
1548
1549 /* Build tuplestore to hold the result rows */
1550 InitMaterializedSRF(fcinfo, 0);
1551
1553 {
1554 SQLDropObject *obj;
1555 int i = 0;
1556 Datum values[12] = {0};
1557 bool nulls[12] = {0};
1558
1559 obj = slist_container(SQLDropObject, next, iter.cur);
1560
1561 /* classid */
1563
1564 /* objid */
1566
1567 /* objsubid */
1569
1570 /* original */
1571 values[i++] = BoolGetDatum(obj->original);
1572
1573 /* normal */
1574 values[i++] = BoolGetDatum(obj->normal);
1575
1576 /* is_temporary */
1577 values[i++] = BoolGetDatum(obj->istemp);
1578
1579 /* object_type */
1581
1582 /* schema_name */
1583 if (obj->schemaname)
1585 else
1586 nulls[i++] = true;
1587
1588 /* object_name */
1589 if (obj->objname)
1591 else
1592 nulls[i++] = true;
1593
1594 /* object_identity */
1595 if (obj->objidentity)
1597 else
1598 nulls[i++] = true;
1599
1600 /* address_names and address_args */
1601 if (obj->addrnames)
1602 {
1604
1605 if (obj->addrargs)
1607 else
1609 }
1610 else
1611 {
1612 nulls[i++] = true;
1613 nulls[i++] = true;
1614 }
1615
1616 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1617 values, nulls);
1618 }
1619
1620 return (Datum) 0;
1621}
1622
1623/*
1624 * pg_event_trigger_table_rewrite_oid
1625 *
1626 * Make the Oid of the table going to be rewritten available to the user
1627 * function run by the Event Trigger.
1628 */
1629Datum
1631{
1632 /*
1633 * Protect this function from being called out of context
1634 */
1637 ereport(ERROR,
1639 errmsg("%s can only be called in a table_rewrite event trigger function",
1640 "pg_event_trigger_table_rewrite_oid()")));
1641
1643}
1644
1645/*
1646 * pg_event_trigger_table_rewrite_reason
1647 *
1648 * Make the rewrite reason available to the user.
1649 */
1650Datum
1652{
1653 /*
1654 * Protect this function from being called out of context
1655 */
1658 ereport(ERROR,
1660 errmsg("%s can only be called in a table_rewrite event trigger function",
1661 "pg_event_trigger_table_rewrite_reason()")));
1662
1664}
1665
1666/*-------------------------------------------------------------------------
1667 * Support for DDL command deparsing
1668 *
1669 * The routines below enable an event trigger function to obtain a list of
1670 * DDL commands as they are executed. There are three main pieces to this
1671 * feature:
1672 *
1673 * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1674 * adds a struct CollectedCommand representation of itself to the command list,
1675 * using the routines below.
1676 *
1677 * 2) Some time after that, ddl_command_end fires and the command list is made
1678 * available to the event trigger function via pg_event_trigger_ddl_commands();
1679 * the complete command details are exposed as a column of type pg_ddl_command.
1680 *
1681 * 3) An extension can install a function capable of taking a value of type
1682 * pg_ddl_command and transform it into some external, user-visible and/or
1683 * -modifiable representation.
1684 *-------------------------------------------------------------------------
1685 */
1686
1687/*
1688 * Inhibit DDL command collection.
1689 */
1690void
1698
1699/*
1700 * Re-establish DDL command collection.
1701 */
1702void
1710
1711/*
1712 * EventTriggerCollectSimpleCommand
1713 * Save data about a simple DDL command that was just executed
1714 *
1715 * address identifies the object being operated on. secondaryObject is an
1716 * object address that was related in some way to the executed command; its
1717 * meaning is command-specific.
1718 *
1719 * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1720 * object being moved, objectId is its OID, and secondaryOid is the OID of the
1721 * old schema. (The destination schema OID can be obtained by catalog lookup
1722 * of the object.)
1723 */
1724void
1726 ObjectAddress secondaryObject,
1727 const Node *parsetree)
1728{
1730 CollectedCommand *command;
1731
1732 /* ignore if event trigger context not set, or collection disabled */
1735 return;
1736
1738
1740
1741 command->type = SCT_Simple;
1743
1744 command->d.simple.address = address;
1745 command->d.simple.secondaryObject = secondaryObject;
1746 command->parsetree = copyObject(parsetree);
1747
1749 command);
1750
1752}
1753
1754/*
1755 * EventTriggerAlterTableStart
1756 * Prepare to receive data on an ALTER TABLE command about to be executed
1757 *
1758 * Note we don't collect the command immediately; instead we keep it in
1759 * currentCommand, and only when we're done processing the subcommands we will
1760 * add it to the command list.
1761 */
1762void
1764{
1766 CollectedCommand *command;
1767
1768 /* ignore if event trigger context not set, or collection disabled */
1771 return;
1772
1774
1776
1777 command->type = SCT_AlterTable;
1779
1781 command->d.alterTable.objectId = InvalidOid;
1782 command->d.alterTable.subcmds = NIL;
1783 command->parsetree = copyObject(parsetree);
1784
1787
1789}
1790
1791/*
1792 * Remember the OID of the object being affected by an ALTER TABLE.
1793 *
1794 * This is needed because in some cases we don't know the OID until later.
1795 */
1796void
1805
1806/*
1807 * EventTriggerCollectAlterTableSubcmd
1808 * Save data about a single part of an ALTER TABLE.
1809 *
1810 * Several different commands go through this path, but apart from ALTER TABLE
1811 * itself, they are all concerned with AlterTableCmd nodes that are generated
1812 * internally, so that's all that this code needs to handle at the moment.
1813 */
1814void
1840
1841/*
1842 * EventTriggerAlterTableEnd
1843 * Finish up saving an ALTER TABLE command, and add it to command list.
1844 *
1845 * FIXME this API isn't considering the possibility that an xact/subxact is
1846 * aborted partway through. Probably it's best to add an
1847 * AtEOSubXact_EventTriggers() to fix this.
1848 */
1849void
1851{
1852 CollectedCommand *parent;
1853
1854 /* ignore if event trigger context not set, or collection disabled */
1857 return;
1858
1860
1861 /* If no subcommands, don't collect */
1863 {
1865
1867
1871
1873 }
1874 else
1876
1878}
1879
1880/*
1881 * EventTriggerCollectGrant
1882 * Save data about a GRANT/REVOKE command being executed
1883 *
1884 * This function creates a copy of the InternalGrant, as the original might
1885 * not have the right lifetime.
1886 */
1887void
1889{
1891 CollectedCommand *command;
1893 ListCell *cell;
1894
1895 /* ignore if event trigger context not set, or collection disabled */
1898 return;
1899
1901
1902 /*
1903 * This is tedious, but necessary.
1904 */
1906 memcpy(icopy, istmt, sizeof(InternalGrant));
1907 icopy->objects = list_copy(istmt->objects);
1908 icopy->grantees = list_copy(istmt->grantees);
1909 icopy->col_privs = NIL;
1910 foreach(cell, istmt->col_privs)
1911 icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1912
1913 /* Now collect it, using the copied InternalGrant */
1915 command->type = SCT_Grant;
1917 command->d.grant.istmt = icopy;
1918 command->parsetree = NULL;
1919
1922
1924}
1925
1926/*
1927 * EventTriggerCollectAlterOpFam
1928 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1929 * executed
1930 */
1931void
1933 List *operators, List *procedures)
1934{
1936 CollectedCommand *command;
1937
1938 /* ignore if event trigger context not set, or collection disabled */
1941 return;
1942
1944
1946 command->type = SCT_AlterOpFamily;
1950 command->d.opfam.operators = operators;
1951 command->d.opfam.procedures = procedures;
1952 command->parsetree = (Node *) copyObject(stmt);
1953
1956
1958}
1959
1960/*
1961 * EventTriggerCollectCreateOpClass
1962 * Save data about a CREATE OPERATOR CLASS command being executed
1963 */
1964void
1966 List *operators, List *procedures)
1967{
1969 CollectedCommand *command;
1970
1971 /* ignore if event trigger context not set, or collection disabled */
1974 return;
1975
1977
1979 command->type = SCT_CreateOpClass;
1983 command->d.createopc.operators = operators;
1984 command->d.createopc.procedures = procedures;
1985 command->parsetree = (Node *) copyObject(stmt);
1986
1989
1991}
1992
1993/*
1994 * EventTriggerCollectAlterTSConfig
1995 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1996 * executed
1997 */
1998void
2000 Oid *dictIds, int ndicts)
2001{
2003 CollectedCommand *command;
2004
2005 /* ignore if event trigger context not set, or collection disabled */
2008 return;
2009
2011
2013 command->type = SCT_AlterTSConfig;
2016 TSConfigRelationId, cfgId);
2017 if (ndicts > 0)
2018 {
2019 command->d.atscfg.dictIds = palloc_array(Oid, ndicts);
2020 memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
2021 }
2022 command->d.atscfg.ndicts = ndicts;
2023 command->parsetree = (Node *) copyObject(stmt);
2024
2027
2029}
2030
2031/*
2032 * EventTriggerCollectAlterDefPrivs
2033 * Save data about an ALTER DEFAULT PRIVILEGES command being
2034 * executed
2035 */
2036void
2038{
2040 CollectedCommand *command;
2041
2042 /* ignore if event trigger context not set, or collection disabled */
2045 return;
2046
2048
2051 command->d.defprivs.objtype = stmt->action->objtype;
2053 command->parsetree = (Node *) copyObject(stmt);
2054
2058}
2059
2060/*
2061 * In a ddl_command_end event trigger, this function reports the DDL commands
2062 * being run.
2063 */
2064Datum
2066{
2067 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2068 ListCell *lc;
2069
2070 /*
2071 * Protect this function from being called out of context
2072 */
2074 ereport(ERROR,
2076 errmsg("%s can only be called in an event trigger function",
2077 "pg_event_trigger_ddl_commands()")));
2078
2079 /* Build tuplestore to hold the result rows */
2080 InitMaterializedSRF(fcinfo, 0);
2081
2083 {
2084 CollectedCommand *cmd = lfirst(lc);
2085 Datum values[9];
2086 bool nulls[9] = {0};
2087 ObjectAddress addr;
2088 int i = 0;
2089
2090 /*
2091 * For IF NOT EXISTS commands that attempt to create an existing
2092 * object, the returned OID is Invalid. Don't return anything.
2093 *
2094 * One might think that a viable alternative would be to look up the
2095 * Oid of the existing object and run the deparse with that. But
2096 * since the parse tree might be different from the one that created
2097 * the object in the first place, we might not end up in a consistent
2098 * state anyway.
2099 */
2100 if (cmd->type == SCT_Simple &&
2102 continue;
2103
2104 switch (cmd->type)
2105 {
2106 case SCT_Simple:
2107 case SCT_AlterTable:
2108 case SCT_AlterOpFamily:
2109 case SCT_CreateOpClass:
2110 case SCT_AlterTSConfig:
2111 {
2112 char *identity;
2113 char *type;
2114 char *schema = NULL;
2115
2116 if (cmd->type == SCT_Simple)
2117 addr = cmd->d.simple.address;
2118 else if (cmd->type == SCT_AlterTable)
2119 ObjectAddressSet(addr,
2120 cmd->d.alterTable.classId,
2121 cmd->d.alterTable.objectId);
2122 else if (cmd->type == SCT_AlterOpFamily)
2123 addr = cmd->d.opfam.address;
2124 else if (cmd->type == SCT_CreateOpClass)
2125 addr = cmd->d.createopc.address;
2126 else if (cmd->type == SCT_AlterTSConfig)
2127 addr = cmd->d.atscfg.address;
2128
2129 /*
2130 * If an object was dropped in the same command we may end
2131 * up in a situation where we generated a message but can
2132 * no longer look for the object information, so skip it
2133 * rather than failing. This can happen for example with
2134 * some subcommand combinations of ALTER TABLE.
2135 */
2136 identity = getObjectIdentity(&addr, true);
2137 if (identity == NULL)
2138 continue;
2139
2140 /* The type can never be NULL. */
2141 type = getObjectTypeDescription(&addr, true);
2142
2143 /*
2144 * Obtain schema name, if any ("pg_temp" if a temp
2145 * object). If the object class is not in the supported
2146 * list here, we assume it's a schema-less object type,
2147 * and thus "schema" remains set to NULL.
2148 */
2150 {
2152
2155 {
2159 bool isnull;
2160
2164 addr.objectId);
2166 elog(ERROR, "cache lookup failed for object %u/%u",
2167 addr.classId, addr.objectId);
2168 schema_oid =
2170 RelationGetDescr(catalog), &isnull));
2171 if (isnull)
2172 elog(ERROR,
2173 "invalid null namespace in object %u/%u/%d",
2174 addr.classId, addr.objectId, addr.objectSubId);
2176
2178 }
2179 }
2180
2181 /* classid */
2182 values[i++] = ObjectIdGetDatum(addr.classId);
2183 /* objid */
2184 values[i++] = ObjectIdGetDatum(addr.objectId);
2185 /* objsubid */
2186 values[i++] = Int32GetDatum(addr.objectSubId);
2187 /* command tag */
2189 /* object_type */
2191 /* schema */
2192 if (schema == NULL)
2193 nulls[i++] = true;
2194 else
2195 values[i++] = CStringGetTextDatum(schema);
2196 /* identity */
2197 values[i++] = CStringGetTextDatum(identity);
2198 /* in_extension */
2199 values[i++] = BoolGetDatum(cmd->in_extension);
2200 /* command */
2201 values[i++] = PointerGetDatum(cmd);
2202 }
2203 break;
2204
2206 /* classid */
2207 nulls[i++] = true;
2208 /* objid */
2209 nulls[i++] = true;
2210 /* objsubid */
2211 nulls[i++] = true;
2212 /* command tag */
2214 /* object_type */
2216 /* schema */
2217 nulls[i++] = true;
2218 /* identity */
2219 nulls[i++] = true;
2220 /* in_extension */
2221 values[i++] = BoolGetDatum(cmd->in_extension);
2222 /* command */
2223 values[i++] = PointerGetDatum(cmd);
2224 break;
2225
2226 case SCT_Grant:
2227 /* classid */
2228 nulls[i++] = true;
2229 /* objid */
2230 nulls[i++] = true;
2231 /* objsubid */
2232 nulls[i++] = true;
2233 /* command tag */
2235 "GRANT" : "REVOKE");
2236 /* object_type */
2238 /* schema */
2239 nulls[i++] = true;
2240 /* identity */
2241 nulls[i++] = true;
2242 /* in_extension */
2243 values[i++] = BoolGetDatum(cmd->in_extension);
2244 /* command */
2245 values[i++] = PointerGetDatum(cmd);
2246 break;
2247 }
2248
2249 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2250 values, nulls);
2251 }
2252
2254}
2255
2256/*
2257 * Return the ObjectType as a string, as it would appear in GRANT and
2258 * REVOKE commands.
2259 */
2260static const char *
2262{
2263 switch (objtype)
2264 {
2265 case OBJECT_COLUMN:
2266 return "COLUMN";
2267 case OBJECT_TABLE:
2268 return "TABLE";
2269 case OBJECT_SEQUENCE:
2270 return "SEQUENCE";
2271 case OBJECT_DATABASE:
2272 return "DATABASE";
2273 case OBJECT_DOMAIN:
2274 return "DOMAIN";
2275 case OBJECT_FDW:
2276 return "FOREIGN DATA WRAPPER";
2278 return "FOREIGN SERVER";
2279 case OBJECT_FUNCTION:
2280 return "FUNCTION";
2281 case OBJECT_LANGUAGE:
2282 return "LANGUAGE";
2283 case OBJECT_LARGEOBJECT:
2284 return "LARGE OBJECT";
2285 case OBJECT_SCHEMA:
2286 return "SCHEMA";
2288 return "PARAMETER";
2289 case OBJECT_PROCEDURE:
2290 return "PROCEDURE";
2291 case OBJECT_ROUTINE:
2292 return "ROUTINE";
2293 case OBJECT_TABLESPACE:
2294 return "TABLESPACE";
2295 case OBJECT_TYPE:
2296 return "TYPE";
2297 /* these currently aren't used */
2299 case OBJECT_AGGREGATE:
2300 case OBJECT_AMOP:
2301 case OBJECT_AMPROC:
2302 case OBJECT_ATTRIBUTE:
2303 case OBJECT_CAST:
2304 case OBJECT_COLLATION:
2305 case OBJECT_CONVERSION:
2306 case OBJECT_DEFAULT:
2307 case OBJECT_DEFACL:
2310 case OBJECT_EXTENSION:
2312 case OBJECT_INDEX:
2313 case OBJECT_MATVIEW:
2314 case OBJECT_OPCLASS:
2315 case OBJECT_OPERATOR:
2316 case OBJECT_OPFAMILY:
2317 case OBJECT_POLICY:
2318 case OBJECT_PROPGRAPH:
2319 case OBJECT_PUBLICATION:
2322 case OBJECT_ROLE:
2323 case OBJECT_RULE:
2327 case OBJECT_TRANSFORM:
2328 case OBJECT_TRIGGER:
2331 case OBJECT_TSPARSER:
2332 case OBJECT_TSTEMPLATE:
2334 case OBJECT_VIEW:
2335 elog(ERROR, "unsupported object type: %d", (int) objtype);
2336 }
2337
2338 return "???"; /* keep compiler quiet */
2339}
2340
2341/*
2342 * Return the ObjectType as a string; as above, but use the spelling
2343 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2344 * the plural.
2345 */
2346static const char *
2348{
2349 switch (objtype)
2350 {
2351 case OBJECT_COLUMN:
2352 return "COLUMNS";
2353 case OBJECT_TABLE:
2354 return "TABLES";
2355 case OBJECT_SEQUENCE:
2356 return "SEQUENCES";
2357 case OBJECT_DATABASE:
2358 return "DATABASES";
2359 case OBJECT_DOMAIN:
2360 return "DOMAINS";
2361 case OBJECT_FDW:
2362 return "FOREIGN DATA WRAPPERS";
2364 return "FOREIGN SERVERS";
2365 case OBJECT_FUNCTION:
2366 return "FUNCTIONS";
2367 case OBJECT_LANGUAGE:
2368 return "LANGUAGES";
2369 case OBJECT_LARGEOBJECT:
2370 return "LARGE OBJECTS";
2371 case OBJECT_SCHEMA:
2372 return "SCHEMAS";
2373 case OBJECT_PROCEDURE:
2374 return "PROCEDURES";
2375 case OBJECT_ROUTINE:
2376 return "ROUTINES";
2377 case OBJECT_TABLESPACE:
2378 return "TABLESPACES";
2379 case OBJECT_TYPE:
2380 return "TYPES";
2381 /* these currently aren't used */
2383 case OBJECT_AGGREGATE:
2384 case OBJECT_AMOP:
2385 case OBJECT_AMPROC:
2386 case OBJECT_ATTRIBUTE:
2387 case OBJECT_CAST:
2388 case OBJECT_COLLATION:
2389 case OBJECT_CONVERSION:
2390 case OBJECT_DEFAULT:
2391 case OBJECT_DEFACL:
2394 case OBJECT_EXTENSION:
2396 case OBJECT_INDEX:
2397 case OBJECT_MATVIEW:
2398 case OBJECT_OPCLASS:
2399 case OBJECT_OPERATOR:
2400 case OBJECT_OPFAMILY:
2402 case OBJECT_POLICY:
2403 case OBJECT_PROPGRAPH:
2404 case OBJECT_PUBLICATION:
2407 case OBJECT_ROLE:
2408 case OBJECT_RULE:
2412 case OBJECT_TRANSFORM:
2413 case OBJECT_TRIGGER:
2416 case OBJECT_TSPARSER:
2417 case OBJECT_TSTEMPLATE:
2419 case OBJECT_VIEW:
2420 elog(ERROR, "unsupported object type: %d", (int) objtype);
2421 }
2422
2423 return "???"; /* keep compiler quiet */
2424}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4134
ArrayType * construct_empty_array(Oid elmtype)
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
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:225
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define NameStr(name)
Definition c.h:835
#define Assert(condition)
Definition c.h:943
#define OidIsValid(objectId)
Definition c.h:858
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
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 errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define DEBUG1
Definition elog.h:31
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define PG_FINALLY(...)
Definition elog.h:391
#define ereport(elevel,...)
Definition elog.h:152
void EventTriggerUndoInhibitCommandCollection(void)
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
void EventTriggerOnLogin(void)
bool trackDroppedObjectsNeeded(void)
void EventTriggerCollectAlterTSConfig(const AlterTSConfigurationStmt *stmt, Oid cfgId, Oid *dictIds, int ndicts)
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)
void EventTriggerCollectAlterTableSubcmd(const Node *subcmd, ObjectAddress address)
static void validate_table_rewrite_tags(const char *filtervar, List *taglist)
Oid AlterEventTrigger(AlterEventTrigStmt *stmt)
static const char * stringify_adefprivs_objtype(ObjectType objtype)
void EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
void EventTriggerCollectGrant(InternalGrant *istmt)
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 EventTriggerAlterTableStart(const Node *parsetree)
static EventTriggerQueryState * currentEventTriggerState
void EventTriggerAlterTableEnd(void)
bool event_triggers
static void SetDatabaseHasLoginEventTriggers(void)
static void error_duplicate_filter_variable(const char *defname)
void EventTriggerCollectAlterDefPrivs(const AlterDefaultPrivilegesStmt *stmt)
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 EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, const Node *parsetree)
Oid get_event_trigger_oid(const char *trigname, bool missing_ok)
void EventTriggerCollectAlterOpFam(const AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
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:64
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:80
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_object(type)
Definition fe_memutils.h:90
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#define PG_RETURN_VOID()
Definition fmgr.h:350
#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:355
#define PG_RETURN_OID(x)
Definition fmgr.h:361
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
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
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
bool MyDatabaseHasLoginEventTriggers
Definition globals.c:100
bool IsUnderPostmaster
Definition globals.c:122
Oid MyDatabaseId
Definition globals.c:96
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
static void slist_init(slist_head *head)
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
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
static struct @177 value
int i
Definition isn.c:77
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:3698
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3674
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1961
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1235
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:406
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
MemoryContext TopMemoryContext
Definition mcxt.c:167
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
Oid GetUserId(void)
Definition miscinit.c:470
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:3666
bool isTempNamespace(Oid namespaceId)
Definition namespace.c:3721
bool isAnyTempNamespace(Oid namespaceId)
Definition namespace.c:3759
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define copyObject(obj)
Definition nodes.h:232
static char * errmsg
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
char * getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
ArrayType * strlist_to_textarray(List *list)
bool get_object_namensp_unique(Oid class_id)
HeapTuple get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
AttrNumber get_object_attnum_oid(Oid class_id)
AttrNumber get_object_attnum_namespace(Oid class_id)
char * getObjectIdentityParts(const ObjectAddress *object, List **objname, List **objargs, bool missing_ok)
AttrNumber get_object_attnum_name(Oid class_id)
char * getObjectIdentity(const ObjectAddress *object, bool missing_ok)
bool is_objectclass_supported(Oid class_id)
#define ObjectAddressSet(addr, class_id, object_id)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
ObjectType
@ OBJECT_EVENT_TRIGGER
@ OBJECT_FDW
@ OBJECT_TSPARSER
@ OBJECT_COLLATION
@ OBJECT_USER_MAPPING
@ OBJECT_PROPGRAPH
@ OBJECT_ACCESS_METHOD
@ OBJECT_OPCLASS
@ OBJECT_DEFACL
@ OBJECT_AGGREGATE
@ OBJECT_MATVIEW
@ OBJECT_SCHEMA
@ OBJECT_POLICY
@ OBJECT_OPERATOR
@ OBJECT_FOREIGN_TABLE
@ OBJECT_TSCONFIGURATION
@ OBJECT_OPFAMILY
@ OBJECT_DOMAIN
@ OBJECT_COLUMN
@ OBJECT_TABLESPACE
@ OBJECT_ROLE
@ OBJECT_ROUTINE
@ OBJECT_LARGEOBJECT
@ OBJECT_PUBLICATION_NAMESPACE
@ OBJECT_PROCEDURE
@ OBJECT_EXTENSION
@ OBJECT_INDEX
@ OBJECT_DEFAULT
@ OBJECT_DATABASE
@ OBJECT_SEQUENCE
@ OBJECT_TSTEMPLATE
@ OBJECT_LANGUAGE
@ OBJECT_AMOP
@ OBJECT_PUBLICATION_REL
@ OBJECT_FOREIGN_SERVER
@ OBJECT_TSDICTIONARY
@ OBJECT_ATTRIBUTE
@ OBJECT_PUBLICATION
@ OBJECT_RULE
@ OBJECT_CONVERSION
@ OBJECT_AMPROC
@ OBJECT_TABLE
@ OBJECT_VIEW
@ OBJECT_PARAMETER_ACL
@ OBJECT_TYPE
@ OBJECT_FUNCTION
@ OBJECT_TABCONSTRAINT
@ OBJECT_DOMCONSTRAINT
@ OBJECT_SUBSCRIPTION
@ OBJECT_STATISTIC_EXT
@ OBJECT_CAST
@ OBJECT_TRIGGER
@ OBJECT_TRANSFORM
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition pg_attrdef.c:322
int16 attnum
const void * data
END_CATALOG_STRUCT typedef FormData_pg_database * Form_pg_database
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:206
END_CATALOG_STRUCT typedef 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
END_CATALOG_STRUCT typedef FormData_pg_policy * Form_pg_policy
Definition pg_policy.h:55
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
END_CATALOG_STRUCT typedef FormData_pg_trigger * Form_pg_trigger
Definition pg_trigger.h:84
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
static unsigned char pg_ascii_toupper(unsigned char ch)
Definition port.h:178
static Name DatumGetName(Datum X)
Definition postgres.h:393
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define PointerGetDatum(X)
Definition postgres.h:354
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
unsigned int Oid
static int fb(int x)
static color newsub(struct colormap *cm, color co)
Definition regc_color.c:390
#define RelationGetDescr(relation)
Definition rel.h:542
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
void PopActiveSnapshot(void)
Definition snapmgr.c:775
void check_stack_depth(void)
Definition stack_depth.c:96
#define BTEqualStrategyNumber
Definition stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
CollectedCommandType type
InternalGrant * istmt
union CollectedCommand::@137 d
struct CollectedCommand::@137::@140 grant
struct CollectedCommand::@137::@142 createopc
struct CollectedCommand * parent
struct CollectedCommand::@137::@143 atscfg
ObjectAddress secondaryObject
struct CollectedCommand::@137::@141 opfam
struct CollectedCommand::@137::@144 defprivs
struct CollectedCommand::@137::@138 simple
ObjectAddress address
struct CollectedCommand::@137::@139 alterTable
char * defname
Definition parsenodes.h:860
Node * arg
Definition parsenodes.h:861
Bitmapset * tagset
Definition evtcache.h:33
const char * event
struct EventTriggerQueryState * previous
CollectedCommand * currentCommand
ItemPointerData t_self
Definition htup.h:65
ObjectType objtype
Definition pg_list.h:54
Definition nodes.h:135
ObjectAddress address
const char * schemaname
slist_node next
const char * objidentity
const char * objecttype
const char * objname
Definition c.h:830
slist_node * cur
Definition ilist.h:259
bool superuser_arg(Oid roleid)
Definition superuser.c:57
bool superuser(void)
Definition superuser.c:47
HeapTuple SearchSysCacheLockedCopy1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:400
HeapTuple SearchSysCache1(SysCacheIdentifier 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:65
#define SESSION_REPLICATION_ROLE_REPLICA
Definition trigger.h:143
#define TRIGGER_FIRES_ON_ORIGIN
Definition trigger.h:151
#define TRIGGER_DISABLED
Definition trigger.h:154
#define TRIGGER_FIRES_ON_REPLICA
Definition trigger.h:153
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785
CommandTag CreateCommandTag(Node *parsetree)
Definition utility.c:2385
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:1130
void StartTransactionCommand(void)
Definition xact.c:3109
void CommitTransactionCommand(void)
Definition xact.c:3207
bool RecoveryInProgress(void)
Definition xlog.c:6834