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