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/heapam.h"
17#include "access/htup_details.h"
18#include "access/table.h"
19#include "access/xact.h"
20#include "catalog/catalog.h"
21#include "catalog/dependency.h"
22#include "catalog/indexing.h"
24#include "catalog/pg_attrdef.h"
25#include "catalog/pg_authid.h"
27#include "catalog/pg_database.h"
30#include "catalog/pg_opclass.h"
31#include "catalog/pg_opfamily.h"
33#include "catalog/pg_policy.h"
34#include "catalog/pg_proc.h"
36#include "catalog/pg_trigger.h"
38#include "catalog/pg_type.h"
40#include "commands/extension.h"
41#include "commands/trigger.h"
42#include "funcapi.h"
43#include "lib/ilist.h"
44#include "miscadmin.h"
45#include "parser/parse_func.h"
46#include "pgstat.h"
47#include "storage/lmgr.h"
49#include "tcop/utility.h"
50#include "utils/acl.h"
51#include "utils/builtins.h"
52#include "utils/evtcache.h"
53#include "utils/fmgroids.h"
54#include "utils/fmgrprotos.h"
55#include "utils/lsyscache.h"
56#include "utils/memutils.h"
57#include "utils/rel.h"
58#include "utils/snapmgr.h"
59#include "utils/syscache.h"
60#include "utils/tuplestore.h"
61
63{
64 /* memory context for this state's objects */
66
67 /* sql_drop */
70
71 /* table_rewrite */
72 Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite
73 * event */
74 int table_rewrite_reason; /* AT_REWRITE reason */
75
76 /* Support for command collection */
79 List *commandList; /* list of CollectedCommand; see
80 * deparse_utility.h */
83
85
86/* GUC parameter */
87bool event_triggers = true;
88
89/* Support for dropped objects */
104
108static void error_duplicate_filter_variable(const char *defname);
110static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
112static void validate_ddl_tags(const char *filtervar, List *taglist);
113static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
114static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
115static bool obtain_object_name_namespace(const ObjectAddress *object,
116 SQLDropObject *obj);
117static const char *stringify_grant_objtype(ObjectType objtype);
118static const char *stringify_adefprivs_objtype(ObjectType objtype);
119static void SetDatabaseHasLoginEventTriggers(void);
120
121/*
122 * Create an event trigger.
123 */
124Oid
126{
127 HeapTuple tuple;
128 Oid funcoid;
130 Oid evtowner = GetUserId();
131 ListCell *lc;
132 List *tags = NULL;
133
134 /*
135 * It would be nice to allow database owners or even regular users to do
136 * this, but there are obvious privilege escalation risks which would have
137 * to somehow be plugged first.
138 */
139 if (!superuser())
142 errmsg("permission denied to create event trigger \"%s\"",
143 stmt->trigname),
144 errhint("Must be superuser to create an event trigger.")));
145
146 /* Validate event name. */
147 if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
148 strcmp(stmt->eventname, "ddl_command_end") != 0 &&
149 strcmp(stmt->eventname, "sql_drop") != 0 &&
150 strcmp(stmt->eventname, "login") != 0 &&
151 strcmp(stmt->eventname, "table_rewrite") != 0)
154 errmsg("unrecognized event name \"%s\"",
155 stmt->eventname)));
156
157 /* Validate filter conditions. */
158 foreach(lc, stmt->whenclause)
159 {
160 DefElem *def = (DefElem *) lfirst(lc);
161
162 if (strcmp(def->defname, "tag") == 0)
163 {
164 if (tags != NULL)
166 tags = (List *) def->arg;
167 }
168 else
171 errmsg("unrecognized filter variable \"%s\"", def->defname)));
172 }
173
174 /* Validate tag list, if any. */
175 if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
176 strcmp(stmt->eventname, "ddl_command_end") == 0 ||
177 strcmp(stmt->eventname, "sql_drop") == 0)
178 && tags != NULL)
179 validate_ddl_tags("tag", tags);
180 else if (strcmp(stmt->eventname, "table_rewrite") == 0
181 && tags != NULL)
183 else if (strcmp(stmt->eventname, "login") == 0 && tags != NULL)
186 errmsg("tag filtering is not supported for login event triggers")));
187
188 /*
189 * Give user a nice error message if an event trigger of the same name
190 * already exists.
191 */
193 if (HeapTupleIsValid(tuple))
196 errmsg("event trigger \"%s\" already exists",
197 stmt->trigname)));
198
199 /* Find and validate the trigger function. */
200 funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
205 errmsg("function %s must return type %s",
206 NameListToString(stmt->funcname), "event_trigger")));
207
208 /* Insert catalog entries. */
209 return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
210 evtowner, funcoid, tags);
211}
212
213/*
214 * Validate DDL command tags.
215 */
216static void
218{
219 ListCell *lc;
220
221 foreach(lc, taglist)
222 {
223 const char *tagstr = strVal(lfirst(lc));
224 CommandTag commandTag = GetCommandTagEnum(tagstr);
225
226 if (commandTag == CMDTAG_UNKNOWN)
229 errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
230 tagstr, filtervar)));
231 if (!command_tag_event_trigger_ok(commandTag))
234 /* translator: %s represents an SQL statement name */
235 errmsg("event triggers are not supported for %s",
236 tagstr)));
237 }
238}
239
240/*
241 * Validate DDL command tags for event table_rewrite.
242 */
243static void
245{
246 ListCell *lc;
247
248 foreach(lc, taglist)
249 {
250 const char *tagstr = strVal(lfirst(lc));
251 CommandTag commandTag = GetCommandTagEnum(tagstr);
252
253 if (!command_tag_table_rewrite_ok(commandTag))
256 /* translator: %s represents an SQL statement name */
257 errmsg("event triggers are not supported for %s",
258 tagstr)));
259 }
260}
261
262/*
263 * Complain about a duplicate filter variable.
264 */
265static void
267{
270 errmsg("filter variable \"%s\" specified more than once",
271 defname)));
272}
273
274/*
275 * Insert the new pg_event_trigger row and record dependencies.
276 */
277static Oid
278insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
280{
282 Oid trigoid;
283 HeapTuple tuple;
285 bool nulls[Natts_pg_event_trigger];
290
291 /* Open pg_event_trigger. */
293
294 /* Build the new pg_trigger tuple. */
298 memset(nulls, false, sizeof(nulls));
299 namestrcpy(&evtnamedata, trigname);
301 namestrcpy(&evteventdata, eventname);
307 if (taglist == NIL)
308 nulls[Anum_pg_event_trigger_evttags - 1] = true;
309 else
312
313 /* Insert heap tuple. */
314 tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
316 heap_freetuple(tuple);
317
318 /*
319 * Login event triggers have an additional flag in pg_database to enable
320 * faster lookups in hot codepaths. Set the flag unless already True.
321 */
322 if (strcmp(eventname, "login") == 0)
324
325 /* Depend on owner. */
327
328 /* Depend on event trigger function. */
330 myself.objectId = trigoid;
331 myself.objectSubId = 0;
333 referenced.objectId = funcoid;
334 referenced.objectSubId = 0;
336
337 /* Depend on extension, if any. */
339
340 /* Post creation hook for new event trigger */
342
343 /* Close pg_event_trigger. */
345
346 return trigoid;
347}
348
349/*
350 * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
351 * by a DefElem whose value is a List of String nodes; in the catalog, we
352 * store the list of strings as a text array. This function transforms the
353 * former representation into the latter one.
354 *
355 * For cleanliness, we store command tags in the catalog as text. It's
356 * possible (although not currently anticipated) that we might have
357 * a case-sensitive filter variable in the future, in which case this would
358 * need some further adjustment.
359 */
360static Datum
362{
363 ListCell *lc;
364 Datum *data;
365 int i = 0,
367
368 data = palloc_array(Datum, l);
369
370 foreach(lc, filterlist)
371 {
372 const char *value = strVal(lfirst(lc));
373 char *result,
374 *p;
375
376 result = pstrdup(value);
377 for (p = result; *p; p++)
378 *p = pg_ascii_toupper((unsigned char) *p);
380 pfree(result);
381 }
382
384}
385
386/*
387 * Set pg_database.dathasloginevt flag for current database indicating that
388 * current database has on login event triggers.
389 */
390void
392{
393 /* Set dathasloginevt flag in pg_database */
397 HeapTuple tuple;
398
399 /*
400 * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying
401 * to reset pg_database.dathasloginevt flag. Note, this lock doesn't
402 * effectively blocks database or other objection. It's just custom lock
403 * tag used to prevent multiple backends changing
404 * pg_database.dathasloginevt flag.
405 */
407
409 if (!HeapTupleIsValid(tuple))
410 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
411 otid = tuple->t_self;
412 db = (Form_pg_database) GETSTRUCT(tuple);
413 if (!db->dathasloginevt)
414 {
415 db->dathasloginevt = true;
416 CatalogTupleUpdate(pg_db, &otid, tuple);
418 }
421 heap_freetuple(tuple);
422}
423
424/*
425 * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
426 */
427Oid
429{
432 Oid trigoid;
434 char tgenabled = stmt->tgenabled;
435
437
439 CStringGetDatum(stmt->trigname));
440 if (!HeapTupleIsValid(tup))
443 errmsg("event trigger \"%s\" does not exist",
444 stmt->trigname)));
445
447 trigoid = evtForm->oid;
448
451 stmt->trigname);
452
453 /* tuple is a copy, so we can modify it below */
454 evtForm->evtenabled = tgenabled;
455
456 CatalogTupleUpdate(tgrel, &tup->t_self, tup);
457
458 /*
459 * Login event triggers have an additional flag in pg_database to enable
460 * faster lookups in hot codepaths. Set the flag unless already True.
461 */
462 if (namestrcmp(&evtForm->evtevent, "login") == 0 &&
463 tgenabled != TRIGGER_DISABLED)
465
467 trigoid, 0);
468
469 /* clean up */
472
473 return trigoid;
474}
475
476/*
477 * Change event trigger's owner -- by name
478 */
481{
482 Oid evtOid;
485 Relation rel;
486 ObjectAddress address;
487
489
491
492 if (!HeapTupleIsValid(tup))
495 errmsg("event trigger \"%s\" does not exist", name)));
496
498 evtOid = evtForm->oid;
499
501
503
505
507
508 return address;
509}
510
511/*
512 * Change event trigger owner, by OID
513 */
514void
516{
518 Relation rel;
519
521
523
524 if (!HeapTupleIsValid(tup))
527 errmsg("event trigger with OID %u does not exist", trigOid)));
528
530
532
534}
535
536/*
537 * Internal workhorse for changing an event trigger's owner
538 */
539static void
541{
543
545
546 if (form->evtowner == newOwnerId)
547 return;
548
551 NameStr(form->evtname));
552
553 /* New owner must be a superuser */
557 errmsg("permission denied to change owner of event trigger \"%s\"",
558 NameStr(form->evtname)),
559 errhint("The owner of an event trigger must be a superuser.")));
560
561 form->evtowner = newOwnerId;
562 CatalogTupleUpdate(rel, &tup->t_self, tup);
563
564 /* Update owner dependency reference */
566 form->oid,
567 newOwnerId);
568
570 form->oid, 0);
571}
572
573/*
574 * get_event_trigger_oid - Look up an event trigger by name to find its OID.
575 *
576 * If missing_ok is false, throw an error if trigger not found. If
577 * true, just return InvalidOid.
578 */
579Oid
580get_event_trigger_oid(const char *trigname, bool missing_ok)
581{
582 Oid oid;
583
585 CStringGetDatum(trigname));
586 if (!OidIsValid(oid) && !missing_ok)
589 errmsg("event trigger \"%s\" does not exist", trigname)));
590 return oid;
591}
592
593/*
594 * Return true when we want to fire given Event Trigger and false otherwise,
595 * filtering on the session replication role and the event trigger registered
596 * tags matching.
597 */
598static bool
600{
601 /*
602 * Filter by session replication role, knowing that we never see disabled
603 * items down here.
604 */
606 {
607 if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
608 return false;
609 }
610 else
611 {
613 return false;
614 }
615
616 /* Filter by tags, if any were specified. */
617 if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
618 return false;
619
620 /* if we reach that point, we're not filtering out this item */
621 return true;
622}
623
624static CommandTag
626{
627 if (event == EVT_Login)
628 return CMDTAG_LOGIN;
629 else
630 return CreateCommandTag(parsetree);
631}
632
633/*
634 * Setup for running triggers for the given event. Return value is an OID list
635 * of functions to run; if there are any, trigdata is filled with an
636 * appropriate EventTriggerData for them to receive.
637 */
638static List *
640 EventTriggerEvent event, const char *eventstr,
641 EventTriggerData *trigdata, bool unfiltered)
642{
643 CommandTag tag;
645 ListCell *lc;
646 List *runlist = NIL;
647
648 /*
649 * We want the list of command tags for which this procedure is actually
650 * invoked to match up exactly with the list that CREATE EVENT TRIGGER
651 * accepts. This debugging cross-check will throw an error if this
652 * function is invoked for a command tag that CREATE EVENT TRIGGER won't
653 * accept. (Unfortunately, there doesn't seem to be any simple, automated
654 * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
655 * never reaches this control point.)
656 *
657 * If this cross-check fails for you, you probably need to either adjust
658 * standard_ProcessUtility() not to invoke event triggers for the command
659 * type in question, or you need to adjust event_trigger_ok to accept the
660 * relevant command tag.
661 */
662#ifdef USE_ASSERT_CHECKING
663 {
665
666 dbgtag = EventTriggerGetTag(parsetree, event);
667
668 if (event == EVT_DDLCommandStart ||
669 event == EVT_DDLCommandEnd ||
670 event == EVT_SQLDrop ||
671 event == EVT_Login)
672 {
674 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
675 }
676 else if (event == EVT_TableRewrite)
677 {
679 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
680 }
681 }
682#endif
683
684 /* Use cache to find triggers for this event; fast exit if none. */
686 if (cachelist == NIL)
687 return NIL;
688
689 /* Get the command tag. */
690 tag = EventTriggerGetTag(parsetree, event);
691
692 /*
693 * Filter list of event triggers by command tag, and copy them into our
694 * memory context. Once we start running the command triggers, or indeed
695 * once we do anything at all that touches the catalogs, an invalidation
696 * might leave cachelist pointing at garbage, so we must do this before we
697 * can do much else.
698 */
699 foreach(lc, cachelist)
700 {
702
703 if (unfiltered || filter_event_trigger(tag, item))
704 {
705 /* We must plan to fire this trigger. */
707 }
708 }
709
710 /* Don't spend any more time on this if no functions to run */
711 if (runlist == NIL)
712 return NIL;
713
714 trigdata->type = T_EventTriggerData;
715 trigdata->event = eventstr;
716 trigdata->parsetree = parsetree;
717 trigdata->tag = tag;
718
719 return runlist;
720}
721
722/*
723 * Fire ddl_command_start triggers.
724 */
725void
727{
728 List *runlist;
729 EventTriggerData trigdata;
730
731 /*
732 * Event Triggers are completely disabled in standalone mode. There are
733 * (at least) two reasons for this:
734 *
735 * 1. A sufficiently broken event trigger might not only render the
736 * database unusable, but prevent disabling itself to fix the situation.
737 * In this scenario, restarting in standalone mode provides an escape
738 * hatch.
739 *
740 * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
741 * therefore will malfunction if pg_event_trigger's indexes are damaged.
742 * To allow recovery from a damaged index, we need some operating mode
743 * wherein event triggers are disabled. (Or we could implement
744 * heapscan-and-sort logic for that case, but having disaster recovery
745 * scenarios depend on code that's otherwise untested isn't appetizing.)
746 *
747 * Additionally, event triggers can be disabled with a superuser-only GUC
748 * to make fixing database easier as per 1 above.
749 */
751 return;
752
755 "ddl_command_start",
756 &trigdata, false);
757 if (runlist == NIL)
758 return;
759
760 /* Run the triggers. */
761 EventTriggerInvoke(runlist, &trigdata);
762
763 /* Cleanup. */
765
766 /*
767 * Make sure anything the event triggers did will be visible to the main
768 * command.
769 */
771}
772
773/*
774 * Fire ddl_command_end triggers.
775 */
776void
778{
779 List *runlist;
780 EventTriggerData trigdata;
781
782 /*
783 * See EventTriggerDDLCommandStart for a discussion about why event
784 * triggers are disabled in single user mode or via GUC.
785 */
787 return;
788
789 /*
790 * Also do nothing if our state isn't set up, which it won't be if there
791 * weren't any relevant event triggers at the start of the current DDL
792 * command. This test might therefore seem optional, but it's important
793 * because EventTriggerCommonSetup might find triggers that didn't exist
794 * at the time the command started. Although this function itself
795 * wouldn't crash, the event trigger functions would presumably call
796 * pg_event_trigger_ddl_commands which would fail. Better to do nothing
797 * until the next command.
798 */
800 return;
801
803 EVT_DDLCommandEnd, "ddl_command_end",
804 &trigdata, false);
805 if (runlist == NIL)
806 return;
807
808 /*
809 * Make sure anything the main command did will be visible to the event
810 * triggers.
811 */
813
814 /* Run the triggers. */
815 EventTriggerInvoke(runlist, &trigdata);
816
817 /* Cleanup. */
819}
820
821/*
822 * Fire sql_drop triggers.
823 */
824void
826{
827 List *runlist;
828 EventTriggerData trigdata;
829
830 /*
831 * See EventTriggerDDLCommandStart for a discussion about why event
832 * triggers are disabled in single user mode or via a GUC.
833 */
835 return;
836
837 /*
838 * Use current state to determine whether this event fires at all. If
839 * there are no triggers for the sql_drop event, then we don't have
840 * anything to do here. Note that dropped object collection is disabled
841 * if this is the case, so even if we were to try to run, the list would
842 * be empty.
843 */
846 return;
847
849 EVT_SQLDrop, "sql_drop",
850 &trigdata, false);
851
852 /*
853 * Nothing to do if run list is empty. Note this typically can't happen,
854 * because if there are no sql_drop events, then objects-to-drop wouldn't
855 * have been collected in the first place and we would have quit above.
856 * But it could occur if event triggers were dropped partway through.
857 */
858 if (runlist == NIL)
859 return;
860
861 /*
862 * Make sure anything the main command did will be visible to the event
863 * triggers.
864 */
866
867 /*
868 * Make sure pg_event_trigger_dropped_objects only works when running
869 * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
870 * one trigger fails. (This is perhaps not necessary, as the currentState
871 * variable will be removed shortly by our caller, but it seems better to
872 * play safe.)
873 */
875
876 /* Run the triggers. */
877 PG_TRY();
878 {
879 EventTriggerInvoke(runlist, &trigdata);
880 }
881 PG_FINALLY();
882 {
884 }
885 PG_END_TRY();
886
887 /* Cleanup. */
889}
890
891/*
892 * Fire login event triggers if any are present. The dathasloginevt
893 * pg_database flag is left unchanged when an event trigger is dropped to avoid
894 * complicating the codepath in the case of multiple event triggers. This
895 * function will instead unset the flag if no trigger is defined.
896 */
897void
899{
900 List *runlist;
901 EventTriggerData trigdata;
902
903 /*
904 * See EventTriggerDDLCommandStart for a discussion about why event
905 * triggers are disabled in single user mode or via a GUC. We also need a
906 * database connection (some background workers don't have it).
907 */
910 return;
911
914 EVT_Login, "login",
915 &trigdata, false);
916
917 if (runlist != NIL)
918 {
919 /*
920 * Event trigger execution may require an active snapshot.
921 */
923
924 /* Run the triggers. */
925 EventTriggerInvoke(runlist, &trigdata);
926
927 /* Cleanup. */
929
931 }
932
933 /*
934 * There is no active login event trigger, but our
935 * pg_database.dathasloginevt is set. Try to unset this flag. We use the
936 * lock to prevent concurrent SetDatabaseHasLoginEventTriggers(), but we
937 * don't want to hang the connection waiting on the lock. Thus, we are
938 * just trying to acquire the lock conditionally.
939 */
942 {
943 /*
944 * The lock is held. Now we need to recheck that login event triggers
945 * list is still empty. Once the list is empty, we know that even if
946 * there is a backend which concurrently inserts/enables a login event
947 * trigger, it will update pg_database.dathasloginevt *afterwards*.
948 */
950 EVT_Login, "login",
951 &trigdata, true);
952
953 if (runlist == NIL)
954 {
956 HeapTuple tuple;
957 void *state;
959 ScanKeyData key[1];
960
961 /* Fetch a copy of the tuple to scribble on */
962 ScanKeyInit(&key[0],
966
968 NULL, 1, key, &tuple, &state);
969
970 if (!HeapTupleIsValid(tuple))
971 elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
972
973 db = (Form_pg_database) GETSTRUCT(tuple);
974 if (db->dathasloginevt)
975 {
976 db->dathasloginevt = false;
977
978 /*
979 * Do an "in place" update of the pg_database tuple. Doing
980 * this instead of regular updates serves two purposes. First,
981 * that avoids possible waiting on the row-level lock. Second,
982 * that avoids dealing with TOAST.
983 */
985 }
986 else
989 heap_freetuple(tuple);
990 }
991 else
992 {
994 }
995 }
997}
998
999
1000/*
1001 * Fire table_rewrite triggers.
1002 */
1003void
1004EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
1005{
1006 List *runlist;
1007 EventTriggerData trigdata;
1008
1009 /*
1010 * See EventTriggerDDLCommandStart for a discussion about why event
1011 * triggers are disabled in single user mode or via a GUC.
1012 */
1014 return;
1015
1016 /*
1017 * Also do nothing if our state isn't set up, which it won't be if there
1018 * weren't any relevant event triggers at the start of the current DDL
1019 * command. This test might therefore seem optional, but it's
1020 * *necessary*, because EventTriggerCommonSetup might find triggers that
1021 * didn't exist at the time the command started.
1022 */
1024 return;
1025
1026 runlist = EventTriggerCommonSetup(parsetree,
1028 "table_rewrite",
1029 &trigdata, false);
1030 if (runlist == NIL)
1031 return;
1032
1033 /*
1034 * Make sure pg_event_trigger_table_rewrite_oid only works when running
1035 * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
1036 * when one trigger fails. (This is perhaps not necessary, as the
1037 * currentState variable will be removed shortly by our caller, but it
1038 * seems better to play safe.)
1039 */
1042
1043 /* Run the triggers. */
1044 PG_TRY();
1045 {
1046 EventTriggerInvoke(runlist, &trigdata);
1047 }
1048 PG_FINALLY();
1049 {
1052 }
1053 PG_END_TRY();
1054
1055 /* Cleanup. */
1057
1058 /*
1059 * Make sure anything the event triggers did will be visible to the main
1060 * command.
1061 */
1063}
1064
1065/*
1066 * Invoke each event trigger in a list of event triggers.
1067 */
1068static void
1070{
1071 MemoryContext context;
1072 MemoryContext oldcontext;
1073 ListCell *lc;
1074 bool first = true;
1075
1076 /* Guard against stack overflow due to recursive event trigger */
1078
1079 /*
1080 * Let's evaluate event triggers in their own memory context, so that any
1081 * leaks get cleaned up promptly.
1082 */
1084 "event trigger context",
1086 oldcontext = MemoryContextSwitchTo(context);
1087
1088 /* Call each event trigger. */
1089 foreach(lc, fn_oid_list)
1090 {
1091 LOCAL_FCINFO(fcinfo, 0);
1092 Oid fnoid = lfirst_oid(lc);
1093 FmgrInfo flinfo;
1095
1096 elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
1097
1098 /*
1099 * We want each event trigger to be able to see the results of the
1100 * previous event trigger's action. Caller is responsible for any
1101 * command-counter increment that is needed between the event trigger
1102 * and anything else in the transaction.
1103 */
1104 if (first)
1105 first = false;
1106 else
1108
1109 /* Look up the function */
1110 fmgr_info(fnoid, &flinfo);
1111
1112 /* Call the function, passing no arguments but setting a context. */
1113 InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
1114 InvalidOid, (Node *) trigdata, NULL);
1116 FunctionCallInvoke(fcinfo);
1118
1119 /* Reclaim memory. */
1120 MemoryContextReset(context);
1121 }
1122
1123 /* Restore old memory context and delete the temporary one. */
1124 MemoryContextSwitchTo(oldcontext);
1125 MemoryContextDelete(context);
1126}
1127
1128/*
1129 * Do event triggers support this object type?
1130 *
1131 * See also event trigger documentation in event-trigger.sgml.
1132 */
1133bool
1135{
1136 switch (obtype)
1137 {
1138 case OBJECT_DATABASE:
1139 case OBJECT_TABLESPACE:
1140 case OBJECT_ROLE:
1142 /* no support for global objects (except subscriptions) */
1143 return false;
1145 /* no support for event triggers on event triggers */
1146 return false;
1147 default:
1148 return true;
1149 }
1150}
1151
1152/*
1153 * Do event triggers support this object class?
1154 *
1155 * See also event trigger documentation in event-trigger.sgml.
1156 */
1157bool
1159{
1160 switch (object->classId)
1161 {
1162 case DatabaseRelationId:
1164 case AuthIdRelationId:
1165 case AuthMemRelationId:
1167 /* no support for global objects (except subscriptions) */
1168 return false;
1170 /* no support for event triggers on event triggers */
1171 return false;
1172 default:
1173 return true;
1174 }
1175}
1176
1177/*
1178 * Prepare event trigger state for a new complete query to run, if necessary;
1179 * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1180 * be called when the query is done, regardless of whether it succeeds or fails
1181 * -- so use of a PG_TRY block is mandatory.
1182 */
1183bool
1185{
1187 MemoryContext cxt;
1188
1189 /*
1190 * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1191 * reason to have event trigger state at all; so if there are none, don't
1192 * install one.
1193 */
1195 return false;
1196
1198 "event trigger state",
1201 state->cxt = cxt;
1202 slist_init(&(state->SQLDropList));
1203 state->in_sql_drop = false;
1204 state->table_rewrite_oid = InvalidOid;
1205
1206 state->commandCollectionInhibited = currentEventTriggerState ?
1208 state->currentCommand = NULL;
1209 state->commandList = NIL;
1210 state->previous = currentEventTriggerState;
1212
1213 return true;
1214}
1215
1216/*
1217 * Query completed (or errored out) -- clean up local state, return to previous
1218 * one.
1219 *
1220 * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1221 * returned false previously.
1222 *
1223 * Note: this might be called in the PG_CATCH block of a failing transaction,
1224 * so be wary of running anything unnecessary. (In particular, it's probably
1225 * unwise to try to allocate memory.)
1226 */
1227void
1229{
1231
1233
1234 /* this avoids the need for retail pfree of SQLDropList items: */
1236
1238}
1239
1240/*
1241 * Do we need to keep close track of objects being dropped?
1242 *
1243 * This is useful because there is a cost to running with them enabled.
1244 */
1245bool
1247{
1248 /*
1249 * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1250 * exists
1251 */
1252 return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
1255}
1256
1257/*
1258 * Support for dropped objects information on event trigger functions.
1259 *
1260 * We keep the list of objects dropped by the current command in current
1261 * state's SQLDropList (comprising SQLDropObject items). Each time a new
1262 * command is to start, a clean EventTriggerQueryState is created; commands
1263 * that drop objects do the dependency.c dance to drop objects, which
1264 * populates the current state's SQLDropList; when the event triggers are
1265 * invoked they can consume the list via pg_event_trigger_dropped_objects().
1266 * When the command finishes, the EventTriggerQueryState is cleared, and
1267 * the one from the previous command is restored (when no command is in
1268 * execution, the current state is NULL).
1269 *
1270 * All this lets us support the case that an event trigger function drops
1271 * objects "reentrantly".
1272 */
1273
1274/*
1275 * Register one object as being dropped by the current command.
1276 */
1277void
1278EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1279{
1280 SQLDropObject *obj;
1282
1284 return;
1285
1287
1289
1291 obj->address = *object;
1292 obj->original = original;
1293 obj->normal = normal;
1294
1295 if (object->classId == NamespaceRelationId)
1296 {
1297 /* Special handling is needed for temp namespaces */
1298 if (isTempNamespace(object->objectId))
1299 obj->istemp = true;
1300 else if (isAnyTempNamespace(object->objectId))
1301 {
1302 /* don't report temp schemas except my own */
1303 pfree(obj);
1305 return;
1306 }
1307 obj->objname = get_namespace_name(object->objectId);
1308 }
1309 else if (object->classId == AttrDefaultRelationId)
1310 {
1311 /* We treat a column default as temp if its table is temp */
1313
1315 if (OidIsValid(colobject.objectId))
1316 {
1318 {
1319 pfree(obj);
1321 return;
1322 }
1323 }
1324 }
1325 else if (object->classId == TriggerRelationId)
1326 {
1327 /* Similarly, a trigger is temp if its table is temp */
1328 /* Sadly, there's no lsyscache.c support for trigger objects */
1330 ScanKeyData skey[1];
1332 HeapTuple tuple;
1333 Oid relid;
1334
1335 /* Fetch the trigger's table OID the hard way */
1337 ScanKeyInit(&skey[0],
1340 ObjectIdGetDatum(object->objectId));
1342 NULL, 1, skey);
1343 tuple = systable_getnext(sscan);
1344 if (HeapTupleIsValid(tuple))
1345 relid = ((Form_pg_trigger) GETSTRUCT(tuple))->tgrelid;
1346 else
1347 relid = InvalidOid; /* shouldn't happen */
1350 /* Do nothing if we didn't find the trigger */
1351 if (OidIsValid(relid))
1352 {
1354
1356 relobject.objectId = relid;
1357 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1358 relobject.objectSubId = 1;
1360 {
1361 pfree(obj);
1363 return;
1364 }
1365 }
1366 }
1367 else if (object->classId == PolicyRelationId)
1368 {
1369 /* Similarly, a policy is temp if its table is temp */
1370 /* Sadly, there's no lsyscache.c support for policy objects */
1372 ScanKeyData skey[1];
1374 HeapTuple tuple;
1375 Oid relid;
1376
1377 /* Fetch the policy's table OID the hard way */
1379 ScanKeyInit(&skey[0],
1382 ObjectIdGetDatum(object->objectId));
1384 NULL, 1, skey);
1385 tuple = systable_getnext(sscan);
1386 if (HeapTupleIsValid(tuple))
1387 relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
1388 else
1389 relid = InvalidOid; /* shouldn't happen */
1392 /* Do nothing if we didn't find the policy */
1393 if (OidIsValid(relid))
1394 {
1396
1398 relobject.objectId = relid;
1399 /* Arbitrarily set objectSubId nonzero so as not to fill objname */
1400 relobject.objectSubId = 1;
1402 {
1403 pfree(obj);
1405 return;
1406 }
1407 }
1408 }
1409 else
1410 {
1411 /* Generic handling for all other object classes */
1412 if (!obtain_object_name_namespace(object, obj))
1413 {
1414 /* don't report temp objects except my own */
1415 pfree(obj);
1417 return;
1418 }
1419 }
1420
1421 /* object identity, objname and objargs */
1422 obj->objidentity =
1424 false);
1425
1426 /* object type */
1427 obj->objecttype = getObjectTypeDescription(&obj->address, false);
1428
1430
1432}
1433
1434/*
1435 * Fill obj->objname, obj->schemaname, and obj->istemp based on object.
1436 *
1437 * Returns true if this object should be reported, false if it should
1438 * be ignored because it is a temporary object of another session.
1439 */
1440static bool
1442{
1443 /*
1444 * Obtain schema names from the object's catalog tuple, if one exists;
1445 * this lets us skip objects in temp schemas. We trust that
1446 * ObjectProperty contains all object classes that can be
1447 * schema-qualified.
1448 *
1449 * Currently, this function does nothing for object classes that are not
1450 * in ObjectProperty, but we might sometime add special cases for that.
1451 */
1452 if (is_objectclass_supported(object->classId))
1453 {
1455 HeapTuple tuple;
1456
1460 object->objectId);
1461
1462 if (tuple)
1463 {
1465 Datum datum;
1466 bool isnull;
1467
1470 {
1471 datum = heap_getattr(tuple, attnum,
1472 RelationGetDescr(catalog), &isnull);
1473 if (!isnull)
1474 {
1476
1478 /* temp objects are only reported if they are my own */
1480 {
1481 obj->schemaname = "pg_temp";
1482 obj->istemp = true;
1483 }
1485 {
1486 /* no need to fill any fields of *obj */
1488 return false;
1489 }
1490 else
1491 {
1493 obj->istemp = false;
1494 }
1495 }
1496 }
1497
1498 if (get_object_namensp_unique(object->classId) &&
1499 object->objectSubId == 0)
1500 {
1503 {
1504 datum = heap_getattr(tuple, attnum,
1505 RelationGetDescr(catalog), &isnull);
1506 if (!isnull)
1507 obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1508 }
1509 }
1510 }
1511
1513 }
1514
1515 return true;
1516}
1517
1518/*
1519 * pg_event_trigger_dropped_objects
1520 *
1521 * Make the list of dropped objects available to the user function run by the
1522 * Event Trigger.
1523 */
1524Datum
1526{
1527 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1528 slist_iter iter;
1529
1530 /*
1531 * Protect this function from being called out of context
1532 */
1535 ereport(ERROR,
1537 errmsg("%s can only be called in a sql_drop event trigger function",
1538 "pg_event_trigger_dropped_objects()")));
1539
1540 /* Build tuplestore to hold the result rows */
1541 InitMaterializedSRF(fcinfo, 0);
1542
1544 {
1545 SQLDropObject *obj;
1546 int i = 0;
1547 Datum values[12] = {0};
1548 bool nulls[12] = {0};
1549
1550 obj = slist_container(SQLDropObject, next, iter.cur);
1551
1552 /* classid */
1554
1555 /* objid */
1557
1558 /* objsubid */
1560
1561 /* original */
1562 values[i++] = BoolGetDatum(obj->original);
1563
1564 /* normal */
1565 values[i++] = BoolGetDatum(obj->normal);
1566
1567 /* is_temporary */
1568 values[i++] = BoolGetDatum(obj->istemp);
1569
1570 /* object_type */
1572
1573 /* schema_name */
1574 if (obj->schemaname)
1576 else
1577 nulls[i++] = true;
1578
1579 /* object_name */
1580 if (obj->objname)
1582 else
1583 nulls[i++] = true;
1584
1585 /* object_identity */
1586 if (obj->objidentity)
1588 else
1589 nulls[i++] = true;
1590
1591 /* address_names and address_args */
1592 if (obj->addrnames)
1593 {
1595
1596 if (obj->addrargs)
1598 else
1600 }
1601 else
1602 {
1603 nulls[i++] = true;
1604 nulls[i++] = true;
1605 }
1606
1607 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1608 values, nulls);
1609 }
1610
1611 return (Datum) 0;
1612}
1613
1614/*
1615 * pg_event_trigger_table_rewrite_oid
1616 *
1617 * Make the Oid of the table going to be rewritten available to the user
1618 * function run by the Event Trigger.
1619 */
1620Datum
1622{
1623 /*
1624 * Protect this function from being called out of context
1625 */
1628 ereport(ERROR,
1630 errmsg("%s can only be called in a table_rewrite event trigger function",
1631 "pg_event_trigger_table_rewrite_oid()")));
1632
1634}
1635
1636/*
1637 * pg_event_trigger_table_rewrite_reason
1638 *
1639 * Make the rewrite reason available to the user.
1640 */
1641Datum
1643{
1644 /*
1645 * Protect this function from being called out of context
1646 */
1649 ereport(ERROR,
1651 errmsg("%s can only be called in a table_rewrite event trigger function",
1652 "pg_event_trigger_table_rewrite_reason()")));
1653
1655}
1656
1657/*-------------------------------------------------------------------------
1658 * Support for DDL command deparsing
1659 *
1660 * The routines below enable an event trigger function to obtain a list of
1661 * DDL commands as they are executed. There are three main pieces to this
1662 * feature:
1663 *
1664 * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1665 * adds a struct CollectedCommand representation of itself to the command list,
1666 * using the routines below.
1667 *
1668 * 2) Some time after that, ddl_command_end fires and the command list is made
1669 * available to the event trigger function via pg_event_trigger_ddl_commands();
1670 * the complete command details are exposed as a column of type pg_ddl_command.
1671 *
1672 * 3) An extension can install a function capable of taking a value of type
1673 * pg_ddl_command and transform it into some external, user-visible and/or
1674 * -modifiable representation.
1675 *-------------------------------------------------------------------------
1676 */
1677
1678/*
1679 * Inhibit DDL command collection.
1680 */
1681void
1689
1690/*
1691 * Re-establish DDL command collection.
1692 */
1693void
1701
1702/*
1703 * EventTriggerCollectSimpleCommand
1704 * Save data about a simple DDL command that was just executed
1705 *
1706 * address identifies the object being operated on. secondaryObject is an
1707 * object address that was related in some way to the executed command; its
1708 * meaning is command-specific.
1709 *
1710 * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1711 * object being moved, objectId is its OID, and secondaryOid is the OID of the
1712 * old schema. (The destination schema OID can be obtained by catalog lookup
1713 * of the object.)
1714 */
1715void
1717 ObjectAddress secondaryObject,
1718 const Node *parsetree)
1719{
1721 CollectedCommand *command;
1722
1723 /* ignore if event trigger context not set, or collection disabled */
1726 return;
1727
1729
1731
1732 command->type = SCT_Simple;
1734
1735 command->d.simple.address = address;
1736 command->d.simple.secondaryObject = secondaryObject;
1737 command->parsetree = copyObject(parsetree);
1738
1740 command);
1741
1743}
1744
1745/*
1746 * EventTriggerAlterTableStart
1747 * Prepare to receive data on an ALTER TABLE command about to be executed
1748 *
1749 * Note we don't collect the command immediately; instead we keep it in
1750 * currentCommand, and only when we're done processing the subcommands we will
1751 * add it to the command list.
1752 */
1753void
1755{
1757 CollectedCommand *command;
1758
1759 /* ignore if event trigger context not set, or collection disabled */
1762 return;
1763
1765
1767
1768 command->type = SCT_AlterTable;
1770
1772 command->d.alterTable.objectId = InvalidOid;
1773 command->d.alterTable.subcmds = NIL;
1774 command->parsetree = copyObject(parsetree);
1775
1778
1780}
1781
1782/*
1783 * Remember the OID of the object being affected by an ALTER TABLE.
1784 *
1785 * This is needed because in some cases we don't know the OID until later.
1786 */
1787void
1796
1797/*
1798 * EventTriggerCollectAlterTableSubcmd
1799 * Save data about a single part of an ALTER TABLE.
1800 *
1801 * Several different commands go through this path, but apart from ALTER TABLE
1802 * itself, they are all concerned with AlterTableCmd nodes that are generated
1803 * internally, so that's all that this code needs to handle at the moment.
1804 */
1805void
1831
1832/*
1833 * EventTriggerAlterTableEnd
1834 * Finish up saving an ALTER TABLE command, and add it to command list.
1835 *
1836 * FIXME this API isn't considering the possibility that an xact/subxact is
1837 * aborted partway through. Probably it's best to add an
1838 * AtEOSubXact_EventTriggers() to fix this.
1839 */
1840void
1842{
1843 CollectedCommand *parent;
1844
1845 /* ignore if event trigger context not set, or collection disabled */
1848 return;
1849
1851
1852 /* If no subcommands, don't collect */
1854 {
1856
1858
1862
1864 }
1865 else
1867
1869}
1870
1871/*
1872 * EventTriggerCollectGrant
1873 * Save data about a GRANT/REVOKE command being executed
1874 *
1875 * This function creates a copy of the InternalGrant, as the original might
1876 * not have the right lifetime.
1877 */
1878void
1880{
1882 CollectedCommand *command;
1884 ListCell *cell;
1885
1886 /* ignore if event trigger context not set, or collection disabled */
1889 return;
1890
1892
1893 /*
1894 * This is tedious, but necessary.
1895 */
1897 memcpy(icopy, istmt, sizeof(InternalGrant));
1898 icopy->objects = list_copy(istmt->objects);
1899 icopy->grantees = list_copy(istmt->grantees);
1900 icopy->col_privs = NIL;
1901 foreach(cell, istmt->col_privs)
1902 icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1903
1904 /* Now collect it, using the copied InternalGrant */
1906 command->type = SCT_Grant;
1908 command->d.grant.istmt = icopy;
1909 command->parsetree = NULL;
1910
1913
1915}
1916
1917/*
1918 * EventTriggerCollectAlterOpFam
1919 * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1920 * executed
1921 */
1922void
1924 List *operators, List *procedures)
1925{
1927 CollectedCommand *command;
1928
1929 /* ignore if event trigger context not set, or collection disabled */
1932 return;
1933
1935
1937 command->type = SCT_AlterOpFamily;
1941 command->d.opfam.operators = operators;
1942 command->d.opfam.procedures = procedures;
1943 command->parsetree = (Node *) copyObject(stmt);
1944
1947
1949}
1950
1951/*
1952 * EventTriggerCollectCreateOpClass
1953 * Save data about a CREATE OPERATOR CLASS command being executed
1954 */
1955void
1957 List *operators, List *procedures)
1958{
1960 CollectedCommand *command;
1961
1962 /* ignore if event trigger context not set, or collection disabled */
1965 return;
1966
1968
1970 command->type = SCT_CreateOpClass;
1974 command->d.createopc.operators = operators;
1975 command->d.createopc.procedures = procedures;
1976 command->parsetree = (Node *) copyObject(stmt);
1977
1980
1982}
1983
1984/*
1985 * EventTriggerCollectAlterTSConfig
1986 * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1987 * executed
1988 */
1989void
1991 Oid *dictIds, int ndicts)
1992{
1994 CollectedCommand *command;
1995
1996 /* ignore if event trigger context not set, or collection disabled */
1999 return;
2000
2002
2004 command->type = SCT_AlterTSConfig;
2007 TSConfigRelationId, cfgId);
2008 if (ndicts > 0)
2009 {
2010 command->d.atscfg.dictIds = palloc_array(Oid, ndicts);
2011 memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
2012 }
2013 command->d.atscfg.ndicts = ndicts;
2014 command->parsetree = (Node *) copyObject(stmt);
2015
2018
2020}
2021
2022/*
2023 * EventTriggerCollectAlterDefPrivs
2024 * Save data about an ALTER DEFAULT PRIVILEGES command being
2025 * executed
2026 */
2027void
2029{
2031 CollectedCommand *command;
2032
2033 /* ignore if event trigger context not set, or collection disabled */
2036 return;
2037
2039
2042 command->d.defprivs.objtype = stmt->action->objtype;
2044 command->parsetree = (Node *) copyObject(stmt);
2045
2049}
2050
2051/*
2052 * In a ddl_command_end event trigger, this function reports the DDL commands
2053 * being run.
2054 */
2055Datum
2057{
2058 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2059 ListCell *lc;
2060
2061 /*
2062 * Protect this function from being called out of context
2063 */
2065 ereport(ERROR,
2067 errmsg("%s can only be called in an event trigger function",
2068 "pg_event_trigger_ddl_commands()")));
2069
2070 /* Build tuplestore to hold the result rows */
2071 InitMaterializedSRF(fcinfo, 0);
2072
2074 {
2075 CollectedCommand *cmd = lfirst(lc);
2076 Datum values[9];
2077 bool nulls[9] = {0};
2078 ObjectAddress addr;
2079 int i = 0;
2080
2081 /*
2082 * For IF NOT EXISTS commands that attempt to create an existing
2083 * object, the returned OID is Invalid. Don't return anything.
2084 *
2085 * One might think that a viable alternative would be to look up the
2086 * Oid of the existing object and run the deparse with that. But
2087 * since the parse tree might be different from the one that created
2088 * the object in the first place, we might not end up in a consistent
2089 * state anyway.
2090 */
2091 if (cmd->type == SCT_Simple &&
2093 continue;
2094
2095 switch (cmd->type)
2096 {
2097 case SCT_Simple:
2098 case SCT_AlterTable:
2099 case SCT_AlterOpFamily:
2100 case SCT_CreateOpClass:
2101 case SCT_AlterTSConfig:
2102 {
2103 char *identity;
2104 char *type;
2105 char *schema = NULL;
2106
2107 if (cmd->type == SCT_Simple)
2108 addr = cmd->d.simple.address;
2109 else if (cmd->type == SCT_AlterTable)
2110 ObjectAddressSet(addr,
2111 cmd->d.alterTable.classId,
2112 cmd->d.alterTable.objectId);
2113 else if (cmd->type == SCT_AlterOpFamily)
2114 addr = cmd->d.opfam.address;
2115 else if (cmd->type == SCT_CreateOpClass)
2116 addr = cmd->d.createopc.address;
2117 else if (cmd->type == SCT_AlterTSConfig)
2118 addr = cmd->d.atscfg.address;
2119
2120 /*
2121 * If an object was dropped in the same command we may end
2122 * up in a situation where we generated a message but can
2123 * no longer look for the object information, so skip it
2124 * rather than failing. This can happen for example with
2125 * some subcommand combinations of ALTER TABLE.
2126 */
2127 identity = getObjectIdentity(&addr, true);
2128 if (identity == NULL)
2129 continue;
2130
2131 /* The type can never be NULL. */
2132 type = getObjectTypeDescription(&addr, true);
2133
2134 /*
2135 * Obtain schema name, if any ("pg_temp" if a temp
2136 * object). If the object class is not in the supported
2137 * list here, we assume it's a schema-less object type,
2138 * and thus "schema" remains set to NULL.
2139 */
2141 {
2143
2146 {
2150 bool isnull;
2151
2155 addr.objectId);
2157 elog(ERROR, "cache lookup failed for object %u/%u",
2158 addr.classId, addr.objectId);
2159 schema_oid =
2161 RelationGetDescr(catalog), &isnull));
2162 if (isnull)
2163 elog(ERROR,
2164 "invalid null namespace in object %u/%u/%d",
2165 addr.classId, addr.objectId, addr.objectSubId);
2167
2169 }
2170 }
2171
2172 /* classid */
2173 values[i++] = ObjectIdGetDatum(addr.classId);
2174 /* objid */
2175 values[i++] = ObjectIdGetDatum(addr.objectId);
2176 /* objsubid */
2177 values[i++] = Int32GetDatum(addr.objectSubId);
2178 /* command tag */
2180 /* object_type */
2182 /* schema */
2183 if (schema == NULL)
2184 nulls[i++] = true;
2185 else
2186 values[i++] = CStringGetTextDatum(schema);
2187 /* identity */
2188 values[i++] = CStringGetTextDatum(identity);
2189 /* in_extension */
2190 values[i++] = BoolGetDatum(cmd->in_extension);
2191 /* command */
2192 values[i++] = PointerGetDatum(cmd);
2193 }
2194 break;
2195
2197 /* classid */
2198 nulls[i++] = true;
2199 /* objid */
2200 nulls[i++] = true;
2201 /* objsubid */
2202 nulls[i++] = true;
2203 /* command tag */
2205 /* object_type */
2207 /* schema */
2208 nulls[i++] = true;
2209 /* identity */
2210 nulls[i++] = true;
2211 /* in_extension */
2212 values[i++] = BoolGetDatum(cmd->in_extension);
2213 /* command */
2214 values[i++] = PointerGetDatum(cmd);
2215 break;
2216
2217 case SCT_Grant:
2218 /* classid */
2219 nulls[i++] = true;
2220 /* objid */
2221 nulls[i++] = true;
2222 /* objsubid */
2223 nulls[i++] = true;
2224 /* command tag */
2226 "GRANT" : "REVOKE");
2227 /* object_type */
2229 /* schema */
2230 nulls[i++] = true;
2231 /* identity */
2232 nulls[i++] = true;
2233 /* in_extension */
2234 values[i++] = BoolGetDatum(cmd->in_extension);
2235 /* command */
2236 values[i++] = PointerGetDatum(cmd);
2237 break;
2238 }
2239
2240 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2241 values, nulls);
2242 }
2243
2245}
2246
2247/*
2248 * Return the ObjectType as a string, as it would appear in GRANT and
2249 * REVOKE commands.
2250 */
2251static const char *
2253{
2254 switch (objtype)
2255 {
2256 case OBJECT_COLUMN:
2257 return "COLUMN";
2258 case OBJECT_TABLE:
2259 return "TABLE";
2260 case OBJECT_SEQUENCE:
2261 return "SEQUENCE";
2262 case OBJECT_DATABASE:
2263 return "DATABASE";
2264 case OBJECT_DOMAIN:
2265 return "DOMAIN";
2266 case OBJECT_FDW:
2267 return "FOREIGN DATA WRAPPER";
2269 return "FOREIGN SERVER";
2270 case OBJECT_FUNCTION:
2271 return "FUNCTION";
2272 case OBJECT_LANGUAGE:
2273 return "LANGUAGE";
2274 case OBJECT_LARGEOBJECT:
2275 return "LARGE OBJECT";
2276 case OBJECT_SCHEMA:
2277 return "SCHEMA";
2279 return "PARAMETER";
2280 case OBJECT_PROCEDURE:
2281 return "PROCEDURE";
2282 case OBJECT_ROUTINE:
2283 return "ROUTINE";
2284 case OBJECT_TABLESPACE:
2285 return "TABLESPACE";
2286 case OBJECT_TYPE:
2287 return "TYPE";
2288 /* these currently aren't used */
2290 case OBJECT_AGGREGATE:
2291 case OBJECT_AMOP:
2292 case OBJECT_AMPROC:
2293 case OBJECT_ATTRIBUTE:
2294 case OBJECT_CAST:
2295 case OBJECT_COLLATION:
2296 case OBJECT_CONVERSION:
2297 case OBJECT_DEFAULT:
2298 case OBJECT_DEFACL:
2301 case OBJECT_EXTENSION:
2303 case OBJECT_INDEX:
2304 case OBJECT_MATVIEW:
2305 case OBJECT_OPCLASS:
2306 case OBJECT_OPERATOR:
2307 case OBJECT_OPFAMILY:
2308 case OBJECT_POLICY:
2309 case OBJECT_PROPGRAPH:
2310 case OBJECT_PUBLICATION:
2313 case OBJECT_ROLE:
2314 case OBJECT_RULE:
2318 case OBJECT_TRANSFORM:
2319 case OBJECT_TRIGGER:
2322 case OBJECT_TSPARSER:
2323 case OBJECT_TSTEMPLATE:
2325 case OBJECT_VIEW:
2326 elog(ERROR, "unsupported object type: %d", (int) objtype);
2327 }
2328
2329 return "???"; /* keep compiler quiet */
2330}
2331
2332/*
2333 * Return the ObjectType as a string; as above, but use the spelling
2334 * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2335 * the plural.
2336 */
2337static const char *
2339{
2340 switch (objtype)
2341 {
2342 case OBJECT_COLUMN:
2343 return "COLUMNS";
2344 case OBJECT_TABLE:
2345 return "TABLES";
2346 case OBJECT_SEQUENCE:
2347 return "SEQUENCES";
2348 case OBJECT_DATABASE:
2349 return "DATABASES";
2350 case OBJECT_DOMAIN:
2351 return "DOMAINS";
2352 case OBJECT_FDW:
2353 return "FOREIGN DATA WRAPPERS";
2355 return "FOREIGN SERVERS";
2356 case OBJECT_FUNCTION:
2357 return "FUNCTIONS";
2358 case OBJECT_LANGUAGE:
2359 return "LANGUAGES";
2360 case OBJECT_LARGEOBJECT:
2361 return "LARGE OBJECTS";
2362 case OBJECT_SCHEMA:
2363 return "SCHEMAS";
2364 case OBJECT_PROCEDURE:
2365 return "PROCEDURES";
2366 case OBJECT_ROUTINE:
2367 return "ROUTINES";
2368 case OBJECT_TABLESPACE:
2369 return "TABLESPACES";
2370 case OBJECT_TYPE:
2371 return "TYPES";
2372 /* these currently aren't used */
2374 case OBJECT_AGGREGATE:
2375 case OBJECT_AMOP:
2376 case OBJECT_AMPROC:
2377 case OBJECT_ATTRIBUTE:
2378 case OBJECT_CAST:
2379 case OBJECT_COLLATION:
2380 case OBJECT_CONVERSION:
2381 case OBJECT_DEFAULT:
2382 case OBJECT_DEFACL:
2385 case OBJECT_EXTENSION:
2387 case OBJECT_INDEX:
2388 case OBJECT_MATVIEW:
2389 case OBJECT_OPCLASS:
2390 case OBJECT_OPERATOR:
2391 case OBJECT_OPFAMILY:
2393 case OBJECT_POLICY:
2394 case OBJECT_PROPGRAPH:
2395 case OBJECT_PUBLICATION:
2398 case OBJECT_ROLE:
2399 case OBJECT_RULE:
2403 case OBJECT_TRANSFORM:
2404 case OBJECT_TRIGGER:
2407 case OBJECT_TSPARSER:
2408 case OBJECT_TSTEMPLATE:
2410 case OBJECT_VIEW:
2411 elog(ERROR, "unsupported object type: %d", (int) objtype);
2412 }
2413
2414 return "???"; /* keep compiler quiet */
2415}
@ 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:4133
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:188
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define NameStr(name)
Definition c.h:837
#define Assert(condition)
Definition c.h:945
#define OidIsValid(objectId)
Definition c.h:860
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
const char * GetCommandTagName(CommandTag commandTag)
Definition cmdtag.c:47
CommandTag GetCommandTagEnum(const char *commandname)
Definition cmdtag.c:83
bool command_tag_event_trigger_ok(CommandTag commandTag)
Definition cmdtag.c:66
bool command_tag_table_rewrite_ok(CommandTag commandTag)
Definition cmdtag.c:72
CommandTag
Definition cmdtag.h:23
@ SCT_Simple
@ SCT_AlterTSConfig
@ SCT_AlterDefaultPrivileges
@ SCT_Grant
@ SCT_CreateOpClass
@ SCT_AlterOpFamily
@ SCT_AlterTable
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
#define PG_TRY(...)
Definition elog.h:372
#define PG_END_TRY(...)
Definition elog.h:397
#define DEBUG1
Definition elog.h:30
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define PG_FINALLY(...)
Definition elog.h:389
#define ereport(elevel,...)
Definition elog.h:150
void EventTriggerUndoInhibitCommandCollection(void)
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
void 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:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
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, bits32 flags)
Definition funcapi.c:76
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
void systable_inplace_update_cancel(void *state)
Definition genam.c:903
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:808
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition genam.c:884
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
bool MyDatabaseHasLoginEventTriggers
Definition globals.c:98
bool IsUnderPostmaster
Definition globals.c:120
Oid MyDatabaseId
Definition globals.c:94
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1037
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1384
#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 @174 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:3612
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1875
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
MemoryContext TopMemoryContext
Definition mcxt.c:166
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#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:124
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:47
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:195
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:177
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Name DatumGetName(Datum X)
Definition postgres.h:380
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:393
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:370
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
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:389
#define RelationGetDescr(relation)
Definition rel.h:540
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c: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:95
#define BTEqualStrategyNumber
Definition stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
CollectedCommandType type
struct CollectedCommand::@134::@138 opfam
struct CollectedCommand::@134::@135 simple
InternalGrant * istmt
struct CollectedCommand::@134::@141 defprivs
struct CollectedCommand * parent
struct CollectedCommand::@134::@136 alterTable
union CollectedCommand::@134 d
struct CollectedCommand::@134::@137 grant
struct CollectedCommand::@134::@140 atscfg
struct CollectedCommand::@134::@139 createopc
ObjectAddress secondaryObject
ObjectAddress address
char * defname
Definition parsenodes.h:857
Node * arg
Definition parsenodes.h:858
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:832
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:399
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition syscache.h:109
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
int SessionReplicationRole
Definition trigger.c: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:2384
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:1102
void StartTransactionCommand(void)
Definition xact.c:3081
void CommitTransactionCommand(void)
Definition xact.c:3179