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