event-trigger-morecleanup.patch

application/octet-stream

Filename: event-trigger-morecleanup.patch
Type: application/octet-stream
Part: 0
Message: Re: Event Triggers reduced, v1

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/catalog/aclchk.c 40 0
src/backend/catalog/objectaddress.c 5 1
src/backend/commands/alter.c 4 4
src/backend/commands/dropcmds.c 4 0
src/backend/commands/event_trigger.c 48 49
src/backend/parser/gram.y 2 23
src/backend/tcop/utility.c 1 1
src/backend/utils/adt/pseudotypes.c 27 0
src/bin/pg_dump/pg_dump.c 4 4
src/bin/pg_dump/pg_dump_sort.c 4 3
src/include/catalog/pg_proc.h 4 0
src/include/catalog/pg_type.h 1 1
src/include/utils/acl.h 2 0
src/include/utils/builtins.h 2 0
src/pl/plperl/plperl.c 1 1
src/pl/plpgsql/src/pl_comp.c 2 2
src/pl/plpgsql/src/pl_exec.c 2 2
src/test/regress/expected/event_triggers.out 17 14
src/test/regress/expected/type_sanity.out 8 10
src/test/regress/sql/event_triggers.sql 13 14
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 56c40b1..b097813 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -29,6 +29,7 @@
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_default_acl.h"
+#include "catalog/pg_event_trigger.h"
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
@@ -277,6 +278,10 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
 		case ACL_KIND_FOREIGN_SERVER:
 			whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 			break;
+		case ACL_KIND_EVENT_TRIGGER:
+			elog(ERROR, "grantable rights not supported for event triggers");
+			/* not reached, but keep compiler quiet */
+			return ACL_NO_RIGHTS;
 		case ACL_KIND_TYPE:
 			whole_mask = ACL_ALL_RIGHTS_TYPE;
 			break;
@@ -3286,6 +3291,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
 	gettext_noop("permission denied for foreign-data wrapper %s"),
 	/* ACL_KIND_FOREIGN_SERVER */
 	gettext_noop("permission denied for foreign server %s"),
+	/* ACL_KIND_EVENT_TRIGGER */
+	gettext_noop("permission denied for event trigger %s"),
 	/* ACL_KIND_EXTENSION */
 	gettext_noop("permission denied for extension %s"),
 };
@@ -3330,6 +3337,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
 	gettext_noop("must be owner of foreign-data wrapper %s"),
 	/* ACL_KIND_FOREIGN_SERVER */
 	gettext_noop("must be owner of foreign server %s"),
+	/* ACL_KIND_EVENT_TRIGGER */
+	gettext_noop("must be owner of event trigger %s"),
 	/* ACL_KIND_EXTENSION */
 	gettext_noop("must be owner of extension %s"),
 };
@@ -3455,6 +3464,10 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
 			return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
 		case ACL_KIND_FOREIGN_SERVER:
 			return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
+		case ACL_KIND_EVENT_TRIGGER:
+			elog(ERROR, "grantable rights not supported for event triggers");
+			/* not reached, but keep compiler quiet */
+			return ACL_NO_RIGHTS;
 		case ACL_KIND_TYPE:
 			return pg_type_aclmask(table_oid, roleid, mask, how);
 		default:
@@ -4876,6 +4889,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
 }
 
 /*
+ * Ownership check for an event trigger (specified by OID).
+ */
+bool
+pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
+{
+	HeapTuple	tuple;
+	Oid			ownerId;
+
+	/* Superusers bypass all permission checking. */
+	if (superuser_arg(roleid))
+		return true;
+
+	tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("event trigger with OID %u does not exist",
+						et_oid)));
+
+	ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
+
+	ReleaseSysCache(tuple);
+
+	return has_privs_of_role(roleid, ownerId);
+}
+
+/*
  * Ownership check for a database (specified by OID).
  */
 bool
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 40ae60d..5b8140b 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -997,6 +997,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
 							   NameListToString(objname));
 			break;
+		case OBJECT_EVENT_TRIGGER:
+			if (!pg_event_trigger_ownercheck(address.objectId, roleid))
+				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+							   NameListToString(objname));
+			break;
 		case OBJECT_LANGUAGE:
 			if (!pg_language_ownercheck(address.objectId, roleid))
 				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
@@ -1075,7 +1080,6 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 			break;
 		case OBJECT_TSPARSER:
 		case OBJECT_TSTEMPLATE:
-		case OBJECT_EVENT_TRIGGER:
 			/* We treat these object types as being owned by superusers */
 			if (!superuser_arg(roleid))
 				ereport(ERROR,
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78ef831..19f9895 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -70,10 +70,6 @@ ExecRenameStmt(RenameStmt *stmt)
 			RenameDatabase(stmt->subname, stmt->newname);
 			break;
 
-		case OBJECT_EVENT_TRIGGER:
-			RenameEventTrigger(stmt->subname, stmt->newname);
-			break;
-
 		case OBJECT_FDW:
 			RenameForeignDataWrapper(stmt->subname, stmt->newname);
 			break;
@@ -82,6 +78,10 @@ ExecRenameStmt(RenameStmt *stmt)
 			RenameForeignServer(stmt->subname, stmt->newname);
 			break;
 
+		case OBJECT_EVENT_TRIGGER:
+			RenameEventTrigger(stmt->subname, stmt->newname);
+			break;
+
 		case OBJECT_FUNCTION:
 			RenameFunction(stmt->object, stmt->objarg, stmt->newname);
 			break;
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index 1b8529e..8f5d7e0 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -206,6 +206,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 			args = NameListToString(list_truncate(objname,
 												  list_length(objname) - 1));
 			break;
+		case OBJECT_EVENT_TRIGGER:
+			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
+			name = NameListToString(objname);
+			break;
 		case OBJECT_RULE:
 			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
 			name = strVal(llast(objname));
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 561ce42..f9a3ea2 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -49,23 +49,6 @@ static void AlterEventTriggerOwner_internal(Relation rel,
 											Oid newOwnerId);
 
 /*
- * Check permission: event triggers are only available for superusers. Raise
- * an exception when requirements are not fullfilled.
- *
- * It's not clear how to accept that database owners be able to create command
- * triggers, a superuser could run a command that fires a trigger's procedure
- * written by the database owner and now running with superuser privileges.
- */
-static void
-CheckEventTriggerPrivileges()
-{
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to use event triggers"))));
-}
-
-/*
  * Insert Command Trigger Tuple
  *
  * Insert the new pg_event_trigger row, and return the OID assigned to the new
@@ -158,7 +141,16 @@ CreateEventTrigger(CreateEventTrigStmt *stmt, const char *queryString)
 	Oid			funcrettype;
 	Oid			evtowner = GetUserId();
 
-	CheckEventTriggerPrivileges();
+	/*
+	 * It would be nice to allow database owners or even regular users to do
+	 * this, but there are obvious privilege escalation risks which would have
+	 * to somehow be plugged first.
+	 */
+	if (!superuser())
+		ereport(ERROR,
+			(errmsg("permission denied to create event trigger \"%s\"",
+                   stmt->trigname),
+            errhint("Must be superuser to create an event trigger.")));
 
 	/*
 	 * Find and validate the trigger function.
@@ -171,7 +163,7 @@ CreateEventTrigger(CreateEventTrigStmt *stmt, const char *queryString)
 	if (funcrettype != EVTTRIGGEROID)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-				 errmsg("function \"%s\" must return type \"command_trigger\"",
+				 errmsg("function \"%s\" must return type \"event_trigger\"",
 						NameListToString(stmt->funcname))));
 
 	/*
@@ -224,15 +216,18 @@ AlterEventTrigger(AlterEventTrigStmt *stmt)
 	Form_pg_event_trigger evtForm;
 	char        tgenabled = stmt->tgenabled;
 
-	CheckEventTriggerPrivileges();
-
 	tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
 
-	tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
+	tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
+							  CStringGetDatum(stmt->trigname));
 	if (!HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("event trigger \"%s\" does not exist", stmt->trigname)));
+				 errmsg("event trigger \"%s\" does not exist",
+					stmt->trigname)));
+    if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+                       stmt->trigname);
 
 	/* tuple is a copy, so we can modify it below */
 	evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
@@ -257,8 +252,6 @@ RenameEventTrigger(const char *trigname, const char *newname)
 	Relation	rel;
 	Form_pg_event_trigger evtForm;
 
-	CheckEventTriggerPrivileges();
-
 	rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
 
 	/* newname must be available */
@@ -273,6 +266,9 @@ RenameEventTrigger(const char *trigname, const char *newname)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("event trigger \"%s\" does not exist", trigname)));
+    if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+                       trigname);
 
 	evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
 
@@ -344,22 +340,31 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 {
 	Form_pg_event_trigger form;
 
-	CheckEventTriggerPrivileges();
-
 	form = (Form_pg_event_trigger) GETSTRUCT(tup);
 
-	if (form->evtowner != newOwnerId)
-	{
-		form->evtowner = newOwnerId;
+	if (form->evtowner == newOwnerId)
+		return;
 
-		simple_heap_update(rel, &tup->t_self, tup);
-		CatalogUpdateIndexes(rel, tup);
+    if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
+                       NameStr(form->evtname));
 
-		/* Update owner dependency reference */
-		changeDependencyOnOwner(EventTriggerRelationId,
-								HeapTupleGetOid(tup),
-								newOwnerId);
-	}
+	/* New owner must be a superuser */
+	if (!superuser_arg(newOwnerId))
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied to change owner of event trigger \"%s\"",
+					NameStr(form->evtname)),
+				 errhint("The owner of an event trigger must be a superuser.")));
+
+	form->evtowner = newOwnerId;
+	simple_heap_update(rel, &tup->t_self, tup);
+	CatalogUpdateIndexes(rel, tup);
+
+	/* Update owner dependency reference */
+	changeDependencyOnOwner(EventTriggerRelationId,
+							HeapTupleGetOid(tup),
+							newOwnerId);
 }
 
 /*
@@ -412,14 +417,14 @@ call_event_trigger_procedure(EventContext ev_ctx, TrigEvent tev,
 	 * Prepare the event trigger function context from the Command Context.
 	 * We prepare a dedicated Node here so as not to publish internal data.
 	 */
-	trigdata.type		= T_EventTriggerData;
-	trigdata.toplevel	= ev_ctx->toplevel;
-	trigdata.tag		= ev_ctx->tag;
-	trigdata.objectId	= ev_ctx->objectId;
+	trigdata.type = T_EventTriggerData;
+	trigdata.toplevel = ev_ctx->toplevel;
+	trigdata.tag = ev_ctx->tag;
+	trigdata.objectId = ev_ctx->objectId;
 	trigdata.schemaname = ev_ctx->schemaname;
 	trigdata.objectname = ev_ctx->objectname;
-	trigdata.parsetree	= ev_ctx->parsetree;
-	trigdata.when       = pstrdup(event_to_string(tev));
+	trigdata.parsetree = ev_ctx->parsetree;
+	trigdata.when = pstrdup(event_to_string(tev));
 
 	/*
 	 * Call the function, passing no arguments but setting a context.
@@ -448,12 +453,6 @@ InitEventContext(EventContext evt, const Node *parsetree)
 	evt->objectname = NULL;
 	evt->schemaname = NULL;
 
-	/*
-	 * Fill in the event command, which is an enum constant to match against
-	 * what's stored into catalogs. As we are storing that on disk, we need the
-	 * enum values to be stable, see src/include/catalog/pg_event_trigger.h for
-	 * details.
-	 */
 	switch (nodeTag(parsetree))
 	{
 		case T_CreateSchemaStmt:
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ec5c8f8..068834b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -214,7 +214,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
 		CreateUserStmt CreateUserMappingStmt CreateRoleStmt
 		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
 		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
-		DropAssertStmt DropTrigStmt DropEventTrigStmt DropRuleStmt DropCastStmt
+		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
 		DropRoleStmt DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
 		DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
 		GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
@@ -755,7 +755,6 @@ stmt :
 			| DropStmt
 			| DropTableSpaceStmt
 			| DropTrigStmt
-			| DropEventTrigStmt
 			| DropRoleStmt
 			| DropUserStmt
 			| DropUserMappingStmt
@@ -4378,27 +4377,6 @@ trigger_command:
 		;
 
 
-DropEventTrigStmt:
-			DROP EVENT TRIGGER name opt_drop_behavior
-				{
-					DropStmt *n = makeNode(DropStmt);
-					n->removeType = OBJECT_EVENT_TRIGGER;
-					n->objects = list_make1(list_make1(makeString($4)));
-					n->behavior = $5;
-					n->missing_ok = false;
-					$$ = (Node *) n;
-				}
-			| DROP EVENT TRIGGER IF_P EXISTS name opt_drop_behavior
-				{
-					DropStmt *n = makeNode(DropStmt);
-					n->removeType = OBJECT_EVENT_TRIGGER;
-					n->objects = list_make1(list_make1(makeString($6)));
-					n->behavior = $7;
-					n->missing_ok = true;
-					$$ = (Node *) n;
-				}
-		;
-
 AlterEventTrigStmt:
 			ALTER EVENT TRIGGER name enable_trigger
 				{
@@ -5002,6 +4980,7 @@ drop_type:	TABLE									{ $$ = OBJECT_TABLE; }
 			| VIEW									{ $$ = OBJECT_VIEW; }
 			| INDEX									{ $$ = OBJECT_INDEX; }
 			| FOREIGN TABLE							{ $$ = OBJECT_FOREIGN_TABLE; }
+			| EVENT TRIGGER 						{ $$ = OBJECT_EVENT_TRIGGER; }
 			| TYPE_P								{ $$ = OBJECT_TYPE; }
 			| DOMAIN_P								{ $$ = OBJECT_DOMAIN; }
 			| COLLATION								{ $$ = OBJECT_COLLATION; }
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c8c1a81..b772f2b 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -356,7 +356,7 @@ standard_ProcessUtility(Node *parsetree,
 		completionTag[0] = '\0';
 
 	/* Event Trigger support for command_start */
-	InitEventContext(&evt, (Node *)parsetree);
+	InitEventContext(&evt, parsetree);
 	if (CommandFiresTriggersForEvent(&evt, E_CommandStart))
 		ExecEventTriggers(&evt, E_CommandStart);
 
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index d7770b8..8590f3c 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -293,6 +293,33 @@ trigger_out(PG_FUNCTION_ARGS)
 
 
 /*
+ * event_trigger_in	- input routine for pseudo-type event_trigger.
+ */
+Datum
+event_trigger_in(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type event_trigger")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * event_trigger_out - output routine for pseudo-type event_trigger.
+ */
+Datum
+event_trigger_out(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot display a value of type event_trigger")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+
+/*
  * language_handler_in		- input routine for pseudo-type LANGUAGE_HANDLER.
  */
 Datum
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bcd042e..09ca6dd 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5313,7 +5313,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 				i_oid,
 				i_evtname,
 				i_evtevent,
-                i_evtowner,
+				i_evtowner,
 				i_evttags,
 				i_evtfname,
 				i_evtenabled;
@@ -5333,7 +5333,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 					  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
 					  "evtevent, (%s evtowner) AS evtowner, "
 					  "array_to_string(array("
-					  "select '''' || x || '''' "
+					  "select quote_literal(x) "
 					  " from unnest(evttags) as t(x)), ', ') as evttags, "
 					  "e.evtfoid::regproc as evtfname "
 					  "FROM pg_event_trigger e "
@@ -13756,7 +13756,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 	appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
 	appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
 	appendPQExpBuffer(query, " ON ");
-	appendPQExpBufferStr(query, evtinfo->evtevent);
+	appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
 	appendPQExpBufferStr(query, " ");
 
 	if (strcmp("", evtinfo->evttags) != 0)
@@ -13768,7 +13768,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 
 	appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
 	appendPQExpBufferStr(query, evtinfo->evtfname);
-	appendPQExpBuffer(query, " ();\n");
+	appendPQExpBuffer(query, "();\n");
 
 	if (evtinfo->evtenabled != 'O')
 	{
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 6d4c2ba..5318e7a 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -24,8 +24,9 @@ static const char *modulename = gettext_noop("sorter");
  * Objects are sorted by priority levels, and within an equal priority level
  * by OID.	(This is a relatively crude hack to provide semi-reasonable
  * behavior for old databases without full dependency info.)  Note: collations,
- * extensions, text search, foreign-data, and default ACL objects can't really
- * happen here, so the rather bogus priorities for them don't matter.
+ * extensions, text search, foreign-data, event trigger, and default ACL
+ * objects can't really happen here, so the rather bogus priorities for them
+ * don't matter.
  *
  * NOTE: object-type priorities must match the section assignments made in
  * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
@@ -114,7 +115,7 @@ static const int newObjectTypePriority[] =
 	24,							/* DO_BLOB_DATA */
 	22,							/* DO_PRE_DATA_BOUNDARY */
 	25,							/* DO_POST_DATA_BOUNDARY */
-	30							/* DO_EVENT_TRIGGER */
+	32							/* DO_EVENT_TRIGGER */
 };
 
 static DumpId preDataBoundId;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bee7154..743f890 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3456,6 +3456,10 @@ DATA(insert OID = 2300 (  trigger_in		PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2
 DESCR("I/O");
 DATA(insert OID = 2301 (  trigger_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2279" _null_ _null_ _null_ _null_ trigger_out _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3594 (  event_trigger_in	PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 3838 "2275" _null_ _null_ _null_ _null_ event_trigger_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3595 (  event_trigger_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3838" _null_ _null_ _null_ _null_ event_trigger_out _null_ _null_ _null_ ));
+DESCR("I/O");
 DATA(insert OID = 2302 (  language_handler_in	PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2280 "2275" _null_ _null_ _null_ _null_ language_handler_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2303 (  language_handler_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "2280" _null_ _null_ _null_ _null_ language_handler_out _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 98c7dd5..86be998 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -650,7 +650,7 @@ DATA(insert OID = 2278 ( void			PGNSP PGUID  4 t p P f t \054 0 0 0 void_in void
 #define VOIDOID			2278
 DATA(insert OID = 2279 ( trigger		PGNSP PGUID  4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 #define TRIGGEROID		2279
-DATA(insert OID = 3838 ( event_trigger		PGNSP PGUID  4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3838 ( event_trigger		PGNSP PGUID  4 t p P f t \054 0 0 0 event_trigger_in event_trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 #define EVTTRIGGEROID		3838
 DATA(insert OID = 2280 ( language_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 #define LANGUAGE_HANDLEROID		2280
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 2d1cccb..5700e54 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -195,6 +195,7 @@ typedef enum AclObjectKind
 	ACL_KIND_TSCONFIGURATION,	/* pg_ts_config */
 	ACL_KIND_FDW,				/* pg_foreign_data_wrapper */
 	ACL_KIND_FOREIGN_SERVER,	/* pg_foreign_server */
+	ACL_KIND_EVENT_TRIGGER,		/* pg_event_trigger */
 	ACL_KIND_EXTENSION,			/* pg_extension */
 	MAX_ACL_KIND				/* MUST BE LAST */
 } AclObjectKind;
@@ -322,6 +323,7 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid);
 extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
 extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid);
 extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
+extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid);
 extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
 extern bool has_createrole_privilege(Oid roleid);
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 1063403..8b9291c 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -532,6 +532,8 @@ extern Datum void_recv(PG_FUNCTION_ARGS);
 extern Datum void_send(PG_FUNCTION_ARGS);
 extern Datum trigger_in(PG_FUNCTION_ARGS);
 extern Datum trigger_out(PG_FUNCTION_ARGS);
+extern Datum event_trigger_in(PG_FUNCTION_ARGS);
+extern Datum event_trigger_out(PG_FUNCTION_ARGS);
 extern Datum language_handler_in(PG_FUNCTION_ARGS);
 extern Datum language_handler_out(PG_FUNCTION_ARGS);
 extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 5b456aa..f772fd4 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1571,7 +1571,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo)
 }
 
 
-/* Set up the arguments for a command trigger call. */
+/* Set up the arguments for an event trigger call. */
 static SV  *
 plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
 {
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 77c5ed9..9d17686 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -536,7 +536,7 @@ do_compile(FunctionCallInfo fcinfo,
 				if (rettypeid == VOIDOID ||
 					rettypeid == RECORDOID)
 					 /* okay */ ;
-				else if (rettypeid == TRIGGEROID)
+				else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("trigger functions can only be called as triggers")));
@@ -689,7 +689,7 @@ do_compile(FunctionCallInfo fcinfo,
 			if (procStruct->pronargs != 0)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-						 errmsg("command trigger functions cannot have declared arguments")));
+						 errmsg("event trigger functions cannot have declared arguments")));
 
 			/* Add the variable tg_when */
 			var = plpgsql_build_variable("tg_when", 0,
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index fd59d75..373facf 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -773,8 +773,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
 	return rettup;
 }
 
-void plpgsql_exec_event_trigger(PLpgSQL_function *func,
-								EventTriggerData *trigdata)
+void
+plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
 {
 	PLpgSQL_execstate estate;
 	ErrorContextCallback plerrcontext;
diff --git a/src/test/regress/expected/event_triggers.out b/src/test/regress/expected/event_triggers.out
index 415605b..6eac7e9 100644
--- a/src/test/regress/expected/event_triggers.out
+++ b/src/test/regress/expected/event_triggers.out
@@ -10,9 +10,6 @@ begin
   raise notice 'snitch: % % %.%', tg_when, tg_tag, tg_schemaname, tg_objectname;
 end;
 $$;
---
--- TODO: REASSIGN OWNED and DROP OWNED
---
 create event trigger any_t on command_start
    execute procedure snitch();
 create event trigger foo_t on command_start
@@ -67,8 +64,12 @@ NOTICE:  snitch: command_start CREATE SCHEMA <NULL>.<NULL>
 create schema cmd2;
 NOTICE:  snitch: command_start CREATE SCHEMA <NULL>.<NULL>
 NOTICE:  snitch: command_start CREATE SCHEMA <NULL>.<NULL>
-create role regbob;
-alter event trigger snitch owner to regbob;
+create role regression_bob;
+alter event trigger snitch owner to regression_bob;
+ERROR:  permission denied to change owner of event trigger "snitch"
+HINT:  The owner of an event trigger must be a superuser.
+alter role regression_bob superuser;
+alter event trigger snitch owner to regression_bob;
 create table cmd.foo(id bigserial primary key);
 NOTICE:  snitch: command_start CREATE TABLE <NULL>.<NULL>
 NOTICE:  snitch: command_start CREATE TABLE <NULL>.<NULL>
@@ -158,7 +159,7 @@ NOTICE:  snitch: command_start ALTER TABLE <NULL>.<NULL>
 create sequence test_seq_;
 NOTICE:  snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
 NOTICE:  snitch: command_start CREATE SEQUENCE <NULL>.<NULL>
-alter sequence test_seq_ owner to regbob;
+alter sequence test_seq_ owner to regression_bob;
 NOTICE:  snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
 alter sequence test_seq_ rename to test_seq;
@@ -197,7 +198,7 @@ NOTICE:  snitch: command_start ALTER SEQUENCE <NULL>.<NULL>
 create view view_test as select id, things from cmd.test;
 NOTICE:  snitch: command_start CREATE VIEW <NULL>.<NULL>
 NOTICE:  snitch: command_start CREATE VIEW <NULL>.<NULL>
-alter view view_test owner to regbob;
+alter view view_test owner to regression_bob;
 NOTICE:  snitch: command_start ALTER VIEW <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER VIEW <NULL>.<NULL>
 alter view view_test rename to view_test2;
@@ -248,7 +249,7 @@ NOTICE:  snitch: command_start ALTER FUNCTION <NULL>.<NULL>
 alter function notfun(int) set schema cmd;
 NOTICE:  snitch: command_start ALTER FUNCTION <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER FUNCTION <NULL>.<NULL>
-alter function cmd.notfun(int) owner to regbob;
+alter function cmd.notfun(int) owner to regression_bob;
 NOTICE:  snitch: command_start ALTER FUNCTION <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER FUNCTION <NULL>.<NULL>
 alter function cmd.notfun(int) cost 77;
@@ -297,7 +298,7 @@ NOTICE:  snitch: command_start ALTER TYPE <NULL>.<NULL>
 create type cmd.type_test AS (a integer, b integer, c text);
 NOTICE:  snitch: command_start CREATE TYPE <NULL>.<NULL>
 NOTICE:  snitch: command_start CREATE TYPE <NULL>.<NULL>
-alter type cmd.type_test owner to regbob;
+alter type cmd.type_test owner to regression_bob;
 NOTICE:  snitch: command_start ALTER TYPE <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER TYPE <NULL>.<NULL>
 alter type cmd.type_test rename to type_test2;
@@ -349,7 +350,7 @@ NOTICE:  snitch: command_start ALTER DOMAIN <NULL>.<NULL>
 alter domain cmd.us_postal_code drop constraint dummy_constraint;
 NOTICE:  snitch: command_start ALTER DOMAIN <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER DOMAIN <NULL>.<NULL>
-alter domain cmd.us_postal_code owner to regbob;
+alter domain cmd.us_postal_code owner to regression_bob;
 NOTICE:  snitch: command_start ALTER DOMAIN <NULL>.<NULL>
 NOTICE:  snitch: command_start ALTER DOMAIN <NULL>.<NULL>
 alter domain cmd.us_postal_code set schema cmd2;
@@ -455,12 +456,14 @@ drop schema cmd2 cascade;
 NOTICE:  snitch: command_start DROP SCHEMA <NULL>.<NULL>
 NOTICE:  snitch: command_start DROP SCHEMA <NULL>.<NULL>
 -- fail because owning event trigger snitch
-drop role regbob;
-ERROR:  role "regbob" cannot be dropped because some objects depend on it
+drop role regression_bob;
+ERROR:  role "regression_bob" cannot be dropped because some objects depend on it
 DETAIL:  owner of event trigger snitch
 drop event trigger any_t;
-drop event trigger snitch;
-drop role regbob;
+drop event trigger if exists snitch;
+drop event trigger if exists snitch;
+NOTICE:  event trigger "snitch" does not exist, skipping
+drop role regression_bob;
 create table onerow(id integer);
 create or replace function insert_one_row()
  returns event_trigger
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 0dac40f..70eab92 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -134,11 +134,10 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
     (p1.typelem != 0 AND p1.typlen < 0) AND NOT
     (p2.prorettype = p1.oid AND NOT p2.proretset)
 ORDER BY 1;
- oid  |    typname    | oid  |  proname   
-------+---------------+------+------------
- 1790 | refcursor     |   46 | textin
- 3838 | event_trigger | 2300 | trigger_in
-(2 rows)
+ oid  |  typname  | oid | proname 
+------+-----------+-----+---------
+ 1790 | refcursor |  46 | textin
+(1 row)
 
 -- Varlena array types will point to array_in
 -- Exception as of 8.1: int2vector and oidvector have their own I/O routines
@@ -178,11 +177,10 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
       (p2.oid = 'array_out'::regproc AND
        p1.typelem != 0 AND p1.typlen = -1)))
 ORDER BY 1;
- oid  |    typname    | oid  |   proname   
-------+---------------+------+-------------
- 1790 | refcursor     |   47 | textout
- 3838 | event_trigger | 2301 | trigger_out
-(2 rows)
+ oid  |  typname  | oid | proname 
+------+-----------+-----+---------
+ 1790 | refcursor |  47 | textout
+(1 row)
 
 SELECT p1.oid, p1.typname, p2.oid, p2.proname
 FROM pg_type AS p1, pg_proc AS p2
diff --git a/src/test/regress/sql/event_triggers.sql b/src/test/regress/sql/event_triggers.sql
index cf25ee7..84a00e4 100644
--- a/src/test/regress/sql/event_triggers.sql
+++ b/src/test/regress/sql/event_triggers.sql
@@ -11,10 +11,6 @@ begin
 end;
 $$;
 
---
--- TODO: REASSIGN OWNED and DROP OWNED
---
-
 create event trigger any_t on command_start
    execute procedure snitch();
 
@@ -68,9 +64,11 @@ alter event trigger foo_t rename to snitch;
 
 create schema cmd;
 create schema cmd2;
-create role regbob;
 
-alter event trigger snitch owner to regbob;
+create role regression_bob;
+alter event trigger snitch owner to regression_bob;
+alter role regression_bob superuser;
+alter event trigger snitch owner to regression_bob;
 
 create table cmd.foo(id bigserial primary key);
 create view cmd.v as select * from cmd.foo;
@@ -103,7 +101,7 @@ alter table cmd.test set with oids;
 alter table cmd.test set without oids;
 
 create sequence test_seq_;
-alter sequence test_seq_ owner to regbob;
+alter sequence test_seq_ owner to regression_bob;
 alter sequence test_seq_ rename to test_seq;
 alter sequence test_seq set schema cmd;
 alter sequence cmd.test_seq start with 3;
@@ -117,7 +115,7 @@ alter sequence cmd.test_seq cycle;
 alter sequence cmd.test_seq no cycle;
 
 create view view_test as select id, things from cmd.test;
-alter view view_test owner to regbob;
+alter view view_test owner to regression_bob;
 alter view view_test rename to view_test2;
 alter view view_test2 set schema cmd;
 alter view cmd.view_test2 alter column id set default 9;
@@ -142,7 +140,7 @@ as $$ select t from cmd.foo where id = $1; $$;
 alter function fun(int) strict;
 alter function fun(int) rename to notfun;
 alter function notfun(int) set schema cmd;
-alter function cmd.notfun(int) owner to regbob;
+alter function cmd.notfun(int) owner to regression_bob;
 alter function cmd.notfun(int) cost 77;
 drop function cmd.notfun(int);
 
@@ -170,7 +168,7 @@ create type cmd.compfoo AS (f1 int, f2 text);
 alter type cmd.compfoo add attribute f3 text;
 
 create type cmd.type_test AS (a integer, b integer, c text);
-alter type cmd.type_test owner to regbob;
+alter type cmd.type_test owner to regression_bob;
 alter type cmd.type_test rename to type_test2;
 alter type cmd.type_test2 set schema public;
 alter type public.type_test2 rename attribute a to z;
@@ -191,7 +189,7 @@ alter domain cmd.us_postal_code drop default;
 alter domain cmd.us_postal_code drop not null;
 alter domain cmd.us_postal_code add constraint dummy_constraint check (value ~ '^\d{8}$');
 alter domain cmd.us_postal_code drop constraint dummy_constraint;
-alter domain cmd.us_postal_code owner to regbob;
+alter domain cmd.us_postal_code owner to regression_bob;
 alter domain cmd.us_postal_code set schema cmd2;
 drop domain cmd2.us_postal_code;
 
@@ -248,11 +246,12 @@ drop schema cmd1 cascade;
 drop schema cmd2 cascade;
 
 -- fail because owning event trigger snitch
-drop role regbob;
+drop role regression_bob;
 
 drop event trigger any_t;
-drop event trigger snitch;
-drop role regbob;
+drop event trigger if exists snitch;
+drop event trigger if exists snitch;
+drop role regression_bob;
 
 create table onerow(id integer);