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