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