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