TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * event_trigger.c
4 : * PostgreSQL EVENT TRIGGER support code.
5 : *
6 : * Portions Copyright (c) 1996-2023, 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"
23 : #include "catalog/pg_event_trigger.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 */
54 : MemoryContext cxt;
55 :
56 : /* sql_drop */
57 : slist_head SQLDropList;
58 : bool in_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 */
66 : bool commandCollectionInhibited;
67 : CollectedCommand *currentCommand;
68 : List *commandList; /* list of CollectedCommand; see
69 : * deparse_utility.h */
70 : struct EventTriggerQueryState *previous;
71 : } EventTriggerQueryState;
72 :
73 : static EventTriggerQueryState *currentEventTriggerState = NULL;
74 :
75 : /* Support for dropped objects */
76 : typedef struct SQLDropObject
77 : {
78 : ObjectAddress address;
79 : const char *schemaname;
80 : const char *objname;
81 : const char *objidentity;
82 : const char *objecttype;
83 : List *addrnames;
84 : List *addrargs;
85 : bool original;
86 : bool normal;
87 : bool istemp;
88 : slist_node next;
89 : } SQLDropObject;
90 :
91 : static void AlterEventTriggerOwner_internal(Relation rel,
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 *taglist);
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
108 CBC 80 : CreateEventTrigger(CreateEventTrigStmt *stmt)
109 : {
110 : HeapTuple tuple;
111 : Oid funcoid;
112 : Oid funcrettype;
113 80 : Oid evtowner = GetUserId();
114 : ListCell *lc;
115 80 : 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 80 : if (!superuser())
123 3 : 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 77 : if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
131 37 : strcmp(stmt->eventname, "ddl_command_end") != 0 &&
132 24 : strcmp(stmt->eventname, "sql_drop") != 0 &&
133 11 : strcmp(stmt->eventname, "table_rewrite") != 0)
134 3 : ereport(ERROR,
135 : (errcode(ERRCODE_SYNTAX_ERROR),
136 : errmsg("unrecognized event name \"%s\"",
137 : stmt->eventname)));
138 :
139 : /* Validate filter conditions. */
140 110 : foreach(lc, stmt->whenclause)
141 : {
142 42 : DefElem *def = (DefElem *) lfirst(lc);
143 :
144 42 : if (strcmp(def->defname, "tag") == 0)
145 : {
146 39 : if (tags != NULL)
147 3 : error_duplicate_filter_variable(def->defname);
148 36 : tags = (List *) def->arg;
149 : }
150 : else
151 3 : ereport(ERROR,
152 : (errcode(ERRCODE_SYNTAX_ERROR),
153 : errmsg("unrecognized filter variable \"%s\"", def->defname)));
154 : }
155 :
156 : /* Validate tag list, if any. */
157 68 : if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
158 34 : strcmp(stmt->eventname, "ddl_command_end") == 0 ||
159 21 : strcmp(stmt->eventname, "sql_drop") == 0)
160 60 : && tags != NULL)
161 33 : validate_ddl_tags("tag", tags);
162 35 : else if (strcmp(stmt->eventname, "table_rewrite") == 0
163 8 : && tags != NULL)
164 UBC 0 : 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 : */
170 CBC 50 : tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
171 50 : if (HeapTupleIsValid(tuple))
172 UBC 0 : ereport(ERROR,
173 : (errcode(ERRCODE_DUPLICATE_OBJECT),
174 : errmsg("event trigger \"%s\" already exists",
175 : stmt->trigname)));
176 :
177 : /* Find and validate the trigger function. */
178 CBC 50 : funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
179 50 : funcrettype = get_func_rettype(funcoid);
180 50 : if (funcrettype != EVENT_TRIGGEROID)
181 3 : 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 47 : 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 33 : validate_ddl_tags(const char *filtervar, List *taglist)
196 : {
197 : ListCell *lc;
198 :
199 81 : foreach(lc, taglist)
200 : {
201 66 : const char *tagstr = strVal(lfirst(lc));
202 66 : CommandTag commandTag = GetCommandTagEnum(tagstr);
203 :
204 66 : if (commandTag == CMDTAG_UNKNOWN)
205 6 : ereport(ERROR,
206 : (errcode(ERRCODE_SYNTAX_ERROR),
207 : errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
208 : tagstr, filtervar)));
209 60 : if (!command_tag_event_trigger_ok(commandTag))
210 12 : 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 15 : }
217 :
218 : /*
219 : * Validate DDL command tags for event table_rewrite.
220 : */
221 : static void
222 UBC 0 : validate_table_rewrite_tags(const char *filtervar, List *taglist)
223 : {
224 : ListCell *lc;
225 :
226 0 : foreach(lc, taglist)
227 : {
228 0 : const char *tagstr = strVal(lfirst(lc));
229 0 : CommandTag commandTag = GetCommandTagEnum(tagstr);
230 :
231 0 : if (!command_tag_table_rewrite_ok(commandTag))
232 0 : 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 0 : }
239 :
240 : /*
241 : * Complain about a duplicate filter variable.
242 : */
243 : static void
244 CBC 3 : error_duplicate_filter_variable(const char *defname)
245 : {
246 3 : 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 47 : 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 47 : tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
271 :
272 : /* Build the new pg_trigger tuple. */
273 47 : trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId,
274 : Anum_pg_event_trigger_oid);
275 47 : values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
276 47 : memset(nulls, false, sizeof(nulls));
277 47 : namestrcpy(&evtnamedata, trigname);
278 47 : values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
279 47 : namestrcpy(&evteventdata, eventname);
280 47 : values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
281 47 : values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
282 47 : values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
283 47 : values[Anum_pg_event_trigger_evtenabled - 1] =
284 47 : CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
285 47 : if (taglist == NIL)
286 32 : nulls[Anum_pg_event_trigger_evttags - 1] = true;
287 : else
288 15 : values[Anum_pg_event_trigger_evttags - 1] =
289 15 : filter_list_to_array(taglist);
290 :
291 : /* Insert heap tuple. */
292 47 : tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
293 47 : CatalogTupleInsert(tgrel, tuple);
294 47 : heap_freetuple(tuple);
295 :
296 : /* Depend on owner. */
297 47 : recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
298 :
299 : /* Depend on event trigger function. */
300 47 : myself.classId = EventTriggerRelationId;
301 47 : myself.objectId = trigoid;
302 47 : myself.objectSubId = 0;
303 47 : referenced.classId = ProcedureRelationId;
304 47 : referenced.objectId = funcoid;
305 47 : referenced.objectSubId = 0;
306 47 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
307 :
308 : /* Depend on extension, if any. */
309 47 : recordDependencyOnCurrentExtension(&myself, false);
310 :
311 : /* Post creation hook for new event trigger */
312 47 : InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
313 :
314 : /* Close pg_event_trigger. */
315 47 : table_close(tgrel, RowExclusiveLock);
316 :
317 47 : 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
332 15 : filter_list_to_array(List *filterlist)
333 : {
334 : ListCell *lc;
335 : Datum *data;
336 15 : int i = 0,
337 15 : l = list_length(filterlist);
338 :
339 15 : data = (Datum *) palloc(l * sizeof(Datum));
340 :
341 60 : foreach(lc, filterlist)
342 : {
343 45 : const char *value = strVal(lfirst(lc));
344 : char *result,
345 : *p;
346 :
347 45 : result = pstrdup(value);
348 567 : for (p = result; *p; p++)
349 522 : *p = pg_ascii_toupper((unsigned char) *p);
350 45 : data[i++] = PointerGetDatum(cstring_to_text(result));
351 45 : pfree(result);
352 : }
353 :
354 GNC 15 : return PointerGetDatum(construct_array_builtin(data, l, TEXTOID));
355 : }
356 :
357 : /*
358 : * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
359 : */
360 ECB : Oid
361 GIC 16 : AlterEventTrigger(AlterEventTrigStmt *stmt)
362 : {
363 : Relation tgrel;
364 : HeapTuple tup;
365 : Oid trigoid;
366 ECB : Form_pg_event_trigger evtForm;
367 GIC 16 : char tgenabled = stmt->tgenabled;
368 ECB :
369 GIC 16 : tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
370 ECB :
371 GIC 16 : tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
372 ECB : CStringGetDatum(stmt->trigname));
373 GBC 16 : if (!HeapTupleIsValid(tup))
374 UIC 0 : ereport(ERROR,
375 : (errcode(ERRCODE_UNDEFINED_OBJECT),
376 : errmsg("event trigger \"%s\" does not exist",
377 : stmt->trigname)));
378 ECB :
379 CBC 16 : evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
380 GIC 16 : trigoid = evtForm->oid;
381 ECB :
382 GNC 16 : if (!object_ownercheck(EventTriggerRelationId, trigoid, GetUserId()))
383 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
384 UIC 0 : stmt->trigname);
385 :
386 ECB : /* tuple is a copy, so we can modify it below */
387 GIC 16 : evtForm->evtenabled = tgenabled;
388 ECB :
389 GIC 16 : CatalogTupleUpdate(tgrel, &tup->t_self, tup);
390 ECB :
391 GIC 16 : InvokeObjectPostAlterHook(EventTriggerRelationId,
392 : trigoid, 0);
393 :
394 ECB : /* clean up */
395 CBC 16 : heap_freetuple(tup);
396 GIC 16 : table_close(tgrel, RowExclusiveLock);
397 ECB :
398 GIC 16 : return trigoid;
399 : }
400 :
401 : /*
402 : * Change event trigger's owner -- by name
403 : */
404 ECB : ObjectAddress
405 GIC 6 : 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 ECB :
413 GIC 6 : rel = table_open(EventTriggerRelationId, RowExclusiveLock);
414 ECB :
415 GIC 6 : tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
416 ECB :
417 GBC 6 : if (!HeapTupleIsValid(tup))
418 UIC 0 : ereport(ERROR,
419 : (errcode(ERRCODE_UNDEFINED_OBJECT),
420 : errmsg("event trigger \"%s\" does not exist", name)));
421 ECB :
422 CBC 6 : evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
423 GIC 6 : evtOid = evtForm->oid;
424 ECB :
425 GIC 6 : AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
426 ECB :
427 GIC 3 : ObjectAddressSet(address, EventTriggerRelationId, evtOid);
428 ECB :
429 GIC 3 : heap_freetuple(tup);
430 ECB :
431 GIC 3 : table_close(rel, RowExclusiveLock);
432 ECB :
433 GIC 3 : return address;
434 : }
435 :
436 : /*
437 : * Change event trigger owner, by OID
438 : */
439 EUB : void
440 UIC 0 : AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
441 : {
442 : HeapTuple tup;
443 : Relation rel;
444 EUB :
445 UIC 0 : rel = table_open(EventTriggerRelationId, RowExclusiveLock);
446 EUB :
447 UIC 0 : tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
448 EUB :
449 UBC 0 : if (!HeapTupleIsValid(tup))
450 UIC 0 : ereport(ERROR,
451 : (errcode(ERRCODE_UNDEFINED_OBJECT),
452 : errmsg("event trigger with OID %u does not exist", trigOid)));
453 EUB :
454 UIC 0 : AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
455 EUB :
456 UIC 0 : heap_freetuple(tup);
457 EUB :
458 UBC 0 : table_close(rel, RowExclusiveLock);
459 UIC 0 : }
460 :
461 : /*
462 : * Internal workhorse for changing an event trigger's owner
463 : */
464 ECB : static void
465 GIC 6 : AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
466 : {
467 : Form_pg_event_trigger form;
468 ECB :
469 GIC 6 : form = (Form_pg_event_trigger) GETSTRUCT(tup);
470 ECB :
471 GBC 6 : if (form->evtowner == newOwnerId)
472 UIC 0 : return;
473 ECB :
474 GNC 6 : if (!object_ownercheck(EventTriggerRelationId, form->oid, GetUserId()))
475 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
476 UIC 0 : NameStr(form->evtname));
477 :
478 ECB : /* New owner must be a superuser */
479 CBC 6 : if (!superuser_arg(newOwnerId))
480 GIC 3 : 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 ECB :
486 CBC 3 : form->evtowner = newOwnerId;
487 GIC 3 : CatalogTupleUpdate(rel, &tup->t_self, tup);
488 :
489 ECB : /* Update owner dependency reference */
490 GIC 3 : changeDependencyOnOwner(EventTriggerRelationId,
491 : form->oid,
492 : newOwnerId);
493 ECB :
494 GIC 3 : 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 ECB : Oid
505 GIC 71 : get_event_trigger_oid(const char *trigname, bool missing_ok)
506 : {
507 : Oid oid;
508 ECB :
509 GIC 71 : oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
510 ECB : CStringGetDatum(trigname));
511 CBC 71 : if (!OidIsValid(oid) && !missing_ok)
512 GIC 6 : ereport(ERROR,
513 : (errcode(ERRCODE_UNDEFINED_OBJECT),
514 ECB : errmsg("event trigger \"%s\" does not exist", trigname)));
515 GIC 65 : 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 ECB : static bool
524 GIC 600 : filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item)
525 : {
526 : /*
527 : * Filter by session replication role, knowing that we never see disabled
528 : * items down here.
529 ECB : */
530 GIC 600 : if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
531 ECB : {
532 CBC 27 : if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
533 GIC 21 : return false;
534 : }
535 : else
536 ECB : {
537 GBC 573 : if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
538 UIC 0 : return false;
539 : }
540 :
541 ECB : /* Filter by tags, if any were specified. */
542 CBC 579 : if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
543 GIC 33 : return false;
544 :
545 ECB : /* if we reach that point, we're not filtering out this item */
546 GIC 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 ECB : static List *
555 GIC 61251 : EventTriggerCommonSetup(Node *parsetree,
556 : EventTriggerEvent event, const char *eventstr,
557 : EventTriggerData *trigdata)
558 : {
559 : CommandTag tag;
560 : List *cachelist;
561 ECB : ListCell *lc;
562 GIC 61251 : 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 ECB :
582 CBC 61251 : dbgtag = CreateCommandTag(parsetree);
583 61251 : if (event == EVT_DDLCommandStart ||
584 GIC 216 : event == EVT_DDLCommandEnd ||
585 : event == EVT_SQLDrop)
586 ECB : {
587 GBC 61210 : if (!command_tag_event_trigger_ok(dbgtag))
588 UIC 0 : elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
589 ECB : }
590 GIC 41 : else if (event == EVT_TableRewrite)
591 ECB : {
592 GBC 41 : if (!command_tag_table_rewrite_ok(dbgtag))
593 UIC 0 : elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
594 : }
595 : }
596 : #endif
597 :
598 ECB : /* Use cache to find triggers for this event; fast exit if none. */
599 CBC 61251 : cachelist = EventCacheLookup(event);
600 61251 : if (cachelist == NIL)
601 GIC 60699 : return NIL;
602 :
603 ECB : /* Get the command tag. */
604 GIC 552 : 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 ECB : */
613 GIC 1152 : foreach(lc, cachelist)
614 ECB : {
615 GIC 600 : EventTriggerCacheItem *item = lfirst(lc);
616 ECB :
617 GIC 600 : if (filter_event_trigger(tag, item))
618 : {
619 ECB : /* We must plan to fire this trigger. */
620 GIC 546 : runlist = lappend_oid(runlist, item->fnoid);
621 : }
622 : }
623 :
624 ECB : /* don't spend any more time on this if no functions to run */
625 CBC 552 : if (runlist == NIL)
626 GIC 42 : return NIL;
627 ECB :
628 CBC 510 : trigdata->type = T_EventTriggerData;
629 510 : trigdata->event = eventstr;
630 510 : trigdata->parsetree = parsetree;
631 GIC 510 : trigdata->tag = tag;
632 ECB :
633 GIC 510 : return runlist;
634 : }
635 :
636 : /*
637 : * Fire ddl_command_start triggers.
638 : */
639 ECB : void
640 GIC 276916 : EventTriggerDDLCommandStart(Node *parsetree)
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 ECB : */
661 CBC 276916 : if (!IsUnderPostmaster)
662 GIC 276760 : return;
663 ECB :
664 GIC 60271 : runlist = EventTriggerCommonSetup(parsetree,
665 : EVT_DDLCommandStart,
666 : "ddl_command_start",
667 ECB : &trigdata);
668 CBC 60271 : if (runlist == NIL)
669 GIC 60115 : return;
670 :
671 ECB : /* Run the triggers. */
672 GIC 156 : EventTriggerInvoke(runlist, &trigdata);
673 :
674 ECB : /* Cleanup. */
675 GIC 156 : list_free(runlist);
676 :
677 : /*
678 : * Make sure anything the event triggers did will be visible to the main
679 : * command.
680 ECB : */
681 GIC 156 : CommandCounterIncrement();
682 : }
683 :
684 : /*
685 : * Fire ddl_command_end triggers.
686 : */
687 ECB : void
688 GIC 271942 : EventTriggerDDLCommandEnd(Node *parsetree)
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 ECB : */
697 CBC 271942 : if (!IsUnderPostmaster)
698 GIC 271663 : 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 ECB : */
710 CBC 55297 : if (!currentEventTriggerState)
711 GIC 54533 : return;
712 ECB :
713 GIC 764 : runlist = EventTriggerCommonSetup(parsetree,
714 : EVT_DDLCommandEnd, "ddl_command_end",
715 ECB : &trigdata);
716 CBC 764 : if (runlist == NIL)
717 GIC 485 : return;
718 :
719 : /*
720 : * Make sure anything the main command did will be visible to the event
721 : * triggers.
722 ECB : */
723 GIC 279 : CommandCounterIncrement();
724 :
725 ECB : /* Run the triggers. */
726 GIC 279 : EventTriggerInvoke(runlist, &trigdata);
727 :
728 ECB : /* Cleanup. */
729 GIC 279 : list_free(runlist);
730 : }
731 :
732 : /*
733 : * Fire sql_drop triggers.
734 : */
735 ECB : void
736 GIC 271951 : EventTriggerSQLDrop(Node *parsetree)
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 ECB : */
745 CBC 271951 : if (!IsUnderPostmaster)
746 GIC 271903 : 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 ECB : */
755 CBC 55306 : if (!currentEventTriggerState ||
756 773 : slist_is_empty(¤tEventTriggerState->SQLDropList))
757 GIC 55131 : return;
758 ECB :
759 GIC 175 : 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 ECB : */
769 CBC 175 : if (runlist == NIL)
770 GIC 127 : return;
771 :
772 : /*
773 : * Make sure anything the main command did will be visible to the event
774 : * triggers.
775 ECB : */
776 GIC 48 : CommandCounterIncrement();
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 ECB : */
785 GIC 48 : currentEventTriggerState->in_sql_drop = true;
786 :
787 ECB : /* Run the triggers. */
788 GIC 48 : PG_TRY();
789 ECB : {
790 GIC 48 : EventTriggerInvoke(runlist, &trigdata);
791 ECB : }
792 GIC 9 : PG_FINALLY();
793 ECB : {
794 GIC 48 : currentEventTriggerState->in_sql_drop = false;
795 ECB : }
796 GIC 48 : PG_END_TRY();
797 :
798 ECB : /* Cleanup. */
799 GIC 39 : list_free(runlist);
800 : }
801 :
802 :
803 : /*
804 : * Fire table_rewrite triggers.
805 : */
806 ECB : void
807 GIC 371 : 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 ECB : */
816 CBC 371 : if (!IsUnderPostmaster)
817 GIC 344 : 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 ECB : */
826 CBC 371 : if (!currentEventTriggerState)
827 GIC 330 : return;
828 ECB :
829 GIC 41 : runlist = EventTriggerCommonSetup(parsetree,
830 : EVT_TableRewrite,
831 : "table_rewrite",
832 ECB : &trigdata);
833 CBC 41 : if (runlist == NIL)
834 GIC 14 : 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 ECB : */
843 CBC 27 : currentEventTriggerState->table_rewrite_oid = tableOid;
844 GIC 27 : currentEventTriggerState->table_rewrite_reason = reason;
845 :
846 ECB : /* Run the triggers. */
847 GIC 27 : PG_TRY();
848 ECB : {
849 GIC 27 : EventTriggerInvoke(runlist, &trigdata);
850 ECB : }
851 GIC 3 : PG_FINALLY();
852 ECB : {
853 CBC 27 : currentEventTriggerState->table_rewrite_oid = InvalidOid;
854 GIC 27 : currentEventTriggerState->table_rewrite_reason = 0;
855 ECB : }
856 GIC 27 : PG_END_TRY();
857 :
858 ECB : /* Cleanup. */
859 GIC 24 : list_free(runlist);
860 :
861 : /*
862 : * Make sure anything the event triggers did will be visible to the main
863 : * command.
864 ECB : */
865 GIC 24 : CommandCounterIncrement();
866 : }
867 :
868 : /*
869 : * Invoke each event trigger in a list of event triggers.
870 : */
871 ECB : static void
872 GIC 510 : EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
873 : {
874 : MemoryContext context;
875 : MemoryContext oldcontext;
876 ECB : ListCell *lc;
877 GIC 510 : bool first = true;
878 :
879 ECB : /* Guard against stack overflow due to recursive event trigger */
880 GIC 510 : check_stack_depth();
881 :
882 : /*
883 : * Let's evaluate event triggers in their own memory context, so that any
884 : * leaks get cleaned up promptly.
885 ECB : */
886 GIC 510 : context = AllocSetContextCreate(CurrentMemoryContext,
887 : "event trigger context",
888 ECB : ALLOCSET_DEFAULT_SIZES);
889 GIC 510 : oldcontext = MemoryContextSwitchTo(context);
890 :
891 ECB : /* Call each event trigger. */
892 GIC 1041 : foreach(lc, fn_oid_list)
893 ECB : {
894 CBC 543 : LOCAL_FCINFO(fcinfo, 0);
895 GIC 543 : Oid fnoid = lfirst_oid(lc);
896 : FmgrInfo flinfo;
897 : PgStat_FunctionCallUsage fcusage;
898 ECB :
899 GIC 543 : 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 ECB : */
907 CBC 543 : if (first)
908 GIC 510 : first = false;
909 ECB : else
910 GIC 33 : CommandCounterIncrement();
911 :
912 ECB : /* Look up the function */
913 GIC 543 : fmgr_info(fnoid, &flinfo);
914 :
915 ECB : /* Call the function, passing no arguments but setting a context. */
916 GIC 543 : InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
917 ECB : InvalidOid, (Node *) trigdata, NULL);
918 CBC 543 : pgstat_init_function_usage(fcinfo, &fcusage);
919 543 : FunctionCallInvoke(fcinfo);
920 GIC 531 : pgstat_end_function_usage(&fcusage, true);
921 :
922 ECB : /* Reclaim memory. */
923 GIC 531 : MemoryContextReset(context);
924 : }
925 :
926 ECB : /* Restore old memory context and delete the temporary one. */
927 CBC 498 : MemoryContextSwitchTo(oldcontext);
928 498 : MemoryContextDelete(context);
929 GIC 498 : }
930 :
931 : /*
932 : * Do event triggers support this object type?
933 : */
934 ECB : bool
935 GIC 129757 : EventTriggerSupportsObjectType(ObjectType obtype)
936 ECB : {
937 GIC 129757 : switch (obtype)
938 ECB : {
939 GIC 2074 : case OBJECT_DATABASE:
940 : case OBJECT_TABLESPACE:
941 : case OBJECT_ROLE:
942 : case OBJECT_PARAMETER_ACL:
943 ECB : /* no support for global objects */
944 CBC 2074 : return false;
945 GIC 62 : case OBJECT_EVENT_TRIGGER:
946 ECB : /* no support for event triggers on event triggers */
947 CBC 62 : return false;
948 GIC 127621 : case OBJECT_ACCESS_METHOD:
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:
960 : case OBJECT_DOMCONSTRAINT:
961 : case OBJECT_EXTENSION:
962 : case OBJECT_FDW:
963 : case OBJECT_FOREIGN_SERVER:
964 : case OBJECT_FOREIGN_TABLE:
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:
976 : case OBJECT_PUBLICATION_NAMESPACE:
977 : case OBJECT_PUBLICATION_REL:
978 : case OBJECT_ROUTINE:
979 : case OBJECT_RULE:
980 : case OBJECT_SCHEMA:
981 : case OBJECT_SEQUENCE:
982 : case OBJECT_SUBSCRIPTION:
983 : case OBJECT_STATISTIC_EXT:
984 : case OBJECT_TABCONSTRAINT:
985 : case OBJECT_TABLE:
986 : case OBJECT_TRANSFORM:
987 : case OBJECT_TRIGGER:
988 : case OBJECT_TSCONFIGURATION:
989 : case OBJECT_TSDICTIONARY:
990 : case OBJECT_TSPARSER:
991 : case OBJECT_TSTEMPLATE:
992 : case OBJECT_TYPE:
993 : case OBJECT_USER_MAPPING:
994 ECB : case OBJECT_VIEW:
995 GIC 127621 : 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 EUB : /* Shouldn't get here, but if we do, say "no support" */
1004 UIC 0 : return false;
1005 : }
1006 :
1007 : /*
1008 : * Do event triggers support this object class?
1009 : */
1010 ECB : bool
1011 GIC 2456 : EventTriggerSupportsObjectClass(ObjectClass objclass)
1012 ECB : {
1013 GIC 2456 : switch (objclass)
1014 EUB : {
1015 UIC 0 : case OCLASS_DATABASE:
1016 : case OCLASS_TBLSPACE:
1017 : case OCLASS_ROLE:
1018 : case OCLASS_ROLE_MEMBERSHIP:
1019 : case OCLASS_PARAMETER_ACL:
1020 : /* no support for global objects */
1021 UBC 0 : return false;
1022 CBC 44 : case OCLASS_EVENT_TRIGGER:
1023 : /* no support for event triggers on event triggers */
1024 44 : return false;
1025 2412 : case OCLASS_CLASS:
1026 : case OCLASS_PROC:
1027 : case OCLASS_TYPE:
1028 : case OCLASS_CAST:
1029 : case OCLASS_COLLATION:
1030 : case OCLASS_CONSTRAINT:
1031 : case OCLASS_CONVERSION:
1032 : case OCLASS_DEFAULT:
1033 : case OCLASS_LANGUAGE:
1034 : case OCLASS_LARGEOBJECT:
1035 : case OCLASS_OPERATOR:
1036 : case OCLASS_OPCLASS:
1037 : case OCLASS_OPFAMILY:
1038 : case OCLASS_AM:
1039 : case OCLASS_AMOP:
1040 : case OCLASS_AMPROC:
1041 : case OCLASS_REWRITE:
1042 : case OCLASS_TRIGGER:
1043 : case OCLASS_SCHEMA:
1044 : case OCLASS_STATISTIC_EXT:
1045 : case OCLASS_TSPARSER:
1046 : case OCLASS_TSDICT:
1047 : case OCLASS_TSTEMPLATE:
1048 : case OCLASS_TSCONFIG:
1049 : case OCLASS_FDW:
1050 : case OCLASS_FOREIGN_SERVER:
1051 : case OCLASS_USER_MAPPING:
1052 : case OCLASS_DEFACL:
1053 : case OCLASS_EXTENSION:
1054 : case OCLASS_POLICY:
1055 : case OCLASS_PUBLICATION:
1056 : case OCLASS_PUBLICATION_NAMESPACE:
1057 : case OCLASS_PUBLICATION_REL:
1058 : case OCLASS_SUBSCRIPTION:
1059 : case OCLASS_TRANSFORM:
1060 2412 : return true;
1061 :
1062 : /*
1063 : * There's intentionally no default: case here; we want the
1064 : * compiler to warn if a new OCLASS hasn't been handled above.
1065 : */
1066 : }
1067 :
1068 : /* Shouldn't get here, but if we do, say "no support" */
1069 UBC 0 : return false;
1070 : }
1071 :
1072 : /*
1073 : * Prepare event trigger state for a new complete query to run, if necessary;
1074 : * returns whether this was done. If it was, EventTriggerEndCompleteQuery must
1075 : * be called when the query is done, regardless of whether it succeeds or fails
1076 : * -- so use of a PG_TRY block is mandatory.
1077 : */
1078 : bool
1079 CBC 276916 : EventTriggerBeginCompleteQuery(void)
1080 : {
1081 : EventTriggerQueryState *state;
1082 : MemoryContext cxt;
1083 :
1084 : /*
1085 : * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
1086 : * reason to have event trigger state at all; so if there are none, don't
1087 : * install one.
1088 : */
1089 276916 : if (!trackDroppedObjectsNeeded())
1090 276136 : return false;
1091 :
1092 780 : cxt = AllocSetContextCreate(TopMemoryContext,
1093 : "event trigger state",
1094 : ALLOCSET_DEFAULT_SIZES);
1095 780 : state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState));
1096 780 : state->cxt = cxt;
1097 780 : slist_init(&(state->SQLDropList));
1098 780 : state->in_sql_drop = false;
1099 780 : state->table_rewrite_oid = InvalidOid;
1100 :
1101 780 : state->commandCollectionInhibited = currentEventTriggerState ?
1102 780 : currentEventTriggerState->commandCollectionInhibited : false;
1103 780 : state->currentCommand = NULL;
1104 780 : state->commandList = NIL;
1105 780 : state->previous = currentEventTriggerState;
1106 780 : currentEventTriggerState = state;
1107 :
1108 780 : return true;
1109 : }
1110 :
1111 : /*
1112 : * Query completed (or errored out) -- clean up local state, return to previous
1113 : * one.
1114 : *
1115 : * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
1116 : * returned false previously.
1117 : *
1118 : * Note: this might be called in the PG_CATCH block of a failing transaction,
1119 : * so be wary of running anything unnecessary. (In particular, it's probably
1120 : * unwise to try to allocate memory.)
1121 : */
1122 : void
1123 780 : EventTriggerEndCompleteQuery(void)
1124 : {
1125 : EventTriggerQueryState *prevstate;
1126 :
1127 780 : prevstate = currentEventTriggerState->previous;
1128 :
1129 : /* this avoids the need for retail pfree of SQLDropList items: */
1130 780 : MemoryContextDelete(currentEventTriggerState->cxt);
1131 :
1132 780 : currentEventTriggerState = prevstate;
1133 780 : }
1134 :
1135 : /*
1136 : * Do we need to keep close track of objects being dropped?
1137 : *
1138 : * This is useful because there is a cost to running with them enabled.
1139 : */
1140 : bool
1141 290528 : trackDroppedObjectsNeeded(void)
1142 : {
1143 : /*
1144 : * true if any sql_drop, table_rewrite, ddl_command_end event trigger
1145 : * exists
1146 : */
1147 GNC 580844 : return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
1148 580844 : (EventCacheLookup(EVT_TableRewrite) != NIL) ||
1149 289649 : (EventCacheLookup(EVT_DDLCommandEnd) != NIL);
1150 : }
1151 :
1152 : /*
1153 : * Support for dropped objects information on event trigger functions.
1154 : *
1155 : * We keep the list of objects dropped by the current command in current
1156 : * state's SQLDropList (comprising SQLDropObject items). Each time a new
1157 : * command is to start, a clean EventTriggerQueryState is created; commands
1158 : * that drop objects do the dependency.c dance to drop objects, which
1159 : * populates the current state's SQLDropList; when the event triggers are
1160 : * invoked they can consume the list via pg_event_trigger_dropped_objects().
1161 : * When the command finishes, the EventTriggerQueryState is cleared, and
1162 : * the one from the previous command is restored (when no command is in
1163 : * execution, the current state is NULL).
1164 : *
1165 : * All this lets us support the case that an event trigger function drops
1166 : * objects "reentrantly".
1167 : */
1168 :
1169 : /*
1170 : * Register one object as being dropped by the current command.
1171 : */
1172 : void
1173 CBC 1275 : EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1174 : {
1175 : SQLDropObject *obj;
1176 : MemoryContext oldcxt;
1177 :
1178 1275 : if (!currentEventTriggerState)
1179 69 : return;
1180 :
1181 1206 : Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
1182 :
1183 : /* don't report temp schemas except my own */
1184 1230 : if (object->classId == NamespaceRelationId &&
1185 24 : (isAnyTempNamespace(object->objectId) &&
1186 UBC 0 : !isTempNamespace(object->objectId)))
1187 0 : return;
1188 :
1189 CBC 1206 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1190 :
1191 1206 : obj = palloc0(sizeof(SQLDropObject));
1192 1206 : obj->address = *object;
1193 1206 : obj->original = original;
1194 1206 : obj->normal = normal;
1195 :
1196 : /*
1197 : * Obtain schema names from the object's catalog tuple, if one exists;
1198 : * this lets us skip objects in temp schemas. We trust that
1199 : * ObjectProperty contains all object classes that can be
1200 : * schema-qualified.
1201 : */
1202 1206 : if (is_objectclass_supported(object->classId))
1203 : {
1204 : Relation catalog;
1205 : HeapTuple tuple;
1206 :
1207 1034 : catalog = table_open(obj->address.classId, AccessShareLock);
1208 1034 : tuple = get_catalog_object_by_oid(catalog,
1209 1034 : get_object_attnum_oid(object->classId),
1210 : obj->address.objectId);
1211 :
1212 1034 : if (tuple)
1213 : {
1214 : AttrNumber attnum;
1215 : Datum datum;
1216 : bool isnull;
1217 :
1218 1034 : attnum = get_object_attnum_namespace(obj->address.classId);
1219 1034 : if (attnum != InvalidAttrNumber)
1220 : {
1221 940 : datum = heap_getattr(tuple, attnum,
1222 : RelationGetDescr(catalog), &isnull);
1223 940 : if (!isnull)
1224 : {
1225 : Oid namespaceId;
1226 :
1227 940 : namespaceId = DatumGetObjectId(datum);
1228 : /* temp objects are only reported if they are my own */
1229 940 : if (isTempNamespace(namespaceId))
1230 : {
1231 9 : obj->schemaname = "pg_temp";
1232 9 : obj->istemp = true;
1233 : }
1234 931 : else if (isAnyTempNamespace(namespaceId))
1235 : {
1236 UBC 0 : pfree(obj);
1237 0 : table_close(catalog, AccessShareLock);
1238 0 : MemoryContextSwitchTo(oldcxt);
1239 0 : return;
1240 : }
1241 : else
1242 : {
1243 CBC 931 : obj->schemaname = get_namespace_name(namespaceId);
1244 931 : obj->istemp = false;
1245 : }
1246 : }
1247 : }
1248 :
1249 1034 : if (get_object_namensp_unique(obj->address.classId) &&
1250 769 : obj->address.objectSubId == 0)
1251 : {
1252 757 : attnum = get_object_attnum_name(obj->address.classId);
1253 757 : if (attnum != InvalidAttrNumber)
1254 : {
1255 757 : datum = heap_getattr(tuple, attnum,
1256 : RelationGetDescr(catalog), &isnull);
1257 757 : if (!isnull)
1258 757 : obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
1259 : }
1260 : }
1261 : }
1262 :
1263 1034 : table_close(catalog, AccessShareLock);
1264 : }
1265 : else
1266 : {
1267 172 : if (object->classId == NamespaceRelationId &&
1268 UBC 0 : isTempNamespace(object->objectId))
1269 0 : obj->istemp = true;
1270 : }
1271 :
1272 : /* object identity, objname and objargs */
1273 CBC 1206 : obj->objidentity =
1274 1206 : getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
1275 : false);
1276 :
1277 : /* object type */
1278 1206 : obj->objecttype = getObjectTypeDescription(&obj->address, false);
1279 :
1280 1206 : slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
1281 :
1282 1206 : MemoryContextSwitchTo(oldcxt);
1283 : }
1284 :
1285 : /*
1286 : * pg_event_trigger_dropped_objects
1287 : *
1288 : * Make the list of dropped objects available to the user function run by the
1289 : * Event Trigger.
1290 : */
1291 : Datum
1292 57 : pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
1293 : {
1294 57 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1295 : slist_iter iter;
1296 :
1297 : /*
1298 : * Protect this function from being called out of context
1299 : */
1300 57 : if (!currentEventTriggerState ||
1301 57 : !currentEventTriggerState->in_sql_drop)
1302 UBC 0 : ereport(ERROR,
1303 : (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1304 : errmsg("%s can only be called in a sql_drop event trigger function",
1305 : "pg_event_trigger_dropped_objects()")));
1306 :
1307 : /* Build tuplestore to hold the result rows */
1308 CBC 57 : InitMaterializedSRF(fcinfo, 0);
1309 :
1310 594 : slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
1311 : {
1312 : SQLDropObject *obj;
1313 537 : int i = 0;
1314 GNC 537 : Datum values[12] = {0};
1315 537 : bool nulls[12] = {0};
1316 :
1317 CBC 537 : obj = slist_container(SQLDropObject, next, iter.cur);
1318 :
1319 : /* classid */
1320 537 : values[i++] = ObjectIdGetDatum(obj->address.classId);
1321 :
1322 : /* objid */
1323 537 : values[i++] = ObjectIdGetDatum(obj->address.objectId);
1324 :
1325 : /* objsubid */
1326 537 : values[i++] = Int32GetDatum(obj->address.objectSubId);
1327 :
1328 : /* original */
1329 537 : values[i++] = BoolGetDatum(obj->original);
1330 :
1331 : /* normal */
1332 537 : values[i++] = BoolGetDatum(obj->normal);
1333 :
1334 : /* is_temporary */
1335 537 : values[i++] = BoolGetDatum(obj->istemp);
1336 :
1337 : /* object_type */
1338 537 : values[i++] = CStringGetTextDatum(obj->objecttype);
1339 ECB :
1340 : /* schema_name */
1341 CBC 537 : if (obj->schemaname)
1342 GIC 477 : values[i++] = CStringGetTextDatum(obj->schemaname);
1343 : else
1344 CBC 60 : nulls[i++] = true;
1345 ECB :
1346 : /* object_name */
1347 CBC 537 : if (obj->objname)
1348 GIC 438 : values[i++] = CStringGetTextDatum(obj->objname);
1349 : else
1350 CBC 99 : nulls[i++] = true;
1351 ECB :
1352 : /* object_identity */
1353 GBC 537 : if (obj->objidentity)
1354 GIC 537 : values[i++] = CStringGetTextDatum(obj->objidentity);
1355 : else
1356 LBC 0 : nulls[i++] = true;
1357 :
1358 ECB : /* address_names and address_args */
1359 GIC 537 : if (obj->addrnames)
1360 ECB : {
1361 CBC 537 : values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrnames));
1362 :
1363 537 : if (obj->addrargs)
1364 GIC 30 : values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrargs));
1365 : else
1366 507 : values[i++] = PointerGetDatum(construct_empty_array(TEXTOID));
1367 EUB : }
1368 : else
1369 : {
1370 UIC 0 : nulls[i++] = true;
1371 LBC 0 : nulls[i++] = true;
1372 : }
1373 :
1374 GIC 537 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1375 ECB : values, nulls);
1376 : }
1377 :
1378 GIC 57 : return (Datum) 0;
1379 : }
1380 :
1381 : /*
1382 : * pg_event_trigger_table_rewrite_oid
1383 : *
1384 : * Make the Oid of the table going to be rewritten available to the user
1385 ECB : * function run by the Event Trigger.
1386 : */
1387 : Datum
1388 GIC 33 : pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
1389 : {
1390 ECB : /*
1391 : * Protect this function from being called out of context
1392 : */
1393 GIC 33 : if (!currentEventTriggerState ||
1394 30 : currentEventTriggerState->table_rewrite_oid == InvalidOid)
1395 3 : ereport(ERROR,
1396 : (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1397 ECB : errmsg("%s can only be called in a table_rewrite event trigger function",
1398 : "pg_event_trigger_table_rewrite_oid()")));
1399 :
1400 GIC 30 : PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
1401 : }
1402 :
1403 : /*
1404 : * pg_event_trigger_table_rewrite_reason
1405 : *
1406 ECB : * Make the rewrite reason available to the user.
1407 : */
1408 : Datum
1409 GIC 24 : pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
1410 : {
1411 ECB : /*
1412 : * Protect this function from being called out of context
1413 EUB : */
1414 GIC 24 : if (!currentEventTriggerState ||
1415 24 : currentEventTriggerState->table_rewrite_reason == 0)
1416 UIC 0 : ereport(ERROR,
1417 : (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1418 ECB : errmsg("%s can only be called in a table_rewrite event trigger function",
1419 : "pg_event_trigger_table_rewrite_reason()")));
1420 :
1421 GIC 24 : PG_RETURN_INT32(currentEventTriggerState->table_rewrite_reason);
1422 : }
1423 :
1424 : /*-------------------------------------------------------------------------
1425 : * Support for DDL command deparsing
1426 : *
1427 : * The routines below enable an event trigger function to obtain a list of
1428 : * DDL commands as they are executed. There are three main pieces to this
1429 : * feature:
1430 : *
1431 : * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
1432 : * adds a struct CollectedCommand representation of itself to the command list,
1433 : * using the routines below.
1434 : *
1435 : * 2) Some time after that, ddl_command_end fires and the command list is made
1436 : * available to the event trigger function via pg_event_trigger_ddl_commands();
1437 : * the complete command details are exposed as a column of type pg_ddl_command.
1438 : *
1439 : * 3) An extension can install a function capable of taking a value of type
1440 : * pg_ddl_command and transform it into some external, user-visible and/or
1441 : * -modifiable representation.
1442 : *-------------------------------------------------------------------------
1443 : */
1444 :
1445 : /*
1446 ECB : * Inhibit DDL command collection.
1447 : */
1448 : void
1449 CBC 123 : EventTriggerInhibitCommandCollection(void)
1450 : {
1451 123 : if (!currentEventTriggerState)
1452 GIC 122 : return;
1453 :
1454 1 : currentEventTriggerState->commandCollectionInhibited = true;
1455 : }
1456 :
1457 : /*
1458 ECB : * Re-establish DDL command collection.
1459 : */
1460 : void
1461 CBC 123 : EventTriggerUndoInhibitCommandCollection(void)
1462 : {
1463 123 : if (!currentEventTriggerState)
1464 GIC 122 : return;
1465 :
1466 1 : currentEventTriggerState->commandCollectionInhibited = false;
1467 : }
1468 :
1469 : /*
1470 : * EventTriggerCollectSimpleCommand
1471 : * Save data about a simple DDL command that was just executed
1472 : *
1473 : * address identifies the object being operated on. secondaryObject is an
1474 : * object address that was related in some way to the executed command; its
1475 : * meaning is command-specific.
1476 : *
1477 : * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
1478 : * object being moved, objectId is its OID, and secondaryOid is the OID of the
1479 : * old schema. (The destination schema OID can be obtained by catalog lookup
1480 ECB : * of the object.)
1481 : */
1482 : void
1483 GIC 151428 : EventTriggerCollectSimpleCommand(ObjectAddress address,
1484 : ObjectAddress secondaryObject,
1485 : Node *parsetree)
1486 : {
1487 : MemoryContext oldcxt;
1488 ECB : CollectedCommand *command;
1489 :
1490 : /* ignore if event trigger context not set, or collection disabled */
1491 GIC 151428 : if (!currentEventTriggerState ||
1492 CBC 483 : currentEventTriggerState->commandCollectionInhibited)
1493 GIC 150945 : return;
1494 ECB :
1495 GIC 483 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1496 ECB :
1497 CBC 483 : command = palloc(sizeof(CollectedCommand));
1498 :
1499 483 : command->type = SCT_Simple;
1500 483 : command->in_extension = creating_extension;
1501 ECB :
1502 GIC 483 : command->d.simple.address = address;
1503 CBC 483 : command->d.simple.secondaryObject = secondaryObject;
1504 GIC 483 : command->parsetree = copyObject(parsetree);
1505 :
1506 CBC 483 : currentEventTriggerState->commandList = lappend(currentEventTriggerState->commandList,
1507 : command);
1508 :
1509 GIC 483 : MemoryContextSwitchTo(oldcxt);
1510 : }
1511 :
1512 : /*
1513 : * EventTriggerAlterTableStart
1514 : * Prepare to receive data on an ALTER TABLE command about to be executed
1515 : *
1516 : * Note we don't collect the command immediately; instead we keep it in
1517 : * currentCommand, and only when we're done processing the subcommands we will
1518 ECB : * add it to the command list.
1519 : */
1520 : void
1521 GIC 94996 : EventTriggerAlterTableStart(Node *parsetree)
1522 : {
1523 : MemoryContext oldcxt;
1524 ECB : CollectedCommand *command;
1525 :
1526 : /* ignore if event trigger context not set, or collection disabled */
1527 GIC 94996 : if (!currentEventTriggerState ||
1528 CBC 419 : currentEventTriggerState->commandCollectionInhibited)
1529 GIC 94577 : return;
1530 ECB :
1531 GIC 419 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1532 ECB :
1533 CBC 419 : command = palloc(sizeof(CollectedCommand));
1534 :
1535 419 : command->type = SCT_AlterTable;
1536 419 : command->in_extension = creating_extension;
1537 ECB :
1538 CBC 419 : command->d.alterTable.classId = RelationRelationId;
1539 GIC 419 : command->d.alterTable.objectId = InvalidOid;
1540 CBC 419 : command->d.alterTable.subcmds = NIL;
1541 419 : command->parsetree = copyObject(parsetree);
1542 :
1543 419 : command->parent = currentEventTriggerState->currentCommand;
1544 GIC 419 : currentEventTriggerState->currentCommand = command;
1545 :
1546 419 : MemoryContextSwitchTo(oldcxt);
1547 : }
1548 :
1549 : /*
1550 : * Remember the OID of the object being affected by an ALTER TABLE.
1551 : *
1552 ECB : * This is needed because in some cases we don't know the OID until later.
1553 : */
1554 : void
1555 CBC 45170 : EventTriggerAlterTableRelid(Oid objectId)
1556 ECB : {
1557 GIC 45170 : if (!currentEventTriggerState ||
1558 CBC 337 : currentEventTriggerState->commandCollectionInhibited)
1559 GIC 44833 : return;
1560 :
1561 337 : currentEventTriggerState->currentCommand->d.alterTable.objectId = objectId;
1562 : }
1563 :
1564 : /*
1565 : * EventTriggerCollectAlterTableSubcmd
1566 : * Save data about a single part of an ALTER TABLE.
1567 : *
1568 : * Several different commands go through this path, but apart from ALTER TABLE
1569 : * itself, they are all concerned with AlterTableCmd nodes that are generated
1570 ECB : * internally, so that's all that this code needs to handle at the moment.
1571 : */
1572 : void
1573 GIC 70431 : EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
1574 : {
1575 : MemoryContext oldcxt;
1576 ECB : CollectedATSubcmd *newsub;
1577 :
1578 : /* ignore if event trigger context not set, or collection disabled */
1579 GIC 70431 : if (!currentEventTriggerState ||
1580 CBC 507 : currentEventTriggerState->commandCollectionInhibited)
1581 69924 : return;
1582 ECB :
1583 GIC 507 : Assert(IsA(subcmd, AlterTableCmd));
1584 CBC 507 : Assert(currentEventTriggerState->currentCommand != NULL);
1585 GIC 507 : Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
1586 ECB :
1587 CBC 507 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1588 ECB :
1589 GIC 507 : newsub = palloc(sizeof(CollectedATSubcmd));
1590 CBC 507 : newsub->address = address;
1591 507 : newsub->parsetree = copyObject(subcmd);
1592 :
1593 1014 : currentEventTriggerState->currentCommand->d.alterTable.subcmds =
1594 GIC 507 : lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub);
1595 :
1596 507 : MemoryContextSwitchTo(oldcxt);
1597 : }
1598 :
1599 : /*
1600 : * EventTriggerAlterTableEnd
1601 : * Finish up saving an ALTER TABLE command, and add it to command list.
1602 : *
1603 : * FIXME this API isn't considering the possibility that an xact/subxact is
1604 : * aborted partway through. Probably it's best to add an
1605 ECB : * AtEOSubXact_EventTriggers() to fix this.
1606 : */
1607 : void
1608 GIC 93452 : EventTriggerAlterTableEnd(void)
1609 : {
1610 ECB : CollectedCommand *parent;
1611 :
1612 : /* ignore if event trigger context not set, or collection disabled */
1613 GIC 93452 : if (!currentEventTriggerState ||
1614 CBC 413 : currentEventTriggerState->commandCollectionInhibited)
1615 GIC 93039 : return;
1616 :
1617 CBC 413 : parent = currentEventTriggerState->currentCommand->parent;
1618 :
1619 : /* If no subcommands, don't collect */
1620 GNC 413 : if (currentEventTriggerState->currentCommand->d.alterTable.subcmds != NIL)
1621 ECB : {
1622 : MemoryContext oldcxt;
1623 :
1624 CBC 320 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1625 ECB :
1626 GIC 640 : currentEventTriggerState->commandList =
1627 CBC 320 : lappend(currentEventTriggerState->commandList,
1628 GIC 320 : currentEventTriggerState->currentCommand);
1629 :
1630 CBC 320 : MemoryContextSwitchTo(oldcxt);
1631 : }
1632 ECB : else
1633 GIC 93 : pfree(currentEventTriggerState->currentCommand);
1634 :
1635 413 : currentEventTriggerState->currentCommand = parent;
1636 : }
1637 :
1638 : /*
1639 : * EventTriggerCollectGrant
1640 : * Save data about a GRANT/REVOKE command being executed
1641 : *
1642 : * This function creates a copy of the InternalGrant, as the original might
1643 ECB : * not have the right lifetime.
1644 : */
1645 : void
1646 GIC 48143 : EventTriggerCollectGrant(InternalGrant *istmt)
1647 : {
1648 : MemoryContext oldcxt;
1649 : CollectedCommand *command;
1650 : InternalGrant *icopy;
1651 ECB : ListCell *cell;
1652 :
1653 : /* ignore if event trigger context not set, or collection disabled */
1654 GIC 48143 : if (!currentEventTriggerState ||
1655 CBC 15 : currentEventTriggerState->commandCollectionInhibited)
1656 GIC 48128 : return;
1657 :
1658 15 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1659 :
1660 ECB : /*
1661 : * This is tedious, but necessary.
1662 : */
1663 CBC 15 : icopy = palloc(sizeof(InternalGrant));
1664 15 : memcpy(icopy, istmt, sizeof(InternalGrant));
1665 15 : icopy->objects = list_copy(istmt->objects);
1666 GBC 15 : icopy->grantees = list_copy(istmt->grantees);
1667 GIC 15 : icopy->col_privs = NIL;
1668 15 : foreach(cell, istmt->col_privs)
1669 LBC 0 : icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
1670 ECB :
1671 : /* Now collect it, using the copied InternalGrant */
1672 CBC 15 : command = palloc(sizeof(CollectedCommand));
1673 15 : command->type = SCT_Grant;
1674 GIC 15 : command->in_extension = creating_extension;
1675 CBC 15 : command->d.grant.istmt = icopy;
1676 15 : command->parsetree = NULL;
1677 :
1678 30 : currentEventTriggerState->commandList =
1679 GIC 15 : lappend(currentEventTriggerState->commandList, command);
1680 :
1681 15 : MemoryContextSwitchTo(oldcxt);
1682 : }
1683 :
1684 : /*
1685 : * EventTriggerCollectAlterOpFam
1686 : * Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
1687 ECB : * executed
1688 : */
1689 : void
1690 GIC 145 : EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
1691 : List *operators, List *procedures)
1692 : {
1693 : MemoryContext oldcxt;
1694 ECB : CollectedCommand *command;
1695 :
1696 : /* ignore if event trigger context not set, or collection disabled */
1697 GIC 145 : if (!currentEventTriggerState ||
1698 CBC 1 : currentEventTriggerState->commandCollectionInhibited)
1699 GIC 144 : return;
1700 ECB :
1701 CBC 1 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1702 ECB :
1703 CBC 1 : command = palloc(sizeof(CollectedCommand));
1704 GIC 1 : command->type = SCT_AlterOpFamily;
1705 CBC 1 : command->in_extension = creating_extension;
1706 1 : ObjectAddressSet(command->d.opfam.address,
1707 ECB : OperatorFamilyRelationId, opfamoid);
1708 GIC 1 : command->d.opfam.operators = operators;
1709 CBC 1 : command->d.opfam.procedures = procedures;
1710 1 : command->parsetree = (Node *) copyObject(stmt);
1711 :
1712 2 : currentEventTriggerState->commandList =
1713 GIC 1 : lappend(currentEventTriggerState->commandList, command);
1714 :
1715 1 : MemoryContextSwitchTo(oldcxt);
1716 : }
1717 :
1718 : /*
1719 : * EventTriggerCollectCreateOpClass
1720 ECB : * Save data about a CREATE OPERATOR CLASS command being executed
1721 : */
1722 : void
1723 GIC 183 : EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
1724 : List *operators, List *procedures)
1725 : {
1726 : MemoryContext oldcxt;
1727 ECB : CollectedCommand *command;
1728 :
1729 : /* ignore if event trigger context not set, or collection disabled */
1730 GIC 183 : if (!currentEventTriggerState ||
1731 CBC 4 : currentEventTriggerState->commandCollectionInhibited)
1732 GIC 179 : return;
1733 ECB :
1734 CBC 4 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1735 ECB :
1736 CBC 4 : command = palloc0(sizeof(CollectedCommand));
1737 GIC 4 : command->type = SCT_CreateOpClass;
1738 CBC 4 : command->in_extension = creating_extension;
1739 4 : ObjectAddressSet(command->d.createopc.address,
1740 ECB : OperatorClassRelationId, opcoid);
1741 GIC 4 : command->d.createopc.operators = operators;
1742 CBC 4 : command->d.createopc.procedures = procedures;
1743 4 : command->parsetree = (Node *) copyObject(stmt);
1744 :
1745 8 : currentEventTriggerState->commandList =
1746 GIC 4 : lappend(currentEventTriggerState->commandList, command);
1747 :
1748 4 : MemoryContextSwitchTo(oldcxt);
1749 : }
1750 :
1751 : /*
1752 : * EventTriggerCollectAlterTSConfig
1753 : * Save data about an ALTER TEXT SEARCH CONFIGURATION command being
1754 ECB : * executed
1755 : */
1756 : void
1757 GIC 25548 : EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
1758 : Oid *dictIds, int ndicts)
1759 : {
1760 : MemoryContext oldcxt;
1761 ECB : CollectedCommand *command;
1762 :
1763 : /* ignore if event trigger context not set, or collection disabled */
1764 GIC 25548 : if (!currentEventTriggerState ||
1765 CBC 1 : currentEventTriggerState->commandCollectionInhibited)
1766 GIC 25547 : return;
1767 ECB :
1768 CBC 1 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1769 ECB :
1770 CBC 1 : command = palloc0(sizeof(CollectedCommand));
1771 GIC 1 : command->type = SCT_AlterTSConfig;
1772 CBC 1 : command->in_extension = creating_extension;
1773 1 : ObjectAddressSet(command->d.atscfg.address,
1774 ECB : TSConfigRelationId, cfgId);
1775 CBC 1 : command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
1776 GIC 1 : memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
1777 CBC 1 : command->d.atscfg.ndicts = ndicts;
1778 1 : command->parsetree = (Node *) copyObject(stmt);
1779 :
1780 2 : currentEventTriggerState->commandList =
1781 GIC 1 : lappend(currentEventTriggerState->commandList, command);
1782 :
1783 1 : MemoryContextSwitchTo(oldcxt);
1784 : }
1785 :
1786 : /*
1787 : * EventTriggerCollectAlterDefPrivs
1788 : * Save data about an ALTER DEFAULT PRIVILEGES command being
1789 ECB : * executed
1790 : */
1791 : void
1792 GIC 77 : EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
1793 : {
1794 : MemoryContext oldcxt;
1795 ECB : CollectedCommand *command;
1796 :
1797 : /* ignore if event trigger context not set, or collection disabled */
1798 GIC 77 : if (!currentEventTriggerState ||
1799 CBC 4 : currentEventTriggerState->commandCollectionInhibited)
1800 GIC 73 : return;
1801 ECB :
1802 CBC 4 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1803 ECB :
1804 CBC 4 : command = palloc0(sizeof(CollectedCommand));
1805 4 : command->type = SCT_AlterDefaultPrivileges;
1806 GIC 4 : command->d.defprivs.objtype = stmt->action->objtype;
1807 CBC 4 : command->in_extension = creating_extension;
1808 4 : command->parsetree = (Node *) copyObject(stmt);
1809 ECB :
1810 GIC 8 : currentEventTriggerState->commandList =
1811 4 : lappend(currentEventTriggerState->commandList, command);
1812 4 : MemoryContextSwitchTo(oldcxt);
1813 : }
1814 :
1815 : /*
1816 : * In a ddl_command_end event trigger, this function reports the DDL commands
1817 ECB : * being run.
1818 : */
1819 : Datum
1820 GIC 208 : pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
1821 : {
1822 208 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1823 : ListCell *lc;
1824 :
1825 ECB : /*
1826 EUB : * Protect this function from being called out of context
1827 : */
1828 GIC 208 : if (!currentEventTriggerState)
1829 UIC 0 : ereport(ERROR,
1830 : (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
1831 : errmsg("%s can only be called in an event trigger function",
1832 ECB : "pg_event_trigger_ddl_commands()")));
1833 :
1834 : /* Build tuplestore to hold the result rows */
1835 GIC 208 : InitMaterializedSRF(fcinfo, 0);
1836 ECB :
1837 GIC 487 : foreach(lc, currentEventTriggerState->commandList)
1838 ECB : {
1839 GIC 279 : CollectedCommand *cmd = lfirst(lc);
1840 ECB : Datum values[9];
1841 GNC 279 : bool nulls[9] = {0};
1842 : ObjectAddress addr;
1843 GIC 279 : int i = 0;
1844 :
1845 : /*
1846 : * For IF NOT EXISTS commands that attempt to create an existing
1847 : * object, the returned OID is Invalid. Don't return anything.
1848 : *
1849 : * One might think that a viable alternative would be to look up the
1850 : * Oid of the existing object and run the deparse with that. But
1851 : * since the parse tree might be different from the one that created
1852 ECB : * the object in the first place, we might not end up in a consistent
1853 : * state anyway.
1854 : */
1855 GIC 279 : if (cmd->type == SCT_Simple &&
1856 CBC 196 : !OidIsValid(cmd->d.simple.address.objectId))
1857 GIC 3 : continue;
1858 ECB :
1859 GIC 279 : switch (cmd->type)
1860 : {
1861 269 : case SCT_Simple:
1862 : case SCT_AlterTable:
1863 : case SCT_AlterOpFamily:
1864 ECB : case SCT_CreateOpClass:
1865 : case SCT_AlterTSConfig:
1866 : {
1867 : char *identity;
1868 : char *type;
1869 CBC 269 : char *schema = NULL;
1870 :
1871 GIC 269 : if (cmd->type == SCT_Simple)
1872 CBC 196 : addr = cmd->d.simple.address;
1873 73 : else if (cmd->type == SCT_AlterTable)
1874 67 : ObjectAddressSet(addr,
1875 ECB : cmd->d.alterTable.classId,
1876 : cmd->d.alterTable.objectId);
1877 CBC 6 : else if (cmd->type == SCT_AlterOpFamily)
1878 GIC 1 : addr = cmd->d.opfam.address;
1879 5 : else if (cmd->type == SCT_CreateOpClass)
1880 4 : addr = cmd->d.createopc.address;
1881 1 : else if (cmd->type == SCT_AlterTSConfig)
1882 1 : addr = cmd->d.atscfg.address;
1883 :
1884 : /*
1885 : * If an object was dropped in the same command we may end
1886 ECB : * up in a situation where we generated a message but can
1887 : * no longer look for the object information, so skip it
1888 : * rather than failing. This can happen for example with
1889 : * some subcommand combinations of ALTER TABLE.
1890 : */
1891 CBC 269 : identity = getObjectIdentity(&addr, true);
1892 GIC 269 : if (identity == NULL)
1893 3 : continue;
1894 :
1895 : /* The type can never be NULL. */
1896 266 : type = getObjectTypeDescription(&addr, true);
1897 :
1898 : /*
1899 ECB : * Obtain schema name, if any ("pg_temp" if a temp
1900 : * object). If the object class is not in the supported
1901 : * list here, we assume it's a schema-less object type,
1902 : * and thus "schema" remains set to NULL.
1903 : */
1904 CBC 266 : if (is_objectclass_supported(addr.classId))
1905 : {
1906 : AttrNumber nspAttnum;
1907 :
1908 GIC 266 : nspAttnum = get_object_attnum_namespace(addr.classId);
1909 266 : if (nspAttnum != InvalidAttrNumber)
1910 : {
1911 ECB : Relation catalog;
1912 : HeapTuple objtup;
1913 : Oid schema_oid;
1914 : bool isnull;
1915 :
1916 GBC 238 : catalog = table_open(addr.classId, AccessShareLock);
1917 GIC 238 : objtup = get_catalog_object_by_oid(catalog,
1918 CBC 238 : get_object_attnum_oid(addr.classId),
1919 ECB : addr.objectId);
1920 GIC 238 : if (!HeapTupleIsValid(objtup))
1921 LBC 0 : elog(ERROR, "cache lookup failed for object %u/%u",
1922 EUB : addr.classId, addr.objectId);
1923 GIC 238 : schema_oid =
1924 238 : heap_getattr(objtup, nspAttnum,
1925 ECB : RelationGetDescr(catalog), &isnull);
1926 GIC 238 : if (isnull)
1927 LBC 0 : elog(ERROR,
1928 : "invalid null namespace in object %u/%u/%d",
1929 : addr.classId, addr.objectId, addr.objectSubId);
1930 GIC 238 : schema = get_namespace_name_or_temp(schema_oid);
1931 :
1932 CBC 238 : table_close(catalog, AccessShareLock);
1933 : }
1934 ECB : }
1935 :
1936 : /* classid */
1937 GIC 266 : values[i++] = ObjectIdGetDatum(addr.classId);
1938 ECB : /* objid */
1939 GIC 266 : values[i++] = ObjectIdGetDatum(addr.objectId);
1940 ECB : /* objsubid */
1941 GIC 266 : values[i++] = Int32GetDatum(addr.objectSubId);
1942 ECB : /* command tag */
1943 CBC 266 : values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
1944 : /* object_type */
1945 266 : values[i++] = CStringGetTextDatum(type);
1946 : /* schema */
1947 266 : if (schema == NULL)
1948 GIC 28 : nulls[i++] = true;
1949 ECB : else
1950 GIC 238 : values[i++] = CStringGetTextDatum(schema);
1951 ECB : /* identity */
1952 GIC 266 : values[i++] = CStringGetTextDatum(identity);
1953 ECB : /* in_extension */
1954 GIC 266 : values[i++] = BoolGetDatum(cmd->in_extension);
1955 ECB : /* command */
1956 GIC 266 : values[i++] = PointerGetDatum(cmd);
1957 ECB : }
1958 GIC 266 : break;
1959 ECB :
1960 GIC 1 : case SCT_AlterDefaultPrivileges:
1961 ECB : /* classid */
1962 GIC 1 : nulls[i++] = true;
1963 ECB : /* objid */
1964 GIC 1 : nulls[i++] = true;
1965 ECB : /* objsubid */
1966 GIC 1 : nulls[i++] = true;
1967 ECB : /* command tag */
1968 GIC 1 : values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
1969 ECB : /* object_type */
1970 GIC 1 : values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
1971 ECB : /* schema */
1972 GIC 1 : nulls[i++] = true;
1973 ECB : /* identity */
1974 CBC 1 : nulls[i++] = true;
1975 : /* in_extension */
1976 1 : values[i++] = BoolGetDatum(cmd->in_extension);
1977 : /* command */
1978 1 : values[i++] = PointerGetDatum(cmd);
1979 GIC 1 : break;
1980 ECB :
1981 GIC 9 : case SCT_Grant:
1982 ECB : /* classid */
1983 GIC 9 : nulls[i++] = true;
1984 ECB : /* objid */
1985 GIC 9 : nulls[i++] = true;
1986 : /* objsubid */
1987 CBC 9 : nulls[i++] = true;
1988 : /* command tag */
1989 9 : values[i++] = CStringGetTextDatum(cmd->d.grant.istmt->is_grant ?
1990 : "GRANT" : "REVOKE");
1991 ECB : /* object_type */
1992 GIC 9 : values[i++] = CStringGetTextDatum(stringify_grant_objtype(cmd->d.grant.istmt->objtype));
1993 ECB : /* schema */
1994 GIC 9 : nulls[i++] = true;
1995 ECB : /* identity */
1996 CBC 9 : nulls[i++] = true;
1997 : /* in_extension */
1998 GIC 9 : values[i++] = BoolGetDatum(cmd->in_extension);
1999 ECB : /* command */
2000 GIC 9 : values[i++] = PointerGetDatum(cmd);
2001 9 : break;
2002 : }
2003 ECB :
2004 GIC 276 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2005 : values, nulls);
2006 : }
2007 :
2008 208 : PG_RETURN_VOID();
2009 : }
2010 :
2011 ECB : /*
2012 : * Return the ObjectType as a string, as it would appear in GRANT and
2013 : * REVOKE commands.
2014 : */
2015 EUB : static const char *
2016 GBC 9 : stringify_grant_objtype(ObjectType objtype)
2017 ECB : {
2018 CBC 9 : switch (objtype)
2019 EUB : {
2020 UBC 0 : case OBJECT_COLUMN:
2021 0 : return "COLUMN";
2022 GBC 5 : case OBJECT_TABLE:
2023 5 : return "TABLE";
2024 UBC 0 : case OBJECT_SEQUENCE:
2025 0 : return "SEQUENCE";
2026 0 : case OBJECT_DATABASE:
2027 0 : return "DATABASE";
2028 0 : case OBJECT_DOMAIN:
2029 LBC 0 : return "DOMAIN";
2030 0 : case OBJECT_FDW:
2031 UBC 0 : return "FOREIGN DATA WRAPPER";
2032 0 : case OBJECT_FOREIGN_SERVER:
2033 0 : return "FOREIGN SERVER";
2034 GBC 4 : case OBJECT_FUNCTION:
2035 4 : return "FUNCTION";
2036 UBC 0 : case OBJECT_LANGUAGE:
2037 0 : return "LANGUAGE";
2038 0 : case OBJECT_LARGEOBJECT:
2039 0 : return "LARGE OBJECT";
2040 0 : case OBJECT_SCHEMA:
2041 0 : return "SCHEMA";
2042 0 : case OBJECT_PARAMETER_ACL:
2043 0 : return "PARAMETER";
2044 0 : case OBJECT_PROCEDURE:
2045 0 : return "PROCEDURE";
2046 0 : case OBJECT_ROUTINE:
2047 UIC 0 : return "ROUTINE";
2048 UBC 0 : case OBJECT_TABLESPACE:
2049 UIC 0 : return "TABLESPACE";
2050 0 : case OBJECT_TYPE:
2051 0 : return "TYPE";
2052 : /* these currently aren't used */
2053 0 : case OBJECT_ACCESS_METHOD:
2054 : case OBJECT_AGGREGATE:
2055 : case OBJECT_AMOP:
2056 : case OBJECT_AMPROC:
2057 : case OBJECT_ATTRIBUTE:
2058 : case OBJECT_CAST:
2059 : case OBJECT_COLLATION:
2060 : case OBJECT_CONVERSION:
2061 : case OBJECT_DEFAULT:
2062 : case OBJECT_DEFACL:
2063 : case OBJECT_DOMCONSTRAINT:
2064 : case OBJECT_EVENT_TRIGGER:
2065 : case OBJECT_EXTENSION:
2066 : case OBJECT_FOREIGN_TABLE:
2067 : case OBJECT_INDEX:
2068 : case OBJECT_MATVIEW:
2069 : case OBJECT_OPCLASS:
2070 : case OBJECT_OPERATOR:
2071 : case OBJECT_OPFAMILY:
2072 : case OBJECT_POLICY:
2073 : case OBJECT_PUBLICATION:
2074 : case OBJECT_PUBLICATION_NAMESPACE:
2075 : case OBJECT_PUBLICATION_REL:
2076 : case OBJECT_ROLE:
2077 : case OBJECT_RULE:
2078 : case OBJECT_STATISTIC_EXT:
2079 : case OBJECT_SUBSCRIPTION:
2080 : case OBJECT_TABCONSTRAINT:
2081 : case OBJECT_TRANSFORM:
2082 : case OBJECT_TRIGGER:
2083 : case OBJECT_TSCONFIGURATION:
2084 EUB : case OBJECT_TSDICTIONARY:
2085 : case OBJECT_TSPARSER:
2086 : case OBJECT_TSTEMPLATE:
2087 : case OBJECT_USER_MAPPING:
2088 : case OBJECT_VIEW:
2089 UIC 0 : elog(ERROR, "unsupported object type: %d", (int) objtype);
2090 : }
2091 :
2092 0 : return "???"; /* keep compiler quiet */
2093 : }
2094 :
2095 : /*
2096 ECB : * Return the ObjectType as a string; as above, but use the spelling
2097 : * in ALTER DEFAULT PRIVILEGES commands instead. Generally this is just
2098 : * the plural.
2099 : */
2100 EUB : static const char *
2101 GBC 1 : stringify_adefprivs_objtype(ObjectType objtype)
2102 ECB : {
2103 CBC 1 : switch (objtype)
2104 EUB : {
2105 UBC 0 : case OBJECT_COLUMN:
2106 0 : return "COLUMNS";
2107 GBC 1 : case OBJECT_TABLE:
2108 1 : return "TABLES";
2109 UBC 0 : case OBJECT_SEQUENCE:
2110 0 : return "SEQUENCES";
2111 0 : case OBJECT_DATABASE:
2112 0 : return "DATABASES";
2113 0 : case OBJECT_DOMAIN:
2114 0 : return "DOMAINS";
2115 0 : case OBJECT_FDW:
2116 0 : return "FOREIGN DATA WRAPPERS";
2117 0 : case OBJECT_FOREIGN_SERVER:
2118 0 : return "FOREIGN SERVERS";
2119 0 : case OBJECT_FUNCTION:
2120 0 : return "FUNCTIONS";
2121 0 : case OBJECT_LANGUAGE:
2122 0 : return "LANGUAGES";
2123 0 : case OBJECT_LARGEOBJECT:
2124 0 : return "LARGE OBJECTS";
2125 0 : case OBJECT_SCHEMA:
2126 0 : return "SCHEMAS";
2127 0 : case OBJECT_PROCEDURE:
2128 0 : return "PROCEDURES";
2129 0 : case OBJECT_ROUTINE:
2130 UIC 0 : return "ROUTINES";
2131 UBC 0 : case OBJECT_TABLESPACE:
2132 UIC 0 : return "TABLESPACES";
2133 0 : case OBJECT_TYPE:
2134 0 : return "TYPES";
2135 : /* these currently aren't used */
2136 0 : case OBJECT_ACCESS_METHOD:
2137 : case OBJECT_AGGREGATE:
2138 : case OBJECT_AMOP:
2139 : case OBJECT_AMPROC:
2140 : case OBJECT_ATTRIBUTE:
2141 : case OBJECT_CAST:
2142 : case OBJECT_COLLATION:
2143 : case OBJECT_CONVERSION:
2144 : case OBJECT_DEFAULT:
2145 : case OBJECT_DEFACL:
2146 : case OBJECT_DOMCONSTRAINT:
2147 : case OBJECT_EVENT_TRIGGER:
2148 : case OBJECT_EXTENSION:
2149 : case OBJECT_FOREIGN_TABLE:
2150 : case OBJECT_INDEX:
2151 : case OBJECT_MATVIEW:
2152 : case OBJECT_OPCLASS:
2153 : case OBJECT_OPERATOR:
2154 : case OBJECT_OPFAMILY:
2155 : case OBJECT_PARAMETER_ACL:
2156 : case OBJECT_POLICY:
2157 : case OBJECT_PUBLICATION:
2158 : case OBJECT_PUBLICATION_NAMESPACE:
2159 : case OBJECT_PUBLICATION_REL:
2160 : case OBJECT_ROLE:
2161 : case OBJECT_RULE:
2162 : case OBJECT_STATISTIC_EXT:
2163 : case OBJECT_SUBSCRIPTION:
2164 : case OBJECT_TABCONSTRAINT:
2165 : case OBJECT_TRANSFORM:
2166 : case OBJECT_TRIGGER:
2167 : case OBJECT_TSCONFIGURATION:
2168 EUB : case OBJECT_TSDICTIONARY:
2169 : case OBJECT_TSPARSER:
2170 : case OBJECT_TSTEMPLATE:
2171 : case OBJECT_USER_MAPPING:
2172 : case OBJECT_VIEW:
2173 UIC 0 : elog(ERROR, "unsupported object type: %d", (int) objtype);
2174 : }
2175 :
2176 0 : return "???"; /* keep compiler quiet */
2177 : }
|