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