PostgreSQL Source Code  git master
event_trigger.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * event_trigger.c
4  * PostgreSQL EVENT TRIGGER support code.
5  *
6  * Portions Copyright (c) 1996-2020, 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/htup_details.h"
17 #include "access/table.h"
18 #include "access/xact.h"
19 #include "catalog/catalog.h"
20 #include "catalog/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/objectaccess.h"
24 #include "catalog/pg_namespace.h"
25 #include "catalog/pg_opclass.h"
26 #include "catalog/pg_opfamily.h"
27 #include "catalog/pg_proc.h"
28 #include "catalog/pg_trigger.h"
29 #include "catalog/pg_ts_config.h"
30 #include "catalog/pg_type.h"
31 #include "commands/dbcommands.h"
32 #include "commands/event_trigger.h"
33 #include "commands/extension.h"
34 #include "commands/trigger.h"
35 #include "funcapi.h"
36 #include "lib/ilist.h"
37 #include "miscadmin.h"
38 #include "parser/parse_func.h"
39 #include "pgstat.h"
40 #include "tcop/deparse_utility.h"
41 #include "tcop/utility.h"
42 #include "utils/acl.h"
43 #include "utils/builtins.h"
44 #include "utils/evtcache.h"
45 #include "utils/fmgroids.h"
46 #include "utils/lsyscache.h"
47 #include "utils/memutils.h"
48 #include "utils/rel.h"
49 #include "utils/syscache.h"
50 
51 typedef struct EventTriggerQueryState
52 {
53  /* memory context for this state's objects */
55 
56  /* sql_drop */
59 
60  /* table_rewrite */
61  Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite
62  * event */
63  int table_rewrite_reason; /* AT_REWRITE reason */
64 
65  /* Support for command collection */
68  List *commandList; /* list of CollectedCommand; see
69  * deparse_utility.h */
72 
74 
75 /* Support for dropped objects */
76 typedef struct SQLDropObject
77 {
79  const char *schemaname;
80  const char *objname;
81  const char *objidentity;
82  const char *objecttype;
85  bool original;
86  bool normal;
87  bool istemp;
90 
92  HeapTuple tup,
93  Oid newOwnerId);
94 static void error_duplicate_filter_variable(const char *defname);
95 static Datum filter_list_to_array(List *filterlist);
96 static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname,
97  Oid evtOwner, Oid funcoid, List *tags);
98 static void validate_ddl_tags(const char *filtervar, List *taglist);
99 static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
100 static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
101 static const char *stringify_grant_objtype(ObjectType objtype);
102 static const char *stringify_adefprivs_objtype(ObjectType objtype);
103 
104 /*
105  * Create an event trigger.
106  */
107 Oid
109 {
110  HeapTuple tuple;
111  Oid funcoid;
112  Oid funcrettype;
113  Oid evtowner = GetUserId();
114  ListCell *lc;
115  List *tags = NULL;
116 
117  /*
118  * It would be nice to allow database owners or even regular users to do
119  * this, but there are obvious privilege escalation risks which would have
120  * to somehow be plugged first.
121  */
122  if (!superuser())
123  ereport(ERROR,
124  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
125  errmsg("permission denied to create event trigger \"%s\"",
126  stmt->trigname),
127  errhint("Must be superuser to create an event trigger.")));
128 
129  /* Validate event name. */
130  if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
131  strcmp(stmt->eventname, "ddl_command_end") != 0 &&
132  strcmp(stmt->eventname, "sql_drop") != 0 &&
133  strcmp(stmt->eventname, "table_rewrite") != 0)
134  ereport(ERROR,
135  (errcode(ERRCODE_SYNTAX_ERROR),
136  errmsg("unrecognized event name \"%s\"",
137  stmt->eventname)));
138 
139  /* Validate filter conditions. */
140  foreach(lc, stmt->whenclause)
141  {
142  DefElem *def = (DefElem *) lfirst(lc);
143 
144  if (strcmp(def->defname, "tag") == 0)
145  {
146  if (tags != NULL)
148  tags = (List *) def->arg;
149  }
150  else
151  ereport(ERROR,
152  (errcode(ERRCODE_SYNTAX_ERROR),
153  errmsg("unrecognized filter variable \"%s\"", def->defname)));
154  }
155 
156  /* Validate tag list, if any. */
157  if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
158  strcmp(stmt->eventname, "ddl_command_end") == 0 ||
159  strcmp(stmt->eventname, "sql_drop") == 0)
160  && tags != NULL)
161  validate_ddl_tags("tag", tags);
162  else if (strcmp(stmt->eventname, "table_rewrite") == 0
163  && tags != NULL)
164  validate_table_rewrite_tags("tag", tags);
165 
166  /*
167  * Give user a nice error message if an event trigger of the same name
168  * already exists.
169  */
171  if (HeapTupleIsValid(tuple))
172  ereport(ERROR,
174  errmsg("event trigger \"%s\" already exists",
175  stmt->trigname)));
176 
177  /* Find and validate the trigger function. */
178  funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
179  funcrettype = get_func_rettype(funcoid);
180  if (funcrettype != EVTTRIGGEROID)
181  ereport(ERROR,
182  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
183  errmsg("function %s must return type %s",
184  NameListToString(stmt->funcname), "event_trigger")));
185 
186  /* Insert catalog entries. */
187  return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
188  evtowner, funcoid, tags);
189 }
190 
191 /*
192  * Validate DDL command tags.
193  */
194 static void
195 validate_ddl_tags(const char *filtervar, List *taglist)
196 {
197  ListCell *lc;
198 
199  foreach(lc, taglist)
200  {
201  const char *tagstr = strVal(lfirst(lc));
202  CommandTag commandTag = GetCommandTagEnum(tagstr);
203 
204  if (commandTag == CMDTAG_UNKNOWN)
205  ereport(ERROR,
206  (errcode(ERRCODE_SYNTAX_ERROR),
207  errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
208  tagstr, filtervar)));
209  if (!command_tag_event_trigger_ok(commandTag))
210  ereport(ERROR,
211  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
212  /* translator: %s represents an SQL statement name */
213  errmsg("event triggers are not supported for %s",
214  tagstr)));
215  }
216 }
217 
218 /*
219  * Validate DDL command tags for event table_rewrite.
220  */
221 static void
222 validate_table_rewrite_tags(const char *filtervar, List *taglist)
223 {
224  ListCell *lc;
225 
226  foreach(lc, taglist)
227  {
228  const char *tagstr = strVal(lfirst(lc));
229  CommandTag commandTag = GetCommandTagEnum(tagstr);
230 
231  if (!command_tag_table_rewrite_ok(commandTag))
232  ereport(ERROR,
233  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
234  /* translator: %s represents an SQL statement name */
235  errmsg("event triggers are not supported for %s",
236  tagstr)));
237  }
238 }
239 
240 /*
241  * Complain about a duplicate filter variable.
242  */
243 static void
245 {
246  ereport(ERROR,
247  (errcode(ERRCODE_SYNTAX_ERROR),
248  errmsg("filter variable \"%s\" specified more than once",
249  defname)));
250 }
251 
252 /*
253  * Insert the new pg_event_trigger row and record dependencies.
254  */
255 static Oid
256 insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
257  Oid funcoid, List *taglist)
258 {
259  Relation tgrel;
260  Oid trigoid;
261  HeapTuple tuple;
262  Datum values[Natts_pg_trigger];
263  bool nulls[Natts_pg_trigger];
264  NameData evtnamedata,
265  evteventdata;
266  ObjectAddress myself,
267  referenced;
268 
269  /* Open pg_event_trigger. */
270  tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
271 
272  /* Build the new pg_trigger tuple. */
274  Anum_pg_event_trigger_oid);
275  values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
276  memset(nulls, false, sizeof(nulls));
277  namestrcpy(&evtnamedata, trigname);
278  values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
279  namestrcpy(&evteventdata, eventname);
280  values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
281  values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
282  values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
283  values[Anum_pg_event_trigger_evtenabled - 1] =
285  if (taglist == NIL)
286  nulls[Anum_pg_event_trigger_evttags - 1] = true;
287  else
288  values[Anum_pg_event_trigger_evttags - 1] =
289  filter_list_to_array(taglist);
290 
291  /* Insert heap tuple. */
292  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
293  CatalogTupleInsert(tgrel, tuple);
294  heap_freetuple(tuple);
295 
296  /* Depend on owner. */
297  recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
298 
299  /* Depend on event trigger function. */
300  myself.classId = EventTriggerRelationId;
301  myself.objectId = trigoid;
302  myself.objectSubId = 0;
303  referenced.classId = ProcedureRelationId;
304  referenced.objectId = funcoid;
305  referenced.objectSubId = 0;
306  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
307 
308  /* Depend on extension, if any. */
309  recordDependencyOnCurrentExtension(&myself, false);
310 
311  /* Post creation hook for new event trigger */
312  InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
313 
314  /* Close pg_event_trigger. */
316 
317  return trigoid;
318 }
319 
320 /*
321  * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
322  * by a DefElem whose value is a List of String nodes; in the catalog, we
323  * store the list of strings as a text array. This function transforms the
324  * former representation into the latter one.
325  *
326  * For cleanliness, we store command tags in the catalog as text. It's
327  * possible (although not currently anticipated) that we might have
328  * a case-sensitive filter variable in the future, in which case this would
329  * need some further adjustment.
330  */
331 static Datum
333 {
334  ListCell *lc;
335  Datum *data;
336  int i = 0,
337  l = list_length(filterlist);
338 
339  data = (Datum *) palloc(l * sizeof(Datum));
340 
341  foreach(lc, filterlist)
342  {
343  const char *value = strVal(lfirst(lc));
344  char *result,
345  *p;
346 
347  result = pstrdup(value);
348  for (p = result; *p; p++)
349  *p = pg_ascii_toupper((unsigned char) *p);
350  data[i++] = PointerGetDatum(cstring_to_text(result));
351  pfree(result);
352  }
353 
354  return PointerGetDatum(construct_array(data, l, TEXTOID,
355  -1, false, TYPALIGN_INT));
356 }
357 
358 /*
359  * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
360  */
361 Oid
363 {
364  Relation tgrel;
365  HeapTuple tup;
366  Oid trigoid;
367  Form_pg_event_trigger evtForm;
368  char tgenabled = stmt->tgenabled;
369 
370  tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
371 
373  CStringGetDatum(stmt->trigname));
374  if (!HeapTupleIsValid(tup))
375  ereport(ERROR,
376  (errcode(ERRCODE_UNDEFINED_OBJECT),
377  errmsg("event trigger \"%s\" does not exist",
378  stmt->trigname)));
379 
380  evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
381  trigoid = evtForm->oid;
382 
383  if (!pg_event_trigger_ownercheck(trigoid, GetUserId()))
385  stmt->trigname);
386 
387  /* tuple is a copy, so we can modify it below */
388  evtForm->evtenabled = tgenabled;
389 
390  CatalogTupleUpdate(tgrel, &tup->t_self, tup);
391 
392  InvokeObjectPostAlterHook(EventTriggerRelationId,
393  trigoid, 0);
394 
395  /* clean up */
396  heap_freetuple(tup);
398 
399  return trigoid;
400 }
401 
402 /*
403  * Change event trigger's owner -- by name
404  */
406 AlterEventTriggerOwner(const char *name, Oid newOwnerId)
407 {
408  Oid evtOid;
409  HeapTuple tup;
410  Form_pg_event_trigger evtForm;
411  Relation rel;
412  ObjectAddress address;
413 
414  rel = table_open(EventTriggerRelationId, RowExclusiveLock);
415 
417 
418  if (!HeapTupleIsValid(tup))
419  ereport(ERROR,
420  (errcode(ERRCODE_UNDEFINED_OBJECT),
421  errmsg("event trigger \"%s\" does not exist", name)));
422 
423  evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
424  evtOid = evtForm->oid;
425 
426  AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
427 
428  ObjectAddressSet(address, EventTriggerRelationId, evtOid);
429 
430  heap_freetuple(tup);
431 
433 
434  return address;
435 }
436 
437 /*
438  * Change event trigger owner, by OID
439  */
440 void
441 AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
442 {
443  HeapTuple tup;
444  Relation rel;
445 
446  rel = table_open(EventTriggerRelationId, RowExclusiveLock);
447 
449 
450  if (!HeapTupleIsValid(tup))
451  ereport(ERROR,
452  (errcode(ERRCODE_UNDEFINED_OBJECT),
453  errmsg("event trigger with OID %u does not exist", trigOid)));
454 
455  AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
456 
457  heap_freetuple(tup);
458 
460 }
461 
462 /*
463  * Internal workhorse for changing an event trigger's owner
464  */
465 static void
467 {
469 
470  form = (Form_pg_event_trigger) GETSTRUCT(tup);
471 
472  if (form->evtowner == newOwnerId)
473  return;
474 
475  if (!pg_event_trigger_ownercheck(form->oid, GetUserId()))
477  NameStr(form->evtname));
478 
479  /* New owner must be a superuser */
480  if (!superuser_arg(newOwnerId))
481  ereport(ERROR,
482  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
483  errmsg("permission denied to change owner of event trigger \"%s\"",
484  NameStr(form->evtname)),
485  errhint("The owner of an event trigger must be a superuser.")));
486 
487  form->evtowner = newOwnerId;
488  CatalogTupleUpdate(rel, &tup->t_self, tup);
489 
490  /* Update owner dependency reference */
491  changeDependencyOnOwner(EventTriggerRelationId,
492  form->oid,
493  newOwnerId);
494 
495  InvokeObjectPostAlterHook(EventTriggerRelationId,
496  form->oid, 0);
497 }
498 
499 /*
500  * get_event_trigger_oid - Look up an event trigger by name to find its OID.
501  *
502  * If missing_ok is false, throw an error if trigger not found. If
503  * true, just return InvalidOid.
504  */
505 Oid
506 get_event_trigger_oid(const char *trigname, bool missing_ok)
507 {
508  Oid oid;
509 
510  oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
511  CStringGetDatum(trigname));
512  if (!OidIsValid(oid) && !missing_ok)
513  ereport(ERROR,
514  (errcode(ERRCODE_UNDEFINED_OBJECT),
515  errmsg("event trigger \"%s\" does not exist", trigname)));
516  return oid;
517 }
518 
519 /*
520  * Return true when we want to fire given Event Trigger and false otherwise,
521  * filtering on the session replication role and the event trigger registered
522  * tags matching.
523  */
524 static bool
526 {
527  /*
528  * Filter by session replication role, knowing that we never see disabled
529  * items down here.
530  */
532  {
533  if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
534  return false;
535  }
536  else
537  {
538  if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
539  return false;
540  }
541 
542  /* Filter by tags, if any were specified. */
543  if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
544  return false;
545 
546  /* if we reach that point, we're not filtering out this item */
547  return true;
548 }
549 
550 /*
551  * Setup for running triggers for the given event. Return value is an OID list
552  * of functions to run; if there are any, trigdata is filled with an
553  * appropriate EventTriggerData for them to receive.
554  */
555 static List *
557  EventTriggerEvent event, const char *eventstr,
558  EventTriggerData *trigdata)
559 {
560  CommandTag tag;
561  List *cachelist;
562  ListCell *lc;
563  List *runlist = NIL;
564 
565  /*
566  * We want the list of command tags for which this procedure is actually
567  * invoked to match up exactly with the list that CREATE EVENT TRIGGER
568  * accepts. This debugging cross-check will throw an error if this
569  * function is invoked for a command tag that CREATE EVENT TRIGGER won't
570  * accept. (Unfortunately, there doesn't seem to be any simple, automated
571  * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
572  * never reaches this control point.)
573  *
574  * If this cross-check fails for you, you probably need to either adjust
575  * standard_ProcessUtility() not to invoke event triggers for the command
576  * type in question, or you need to adjust event_trigger_ok to accept the
577  * relevant command tag.
578  */
579 #ifdef USE_ASSERT_CHECKING
580  {
581  CommandTag dbgtag;
582 
583  dbgtag = CreateCommandTag(parsetree);
584  if (event == EVT_DDLCommandStart ||
585  event == EVT_DDLCommandEnd ||
586  event == EVT_SQLDrop)
587  {
588  if (!command_tag_event_trigger_ok(dbgtag))
589  elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
590  }
591  else if (event == EVT_TableRewrite)
592  {
593  if (!command_tag_table_rewrite_ok(dbgtag))
594  elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
595  }
596  }
597 #endif
598 
599  /* Use cache to find triggers for this event; fast exit if none. */
600  cachelist = EventCacheLookup(event);
601  if (cachelist == NIL)
602  return NIL;
603 
604  /* Get the command tag. */
605  tag = CreateCommandTag(parsetree);
606 
607  /*
608  * Filter list of event triggers by command tag, and copy them into our
609  * memory context. Once we start running the command triggers, or indeed
610  * once we do anything at all that touches the catalogs, an invalidation
611  * might leave cachelist pointing at garbage, so we must do this before we
612  * can do much else.
613  */
614  foreach(lc, cachelist)
615  {
616  EventTriggerCacheItem *item = lfirst(lc);
617 
618  if (filter_event_trigger(tag, item))
619  {
620  /* We must plan to fire this trigger. */
621  runlist = lappend_oid(runlist, item->fnoid);
622  }
623  }
624 
625  /* don't spend any more time on this if no functions to run */
626  if (runlist == NIL)
627  return NIL;
628 
629  trigdata->type = T_EventTriggerData;
630  trigdata->event = eventstr;
631  trigdata->parsetree = parsetree;
632  trigdata->tag = tag;
633 
634  return runlist;
635 }
636 
637 /*
638  * Fire ddl_command_start triggers.
639  */
640 void
642 {
643  List *runlist;
644  EventTriggerData trigdata;
645 
646  /*
647  * Event Triggers are completely disabled in standalone mode. There are
648  * (at least) two reasons for this:
649  *
650  * 1. A sufficiently broken event trigger might not only render the
651  * database unusable, but prevent disabling itself to fix the situation.
652  * In this scenario, restarting in standalone mode provides an escape
653  * hatch.
654  *
655  * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
656  * therefore will malfunction if pg_event_trigger's indexes are damaged.
657  * To allow recovery from a damaged index, we need some operating mode
658  * wherein event triggers are disabled. (Or we could implement
659  * heapscan-and-sort logic for that case, but having disaster recovery
660  * scenarios depend on code that's otherwise untested isn't appetizing.)
661  */
662  if (!IsUnderPostmaster)
663  return;
664 
665  runlist = EventTriggerCommonSetup(parsetree,
667  "ddl_command_start",
668  &trigdata);
669  if (runlist == NIL)
670  return;
671 
672  /* Run the triggers. */
673  EventTriggerInvoke(runlist, &trigdata);
674 
675  /* Cleanup. */
676  list_free(runlist);
677 
678  /*
679  * Make sure anything the event triggers did will be visible to the main
680  * command.
681  */
683 }
684 
685 /*
686  * Fire ddl_command_end triggers.
687  */
688 void
690 {
691  List *runlist;
692  EventTriggerData trigdata;
693 
694  /*
695  * See EventTriggerDDLCommandStart for a discussion about why event
696  * triggers are disabled in single user mode.
697  */
698  if (!IsUnderPostmaster)
699  return;
700 
701  /*
702  * Also do nothing if our state isn't set up, which it won't be if there
703  * weren't any relevant event triggers at the start of the current DDL
704  * command. This test might therefore seem optional, but it's important
705  * because EventTriggerCommonSetup might find triggers that didn't exist
706  * at the time the command started. Although this function itself
707  * wouldn't crash, the event trigger functions would presumably call
708  * pg_event_trigger_ddl_commands which would fail. Better to do nothing
709  * until the next command.
710  */
711  if (!currentEventTriggerState)
712  return;
713 
714  runlist = EventTriggerCommonSetup(parsetree,
715  EVT_DDLCommandEnd, "ddl_command_end",
716  &trigdata);
717  if (runlist == NIL)
718  return;
719 
720  /*
721  * Make sure anything the main command did will be visible to the event
722  * triggers.
723  */
725 
726  /* Run the triggers. */
727  EventTriggerInvoke(runlist, &trigdata);
728 
729  /* Cleanup. */
730  list_free(runlist);
731 }
732 
733 /*
734  * Fire sql_drop triggers.
735  */
736 void
738 {
739  List *runlist;
740  EventTriggerData trigdata;
741 
742  /*
743  * See EventTriggerDDLCommandStart for a discussion about why event
744  * triggers are disabled in single user mode.
745  */
746  if (!IsUnderPostmaster)
747  return;
748 
749  /*
750  * Use current state to determine whether this event fires at all. If
751  * there are no triggers for the sql_drop event, then we don't have
752  * anything to do here. Note that dropped object collection is disabled
753  * if this is the case, so even if we were to try to run, the list would
754  * be empty.
755  */
756  if (!currentEventTriggerState ||
757  slist_is_empty(&currentEventTriggerState->SQLDropList))
758  return;
759 
760  runlist = EventTriggerCommonSetup(parsetree,
761  EVT_SQLDrop, "sql_drop",
762  &trigdata);
763 
764  /*
765  * Nothing to do if run list is empty. Note this typically can't happen,
766  * because if there are no sql_drop events, then objects-to-drop wouldn't
767  * have been collected in the first place and we would have quit above.
768  * But it could occur if event triggers were dropped partway through.
769  */
770  if (runlist == NIL)
771  return;
772 
773  /*
774  * Make sure anything the main command did will be visible to the event
775  * triggers.
776  */
778 
779  /*
780  * Make sure pg_event_trigger_dropped_objects only works when running
781  * these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
782  * one trigger fails. (This is perhaps not necessary, as the currentState
783  * variable will be removed shortly by our caller, but it seems better to
784  * play safe.)
785  */
786  currentEventTriggerState->in_sql_drop = true;
787 
788  /* Run the triggers. */
789  PG_TRY();
790  {
791  EventTriggerInvoke(runlist, &trigdata);
792  }
793  PG_FINALLY();
794  {
795  currentEventTriggerState->in_sql_drop = false;
796  }
797  PG_END_TRY();
798 
799  /* Cleanup. */
800  list_free(runlist);
801 }
802 
803 
804 /*
805  * Fire table_rewrite triggers.
806  */
807 void
808 EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
809 {
810  List *runlist;
811  EventTriggerData trigdata;
812 
813  /*
814  * See EventTriggerDDLCommandStart for a discussion about why event
815  * triggers are disabled in single user mode.
816  */
817  if (!IsUnderPostmaster)
818  return;
819 
820  /*
821  * Also do nothing if our state isn't set up, which it won't be if there
822  * weren't any relevant event triggers at the start of the current DDL
823  * command. This test might therefore seem optional, but it's
824  * *necessary*, because EventTriggerCommonSetup might find triggers that
825  * didn't exist at the time the command started.
826  */
827  if (!currentEventTriggerState)
828  return;
829 
830  runlist = EventTriggerCommonSetup(parsetree,
832  "table_rewrite",
833  &trigdata);
834  if (runlist == NIL)
835  return;
836 
837  /*
838  * Make sure pg_event_trigger_table_rewrite_oid only works when running
839  * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
840  * when one trigger fails. (This is perhaps not necessary, as the
841  * currentState variable will be removed shortly by our caller, but it
842  * seems better to play safe.)
843  */
844  currentEventTriggerState->table_rewrite_oid = tableOid;
845  currentEventTriggerState->table_rewrite_reason = reason;
846 
847  /* Run the triggers. */
848  PG_TRY();
849  {
850  EventTriggerInvoke(runlist, &trigdata);
851  }
852  PG_FINALLY();
853  {
854  currentEventTriggerState->table_rewrite_oid = InvalidOid;
855  currentEventTriggerState->table_rewrite_reason = 0;
856  }
857  PG_END_TRY();
858 
859  /* Cleanup. */
860  list_free(runlist);
861 
862  /*
863  * Make sure anything the event triggers did will be visible to the main
864  * command.
865  */
867 }
868 
869 /*
870  * Invoke each event trigger in a list of event triggers.
871  */
872 static void
873 EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
874 {
875  MemoryContext context;
876  MemoryContext oldcontext;
877  ListCell *lc;
878  bool first = true;
879 
880  /* Guard against stack overflow due to recursive event trigger */
882 
883  /*
884  * Let's evaluate event triggers in their own memory context, so that any
885  * leaks get cleaned up promptly.
886  */
888  "event trigger context",
890  oldcontext = MemoryContextSwitchTo(context);
891 
892  /* Call each event trigger. */
893  foreach(lc, fn_oid_list)
894  {
895  LOCAL_FCINFO(fcinfo, 0);
896  Oid fnoid = lfirst_oid(lc);
897  FmgrInfo flinfo;
898  PgStat_FunctionCallUsage fcusage;
899 
900  elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
901 
902  /*
903  * We want each event trigger to be able to see the results of the
904  * previous event trigger's action. Caller is responsible for any
905  * command-counter increment that is needed between the event trigger
906  * and anything else in the transaction.
907  */
908  if (first)
909  first = false;
910  else
912 
913  /* Look up the function */
914  fmgr_info(fnoid, &flinfo);
915 
916  /* Call the function, passing no arguments but setting a context. */
917  InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
918  InvalidOid, (Node *) trigdata, NULL);
919  pgstat_init_function_usage(fcinfo, &fcusage);
920  FunctionCallInvoke(fcinfo);
921  pgstat_end_function_usage(&fcusage, true);
922 
923  /* Reclaim memory. */
924  MemoryContextReset(context);
925  }
926 
927  /* Restore old memory context and delete the temporary one. */
928  MemoryContextSwitchTo(oldcontext);
929  MemoryContextDelete(context);
930 }
931 
932 /*
933  * Do event triggers support this object type?
934  */
935 bool
937 {
938  switch (obtype)
939  {
940  case OBJECT_DATABASE:
941  case OBJECT_TABLESPACE:
942  case OBJECT_ROLE:
943  /* no support for global objects */
944  return false;
946  /* no support for event triggers on event triggers */
947  return false;
949  case OBJECT_AGGREGATE:
950  case OBJECT_AMOP:
951  case OBJECT_AMPROC:
952  case OBJECT_ATTRIBUTE:
953  case OBJECT_CAST:
954  case OBJECT_COLUMN:
955  case OBJECT_COLLATION:
956  case OBJECT_CONVERSION:
957  case OBJECT_DEFACL:
958  case OBJECT_DEFAULT:
959  case OBJECT_DOMAIN:
961  case OBJECT_EXTENSION:
962  case OBJECT_FDW:
965  case OBJECT_FUNCTION:
966  case OBJECT_INDEX:
967  case OBJECT_LANGUAGE:
968  case OBJECT_LARGEOBJECT:
969  case OBJECT_MATVIEW:
970  case OBJECT_OPCLASS:
971  case OBJECT_OPERATOR:
972  case OBJECT_OPFAMILY:
973  case OBJECT_POLICY:
974  case OBJECT_PROCEDURE:
975  case OBJECT_PUBLICATION:
977  case OBJECT_ROUTINE:
978  case OBJECT_RULE:
979  case OBJECT_SCHEMA:
980  case OBJECT_SEQUENCE:
981  case OBJECT_SUBSCRIPTION:
984  case OBJECT_TABLE:
985  case OBJECT_TRANSFORM:
986  case OBJECT_TRIGGER:
988  case OBJECT_TSDICTIONARY:
989  case OBJECT_TSPARSER:
990  case OBJECT_TSTEMPLATE:
991  case OBJECT_TYPE:
992  case OBJECT_USER_MAPPING:
993  case OBJECT_VIEW:
994  return true;
995 
996  /*
997  * There's intentionally no default: case here; we want the
998  * compiler to warn if a new ObjectType hasn't been handled above.
999  */
1000  }
1001 
1002  /* Shouldn't get here, but if we do, say "no support" */
1003  return false;
1004 }
1005 
1006 /*
1007  * Do event triggers support this object class?
1008  */
1009 bool
1011 {
1012  switch (objclass)
1013  {
1014  case OCLASS_DATABASE:
1015  case OCLASS_TBLSPACE:
1016  case OCLASS_ROLE:
1017  /* no support for global objects */
1018  return false;
1019  case OCLASS_EVENT_TRIGGER:
1020  /* no support for event triggers on event triggers */
1021  return false;
1022  case OCLASS_CLASS:
1023  case OCLASS_PROC:
1024  case OCLASS_TYPE:
1025  case OCLASS_CAST:
1026  case OCLASS_COLLATION:
1027  case OCLASS_CONSTRAINT:
1028  case OCLASS_CONVERSION:
1029  case OCLASS_DEFAULT:
1030  case OCLASS_LANGUAGE:
1031  case OCLASS_LARGEOBJECT:
1032  case OCLASS_OPERATOR:
1033  case OCLASS_OPCLASS:
1034  case OCLASS_OPFAMILY:
1035  case OCLASS_AM:
1036  case OCLASS_AMOP:
1037  case OCLASS_AMPROC:
1038  case OCLASS_REWRITE:
1039  case OCLASS_TRIGGER:
1040  case OCLASS_SCHEMA:
1041  case OCLASS_STATISTIC_EXT:
1042  case OCLASS_TSPARSER:
1043  case OCLASS_TSDICT:
1044  case OCLASS_TSTEMPLATE:
1045  case OCLASS_TSCONFIG:
1046  case OCLASS_FDW:
1047  case OCLASS_FOREIGN_SERVER:
1048  case OCLASS_USER_MAPPING:
1049  case OCLASS_DEFACL:
1050  case OCLASS_EXTENSION:
1051  case OCLASS_POLICY:
1052  case OCLASS_PUBLICATION:
1054  case OCLASS_SUBSCRIPTION:
1055  case OCLASS_TRANSFORM:
1056  return true;
1057 
1058  /*
1059  * There's intentionally no default: case here; we want the
1060  * compiler to warn if a new OCLASS hasn't been handled above.
1061  */
1062  }
1063 
1064  /* Shouldn't get here, but if we do, say "no support" */
1065  return false;
1066 }
1067 
1068 /*
1069  * Prepare event trigger state for a new complete query to run, if necessary;
1070  * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1071  * be called when the query is done, regardless of whether it succeeds or fails
1072  * -- so use of a PG_TRY block is mandatory.
1073  */
1074 bool
1076 {
1079 
1080  /*
1081  * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1082  * reason to have event trigger state at all; so if there are none, don't
1083  * install one.
1084  */
1086  return false;
1087 
1089  "event trigger state",
1091  state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState));
1092  state->cxt = cxt;
1093  slist_init(&(state->SQLDropList));
1094  state->in_sql_drop = false;
1095  state->table_rewrite_oid = InvalidOid;
1096 
1097  state->commandCollectionInhibited = currentEventTriggerState ?
1098  currentEventTriggerState->commandCollectionInhibited : false;
1099  state->currentCommand = NULL;
1100  state->commandList = NIL;
1102  currentEventTriggerState = state;
1103 
1104  return true;
1105 }
1106 
1107 /*
1108  * Query completed (or errored out) -- clean up local state, return to previous
1109  * one.
1110  *
1111  * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1112  * returned false previously.
1113  *
1114  * Note: this might be called in the PG_CATCH block of a failing transaction,
1115  * so be wary of running anything unnecessary. (In particular, it's probably
1116  * unwise to try to allocate memory.)
1117  */
1118 void
1120 {
1121  EventTriggerQueryState *prevstate;
1122 
1123  prevstate = currentEventTriggerState->previous;
1124 
1125  /* this avoids the need for retail pfree of SQLDropList items: */
1126  MemoryContextDelete(currentEventTriggerState->cxt);
1127 
1128  currentEventTriggerState = prevstate;
1129 }
1130 
1131 /*
1132  * Do we need to keep close track of objects being dropped?
1133  *
1134  * This is useful because there is a cost to running with them enabled.
1135  */
1136 bool
1138 {
1139  /*
1140  * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1141  * exists
1142  */
1143  return list_length(EventCacheLookup(EVT_SQLDrop)) > 0 ||
1146 }
1147 
1148 /*
1149  * Support for dropped objects information on event trigger functions.
1150  *
1151  * We keep the list of objects dropped by the current command in current
1152  * state's SQLDropList (comprising SQLDropObject items). Each time a new
1153  * command is to start, a clean EventTriggerQueryState is created; commands
1154  * that drop objects do the dependency.c dance to drop objects, which
1155  * populates the current state's SQLDropList; when the event triggers are
1156  * invoked they can consume the list via pg_event_trigger_dropped_objects().
1157  * When the command finishes, the EventTriggerQueryState is cleared, and
1158  * the one from the previous command is restored (when no command is in
1159  * execution, the current state is NULL).
1160  *
1161  * All this lets us support the case that an event trigger function drops
1162  * objects "reentrantly".
1163  */
1164 
1165 /*
1166  * Register one object as being dropped by the current command.
1167  */
1168 void
1169 EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1170 {
1171  SQLDropObject *obj;
1172  MemoryContext oldcxt;
1173 
1174  if (!currentEventTriggerState)
1175  return;
1176 
1178 
1179  /* don't report temp schemas except my own */
1180  if (object->classId == NamespaceRelationId &&
1181  (isAnyTempNamespace(object->objectId) &&
1182  !isTempNamespace(object->objectId)))
1183  return;
1184 
1185  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1186 
1187  obj = palloc0(sizeof(SQLDropObject));
1188  obj->address = *object;
1189  obj->original = original;
1190  obj->normal = normal;
1191 
1192  /*
1193  * Obtain schema names from the object's catalog tuple, if one exists;
1194  * this lets us skip objects in temp schemas. We trust that
1195  * ObjectProperty contains all object classes that can be
1196  * schema-qualified.
1197  */
1198  if (is_objectclass_supported(object->classId))
1199  {
1200  Relation catalog;
1201  HeapTuple tuple;
1202 
1203  catalog = table_open(obj->address.classId, AccessShareLock);
1204  tuple = get_catalog_object_by_oid(catalog,
1205  get_object_attnum_oid(object->classId),
1206  obj->address.objectId);
1207 
1208  if (tuple)
1209  {
1211  Datum datum;
1212  bool isnull;
1213 
1215  if (attnum != InvalidAttrNumber)
1216  {
1217  datum = heap_getattr(tuple, attnum,
1218  RelationGetDescr(catalog), &isnull);
1219  if (!isnull)
1220  {
1221  Oid namespaceId;
1222 
1223  namespaceId = DatumGetObjectId(datum);
1224  /* temp objects are only reported if they are my own */
1225  if (isTempNamespace(namespaceId))
1226  {
1227  obj->schemaname = "pg_temp";
1228  obj->istemp = true;
1229  }
1230  else if (isAnyTempNamespace(namespaceId))
1231  {
1232  pfree(obj);
1233  table_close(catalog, AccessShareLock);
1234  MemoryContextSwitchTo(oldcxt);
1235  return;
1236  }
1237  else
1238  {
1239  obj->schemaname = get_namespace_name(namespaceId);
1240  obj->istemp = false;
1241  }
1242  }
1243  }
1244 
1246  obj->address.objectSubId == 0)
1247  {
1248  attnum = get_object_attnum_name(obj->address.classId);
1249  if (attnum != InvalidAttrNumber)
1250  {
1251  datum = heap_getattr(tuple, attnum,
1252  RelationGetDescr(catalog), &isnull);
1253  if (!isnull)
1254  obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1255  }
1256  }
1257  }
1258 
1259  table_close(catalog, AccessShareLock);
1260  }
1261  else
1262  {
1263  if (object->classId == NamespaceRelationId &&
1264  isTempNamespace(object->objectId))
1265  obj->istemp = true;
1266  }
1267 
1268  /* object identity, objname and objargs */
1269  obj->objidentity =
1270  getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
1271  false);
1272 
1273  /* object type */
1274  obj->objecttype = getObjectTypeDescription(&obj->address, false);
1275 
1276  slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
1277 
1278  MemoryContextSwitchTo(oldcxt);
1279 }
1280 
1281 /*
1282  * pg_event_trigger_dropped_objects
1283  *
1284  * Make the list of dropped objects available to the user function run by the
1285  * Event Trigger.
1286  */
1287 Datum
1289 {
1290  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1291  TupleDesc tupdesc;
1292  Tuplestorestate *tupstore;
1293  MemoryContext per_query_ctx;
1294  MemoryContext oldcontext;
1295  slist_iter iter;
1296 
1297  /*
1298  * Protect this function from being called out of context
1299  */
1300  if (!currentEventTriggerState ||
1301  !currentEventTriggerState->in_sql_drop)
1302  ereport(ERROR,
1303  (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1304  errmsg("%s can only be called in a sql_drop event trigger function",
1305  "pg_event_trigger_dropped_objects()")));
1306 
1307  /* check to see if caller supports us returning a tuplestore */
1308  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1309  ereport(ERROR,
1310  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1311  errmsg("set-valued function called in context that cannot accept a set")));
1312  if (!(rsinfo->allowedModes & SFRM_Materialize))
1313  ereport(ERROR,
1314  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1315  errmsg("materialize mode required, but it is not allowed in this context")));
1316 
1317  /* Build a tuple descriptor for our result type */
1318  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1319  elog(ERROR, "return type must be a row type");
1320 
1321  /* Build tuplestore to hold the result rows */
1322  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1323  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1324 
1325  tupstore = tuplestore_begin_heap(true, false, work_mem);
1326  rsinfo->returnMode = SFRM_Materialize;
1327  rsinfo->setResult = tupstore;
1328  rsinfo->setDesc = tupdesc;
1329 
1330  MemoryContextSwitchTo(oldcontext);
1331 
1332  slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
1333  {
1334  SQLDropObject *obj;
1335  int i = 0;
1336  Datum values[12];
1337  bool nulls[12];
1338 
1339  obj = slist_container(SQLDropObject, next, iter.cur);
1340 
1341  MemSet(values, 0, sizeof(values));
1342  MemSet(nulls, 0, sizeof(nulls));
1343 
1344  /* classid */
1345  values[i++] = ObjectIdGetDatum(obj->address.classId);
1346 
1347  /* objid */
1348  values[i++] = ObjectIdGetDatum(obj->address.objectId);
1349 
1350  /* objsubid */
1351  values[i++] = Int32GetDatum(obj->address.objectSubId);
1352 
1353  /* original */
1354  values[i++] = BoolGetDatum(obj->original);
1355 
1356  /* normal */
1357  values[i++] = BoolGetDatum(obj->normal);
1358 
1359  /* is_temporary */
1360  values[i++] = BoolGetDatum(obj->istemp);
1361 
1362  /* object_type */
1363  values[i++] = CStringGetTextDatum(obj->objecttype);
1364 
1365  /* schema_name */
1366  if (obj->schemaname)
1367  values[i++] = CStringGetTextDatum(obj->schemaname);
1368  else
1369  nulls[i++] = true;
1370 
1371  /* object_name */
1372  if (obj->objname)
1373  values[i++] = CStringGetTextDatum(obj->objname);
1374  else
1375  nulls[i++] = true;
1376 
1377  /* object_identity */
1378  if (obj->objidentity)
1379  values[i++] = CStringGetTextDatum(obj->objidentity);
1380  else
1381  nulls[i++] = true;
1382 
1383  /* address_names and address_args */
1384  if (obj->addrnames)
1385  {
1386  values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrnames));
1387 
1388  if (obj->addrargs)
1389  values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrargs));
1390  else
1391  values[i++] = PointerGetDatum(construct_empty_array(TEXTOID));
1392  }
1393  else
1394  {
1395  nulls[i++] = true;
1396  nulls[i++] = true;
1397  }
1398 
1399  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1400  }
1401 
1402  /* clean up and return the tuplestore */
1403  tuplestore_donestoring(tupstore);
1404 
1405  return (Datum) 0;
1406 }
1407 
1408 /*
1409  * pg_event_trigger_table_rewrite_oid
1410  *
1411  * Make the Oid of the table going to be rewritten available to the user
1412  * function run by the Event Trigger.
1413  */
1414 Datum
1416 {
1417  /*
1418  * Protect this function from being called out of context
1419  */
1420  if (!currentEventTriggerState ||
1421  currentEventTriggerState->table_rewrite_oid == InvalidOid)
1422  ereport(ERROR,
1423  (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1424  errmsg("%s can only be called in a table_rewrite event trigger function",
1425  "pg_event_trigger_table_rewrite_oid()")));
1426 
1427  PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
1428 }
1429 
1430 /*
1431  * pg_event_trigger_table_rewrite_reason
1432  *
1433  * Make the rewrite reason available to the user.
1434  */
1435 Datum
1437 {
1438  /*
1439  * Protect this function from being called out of context
1440  */
1441  if (!currentEventTriggerState ||
1442  currentEventTriggerState->table_rewrite_reason == 0)
1443  ereport(ERROR,
1444  (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1445  errmsg("%s can only be called in a table_rewrite event trigger function",
1446  "pg_event_trigger_table_rewrite_reason()")));
1447 
1448  PG_RETURN_INT32(currentEventTriggerState->table_rewrite_reason);
1449 }
1450 
1451 /*-------------------------------------------------------------------------
1452  * Support for DDL command deparsing
1453  *
1454  * The routines below enable an event trigger function to obtain a list of
1455  * DDL commands as they are executed. There are three main pieces to this
1456  * feature:
1457  *
1458  * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1459  * adds a struct CollectedCommand representation of itself to the command list,
1460  * using the routines below.
1461  *
1462  * 2) Some time after that, ddl_command_end fires and the command list is made
1463  * available to the event trigger function via pg_event_trigger_ddl_commands();
1464  * the complete command details are exposed as a column of type pg_ddl_command.
1465  *
1466  * 3) An extension can install a function capable of taking a value of type
1467  * pg_ddl_command and transform it into some external, user-visible and/or
1468  * -modifiable representation.
1469  *-------------------------------------------------------------------------
1470  */
1471 
1472 /*
1473  * Inhibit DDL command collection.
1474  */
1475 void
1477 {
1478  if (!currentEventTriggerState)
1479  return;
1480 
1481  currentEventTriggerState->commandCollectionInhibited = true;
1482 }
1483 
1484 /*
1485  * Re-establish DDL command collection.
1486  */
1487 void
1489 {
1490  if (!currentEventTriggerState)
1491  return;
1492 
1493  currentEventTriggerState->commandCollectionInhibited = false;
1494 }
1495 
1496 /*
1497  * EventTriggerCollectSimpleCommand
1498  * Save data about a simple DDL command that was just executed
1499  *
1500  * address identifies the object being operated on. secondaryObject is an
1501  * object address that was related in some way to the executed command; its
1502  * meaning is command-specific.
1503  *
1504  * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1505  * object being moved, objectId is its OID, and secondaryOid is the OID of the
1506  * old schema. (The destination schema OID can be obtained by catalog lookup
1507  * of the object.)
1508  */
1509 void
1511  ObjectAddress secondaryObject,
1512  Node *parsetree)
1513 {
1514  MemoryContext oldcxt;
1515  CollectedCommand *command;
1516 
1517  /* ignore if event trigger context not set, or collection disabled */
1518  if (!currentEventTriggerState ||
1519  currentEventTriggerState->commandCollectionInhibited)
1520  return;
1521 
1522  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1523 
1524  command = palloc(sizeof(CollectedCommand));
1525 
1526  command->type = SCT_Simple;
1527  command->in_extension = creating_extension;
1528 
1529  command->d.simple.address = address;
1530  command->d.simple.secondaryObject = secondaryObject;
1531  command->parsetree = copyObject(parsetree);
1532 
1533  currentEventTriggerState->commandList = lappend(currentEventTriggerState->commandList,
1534  command);
1535 
1536  MemoryContextSwitchTo(oldcxt);
1537 }
1538 
1539 /*
1540  * EventTriggerAlterTableStart
1541  * Prepare to receive data on an ALTER TABLE command about to be executed
1542  *
1543  * Note we don't collect the command immediately; instead we keep it in
1544  * currentCommand, and only when we're done processing the subcommands we will
1545  * add it to the command list.
1546  */
1547 void
1549 {
1550  MemoryContext oldcxt;
1551  CollectedCommand *command;
1552 
1553  /* ignore if event trigger context not set, or collection disabled */
1554  if (!currentEventTriggerState ||
1555  currentEventTriggerState->commandCollectionInhibited)
1556  return;
1557 
1558  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1559 
1560  command = palloc(sizeof(CollectedCommand));
1561 
1562  command->type = SCT_AlterTable;
1563  command->in_extension = creating_extension;
1564 
1565  command->d.alterTable.classId = RelationRelationId;
1566  command->d.alterTable.objectId = InvalidOid;
1567  command->d.alterTable.subcmds = NIL;
1568  command->parsetree = copyObject(parsetree);
1569 
1570  command->parent = currentEventTriggerState->currentCommand;
1571  currentEventTriggerState->currentCommand = command;
1572 
1573  MemoryContextSwitchTo(oldcxt);
1574 }
1575 
1576 /*
1577  * Remember the OID of the object being affected by an ALTER TABLE.
1578  *
1579  * This is needed because in some cases we don't know the OID until later.
1580  */
1581 void
1583 {
1584  if (!currentEventTriggerState ||
1585  currentEventTriggerState->commandCollectionInhibited)
1586  return;
1587 
1588  currentEventTriggerState->currentCommand->d.alterTable.objectId = objectId;
1589 }
1590 
1591 /*
1592  * EventTriggerCollectAlterTableSubcmd
1593  * Save data about a single part of an ALTER TABLE.
1594  *
1595  * Several different commands go through this path, but apart from ALTER TABLE
1596  * itself, they are all concerned with AlterTableCmd nodes that are generated
1597  * internally, so that's all that this code needs to handle at the moment.
1598  */
1599 void
1601 {
1602  MemoryContext oldcxt;
1604 
1605  /* ignore if event trigger context not set, or collection disabled */
1606  if (!currentEventTriggerState ||
1607  currentEventTriggerState->commandCollectionInhibited)
1608  return;
1609 
1610  Assert(IsA(subcmd, AlterTableCmd));
1611  Assert(currentEventTriggerState->currentCommand != NULL);
1612  Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
1613 
1614  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1615 
1616  newsub = palloc(sizeof(CollectedATSubcmd));
1617  newsub->address = address;
1618  newsub->parsetree = copyObject(subcmd);
1619 
1620  currentEventTriggerState->currentCommand->d.alterTable.subcmds =
1621  lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub);
1622 
1623  MemoryContextSwitchTo(oldcxt);
1624 }
1625 
1626 /*
1627  * EventTriggerAlterTableEnd
1628  * Finish up saving an ALTER TABLE command, and add it to command list.
1629  *
1630  * FIXME this API isn't considering the possibility that an xact/subxact is
1631  * aborted partway through. Probably it's best to add an
1632  * AtEOSubXact_EventTriggers() to fix this.
1633  */
1634 void
1636 {
1637  CollectedCommand *parent;
1638 
1639  /* ignore if event trigger context not set, or collection disabled */
1640  if (!currentEventTriggerState ||
1641  currentEventTriggerState->commandCollectionInhibited)
1642  return;
1643 
1644  parent = currentEventTriggerState->currentCommand->parent;
1645 
1646  /* If no subcommands, don't collect */
1647  if (list_length(currentEventTriggerState->currentCommand->d.alterTable.subcmds) != 0)
1648  {
1649  MemoryContext oldcxt;
1650 
1651  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1652 
1653  currentEventTriggerState->commandList =
1654  lappend(currentEventTriggerState->commandList,
1655  currentEventTriggerState->currentCommand);
1656 
1657  MemoryContextSwitchTo(oldcxt);
1658  }
1659  else
1660  pfree(currentEventTriggerState->currentCommand);
1661 
1662  currentEventTriggerState->currentCommand = parent;
1663 }
1664 
1665 /*
1666  * EventTriggerCollectGrant
1667  * Save data about a GRANT/REVOKE command being executed
1668  *
1669  * This function creates a copy of the InternalGrant, as the original might
1670  * not have the right lifetime.
1671  */
1672 void
1674 {
1675  MemoryContext oldcxt;
1676  CollectedCommand *command;
1677  InternalGrant *icopy;
1678  ListCell *cell;
1679 
1680  /* ignore if event trigger context not set, or collection disabled */
1681  if (!currentEventTriggerState ||
1682  currentEventTriggerState->commandCollectionInhibited)
1683  return;
1684 
1685  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1686 
1687  /*
1688  * This is tedious, but necessary.
1689  */
1690  icopy = palloc(sizeof(InternalGrant));
1691  memcpy(icopy, istmt, sizeof(InternalGrant));
1692  icopy->objects = list_copy(istmt->objects);
1693  icopy->grantees = list_copy(istmt->grantees);
1694  icopy->col_privs = NIL;
1695  foreach(cell, istmt->col_privs)
1696  icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1697 
1698  /* Now collect it, using the copied InternalGrant */
1699  command = palloc(sizeof(CollectedCommand));
1700  command->type = SCT_Grant;
1701  command->in_extension = creating_extension;
1702  command->d.grant.istmt = icopy;
1703  command->parsetree = NULL;
1704 
1705  currentEventTriggerState->commandList =
1706  lappend(currentEventTriggerState->commandList, command);
1707 
1708  MemoryContextSwitchTo(oldcxt);
1709 }
1710 
1711 /*
1712  * EventTriggerCollectAlterOpFam
1713  * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1714  * executed
1715  */
1716 void
1718  List *operators, List *procedures)
1719 {
1720  MemoryContext oldcxt;
1721  CollectedCommand *command;
1722 
1723  /* ignore if event trigger context not set, or collection disabled */
1724  if (!currentEventTriggerState ||
1725  currentEventTriggerState->commandCollectionInhibited)
1726  return;
1727 
1728  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1729 
1730  command = palloc(sizeof(CollectedCommand));
1731  command->type = SCT_AlterOpFamily;
1732  command->in_extension = creating_extension;
1733  ObjectAddressSet(command->d.opfam.address,
1734  OperatorFamilyRelationId, opfamoid);
1735  command->d.opfam.operators = operators;
1736  command->d.opfam.procedures = procedures;
1737  command->parsetree = (Node *) copyObject(stmt);
1738 
1739  currentEventTriggerState->commandList =
1740  lappend(currentEventTriggerState->commandList, command);
1741 
1742  MemoryContextSwitchTo(oldcxt);
1743 }
1744 
1745 /*
1746  * EventTriggerCollectCreateOpClass
1747  * Save data about a CREATE OPERATOR CLASS command being executed
1748  */
1749 void
1751  List *operators, List *procedures)
1752 {
1753  MemoryContext oldcxt;
1754  CollectedCommand *command;
1755 
1756  /* ignore if event trigger context not set, or collection disabled */
1757  if (!currentEventTriggerState ||
1758  currentEventTriggerState->commandCollectionInhibited)
1759  return;
1760 
1761  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1762 
1763  command = palloc0(sizeof(CollectedCommand));
1764  command->type = SCT_CreateOpClass;
1765  command->in_extension = creating_extension;
1766  ObjectAddressSet(command->d.createopc.address,
1767  OperatorClassRelationId, opcoid);
1768  command->d.createopc.operators = operators;
1769  command->d.createopc.procedures = procedures;
1770  command->parsetree = (Node *) copyObject(stmt);
1771 
1772  currentEventTriggerState->commandList =
1773  lappend(currentEventTriggerState->commandList, command);
1774 
1775  MemoryContextSwitchTo(oldcxt);
1776 }
1777 
1778 /*
1779  * EventTriggerCollectAlterTSConfig
1780  * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1781  * executed
1782  */
1783 void
1785  Oid *dictIds, int ndicts)
1786 {
1787  MemoryContext oldcxt;
1788  CollectedCommand *command;
1789 
1790  /* ignore if event trigger context not set, or collection disabled */
1791  if (!currentEventTriggerState ||
1792  currentEventTriggerState->commandCollectionInhibited)
1793  return;
1794 
1795  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1796 
1797  command = palloc0(sizeof(CollectedCommand));
1798  command->type = SCT_AlterTSConfig;
1799  command->in_extension = creating_extension;
1800  ObjectAddressSet(command->d.atscfg.address,
1801  TSConfigRelationId, cfgId);
1802  command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
1803  memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
1804  command->d.atscfg.ndicts = ndicts;
1805  command->parsetree = (Node *) copyObject(stmt);
1806 
1807  currentEventTriggerState->commandList =
1808  lappend(currentEventTriggerState->commandList, command);
1809 
1810  MemoryContextSwitchTo(oldcxt);
1811 }
1812 
1813 /*
1814  * EventTriggerCollectAlterDefPrivs
1815  * Save data about an ALTER DEFAULT PRIVILEGES command being
1816  * executed
1817  */
1818 void
1820 {
1821  MemoryContext oldcxt;
1822  CollectedCommand *command;
1823 
1824  /* ignore if event trigger context not set, or collection disabled */
1825  if (!currentEventTriggerState ||
1826  currentEventTriggerState->commandCollectionInhibited)
1827  return;
1828 
1829  oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1830 
1831  command = palloc0(sizeof(CollectedCommand));
1832  command->type = SCT_AlterDefaultPrivileges;
1833  command->d.defprivs.objtype = stmt->action->objtype;
1834  command->in_extension = creating_extension;
1835  command->parsetree = (Node *) copyObject(stmt);
1836 
1837  currentEventTriggerState->commandList =
1838  lappend(currentEventTriggerState->commandList, command);
1839  MemoryContextSwitchTo(oldcxt);
1840 }
1841 
1842 /*
1843  * In a ddl_command_end event trigger, this function reports the DDL commands
1844  * being run.
1845  */
1846 Datum
1848 {
1849  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1850  TupleDesc tupdesc;
1851  Tuplestorestate *tupstore;
1852  MemoryContext per_query_ctx;
1853  MemoryContext oldcontext;
1854  ListCell *lc;
1855 
1856  /*
1857  * Protect this function from being called out of context
1858  */
1859  if (!currentEventTriggerState)
1860  ereport(ERROR,
1861  (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1862  errmsg("%s can only be called in an event trigger function",
1863  "pg_event_trigger_ddl_commands()")));
1864 
1865  /* check to see if caller supports us returning a tuplestore */
1866  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1867  ereport(ERROR,
1868  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1869  errmsg("set-valued function called in context that cannot accept a set")));
1870  if (!(rsinfo->allowedModes & SFRM_Materialize))
1871  ereport(ERROR,
1872  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1873  errmsg("materialize mode required, but it is not allowed in this context")));
1874 
1875  /* Build a tuple descriptor for our result type */
1876  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1877  elog(ERROR, "return type must be a row type");
1878 
1879  /* Build tuplestore to hold the result rows */
1880  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1881  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1882 
1883  tupstore = tuplestore_begin_heap(true, false, work_mem);
1884  rsinfo->returnMode = SFRM_Materialize;
1885  rsinfo->setResult = tupstore;
1886  rsinfo->setDesc = tupdesc;
1887 
1888  MemoryContextSwitchTo(oldcontext);
1889 
1890  foreach(lc, currentEventTriggerState->commandList)
1891  {
1892  CollectedCommand *cmd = lfirst(lc);
1893  Datum values[9];
1894  bool nulls[9];
1895  ObjectAddress addr;
1896  int i = 0;
1897 
1898  /*
1899  * For IF NOT EXISTS commands that attempt to create an existing
1900  * object, the returned OID is Invalid. Don't return anything.
1901  *
1902  * One might think that a viable alternative would be to look up the
1903  * Oid of the existing object and run the deparse with that. But
1904  * since the parse tree might be different from the one that created
1905  * the object in the first place, we might not end up in a consistent
1906  * state anyway.
1907  */
1908  if (cmd->type == SCT_Simple &&
1909  !OidIsValid(cmd->d.simple.address.objectId))
1910  continue;
1911 
1912  MemSet(nulls, 0, sizeof(nulls));
1913 
1914  switch (cmd->type)
1915  {
1916  case SCT_Simple:
1917  case SCT_AlterTable:
1918  case SCT_AlterOpFamily:
1919  case SCT_CreateOpClass:
1920  case SCT_AlterTSConfig:
1921  {
1922  char *identity;
1923  char *type;
1924  char *schema = NULL;
1925 
1926  if (cmd->type == SCT_Simple)
1927  addr = cmd->d.simple.address;
1928  else if (cmd->type == SCT_AlterTable)
1929  ObjectAddressSet(addr,
1930  cmd->d.alterTable.classId,
1931  cmd->d.alterTable.objectId);
1932  else if (cmd->type == SCT_AlterOpFamily)
1933  addr = cmd->d.opfam.address;
1934  else if (cmd->type == SCT_CreateOpClass)
1935  addr = cmd->d.createopc.address;
1936  else if (cmd->type == SCT_AlterTSConfig)
1937  addr = cmd->d.atscfg.address;
1938 
1939  type = getObjectTypeDescription(&addr, false);
1940  identity = getObjectIdentity(&addr, false);
1941 
1942  /*
1943  * Obtain schema name, if any ("pg_temp" if a temp
1944  * object). If the object class is not in the supported
1945  * list here, we assume it's a schema-less object type,
1946  * and thus "schema" remains set to NULL.
1947  */
1949  {
1950  AttrNumber nspAttnum;
1951 
1952  nspAttnum = get_object_attnum_namespace(addr.classId);
1953  if (nspAttnum != InvalidAttrNumber)
1954  {
1955  Relation catalog;
1956  HeapTuple objtup;
1957  Oid schema_oid;
1958  bool isnull;
1959 
1960  catalog = table_open(addr.classId, AccessShareLock);
1961  objtup = get_catalog_object_by_oid(catalog,
1963  addr.objectId);
1964  if (!HeapTupleIsValid(objtup))
1965  elog(ERROR, "cache lookup failed for object %u/%u",
1966  addr.classId, addr.objectId);
1967  schema_oid =
1968  heap_getattr(objtup, nspAttnum,
1969  RelationGetDescr(catalog), &isnull);
1970  if (isnull)
1971  elog(ERROR,
1972  "invalid null namespace in object %u/%u/%d",
1973  addr.classId, addr.objectId, addr.objectSubId);
1974  /* XXX not quite get_namespace_name_or_temp */
1975  if (isAnyTempNamespace(schema_oid))
1976  schema = pstrdup("pg_temp");
1977  else
1978  schema = get_namespace_name(schema_oid);
1979 
1980  table_close(catalog, AccessShareLock);
1981  }
1982  }
1983 
1984  /* classid */
1985  values[i++] = ObjectIdGetDatum(addr.classId);
1986  /* objid */
1987  values[i++] = ObjectIdGetDatum(addr.objectId);
1988  /* objsubid */
1989  values[i++] = Int32GetDatum(addr.objectSubId);
1990  /* command tag */
1991  values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
1992  /* object_type */
1993  values[i++] = CStringGetTextDatum(type);
1994  /* schema */
1995  if (schema == NULL)
1996  nulls[i++] = true;
1997  else
1998  values[i++] = CStringGetTextDatum(schema);
1999  /* identity */
2000  values[i++] = CStringGetTextDatum(identity);
2001  /* in_extension */
2002  values[i++] = BoolGetDatum(cmd->in_extension);
2003  /* command */
2004  values[i++] = PointerGetDatum(cmd);
2005  }
2006  break;
2007 
2009  /* classid */
2010  nulls[i++] = true;
2011  /* objid */
2012  nulls[i++] = true;
2013  /* objsubid */
2014  nulls[i++] = true;
2015  /* command tag */
2016  values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
2017  /* object_type */
2018  values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
2019  /* schema */
2020  nulls[i++] = true;
2021  /* identity */
2022  nulls[i++] = true;
2023  /* in_extension */
2024  values[i++] = BoolGetDatum(cmd->in_extension);
2025  /* command */
2026  values[i++] = PointerGetDatum(cmd);
2027  break;
2028 
2029  case SCT_Grant:
2030  /* classid */
2031  nulls[i++] = true;
2032  /* objid */
2033  nulls[i++] = true;
2034  /* objsubid */
2035  nulls[i++] = true;
2036  /* command tag */
2037  values[i++] = CStringGetTextDatum(cmd->d.grant.istmt->is_grant ?
2038  "GRANT" : "REVOKE");
2039  /* object_type */
2040  values[i++] = CStringGetTextDatum(stringify_grant_objtype(cmd->d.grant.istmt->objtype));
2041  /* schema */
2042  nulls[i++] = true;
2043  /* identity */
2044  nulls[i++] = true;
2045  /* in_extension */
2046  values[i++] = BoolGetDatum(cmd->in_extension);
2047  /* command */
2048  values[i++] = PointerGetDatum(cmd);
2049  break;
2050  }
2051 
2052  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2053  }
2054 
2055  /* clean up and return the tuplestore */
2056  tuplestore_donestoring(tupstore);
2057 
2058  PG_RETURN_VOID();
2059 }
2060 
2061 /*
2062  * Return the ObjectType as a string, as it would appear in GRANT and
2063  * REVOKE commands.
2064  */
2065 static const char *
2067 {
2068  switch (objtype)
2069  {
2070  case OBJECT_COLUMN:
2071  return "COLUMN";
2072  case OBJECT_TABLE:
2073  return "TABLE";
2074  case OBJECT_SEQUENCE:
2075  return "SEQUENCE";
2076  case OBJECT_DATABASE:
2077  return "DATABASE";
2078  case OBJECT_DOMAIN:
2079  return "DOMAIN";
2080  case OBJECT_FDW:
2081  return "FOREIGN DATA WRAPPER";
2082  case OBJECT_FOREIGN_SERVER:
2083  return "FOREIGN SERVER";
2084  case OBJECT_FUNCTION:
2085  return "FUNCTION";
2086  case OBJECT_LANGUAGE:
2087  return "LANGUAGE";
2088  case OBJECT_LARGEOBJECT:
2089  return "LARGE OBJECT";
2090  case OBJECT_SCHEMA:
2091  return "SCHEMA";
2092  case OBJECT_PROCEDURE:
2093  return "PROCEDURE";
2094  case OBJECT_ROUTINE:
2095  return "ROUTINE";
2096  case OBJECT_TABLESPACE:
2097  return "TABLESPACE";
2098  case OBJECT_TYPE:
2099  return "TYPE";
2100  /* these currently aren't used */
2101  case OBJECT_ACCESS_METHOD:
2102  case OBJECT_AGGREGATE:
2103  case OBJECT_AMOP:
2104  case OBJECT_AMPROC:
2105  case OBJECT_ATTRIBUTE:
2106  case OBJECT_CAST:
2107  case OBJECT_COLLATION:
2108  case OBJECT_CONVERSION:
2109  case OBJECT_DEFAULT:
2110  case OBJECT_DEFACL:
2111  case OBJECT_DOMCONSTRAINT:
2112  case OBJECT_EVENT_TRIGGER:
2113  case OBJECT_EXTENSION:
2114  case OBJECT_FOREIGN_TABLE:
2115  case OBJECT_INDEX:
2116  case OBJECT_MATVIEW:
2117  case OBJECT_OPCLASS:
2118  case OBJECT_OPERATOR:
2119  case OBJECT_OPFAMILY:
2120  case OBJECT_POLICY:
2121  case OBJECT_PUBLICATION:
2123  case OBJECT_ROLE:
2124  case OBJECT_RULE:
2125  case OBJECT_STATISTIC_EXT:
2126  case OBJECT_SUBSCRIPTION:
2127  case OBJECT_TABCONSTRAINT:
2128  case OBJECT_TRANSFORM:
2129  case OBJECT_TRIGGER:
2131  case OBJECT_TSDICTIONARY:
2132  case OBJECT_TSPARSER:
2133  case OBJECT_TSTEMPLATE:
2134  case OBJECT_USER_MAPPING:
2135  case OBJECT_VIEW:
2136  elog(ERROR, "unsupported object type: %d", (int) objtype);
2137  }
2138 
2139  return "???"; /* keep compiler quiet */
2140 }
2141 
2142 /*
2143  * Return the ObjectType as a string; as above, but use the spelling
2144  * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2145  * the plural.
2146  */
2147 static const char *
2149 {
2150  switch (objtype)
2151  {
2152  case OBJECT_COLUMN:
2153  return "COLUMNS";
2154  case OBJECT_TABLE:
2155  return "TABLES";
2156  case OBJECT_SEQUENCE:
2157  return "SEQUENCES";
2158  case OBJECT_DATABASE:
2159  return "DATABASES";
2160  case OBJECT_DOMAIN:
2161  return "DOMAINS";
2162  case OBJECT_FDW:
2163  return "FOREIGN DATA WRAPPERS";
2164  case OBJECT_FOREIGN_SERVER:
2165  return "FOREIGN SERVERS";
2166  case OBJECT_FUNCTION:
2167  return "FUNCTIONS";
2168  case OBJECT_LANGUAGE:
2169  return "LANGUAGES";
2170  case OBJECT_LARGEOBJECT:
2171  return "LARGE OBJECTS";
2172  case OBJECT_SCHEMA:
2173  return "SCHEMAS";
2174  case OBJECT_PROCEDURE:
2175  return "PROCEDURES";
2176  case OBJECT_ROUTINE:
2177  return "ROUTINES";
2178  case OBJECT_TABLESPACE:
2179  return "TABLESPACES";
2180  case OBJECT_TYPE:
2181  return "TYPES";
2182  /* these currently aren't used */
2183  case OBJECT_ACCESS_METHOD:
2184  case OBJECT_AGGREGATE:
2185  case OBJECT_AMOP:
2186  case OBJECT_AMPROC:
2187  case OBJECT_ATTRIBUTE:
2188  case OBJECT_CAST:
2189  case OBJECT_COLLATION:
2190  case OBJECT_CONVERSION:
2191  case OBJECT_DEFAULT:
2192  case OBJECT_DEFACL:
2193  case OBJECT_DOMCONSTRAINT:
2194  case OBJECT_EVENT_TRIGGER:
2195  case OBJECT_EXTENSION:
2196  case OBJECT_FOREIGN_TABLE:
2197  case OBJECT_INDEX:
2198  case OBJECT_MATVIEW:
2199  case OBJECT_OPCLASS:
2200  case OBJECT_OPERATOR:
2201  case OBJECT_OPFAMILY:
2202  case OBJECT_POLICY:
2203  case OBJECT_PUBLICATION:
2205  case OBJECT_ROLE:
2206  case OBJECT_RULE:
2207  case OBJECT_STATISTIC_EXT:
2208  case OBJECT_SUBSCRIPTION:
2209  case OBJECT_TABCONSTRAINT:
2210  case OBJECT_TRANSFORM:
2211  case OBJECT_TRIGGER:
2213  case OBJECT_TSDICTIONARY:
2214  case OBJECT_TSPARSER:
2215  case OBJECT_TSTEMPLATE:
2216  case OBJECT_USER_MAPPING:
2217  case OBJECT_VIEW:
2218  elog(ERROR, "unsupported object type: %d", (int) objtype);
2219  }
2220 
2221  return "???"; /* keep compiler quiet */
2222 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
bool get_object_namensp_unique(Oid class_id)
#define NIL
Definition: pg_list.h:65
CommandTag
Definition: cmdtag.h:20
char * getObjectIdentityParts(const ObjectAddress *object, List **objname, List **objargs, bool missing_ok)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
slist_node next
Definition: event_trigger.c:88
Definition: fmgr.h:56
static void validate_ddl_tags(const char *filtervar, List *taglist)
struct CollectedCommand::@108::@114 atscfg
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
#define NameGetDatum(X)
Definition: postgres.h:595
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
#define AllocSetContextCreate
Definition: memutils.h:170
#define DEBUG1
Definition: elog.h:25
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
CommandTag tag
Definition: event_trigger.h:29
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
static int32 next
Definition: blutils.c:219
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
ObjectAddress address
Definition: event_trigger.c:78
static struct @142 value
AttrNumber get_object_attnum_oid(Oid class_id)
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:476
Datum pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
void namestrcpy(Name name, const char *str)
Definition: name.c:233
bool trackDroppedObjectsNeeded(void)
#define PointerGetDatum(X)
Definition: postgres.h:556
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
static const char * CreateCommandName(Node *parsetree)
Definition: utility.h:99
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:192
const char * objname
Definition: event_trigger.c:80
#define DatumGetObjectId(X)
Definition: postgres.h:500
char * pstrdup(const char *in)
Definition: mcxt.c:1187
Datum pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define PG_RETURN_INT32(x)
Definition: fmgr.h:353
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3313
#define AccessShareLock
Definition: lockdefs.h:36
void EventTriggerDDLCommandEnd(Node *parsetree)
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:574
List * list_copy(const List *oldlist)
Definition: list.c:1403
Definition: nodes.h:528
List * addrnames
Definition: event_trigger.c:83
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
#define MemSet(start, val, len)
Definition: c.h:949
bool command_tag_table_rewrite_ok(CommandTag commandTag)
Definition: cmdtag.c:63
unsigned char pg_ascii_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:135
void EventTriggerInhibitCommandCollection(void)
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
AttrNumber get_object_attnum_namespace(Oid class_id)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
CollectedCommandType type
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
const char * objidentity
Definition: event_trigger.c:81
Oid get_event_trigger_oid(const char *trigname, bool missing_ok)
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3432
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2722
#define OidIsValid(objectId)
Definition: c.h:651
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:156
int SessionReplicationRole
Definition: trigger.c:67
const char * objecttype
Definition: event_trigger.c:82
static EventTriggerQueryState * currentEventTriggerState
Definition: event_trigger.c:73
static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
EventTriggerEvent
Definition: evtcache.h:20
ObjectAddress AlterEventTriggerOwner(const char *name, Oid newOwnerId)
void EventTriggerAlterTableStart(Node *parsetree)
#define DatumGetName(X)
Definition: postgres.h:585
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:309
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
void pfree(void *pointer)
Definition: mcxt.c:1057
static void slist_init(slist_head *head)
Definition: ilist.h:554
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static void validate_table_rewrite_tags(const char *filtervar, List *taglist)
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
Definition: pgstat.c:1675
bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
Definition: aclchk.c:5078
static Datum filter_list_to_array(List *filterlist)
void EventTriggerDDLCommandStart(Node *parsetree)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * event
Definition: event_trigger.h:27
ItemPointerData t_self
Definition: htup.h:65
void EventTriggerSQLDrop(Node *parsetree)
char * getObjectIdentity(const ObjectAddress *object, bool missing_ok)
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
Definition: c.h:616
static void error_duplicate_filter_variable(const char *defname)
Datum pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
static List * EventTriggerCommonSetup(Node *parsetree, EventTriggerEvent event, const char *eventstr, EventTriggerData *trigdata)
void check_stack_depth(void)
Definition: postgres.c:3312
CollectedCommand * currentCommand
Definition: event_trigger.c:67
bool IsUnderPostmaster
Definition: globals.c:109
ObjectClass
Definition: dependency.h:89
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
struct CollectedCommand::@108::@109 simple
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3156
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId, Oid *dictIds, int ndicts)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
struct EventTriggerQueryState * previous
Definition: event_trigger.c:70
MemoryContext TopMemoryContext
Definition: mcxt.c:44
struct CollectedCommand * parent
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
Oid AlterEventTrigger(AlterEventTrigStmt *stmt)
Node * arg
Definition: parsenodes.h:734
ObjectType
Definition: parsenodes.h:1694
bool EventTriggerSupportsObjectClass(ObjectClass objclass)
List * lappend(List *list, void *datum)
Definition: list.c:321
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
const char * schemaname
Definition: event_trigger.c:79
static bool slist_is_empty(slist_head *head)
Definition: ilist.h:563
void EventTriggerEndCompleteQuery(void)
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
struct EventTriggerQueryState EventTriggerQueryState
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3101
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
#define PG_FINALLY()
Definition: elog.h:312
#define slist_container(type, membername, ptr)
Definition: ilist.h:674
AttrNumber get_object_attnum_name(Oid class_id)
static Oid insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner, Oid funcoid, List *tags)
void * palloc0(Size size)
Definition: mcxt.c:981
void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
HeapTuple get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
void EventTriggerUndoInhibitCommandCollection(void)
uintptr_t Datum
Definition: postgres.h:367
union CollectedCommand::@108 d
#define SESSION_REPLICATION_ROLE_REPLICA
Definition: trigger.h:148
void CommandCounterIncrement(void)
Definition: xact.c:1021
Oid CreateEventTrigger(CreateEventTrigStmt *stmt)
int work_mem
Definition: globals.c:121
static const char * stringify_adefprivs_objtype(ObjectType objtype)
void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
TupleDesc rd_att
Definition: rel.h:110
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:71
int16 attnum
Definition: pg_attribute.h:79
void AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
#define ereport(elevel,...)
Definition: elog.h:144
bool EventTriggerSupportsObjectType(ObjectType obtype)
int allowedModes
Definition: execnodes.h:305
#define PG_RETURN_VOID()
Definition: fmgr.h:348
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
SetFunctionReturnMode returnMode
Definition: execnodes.h:307
text * cstring_to_text(const char *s)
Definition: varlena.c:188
FormData_pg_event_trigger * Form_pg_event_trigger
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:189
Definition: regguts.h:298
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2293
struct CollectedCommand::@108::@115 defprivs
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:180
#define EventTriggerOidIndexId
Definition: indexing.h:271
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
char * getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
static int list_length(const List *l)
Definition: pg_list.h:169
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
struct CollectedCommand::@108::@110 alterTable
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:233
const char * name
Definition: encode.c:561
struct CollectedCommand::@108::@113 createopc
#define InvalidAttrNumber
Definition: attnum.h:23
void EventTriggerAlterTableRelid(Oid objectId)
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
CommandTag GetCommandTagEnum(const char *commandname)
Definition: cmdtag.c:74
Tuplestorestate * setResult
Definition: execnodes.h:310
#define TRIGGER_FIRES_ON_REPLICA
Definition: trigger.h:158
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
Definition: pgstat.c:1747
Bitmapset * tagset
Definition: evtcache.h:32
static Datum values[MAXATTR]
Definition: bootstrap.c:165
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:45
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
ExprContext * econtext
Definition: execnodes.h:303
void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
#define slist_foreach(iter, lhead)
Definition: ilist.h:700
#define Int32GetDatum(X)
Definition: postgres.h:479
struct SQLDropObject SQLDropObject
TupleDesc setDesc
Definition: execnodes.h:311
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:214
int i
List * EventCacheLookup(EventTriggerEvent event)
Definition: evtcache.c:65
ObjectType objtype
Definition: parsenodes.h:1931
#define NameStr(name)
Definition: c.h:622
#define CStringGetTextDatum(s)
Definition: builtins.h:86
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3194
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void EventTriggerCollectGrant(InternalGrant *istmt)
char * defname
Definition: parsenodes.h:733
ArrayType * strlist_to_textarray(List *list)
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
struct CollectedCommand::@108::@111 grant
#define copyObject(obj)
Definition: nodes.h:644
bool is_objectclass_supported(Oid class_id)
#define PG_TRY()
Definition: elog.h:295
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
static color newsub(struct colormap *cm, color co)
Definition: regc_color.c:389
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
bool command_tag_event_trigger_ok(CommandTag commandTag)
Definition: cmdtag.c:57
Definition: pg_list.h:50
#define PG_RETURN_OID(x)
Definition: fmgr.h:359
static const char * stringify_grant_objtype(ObjectType objtype)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21
static bool filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define PG_END_TRY()
Definition: elog.h:320
#define lfirst_oid(lc)
Definition: pg_list.h:191
ObjectAddress address
bool EventTriggerBeginCompleteQuery(void)
struct CollectedCommand::@108::@112 opfam
void EventTriggerAlterTableEnd(void)