Age Owner 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
3917 rhaas 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. */
3730 130 77 : if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
3665 alvherre 131 37 : strcmp(stmt->eventname, "ddl_command_end") != 0 &&
3044 simon 132 24 : strcmp(stmt->eventname, "sql_drop") != 0 &&
133 11 : strcmp(stmt->eventname, "table_rewrite") != 0)
3917 rhaas 134 3 : ereport(ERROR,
135 : (errcode(ERRCODE_SYNTAX_ERROR),
136 : errmsg("unrecognized event name \"%s\"",
137 : stmt->eventname)));
138 :
139 : /* Validate filter conditions. */
3602 bruce 140 110 : foreach(lc, stmt->whenclause)
141 : {
142 42 : DefElem *def = (DefElem *) lfirst(lc);
143 :
3917 rhaas 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. */
3665 alvherre 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)
3917 rhaas 161 33 : validate_ddl_tags("tag", tags);
3044 simon 162 35 : else if (strcmp(stmt->eventname, "table_rewrite") == 0
163 8 : && tags != NULL)
3044 simon 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 : */
3917 rhaas 170 CBC 50 : tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
171 50 : if (HeapTupleIsValid(tuple))
3917 rhaas 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. */
1244 alvherre 178 CBC 50 : funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
3917 rhaas 179 50 : funcrettype = get_func_rettype(funcoid);
892 tgl 180 50 : if (funcrettype != EVENT_TRIGGEROID)
3917 rhaas 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. */
3753 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
3917 195 33 : validate_ddl_tags(const char *filtervar, List *taglist)
196 : {
197 : ListCell *lc;
198 :
3602 bruce 199 81 : foreach(lc, taglist)
200 : {
1133 alvherre 201 66 : const char *tagstr = strVal(lfirst(lc));
202 66 : CommandTag commandTag = GetCommandTagEnum(tagstr);
203 :
204 66 : if (commandTag == CMDTAG_UNKNOWN)
3915 rhaas 205 6 : ereport(ERROR,
206 : (errcode(ERRCODE_SYNTAX_ERROR),
207 : errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
208 : tagstr, filtervar)));
1133 alvherre 209 60 : if (!command_tag_event_trigger_ok(commandTag))
3917 rhaas 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
3044 simon 222 UBC 0 : validate_table_rewrite_tags(const char *filtervar, List *taglist)
223 : {
224 : ListCell *lc;
225 :
226 0 : foreach(lc, taglist)
227 : {
1133 alvherre 228 0 : const char *tagstr = strVal(lfirst(lc));
229 0 : CommandTag commandTag = GetCommandTagEnum(tagstr);
230 :
231 0 : if (!command_tag_table_rewrite_ok(commandTag))
3044 simon 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
3917 rhaas 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
1986 peter_e 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. */
1539 andres 270 47 : tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
271 :
272 : /* Build the new pg_trigger tuple. */
1601 273 47 : trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId,
274 : Anum_pg_event_trigger_oid);
275 47 : values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
3917 rhaas 276 47 : memset(nulls, false, sizeof(nulls));
3588 noah 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);
3917 rhaas 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);
1601 andres 293 47 : CatalogTupleInsert(tgrel, tuple);
3917 rhaas 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. */
3387 tgl 309 47 : recordDependencyOnCurrentExtension(&myself, false);
310 :
311 : /* Post creation hook for new event trigger */
3686 rhaas 312 47 : InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
313 :
314 : /* Close pg_event_trigger. */
1539 andres 315 47 : table_close(tgrel, RowExclusiveLock);
316 :
3753 rhaas 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
3917 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 :
282 peter 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 : */
3753 rhaas 360 ECB : Oid
3917 rhaas 361 GIC 16 : AlterEventTrigger(AlterEventTrigStmt *stmt)
362 : {
363 : Relation tgrel;
364 : HeapTuple tup;
365 : Oid trigoid;
3917 rhaas 366 ECB : Form_pg_event_trigger evtForm;
3602 bruce 367 GIC 16 : char tgenabled = stmt->tgenabled;
3917 rhaas 368 ECB :
1539 andres 369 GIC 16 : tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
3917 rhaas 370 ECB :
3917 rhaas 371 GIC 16 : tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
3917 rhaas 372 ECB : CStringGetDatum(stmt->trigname));
3917 rhaas 373 GBC 16 : if (!HeapTupleIsValid(tup))
3917 rhaas 374 UIC 0 : ereport(ERROR,
375 : (errcode(ERRCODE_UNDEFINED_OBJECT),
376 : errmsg("event trigger \"%s\" does not exist",
377 : stmt->trigname)));
3753 rhaas 378 ECB :
1601 andres 379 CBC 16 : evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
1601 andres 380 GIC 16 : trigoid = evtForm->oid;
3753 rhaas 381 ECB :
147 peter 382 GNC 16 : if (!object_ownercheck(EventTriggerRelationId, trigoid, GetUserId()))
1954 peter_e 383 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
3917 rhaas 384 UIC 0 : stmt->trigname);
385 :
3917 rhaas 386 ECB : /* tuple is a copy, so we can modify it below */
3917 rhaas 387 GIC 16 : evtForm->evtenabled = tgenabled;
3917 rhaas 388 ECB :
2259 alvherre 389 GIC 16 : CatalogTupleUpdate(tgrel, &tup->t_self, tup);
3917 rhaas 390 ECB :
3675 rhaas 391 GIC 16 : InvokeObjectPostAlterHook(EventTriggerRelationId,
392 : trigoid, 0);
393 :
3917 rhaas 394 ECB : /* clean up */
3917 rhaas 395 CBC 16 : heap_freetuple(tup);
1539 andres 396 GIC 16 : table_close(tgrel, RowExclusiveLock);
3753 rhaas 397 ECB :
3753 rhaas 398 GIC 16 : return trigoid;
399 : }
400 :
401 : /*
402 : * Change event trigger's owner -- by name
403 : */
2959 alvherre 404 ECB : ObjectAddress
3917 rhaas 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;
3917 rhaas 412 ECB :
1539 andres 413 GIC 6 : rel = table_open(EventTriggerRelationId, RowExclusiveLock);
3917 rhaas 414 ECB :
3917 rhaas 415 GIC 6 : tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
3917 rhaas 416 ECB :
3917 rhaas 417 GBC 6 : if (!HeapTupleIsValid(tup))
3917 rhaas 418 UIC 0 : ereport(ERROR,
419 : (errcode(ERRCODE_UNDEFINED_OBJECT),
420 : errmsg("event trigger \"%s\" does not exist", name)));
3917 rhaas 421 ECB :
1601 andres 422 CBC 6 : evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
1601 andres 423 GIC 6 : evtOid = evtForm->oid;
3759 rhaas 424 ECB :
3917 rhaas 425 GIC 6 : AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
3917 rhaas 426 ECB :
2959 alvherre 427 GIC 3 : ObjectAddressSet(address, EventTriggerRelationId, evtOid);
2959 alvherre 428 ECB :
3917 rhaas 429 GIC 3 : heap_freetuple(tup);
3917 rhaas 430 ECB :
1539 andres 431 GIC 3 : table_close(rel, RowExclusiveLock);
3759 rhaas 432 ECB :
2959 alvherre 433 GIC 3 : return address;
434 : }
435 :
436 : /*
437 : * Change event trigger owner, by OID
438 : */
3917 rhaas 439 EUB : void
3917 rhaas 440 UIC 0 : AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
441 : {
442 : HeapTuple tup;
443 : Relation rel;
3917 rhaas 444 EUB :
1539 andres 445 UIC 0 : rel = table_open(EventTriggerRelationId, RowExclusiveLock);
3917 rhaas 446 EUB :
3917 rhaas 447 UIC 0 : tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
3917 rhaas 448 EUB :
3917 rhaas 449 UBC 0 : if (!HeapTupleIsValid(tup))
3917 rhaas 450 UIC 0 : ereport(ERROR,
451 : (errcode(ERRCODE_UNDEFINED_OBJECT),
452 : errmsg("event trigger with OID %u does not exist", trigOid)));
3917 rhaas 453 EUB :
3917 rhaas 454 UIC 0 : AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
3917 rhaas 455 EUB :
3917 rhaas 456 UIC 0 : heap_freetuple(tup);
3917 rhaas 457 EUB :
1539 andres 458 UBC 0 : table_close(rel, RowExclusiveLock);
3917 rhaas 459 UIC 0 : }
460 :
461 : /*
462 : * Internal workhorse for changing an event trigger's owner
463 : */
3917 rhaas 464 ECB : static void
3917 rhaas 465 GIC 6 : AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
466 : {
467 : Form_pg_event_trigger form;
3917 rhaas 468 ECB :
3917 rhaas 469 GIC 6 : form = (Form_pg_event_trigger) GETSTRUCT(tup);
3917 rhaas 470 ECB :
3917 rhaas 471 GBC 6 : if (form->evtowner == newOwnerId)
3917 rhaas 472 UIC 0 : return;
3917 rhaas 473 ECB :
147 peter 474 GNC 6 : if (!object_ownercheck(EventTriggerRelationId, form->oid, GetUserId()))
1954 peter_e 475 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
3917 rhaas 476 UIC 0 : NameStr(form->evtname));
477 :
3917 rhaas 478 ECB : /* New owner must be a superuser */
3917 rhaas 479 CBC 6 : if (!superuser_arg(newOwnerId))
3917 rhaas 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.")));
3917 rhaas 485 ECB :
3917 rhaas 486 CBC 3 : form->evtowner = newOwnerId;
2259 alvherre 487 GIC 3 : CatalogTupleUpdate(rel, &tup->t_self, tup);
488 :
3917 rhaas 489 ECB : /* Update owner dependency reference */
3917 rhaas 490 GIC 3 : changeDependencyOnOwner(EventTriggerRelationId,
491 : form->oid,
492 : newOwnerId);
3675 rhaas 493 ECB :
3675 rhaas 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 : */
3917 rhaas 504 ECB : Oid
3917 rhaas 505 GIC 71 : get_event_trigger_oid(const char *trigname, bool missing_ok)
506 : {
507 : Oid oid;
3917 rhaas 508 ECB :
1601 andres 509 GIC 71 : oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
1601 andres 510 ECB : CStringGetDatum(trigname));
3917 rhaas 511 CBC 71 : if (!OidIsValid(oid) && !missing_ok)
3917 rhaas 512 GIC 6 : ereport(ERROR,
513 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3917 rhaas 514 ECB : errmsg("event trigger \"%s\" does not exist", trigname)));
3917 rhaas 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 : */
3730 rhaas 523 ECB : static bool
1133 alvherre 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.
3730 rhaas 529 ECB : */
3730 rhaas 530 GIC 600 : if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
3730 rhaas 531 ECB : {
3730 rhaas 532 CBC 27 : if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
3730 rhaas 533 GIC 21 : return false;
534 : }
535 : else
3730 rhaas 536 ECB : {
3730 rhaas 537 GBC 573 : if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
3730 rhaas 538 UIC 0 : return false;
539 : }
540 :
3730 rhaas 541 ECB : /* Filter by tags, if any were specified. */
1133 alvherre 542 CBC 579 : if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
3730 rhaas 543 GIC 33 : return false;
544 :
3730 rhaas 545 ECB : /* if we reach that point, we're not filtering out this item */
3730 rhaas 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 : */
3665 alvherre 554 ECB : static List *
3665 alvherre 555 GIC 61251 : EventTriggerCommonSetup(Node *parsetree,
556 : EventTriggerEvent event, const char *eventstr,
557 : EventTriggerData *trigdata)
558 : {
559 : CommandTag tag;
560 : List *cachelist;
3915 rhaas 561 ECB : ListCell *lc;
3665 alvherre 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;
3915 rhaas 581 ECB :
3915 rhaas 582 CBC 61251 : dbgtag = CreateCommandTag(parsetree);
3044 simon 583 61251 : if (event == EVT_DDLCommandStart ||
2878 bruce 584 GIC 216 : event == EVT_DDLCommandEnd ||
585 : event == EVT_SQLDrop)
3044 simon 586 ECB : {
1133 alvherre 587 GBC 61210 : if (!command_tag_event_trigger_ok(dbgtag))
1133 alvherre 588 UIC 0 : elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
3044 simon 589 ECB : }
3044 simon 590 GIC 41 : else if (event == EVT_TableRewrite)
3044 simon 591 ECB : {
1133 alvherre 592 GBC 41 : if (!command_tag_table_rewrite_ok(dbgtag))
1133 alvherre 593 UIC 0 : elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
594 : }
595 : }
596 : #endif
597 :
3915 rhaas 598 ECB : /* Use cache to find triggers for this event; fast exit if none. */
3665 alvherre 599 CBC 61251 : cachelist = EventCacheLookup(event);
600 61251 : if (cachelist == NIL)
3665 alvherre 601 GIC 60699 : return NIL;
602 :
3915 rhaas 603 ECB : /* Get the command tag. */
3915 rhaas 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.
3915 rhaas 612 ECB : */
3602 bruce 613 GIC 1152 : foreach(lc, cachelist)
3915 rhaas 614 ECB : {
3602 bruce 615 GIC 600 : EventTriggerCacheItem *item = lfirst(lc);
3915 rhaas 616 ECB :
1133 alvherre 617 GIC 600 : if (filter_event_trigger(tag, item))
618 : {
3730 rhaas 619 ECB : /* We must plan to fire this trigger. */
3730 rhaas 620 GIC 546 : runlist = lappend_oid(runlist, item->fnoid);
621 : }
622 : }
623 :
3665 alvherre 624 ECB : /* don't spend any more time on this if no functions to run */
3665 alvherre 625 CBC 552 : if (runlist == NIL)
3665 alvherre 626 GIC 42 : return NIL;
3665 alvherre 627 ECB :
3665 alvherre 628 CBC 510 : trigdata->type = T_EventTriggerData;
629 510 : trigdata->event = eventstr;
630 510 : trigdata->parsetree = parsetree;
3665 alvherre 631 GIC 510 : trigdata->tag = tag;
3665 alvherre 632 ECB :
3665 alvherre 633 GIC 510 : return runlist;
634 : }
635 :
636 : /*
637 : * Fire ddl_command_start triggers.
638 : */
3665 alvherre 639 ECB : void
3665 alvherre 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.)
3665 alvherre 660 ECB : */
3665 alvherre 661 CBC 276916 : if (!IsUnderPostmaster)
3665 alvherre 662 GIC 276760 : return;
3665 alvherre 663 ECB :
3665 alvherre 664 GIC 60271 : runlist = EventTriggerCommonSetup(parsetree,
665 : EVT_DDLCommandStart,
666 : "ddl_command_start",
3665 alvherre 667 ECB : &trigdata);
3665 alvherre 668 CBC 60271 : if (runlist == NIL)
3665 alvherre 669 GIC 60115 : return;
670 :
3730 rhaas 671 ECB : /* Run the triggers. */
3730 rhaas 672 GIC 156 : EventTriggerInvoke(runlist, &trigdata);
673 :
3730 rhaas 674 ECB : /* Cleanup. */
3730 rhaas 675 GIC 156 : list_free(runlist);
676 :
677 : /*
678 : * Make sure anything the event triggers did will be visible to the main
679 : * command.
3730 rhaas 680 ECB : */
3730 rhaas 681 GIC 156 : CommandCounterIncrement();
682 : }
683 :
684 : /*
685 : * Fire ddl_command_end triggers.
686 : */
3730 rhaas 687 ECB : void
3730 rhaas 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.
3730 rhaas 696 ECB : */
3730 rhaas 697 CBC 271942 : if (!IsUnderPostmaster)
3730 rhaas 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.
1815 tgl 709 ECB : */
1815 tgl 710 CBC 55297 : if (!currentEventTriggerState)
1815 tgl 711 GIC 54533 : return;
1815 tgl 712 ECB :
3665 alvherre 713 GIC 764 : runlist = EventTriggerCommonSetup(parsetree,
714 : EVT_DDLCommandEnd, "ddl_command_end",
3665 alvherre 715 ECB : &trigdata);
3665 alvherre 716 CBC 764 : if (runlist == NIL)
3665 alvherre 717 GIC 485 : return;
718 :
719 : /*
720 : * Make sure anything the main command did will be visible to the event
721 : * triggers.
3730 rhaas 722 ECB : */
3665 alvherre 723 GIC 279 : CommandCounterIncrement();
724 :
3665 alvherre 725 ECB : /* Run the triggers. */
3665 alvherre 726 GIC 279 : EventTriggerInvoke(runlist, &trigdata);
727 :
3665 alvherre 728 ECB : /* Cleanup. */
3665 alvherre 729 GIC 279 : list_free(runlist);
730 : }
731 :
732 : /*
733 : * Fire sql_drop triggers.
734 : */
3665 alvherre 735 ECB : void
3665 alvherre 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.
3730 rhaas 744 ECB : */
3665 alvherre 745 CBC 271951 : if (!IsUnderPostmaster)
3665 alvherre 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.
3665 alvherre 754 ECB : */
3665 alvherre 755 CBC 55306 : if (!currentEventTriggerState ||
756 773 : slist_is_empty(¤tEventTriggerState->SQLDropList))
3665 alvherre 757 GIC 55131 : return;
3915 rhaas 758 ECB :
3665 alvherre 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.
3665 alvherre 768 ECB : */
3665 alvherre 769 CBC 175 : if (runlist == NIL)
3665 alvherre 770 GIC 127 : return;
771 :
772 : /*
773 : * Make sure anything the main command did will be visible to the event
774 : * triggers.
3730 rhaas 775 ECB : */
3730 rhaas 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.)
3665 alvherre 784 ECB : */
3665 alvherre 785 GIC 48 : currentEventTriggerState->in_sql_drop = true;
786 :
3915 rhaas 787 ECB : /* Run the triggers. */
3665 alvherre 788 GIC 48 : PG_TRY();
3665 alvherre 789 ECB : {
3665 alvherre 790 GIC 48 : EventTriggerInvoke(runlist, &trigdata);
3665 alvherre 791 ECB : }
1255 peter 792 GIC 9 : PG_FINALLY();
3665 alvherre 793 ECB : {
3665 alvherre 794 GIC 48 : currentEventTriggerState->in_sql_drop = false;
3665 alvherre 795 ECB : }
3665 alvherre 796 GIC 48 : PG_END_TRY();
797 :
3915 rhaas 798 ECB : /* Cleanup. */
3915 rhaas 799 GIC 39 : list_free(runlist);
800 : }
801 :
802 :
803 : /*
804 : * Fire table_rewrite triggers.
805 : */
3044 simon 806 ECB : void
3044 simon 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.
3044 simon 815 ECB : */
3044 simon 816 CBC 371 : if (!IsUnderPostmaster)
3044 simon 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.
1815 tgl 825 ECB : */
1815 tgl 826 CBC 371 : if (!currentEventTriggerState)
1815 tgl 827 GIC 330 : return;
1815 tgl 828 ECB :
3044 simon 829 GIC 41 : runlist = EventTriggerCommonSetup(parsetree,
830 : EVT_TableRewrite,
831 : "table_rewrite",
3044 simon 832 ECB : &trigdata);
3044 simon 833 CBC 41 : if (runlist == NIL)
3044 simon 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.)
3044 simon 842 ECB : */
3044 simon 843 CBC 27 : currentEventTriggerState->table_rewrite_oid = tableOid;
3044 simon 844 GIC 27 : currentEventTriggerState->table_rewrite_reason = reason;
845 :
3044 simon 846 ECB : /* Run the triggers. */
3044 simon 847 GIC 27 : PG_TRY();
3044 simon 848 ECB : {
3044 simon 849 GIC 27 : EventTriggerInvoke(runlist, &trigdata);
3044 simon 850 ECB : }
1255 peter 851 GIC 3 : PG_FINALLY();
3044 simon 852 ECB : {
3044 simon 853 CBC 27 : currentEventTriggerState->table_rewrite_oid = InvalidOid;
3044 simon 854 GIC 27 : currentEventTriggerState->table_rewrite_reason = 0;
3044 simon 855 ECB : }
3044 simon 856 GIC 27 : PG_END_TRY();
857 :
3044 simon 858 ECB : /* Cleanup. */
3044 simon 859 GIC 24 : list_free(runlist);
860 :
861 : /*
862 : * Make sure anything the event triggers did will be visible to the main
863 : * command.
3044 simon 864 ECB : */
3044 simon 865 GIC 24 : CommandCounterIncrement();
866 : }
867 :
868 : /*
869 : * Invoke each event trigger in a list of event triggers.
870 : */
3915 rhaas 871 ECB : static void
3915 rhaas 872 GIC 510 : EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
873 : {
874 : MemoryContext context;
875 : MemoryContext oldcontext;
3602 bruce 876 ECB : ListCell *lc;
3602 bruce 877 GIC 510 : bool first = true;
878 :
3729 rhaas 879 ECB : /* Guard against stack overflow due to recursive event trigger */
3729 rhaas 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.
3915 rhaas 885 ECB : */
3915 rhaas 886 GIC 510 : context = AllocSetContextCreate(CurrentMemoryContext,
887 : "event trigger context",
2416 tgl 888 ECB : ALLOCSET_DEFAULT_SIZES);
3915 rhaas 889 GIC 510 : oldcontext = MemoryContextSwitchTo(context);
890 :
3915 rhaas 891 ECB : /* Call each event trigger. */
3602 bruce 892 GIC 1041 : foreach(lc, fn_oid_list)
3915 rhaas 893 ECB : {
1534 andres 894 CBC 543 : LOCAL_FCINFO(fcinfo, 0);
3602 bruce 895 GIC 543 : Oid fnoid = lfirst_oid(lc);
896 : FmgrInfo flinfo;
897 : PgStat_FunctionCallUsage fcusage;
3915 rhaas 898 ECB :
3044 simon 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.
3730 rhaas 906 ECB : */
3730 rhaas 907 CBC 543 : if (first)
3730 rhaas 908 GIC 510 : first = false;
3730 rhaas 909 ECB : else
3730 rhaas 910 GIC 33 : CommandCounterIncrement();
911 :
3915 rhaas 912 ECB : /* Look up the function */
3915 rhaas 913 GIC 543 : fmgr_info(fnoid, &flinfo);
914 :
3915 rhaas 915 ECB : /* Call the function, passing no arguments but setting a context. */
1534 andres 916 GIC 543 : InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
3915 rhaas 917 ECB : InvalidOid, (Node *) trigdata, NULL);
1534 andres 918 CBC 543 : pgstat_init_function_usage(fcinfo, &fcusage);
919 543 : FunctionCallInvoke(fcinfo);
3915 rhaas 920 GIC 531 : pgstat_end_function_usage(&fcusage, true);
921 :
3915 rhaas 922 ECB : /* Reclaim memory. */
3915 rhaas 923 GIC 531 : MemoryContextReset(context);
924 : }
925 :
3915 rhaas 926 ECB : /* Restore old memory context and delete the temporary one. */
3915 rhaas 927 CBC 498 : MemoryContextSwitchTo(oldcontext);
928 498 : MemoryContextDelete(context);
3915 rhaas 929 GIC 498 : }
930 :
931 : /*
932 : * Do event triggers support this object type?
933 : */
3915 rhaas 934 ECB : bool
3915 rhaas 935 GIC 129757 : EventTriggerSupportsObjectType(ObjectType obtype)
3915 rhaas 936 ECB : {
3915 rhaas 937 GIC 129757 : switch (obtype)
3915 rhaas 938 ECB : {
3915 rhaas 939 GIC 2074 : case OBJECT_DATABASE:
940 : case OBJECT_TABLESPACE:
941 : case OBJECT_ROLE:
942 : case OBJECT_PARAMETER_ACL:
3915 rhaas 943 ECB : /* no support for global objects */
3915 rhaas 944 CBC 2074 : return false;
3915 rhaas 945 GIC 62 : case OBJECT_EVENT_TRIGGER:
3915 rhaas 946 ECB : /* no support for event triggers on event triggers */
3915 rhaas 947 CBC 62 : return false;
2573 alvherre 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:
3650 alvherre 994 ECB : case OBJECT_VIEW:
3650 alvherre 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 :
2156 tgl 1003 EUB : /* Shouldn't get here, but if we do, say "no support" */
2156 tgl 1004 UIC 0 : return false;
1005 : }
1006 :
1007 : /*
1008 : * Do event triggers support this object class?
1009 : */
3650 alvherre 1010 ECB : bool
3650 alvherre 1011 GIC 2456 : EventTriggerSupportsObjectClass(ObjectClass objclass)
3650 alvherre 1012 ECB : {
3650 alvherre 1013 GIC 2456 : switch (objclass)
3650 alvherre 1014 EUB : {
3650 alvherre 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 */
3650 alvherre 1021 UBC 0 : return false;
3650 alvherre 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" */
2156 tgl 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
3665 alvherre 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;
3044 simon 1099 780 : state->table_rewrite_oid = InvalidOid;
1100 :
2890 alvherre 1101 780 : state->commandCollectionInhibited = currentEventTriggerState ?
1102 780 : currentEventTriggerState->commandCollectionInhibited : false;
1103 780 : state->currentCommand = NULL;
1104 780 : state->commandList = NIL;
3665 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 : */
235 tgl 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
3033 alvherre 1173 CBC 1275 : EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
1174 : {
1175 : SQLDropObject *obj;
1176 : MemoryContext oldcxt;
1177 :
3665 1178 1275 : if (!currentEventTriggerState)
1179 69 : return;
1180 :
3650 1181 1206 : Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
1182 :
1183 : /* don't report temp schemas except my own */
3665 1184 1230 : if (object->classId == NamespaceRelationId &&
2925 1185 24 : (isAnyTempNamespace(object->objectId) &&
2925 alvherre 1186 UBC 0 : !isTempNamespace(object->objectId)))
3665 1187 0 : return;
1188 :
3665 alvherre 1189 CBC 1206 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1190 :
1191 1206 : obj = palloc0(sizeof(SQLDropObject));
1192 1206 : obj->address = *object;
3033 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 : */
3665 1202 1206 : if (is_objectclass_supported(object->classId))
1203 : {
1204 : Relation catalog;
1205 : HeapTuple tuple;
1206 :
1539 andres 1207 1034 : catalog = table_open(obj->address.classId, AccessShareLock);
1601 1208 1034 : tuple = get_catalog_object_by_oid(catalog,
1209 1034 : get_object_attnum_oid(object->classId),
1210 : obj->address.objectId);
1211 :
3665 alvherre 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 */
2925 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 : {
3665 alvherre 1236 UBC 0 : pfree(obj);
1539 andres 1237 0 : table_close(catalog, AccessShareLock);
3665 alvherre 1238 0 : MemoryContextSwitchTo(oldcxt);
1239 0 : return;
1240 : }
1241 : else
1242 : {
2925 alvherre 1243 CBC 931 : obj->schemaname = get_namespace_name(namespaceId);
1244 931 : obj->istemp = false;
1245 : }
1246 : }
1247 : }
1248 :
3665 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 :
1539 andres 1263 1034 : table_close(catalog, AccessShareLock);
1264 : }
1265 : else
1266 : {
2925 alvherre 1267 172 : if (object->classId == NamespaceRelationId &&
2925 alvherre 1268 UBC 0 : isTempNamespace(object->objectId))
1269 0 : obj->istemp = true;
1270 : }
1271 :
1272 : /* object identity, objname and objargs */
3022 alvherre 1273 CBC 1206 : obj->objidentity =
998 michael 1274 1206 : getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
1275 : false);
1276 :
1277 : /* object type */
1278 1206 : obj->objecttype = getObjectTypeDescription(&obj->address, false);
1279 :
3665 alvherre 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 : {
3602 bruce 1294 57 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1295 : slist_iter iter;
1296 :
1297 : /*
1298 : * Protect this function from being called out of context
1299 : */
3665 alvherre 1300 57 : if (!currentEventTriggerState ||
1301 57 : !currentEventTriggerState->in_sql_drop)
3665 alvherre 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 */
173 michael 1308 CBC 57 : InitMaterializedSRF(fcinfo, 0);
1309 :
3665 alvherre 1310 594 : slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
1311 : {
1312 : SQLDropObject *obj;
1313 537 : int i = 0;
267 peter 1314 GNC 537 : Datum values[12] = {0};
1315 537 : bool nulls[12] = {0};
1316 :
3665 alvherre 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 */
3033 1329 537 : values[i++] = BoolGetDatum(obj->original);
1330 :
1331 : /* normal */
1332 537 : values[i++] = BoolGetDatum(obj->normal);
1333 :
1334 : /* is_temporary */
2925 1335 537 : values[i++] = BoolGetDatum(obj->istemp);
1336 :
1337 : /* object_type */
3665 1338 537 : values[i++] = CStringGetTextDatum(obj->objecttype);
3665 alvherre 1339 ECB :
1340 : /* schema_name */
3665 alvherre 1341 CBC 537 : if (obj->schemaname)
3665 alvherre 1342 GIC 477 : values[i++] = CStringGetTextDatum(obj->schemaname);
1343 : else
3665 alvherre 1344 CBC 60 : nulls[i++] = true;
3665 alvherre 1345 ECB :
1346 : /* object_name */
3665 alvherre 1347 CBC 537 : if (obj->objname)
3665 alvherre 1348 GIC 438 : values[i++] = CStringGetTextDatum(obj->objname);
1349 : else
3665 alvherre 1350 CBC 99 : nulls[i++] = true;
3665 alvherre 1351 ECB :
1352 : /* object_identity */
3665 alvherre 1353 GBC 537 : if (obj->objidentity)
3665 alvherre 1354 GIC 537 : values[i++] = CStringGetTextDatum(obj->objidentity);
1355 : else
3665 alvherre 1356 LBC 0 : nulls[i++] = true;
1357 :
3022 alvherre 1358 ECB : /* address_names and address_args */
3022 alvherre 1359 GIC 537 : if (obj->addrnames)
3022 alvherre 1360 ECB : {
3022 alvherre 1361 CBC 537 : values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrnames));
1362 :
1363 537 : if (obj->addrargs)
3022 alvherre 1364 GIC 30 : values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrargs));
1365 : else
1366 507 : values[i++] = PointerGetDatum(construct_empty_array(TEXTOID));
3022 alvherre 1367 EUB : }
1368 : else
1369 : {
3022 alvherre 1370 UIC 0 : nulls[i++] = true;
3022 alvherre 1371 LBC 0 : nulls[i++] = true;
1372 : }
1373 :
398 michael 1374 GIC 537 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
398 michael 1375 ECB : values, nulls);
1376 : }
1377 :
3665 alvherre 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
3044 simon 1385 ECB : * function run by the Event Trigger.
1386 : */
1387 : Datum
3044 simon 1388 GIC 33 : pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
1389 : {
3044 simon 1390 ECB : /*
1391 : * Protect this function from being called out of context
1392 : */
3044 simon 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),
2878 bruce 1397 ECB : errmsg("%s can only be called in a table_rewrite event trigger function",
1398 : "pg_event_trigger_table_rewrite_oid()")));
1399 :
3044 simon 1400 GIC 30 : PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
1401 : }
1402 :
1403 : /*
1404 : * pg_event_trigger_table_rewrite_reason
1405 : *
3044 simon 1406 ECB : * Make the rewrite reason available to the user.
1407 : */
1408 : Datum
3044 simon 1409 GIC 24 : pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
1410 : {
3044 simon 1411 ECB : /*
1412 : * Protect this function from being called out of context
3044 simon 1413 EUB : */
3044 simon 1414 GIC 24 : if (!currentEventTriggerState ||
1415 24 : currentEventTriggerState->table_rewrite_reason == 0)
3044 simon 1416 UIC 0 : ereport(ERROR,
1417 : (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
2878 bruce 1418 ECB : errmsg("%s can only be called in a table_rewrite event trigger function",
1419 : "pg_event_trigger_table_rewrite_reason()")));
1420 :
3044 simon 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 : /*
2890 alvherre 1446 ECB : * Inhibit DDL command collection.
1447 : */
1448 : void
2890 alvherre 1449 CBC 123 : EventTriggerInhibitCommandCollection(void)
1450 : {
1451 123 : if (!currentEventTriggerState)
2890 alvherre 1452 GIC 122 : return;
1453 :
1454 1 : currentEventTriggerState->commandCollectionInhibited = true;
1455 : }
1456 :
1457 : /*
2890 alvherre 1458 ECB : * Re-establish DDL command collection.
1459 : */
1460 : void
2890 alvherre 1461 CBC 123 : EventTriggerUndoInhibitCommandCollection(void)
1462 : {
1463 123 : if (!currentEventTriggerState)
2890 alvherre 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
2890 alvherre 1480 ECB : * of the object.)
1481 : */
1482 : void
2890 alvherre 1483 GIC 151428 : EventTriggerCollectSimpleCommand(ObjectAddress address,
1484 : ObjectAddress secondaryObject,
1485 : Node *parsetree)
1486 : {
1487 : MemoryContext oldcxt;
2890 alvherre 1488 ECB : CollectedCommand *command;
1489 :
1490 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1491 GIC 151428 : if (!currentEventTriggerState ||
2890 alvherre 1492 CBC 483 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1493 GIC 150945 : return;
2890 alvherre 1494 ECB :
2890 alvherre 1495 GIC 483 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1496 ECB :
2890 alvherre 1497 CBC 483 : command = palloc(sizeof(CollectedCommand));
1498 :
1499 483 : command->type = SCT_Simple;
1500 483 : command->in_extension = creating_extension;
2890 alvherre 1501 ECB :
2890 alvherre 1502 GIC 483 : command->d.simple.address = address;
2890 alvherre 1503 CBC 483 : command->d.simple.secondaryObject = secondaryObject;
2890 alvherre 1504 GIC 483 : command->parsetree = copyObject(parsetree);
1505 :
2890 alvherre 1506 CBC 483 : currentEventTriggerState->commandList = lappend(currentEventTriggerState->commandList,
1507 : command);
1508 :
2890 alvherre 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
2890 alvherre 1518 ECB : * add it to the command list.
1519 : */
1520 : void
2890 alvherre 1521 GIC 94996 : EventTriggerAlterTableStart(Node *parsetree)
1522 : {
1523 : MemoryContext oldcxt;
2890 alvherre 1524 ECB : CollectedCommand *command;
1525 :
1526 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1527 GIC 94996 : if (!currentEventTriggerState ||
2890 alvherre 1528 CBC 419 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1529 GIC 94577 : return;
2890 alvherre 1530 ECB :
2890 alvherre 1531 GIC 419 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1532 ECB :
2890 alvherre 1533 CBC 419 : command = palloc(sizeof(CollectedCommand));
1534 :
1535 419 : command->type = SCT_AlterTable;
1536 419 : command->in_extension = creating_extension;
2890 alvherre 1537 ECB :
2890 alvherre 1538 CBC 419 : command->d.alterTable.classId = RelationRelationId;
2890 alvherre 1539 GIC 419 : command->d.alterTable.objectId = InvalidOid;
2890 alvherre 1540 CBC 419 : command->d.alterTable.subcmds = NIL;
1541 419 : command->parsetree = copyObject(parsetree);
1542 :
1646 1543 419 : command->parent = currentEventTriggerState->currentCommand;
2890 alvherre 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 : *
2890 alvherre 1552 ECB : * This is needed because in some cases we don't know the OID until later.
1553 : */
1554 : void
2890 alvherre 1555 CBC 45170 : EventTriggerAlterTableRelid(Oid objectId)
2890 alvherre 1556 ECB : {
2890 alvherre 1557 GIC 45170 : if (!currentEventTriggerState ||
2890 alvherre 1558 CBC 337 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 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
2890 alvherre 1570 ECB : * internally, so that's all that this code needs to handle at the moment.
1571 : */
1572 : void
2890 alvherre 1573 GIC 70431 : EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
1574 : {
1575 : MemoryContext oldcxt;
2890 alvherre 1576 ECB : CollectedATSubcmd *newsub;
1577 :
1578 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1579 GIC 70431 : if (!currentEventTriggerState ||
2890 alvherre 1580 CBC 507 : currentEventTriggerState->commandCollectionInhibited)
1581 69924 : return;
2890 alvherre 1582 ECB :
2890 alvherre 1583 GIC 507 : Assert(IsA(subcmd, AlterTableCmd));
1644 alvherre 1584 CBC 507 : Assert(currentEventTriggerState->currentCommand != NULL);
2890 alvherre 1585 GIC 507 : Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
2890 alvherre 1586 ECB :
2890 alvherre 1587 CBC 507 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1588 ECB :
2890 alvherre 1589 GIC 507 : newsub = palloc(sizeof(CollectedATSubcmd));
2890 alvherre 1590 CBC 507 : newsub->address = address;
1591 507 : newsub->parsetree = copyObject(subcmd);
1592 :
1593 1014 : currentEventTriggerState->currentCommand->d.alterTable.subcmds =
2890 alvherre 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
2890 alvherre 1605 ECB : * AtEOSubXact_EventTriggers() to fix this.
1606 : */
1607 : void
2890 alvherre 1608 GIC 93452 : EventTriggerAlterTableEnd(void)
1609 : {
1646 alvherre 1610 ECB : CollectedCommand *parent;
1611 :
2890 1612 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1613 GIC 93452 : if (!currentEventTriggerState ||
2890 alvherre 1614 CBC 413 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1615 GIC 93039 : return;
1616 :
1646 alvherre 1617 CBC 413 : parent = currentEventTriggerState->currentCommand->parent;
1618 :
1619 : /* If no subcommands, don't collect */
235 tgl 1620 GNC 413 : if (currentEventTriggerState->currentCommand->d.alterTable.subcmds != NIL)
2890 alvherre 1621 ECB : {
1622 : MemoryContext oldcxt;
936 1623 :
936 alvherre 1624 CBC 320 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
936 alvherre 1625 ECB :
2890 alvherre 1626 GIC 640 : currentEventTriggerState->commandList =
2890 alvherre 1627 CBC 320 : lappend(currentEventTriggerState->commandList,
2890 alvherre 1628 GIC 320 : currentEventTriggerState->currentCommand);
1629 :
936 alvherre 1630 CBC 320 : MemoryContextSwitchTo(oldcxt);
1631 : }
2890 alvherre 1632 ECB : else
2890 alvherre 1633 GIC 93 : pfree(currentEventTriggerState->currentCommand);
1634 :
1646 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
2890 alvherre 1643 ECB : * not have the right lifetime.
1644 : */
1645 : void
2890 alvherre 1646 GIC 48143 : EventTriggerCollectGrant(InternalGrant *istmt)
1647 : {
1648 : MemoryContext oldcxt;
1649 : CollectedCommand *command;
1650 : InternalGrant *icopy;
2878 bruce 1651 ECB : ListCell *cell;
2890 alvherre 1652 :
1653 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1654 GIC 48143 : if (!currentEventTriggerState ||
2890 alvherre 1655 CBC 15 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1656 GIC 48128 : return;
1657 :
1658 15 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
1659 :
2890 alvherre 1660 ECB : /*
1661 : * This is tedious, but necessary.
1662 : */
2890 alvherre 1663 CBC 15 : icopy = palloc(sizeof(InternalGrant));
1664 15 : memcpy(icopy, istmt, sizeof(InternalGrant));
1665 15 : icopy->objects = list_copy(istmt->objects);
2890 alvherre 1666 GBC 15 : icopy->grantees = list_copy(istmt->grantees);
2890 alvherre 1667 GIC 15 : icopy->col_privs = NIL;
1668 15 : foreach(cell, istmt->col_privs)
2890 alvherre 1669 LBC 0 : icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
2890 alvherre 1670 ECB :
1671 : /* Now collect it, using the copied InternalGrant */
2890 alvherre 1672 CBC 15 : command = palloc(sizeof(CollectedCommand));
1673 15 : command->type = SCT_Grant;
2890 alvherre 1674 GIC 15 : command->in_extension = creating_extension;
2890 alvherre 1675 CBC 15 : command->d.grant.istmt = icopy;
1676 15 : command->parsetree = NULL;
1677 :
1678 30 : currentEventTriggerState->commandList =
2890 alvherre 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
2890 alvherre 1687 ECB : * executed
1688 : */
1689 : void
2890 alvherre 1690 GIC 145 : EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
1691 : List *operators, List *procedures)
1692 : {
1693 : MemoryContext oldcxt;
2890 alvherre 1694 ECB : CollectedCommand *command;
1695 :
1696 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1697 GIC 145 : if (!currentEventTriggerState ||
2890 alvherre 1698 CBC 1 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1699 GIC 144 : return;
2890 alvherre 1700 ECB :
2890 alvherre 1701 CBC 1 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1702 ECB :
2890 alvherre 1703 CBC 1 : command = palloc(sizeof(CollectedCommand));
2890 alvherre 1704 GIC 1 : command->type = SCT_AlterOpFamily;
2890 alvherre 1705 CBC 1 : command->in_extension = creating_extension;
1706 1 : ObjectAddressSet(command->d.opfam.address,
2890 alvherre 1707 ECB : OperatorFamilyRelationId, opfamoid);
2890 alvherre 1708 GIC 1 : command->d.opfam.operators = operators;
2890 alvherre 1709 CBC 1 : command->d.opfam.procedures = procedures;
2222 peter_e 1710 1 : command->parsetree = (Node *) copyObject(stmt);
1711 :
2890 alvherre 1712 2 : currentEventTriggerState->commandList =
2890 alvherre 1713 GIC 1 : lappend(currentEventTriggerState->commandList, command);
1714 :
1715 1 : MemoryContextSwitchTo(oldcxt);
1716 : }
1717 :
1718 : /*
1719 : * EventTriggerCollectCreateOpClass
2890 alvherre 1720 ECB : * Save data about a CREATE OPERATOR CLASS command being executed
1721 : */
1722 : void
2890 alvherre 1723 GIC 183 : EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
1724 : List *operators, List *procedures)
1725 : {
1726 : MemoryContext oldcxt;
2890 alvherre 1727 ECB : CollectedCommand *command;
1728 :
1729 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1730 GIC 183 : if (!currentEventTriggerState ||
2890 alvherre 1731 CBC 4 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1732 GIC 179 : return;
2890 alvherre 1733 ECB :
2890 alvherre 1734 CBC 4 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1735 ECB :
2890 alvherre 1736 CBC 4 : command = palloc0(sizeof(CollectedCommand));
2890 alvherre 1737 GIC 4 : command->type = SCT_CreateOpClass;
2890 alvherre 1738 CBC 4 : command->in_extension = creating_extension;
1739 4 : ObjectAddressSet(command->d.createopc.address,
2890 alvherre 1740 ECB : OperatorClassRelationId, opcoid);
2890 alvherre 1741 GIC 4 : command->d.createopc.operators = operators;
2890 alvherre 1742 CBC 4 : command->d.createopc.procedures = procedures;
2222 peter_e 1743 4 : command->parsetree = (Node *) copyObject(stmt);
1744 :
2890 alvherre 1745 8 : currentEventTriggerState->commandList =
2890 alvherre 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
2890 alvherre 1754 ECB : * executed
1755 : */
1756 : void
2890 alvherre 1757 GIC 25548 : EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
1758 : Oid *dictIds, int ndicts)
1759 : {
1760 : MemoryContext oldcxt;
2890 alvherre 1761 ECB : CollectedCommand *command;
1762 :
1763 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1764 GIC 25548 : if (!currentEventTriggerState ||
2890 alvherre 1765 CBC 1 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1766 GIC 25547 : return;
2890 alvherre 1767 ECB :
2890 alvherre 1768 CBC 1 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1769 ECB :
2890 alvherre 1770 CBC 1 : command = palloc0(sizeof(CollectedCommand));
2890 alvherre 1771 GIC 1 : command->type = SCT_AlterTSConfig;
2890 alvherre 1772 CBC 1 : command->in_extension = creating_extension;
1773 1 : ObjectAddressSet(command->d.atscfg.address,
2890 alvherre 1774 ECB : TSConfigRelationId, cfgId);
2890 alvherre 1775 CBC 1 : command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
2890 alvherre 1776 GIC 1 : memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
2890 alvherre 1777 CBC 1 : command->d.atscfg.ndicts = ndicts;
2222 peter_e 1778 1 : command->parsetree = (Node *) copyObject(stmt);
1779 :
2890 alvherre 1780 2 : currentEventTriggerState->commandList =
2890 alvherre 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
2890 alvherre 1789 ECB : * executed
1790 : */
1791 : void
2890 alvherre 1792 GIC 77 : EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
1793 : {
1794 : MemoryContext oldcxt;
2890 alvherre 1795 ECB : CollectedCommand *command;
1796 :
1797 : /* ignore if event trigger context not set, or collection disabled */
2890 alvherre 1798 GIC 77 : if (!currentEventTriggerState ||
2890 alvherre 1799 CBC 4 : currentEventTriggerState->commandCollectionInhibited)
2890 alvherre 1800 GIC 73 : return;
2890 alvherre 1801 ECB :
2890 alvherre 1802 CBC 4 : oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
2890 alvherre 1803 ECB :
2890 alvherre 1804 CBC 4 : command = palloc0(sizeof(CollectedCommand));
1805 4 : command->type = SCT_AlterDefaultPrivileges;
2890 alvherre 1806 GIC 4 : command->d.defprivs.objtype = stmt->action->objtype;
2890 alvherre 1807 CBC 4 : command->in_extension = creating_extension;
2222 peter_e 1808 4 : command->parsetree = (Node *) copyObject(stmt);
2890 alvherre 1809 ECB :
2890 alvherre 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
2890 alvherre 1817 ECB : * being run.
1818 : */
1819 : Datum
2890 alvherre 1820 GIC 208 : pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
1821 : {
1822 208 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1823 : ListCell *lc;
1824 :
2890 alvherre 1825 ECB : /*
2890 alvherre 1826 EUB : * Protect this function from being called out of context
1827 : */
2890 alvherre 1828 GIC 208 : if (!currentEventTriggerState)
2890 alvherre 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",
2890 alvherre 1832 ECB : "pg_event_trigger_ddl_commands()")));
1833 :
1834 : /* Build tuplestore to hold the result rows */
173 michael 1835 GIC 208 : InitMaterializedSRF(fcinfo, 0);
2890 alvherre 1836 ECB :
2890 alvherre 1837 GIC 487 : foreach(lc, currentEventTriggerState->commandList)
2890 alvherre 1838 ECB : {
2890 alvherre 1839 GIC 279 : CollectedCommand *cmd = lfirst(lc);
2890 alvherre 1840 ECB : Datum values[9];
267 peter 1841 GNC 279 : bool nulls[9] = {0};
1842 : ObjectAddress addr;
2890 alvherre 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
2878 bruce 1852 ECB : * the object in the first place, we might not end up in a consistent
1853 : * state anyway.
2890 alvherre 1854 : */
2890 alvherre 1855 GIC 279 : if (cmd->type == SCT_Simple &&
2890 alvherre 1856 CBC 196 : !OidIsValid(cmd->d.simple.address.objectId))
2890 alvherre 1857 GIC 3 : continue;
2890 alvherre 1858 ECB :
2890 alvherre 1859 GIC 279 : switch (cmd->type)
1860 : {
1861 269 : case SCT_Simple:
1862 : case SCT_AlterTable:
1863 : case SCT_AlterOpFamily:
2890 alvherre 1864 ECB : case SCT_CreateOpClass:
1865 : case SCT_AlterTSConfig:
1866 : {
1867 : char *identity;
1868 : char *type;
2890 alvherre 1869 CBC 269 : char *schema = NULL;
1870 :
2890 alvherre 1871 GIC 269 : if (cmd->type == SCT_Simple)
2890 alvherre 1872 CBC 196 : addr = cmd->d.simple.address;
1873 73 : else if (cmd->type == SCT_AlterTable)
1874 67 : ObjectAddressSet(addr,
2890 alvherre 1875 ECB : cmd->d.alterTable.classId,
1876 : cmd->d.alterTable.objectId);
2890 alvherre 1877 CBC 6 : else if (cmd->type == SCT_AlterOpFamily)
2890 alvherre 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
664 michael 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 : */
664 michael 1891 CBC 269 : identity = getObjectIdentity(&addr, true);
664 michael 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 : /*
2878 bruce 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.
2890 alvherre 1903 : */
2890 alvherre 1904 CBC 266 : if (is_objectclass_supported(addr.classId))
1905 : {
1906 : AttrNumber nspAttnum;
1907 :
2890 alvherre 1908 GIC 266 : nspAttnum = get_object_attnum_namespace(addr.classId);
1909 266 : if (nspAttnum != InvalidAttrNumber)
1910 : {
2890 alvherre 1911 ECB : Relation catalog;
1912 : HeapTuple objtup;
1913 : Oid schema_oid;
1914 : bool isnull;
1915 :
1539 andres 1916 GBC 238 : catalog = table_open(addr.classId, AccessShareLock);
2890 alvherre 1917 GIC 238 : objtup = get_catalog_object_by_oid(catalog,
1601 andres 1918 CBC 238 : get_object_attnum_oid(addr.classId),
2890 alvherre 1919 ECB : addr.objectId);
2890 alvherre 1920 GIC 238 : if (!HeapTupleIsValid(objtup))
2890 alvherre 1921 LBC 0 : elog(ERROR, "cache lookup failed for object %u/%u",
2890 alvherre 1922 EUB : addr.classId, addr.objectId);
2890 alvherre 1923 GIC 238 : schema_oid =
1924 238 : heap_getattr(objtup, nspAttnum,
2118 tgl 1925 ECB : RelationGetDescr(catalog), &isnull);
2890 alvherre 1926 GIC 238 : if (isnull)
2890 alvherre 1927 LBC 0 : elog(ERROR,
1928 : "invalid null namespace in object %u/%u/%d",
1929 : addr.classId, addr.objectId, addr.objectSubId);
621 tgl 1930 GIC 238 : schema = get_namespace_name_or_temp(schema_oid);
1931 :
1539 andres 1932 CBC 238 : table_close(catalog, AccessShareLock);
1933 : }
2890 alvherre 1934 ECB : }
1935 :
1936 : /* classid */
2890 alvherre 1937 GIC 266 : values[i++] = ObjectIdGetDatum(addr.classId);
2890 alvherre 1938 ECB : /* objid */
2890 alvherre 1939 GIC 266 : values[i++] = ObjectIdGetDatum(addr.objectId);
2890 alvherre 1940 ECB : /* objsubid */
2890 alvherre 1941 GIC 266 : values[i++] = Int32GetDatum(addr.objectSubId);
2890 alvherre 1942 ECB : /* command tag */
1133 alvherre 1943 CBC 266 : values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
1944 : /* object_type */
2890 1945 266 : values[i++] = CStringGetTextDatum(type);
1946 : /* schema */
1947 266 : if (schema == NULL)
2890 alvherre 1948 GIC 28 : nulls[i++] = true;
2890 alvherre 1949 ECB : else
2890 alvherre 1950 GIC 238 : values[i++] = CStringGetTextDatum(schema);
2890 alvherre 1951 ECB : /* identity */
2890 alvherre 1952 GIC 266 : values[i++] = CStringGetTextDatum(identity);
2890 alvherre 1953 ECB : /* in_extension */
2890 alvherre 1954 GIC 266 : values[i++] = BoolGetDatum(cmd->in_extension);
2890 alvherre 1955 ECB : /* command */
2890 alvherre 1956 GIC 266 : values[i++] = PointerGetDatum(cmd);
2890 alvherre 1957 ECB : }
2890 alvherre 1958 GIC 266 : break;
2890 alvherre 1959 ECB :
2890 alvherre 1960 GIC 1 : case SCT_AlterDefaultPrivileges:
2890 alvherre 1961 ECB : /* classid */
2890 alvherre 1962 GIC 1 : nulls[i++] = true;
2890 alvherre 1963 ECB : /* objid */
2890 alvherre 1964 GIC 1 : nulls[i++] = true;
2890 alvherre 1965 ECB : /* objsubid */
2890 alvherre 1966 GIC 1 : nulls[i++] = true;
2890 alvherre 1967 ECB : /* command tag */
1133 alvherre 1968 GIC 1 : values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
2890 alvherre 1969 ECB : /* object_type */
1165 alvherre 1970 GIC 1 : values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
2890 alvherre 1971 ECB : /* schema */
2890 alvherre 1972 GIC 1 : nulls[i++] = true;
2890 alvherre 1973 ECB : /* identity */
2890 alvherre 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);
2890 alvherre 1979 GIC 1 : break;
2890 alvherre 1980 ECB :
2890 alvherre 1981 GIC 9 : case SCT_Grant:
2890 alvherre 1982 ECB : /* classid */
2890 alvherre 1983 GIC 9 : nulls[i++] = true;
2890 alvherre 1984 ECB : /* objid */
2890 alvherre 1985 GIC 9 : nulls[i++] = true;
1986 : /* objsubid */
2890 alvherre 1987 CBC 9 : nulls[i++] = true;
1988 : /* command tag */
1989 9 : values[i++] = CStringGetTextDatum(cmd->d.grant.istmt->is_grant ?
1990 : "GRANT" : "REVOKE");
2890 alvherre 1991 ECB : /* object_type */
1165 alvherre 1992 GIC 9 : values[i++] = CStringGetTextDatum(stringify_grant_objtype(cmd->d.grant.istmt->objtype));
2890 alvherre 1993 ECB : /* schema */
2890 alvherre 1994 GIC 9 : nulls[i++] = true;
2890 alvherre 1995 ECB : /* identity */
2890 alvherre 1996 CBC 9 : nulls[i++] = true;
1997 : /* in_extension */
2890 alvherre 1998 GIC 9 : values[i++] = BoolGetDatum(cmd->in_extension);
2890 alvherre 1999 ECB : /* command */
2890 alvherre 2000 GIC 9 : values[i++] = PointerGetDatum(cmd);
2001 9 : break;
2002 : }
2890 alvherre 2003 ECB :
398 michael 2004 GIC 276 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2005 : values, nulls);
2006 : }
2007 :
2890 alvherre 2008 208 : PG_RETURN_VOID();
2009 : }
2010 :
2890 alvherre 2011 ECB : /*
2012 : * Return the ObjectType as a string, as it would appear in GRANT and
2013 : * REVOKE commands.
2014 : */
2890 alvherre 2015 EUB : static const char *
2006 peter_e 2016 GBC 9 : stringify_grant_objtype(ObjectType objtype)
2890 alvherre 2017 ECB : {
2890 alvherre 2018 CBC 9 : switch (objtype)
2890 alvherre 2019 EUB : {
2006 peter_e 2020 UBC 0 : case OBJECT_COLUMN:
2890 alvherre 2021 0 : return "COLUMN";
2006 peter_e 2022 GBC 5 : case OBJECT_TABLE:
2890 alvherre 2023 5 : return "TABLE";
2006 peter_e 2024 UBC 0 : case OBJECT_SEQUENCE:
2890 alvherre 2025 0 : return "SEQUENCE";
2006 peter_e 2026 0 : case OBJECT_DATABASE:
2890 alvherre 2027 0 : return "DATABASE";
2006 peter_e 2028 0 : case OBJECT_DOMAIN:
2890 alvherre 2029 LBC 0 : return "DOMAIN";
2006 peter_e 2030 0 : case OBJECT_FDW:
2890 alvherre 2031 UBC 0 : return "FOREIGN DATA WRAPPER";
2006 peter_e 2032 0 : case OBJECT_FOREIGN_SERVER:
2890 alvherre 2033 0 : return "FOREIGN SERVER";
2006 peter_e 2034 GBC 4 : case OBJECT_FUNCTION:
2890 alvherre 2035 4 : return "FUNCTION";
2006 peter_e 2036 UBC 0 : case OBJECT_LANGUAGE:
2890 alvherre 2037 0 : return "LANGUAGE";
2006 peter_e 2038 0 : case OBJECT_LARGEOBJECT:
2890 alvherre 2039 0 : return "LARGE OBJECT";
2006 peter_e 2040 0 : case OBJECT_SCHEMA:
2890 alvherre 2041 0 : return "SCHEMA";
368 tgl 2042 0 : case OBJECT_PARAMETER_ACL:
2043 0 : return "PARAMETER";
2006 peter_e 2044 0 : case OBJECT_PROCEDURE:
1956 2045 0 : return "PROCEDURE";
2006 2046 0 : case OBJECT_ROUTINE:
1956 peter_e 2047 UIC 0 : return "ROUTINE";
2006 peter_e 2048 UBC 0 : case OBJECT_TABLESPACE:
2890 alvherre 2049 UIC 0 : return "TABLESPACE";
2006 peter_e 2050 0 : case OBJECT_TYPE:
2890 alvherre 2051 0 : return "TYPE";
2052 : /* these currently aren't used */
2006 peter_e 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:
2006 peter_e 2084 EUB : case OBJECT_TSDICTIONARY:
2085 : case OBJECT_TSPARSER:
2086 : case OBJECT_TSTEMPLATE:
2087 : case OBJECT_USER_MAPPING:
2088 : case OBJECT_VIEW:
2006 peter_e 2089 UIC 0 : elog(ERROR, "unsupported object type: %d", (int) objtype);
2090 : }
2091 :
2153 bruce 2092 0 : return "???"; /* keep compiler quiet */
2093 : }
2094 :
2095 : /*
2006 peter_e 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
2156 tgl 2098 : * the plural.
2099 : */
2890 alvherre 2100 EUB : static const char *
2006 peter_e 2101 GBC 1 : stringify_adefprivs_objtype(ObjectType objtype)
2890 alvherre 2102 ECB : {
2890 alvherre 2103 CBC 1 : switch (objtype)
2890 alvherre 2104 EUB : {
2006 peter_e 2105 UBC 0 : case OBJECT_COLUMN:
2156 tgl 2106 0 : return "COLUMNS";
2006 peter_e 2107 GBC 1 : case OBJECT_TABLE:
2890 alvherre 2108 1 : return "TABLES";
2006 peter_e 2109 UBC 0 : case OBJECT_SEQUENCE:
2890 alvherre 2110 0 : return "SEQUENCES";
2006 peter_e 2111 0 : case OBJECT_DATABASE:
2156 tgl 2112 0 : return "DATABASES";
2006 peter_e 2113 0 : case OBJECT_DOMAIN:
2156 tgl 2114 0 : return "DOMAINS";
2006 peter_e 2115 0 : case OBJECT_FDW:
2156 tgl 2116 0 : return "FOREIGN DATA WRAPPERS";
2006 peter_e 2117 0 : case OBJECT_FOREIGN_SERVER:
2156 tgl 2118 0 : return "FOREIGN SERVERS";
2006 peter_e 2119 0 : case OBJECT_FUNCTION:
2156 tgl 2120 0 : return "FUNCTIONS";
2006 peter_e 2121 0 : case OBJECT_LANGUAGE:
2156 tgl 2122 0 : return "LANGUAGES";
2006 peter_e 2123 0 : case OBJECT_LARGEOBJECT:
2156 tgl 2124 0 : return "LARGE OBJECTS";
2006 peter_e 2125 0 : case OBJECT_SCHEMA:
2156 tgl 2126 0 : return "SCHEMAS";
2006 peter_e 2127 0 : case OBJECT_PROCEDURE:
1956 2128 0 : return "PROCEDURES";
2006 2129 0 : case OBJECT_ROUTINE:
1956 peter_e 2130 UIC 0 : return "ROUTINES";
2006 peter_e 2131 UBC 0 : case OBJECT_TABLESPACE:
2156 tgl 2132 UIC 0 : return "TABLESPACES";
2006 peter_e 2133 0 : case OBJECT_TYPE:
2890 alvherre 2134 0 : return "TYPES";
2135 : /* these currently aren't used */
2006 peter_e 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:
2006 peter_e 2168 EUB : case OBJECT_TSDICTIONARY:
2169 : case OBJECT_TSPARSER:
2170 : case OBJECT_TSTEMPLATE:
2171 : case OBJECT_USER_MAPPING:
2172 : case OBJECT_VIEW:
2006 peter_e 2173 UIC 0 : elog(ERROR, "unsupported object type: %d", (int) objtype);
2174 : }
2175 :
2153 bruce 2176 0 : return "???"; /* keep compiler quiet */
2177 : }
|