[1mdiff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c[m
[1mindex d203725..2233158 100644[m
[1m--- a/src/backend/catalog/dependency.c[m
[1m+++ b/src/backend/catalog/dependency.c[m
[36m@@ -267,6 +267,12 @@[m [mperformDeletion(const ObjectAddress *object,[m
 	{[m
 		ObjectAddress *thisobj = targetObjects->refs + i;[m
 [m
[32m+[m		[32mif ((!(flags & PERFORM_DELETION_INTERNAL)) &&[m
[32m+[m			[32mEventTriggerSupportsObjectType(getObjectClass(thisobj)))[m
[32m+[m		[32m{[m
[32m+[m			[32mevtrig_sqldrop_add_object(thisobj);[m
[32m+[m		[32m}[m
[32m+[m
 		deleteOneObject(thisobj, &depRel, flags);[m
 	}[m
 [m
[36m@@ -349,6 +355,12 @@[m [mperformMultipleDeletions(const ObjectAddresses *objects,[m
 	{[m
 		ObjectAddress *thisobj = targetObjects->refs + i;[m
 [m
[32m+[m		[32mif ((!(flags & PERFORM_DELETION_INTERNAL)) &&[m
[32m+[m			[32mEventTriggerSupportsObjectType(getObjectClass(thisobj)))[m
[32m+[m		[32m{[m
[32m+[m			[32mevtrig_sqldrop_add_object(thisobj);[m
[32m+[m		[32m}[m
[32m+[m
 		deleteOneObject(thisobj, &depRel, flags);[m
 	}[m
 [m
[36m@@ -366,6 +378,10 @@[m [mperformMultipleDeletions(const ObjectAddresses *objects,[m
  * This is currently used only to clean out the contents of a schema[m
  * (namespace): the passed object is a namespace.  We normally want this[m
  * to be done silently, so there's an option to suppress NOTICE messages.[m
[32m+[m[32m *[m
[32m+[m[32m * Note we don't fire object drop event triggers here; it would be wrong to do[m
[32m+[m[32m * so for the current only use of this function, but if more callers are added[m
[32m+[m[32m * this might need to be reconsidered.[m
  */[m
 void[m
 deleteWhatDependsOn(const ObjectAddress *object,[m
[1mdiff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c[m
[1mindex 269d19c..347c405 100644[m
[1m--- a/src/backend/commands/alter.c[m
[1m+++ b/src/backend/commands/alter.c[m
[36m@@ -746,58 +746,6 @@[m [mExecAlterOwnerStmt(AlterOwnerStmt *stmt)[m
 }[m
 [m
 /*[m
[31m- * Return a copy of the tuple for the object with the given object OID, from[m
[31m- * the given catalog (which must have been opened by the caller and suitably[m
[31m- * locked).  NULL is returned if the OID is not found.[m
[31m- *[m
[31m- * We try a syscache first, if available.[m
[31m- *[m
[31m- * XXX this function seems general in possible usage.  Given sufficient callers[m
[31m- * elsewhere, we should consider moving it to a more appropriate place.[m
[31m- */[m
[31m-static HeapTuple[m
[31m-get_catalog_object_by_oid(Relation catalog, Oid objectId)[m
[31m-{[m
[31m-	HeapTuple	tuple;[m
[31m-	Oid			classId = RelationGetRelid(catalog);[m
[31m-	int			oidCacheId = get_object_catcache_oid(classId);[m
[31m-[m
[31m-	if (oidCacheId > 0)[m
[31m-	{[m
[31m-		tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));[m
[31m-		if (!HeapTupleIsValid(tuple))  /* should not happen */[m
[31m-			return NULL;[m
[31m-	}[m
[31m-	else[m
[31m-	{[m
[31m-		Oid			oidIndexId = get_object_oid_index(classId);[m
[31m-		SysScanDesc	scan;[m
[31m-		ScanKeyData	skey;[m
[31m-[m
[31m-		Assert(OidIsValid(oidIndexId));[m
[31m-[m
[31m-		ScanKeyInit(&skey,[m
[31m-					ObjectIdAttributeNumber,[m
[31m-					BTEqualStrategyNumber, F_OIDEQ,[m
[31m-					ObjectIdGetDatum(objectId));[m
[31m-[m
[31m-		scan = systable_beginscan(catalog, oidIndexId, true,[m
[31m-								  SnapshotNow, 1, &skey);[m
[31m-		tuple = systable_getnext(scan);[m
[31m-		if (!HeapTupleIsValid(tuple))[m
[31m-		{[m
[31m-			systable_endscan(scan);[m
[31m-			return NULL;[m
[31m-		}[m
[31m-		tuple = heap_copytuple(tuple);[m
[31m-[m
[31m-		systable_endscan(scan);[m
[31m-	}[m
[31m-[m
[31m-	return tuple;[m
[31m-}[m
[31m-[m
[31m-/*[m
  * Generic function to change the ownership of a given object, for simple[m
  * cases (won't work for tables, nor other cases where we need to do more than[m
  * change the ownership column of a single catalog entry).[m
[1mdiff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c[m
[1mindex 18b3753..66f5005 100644[m
[1m--- a/src/backend/commands/event_trigger.c[m
[1m+++ b/src/backend/commands/event_trigger.c[m
[36m@@ -25,6 +25,7 @@[m
 #include "commands/dbcommands.h"[m
 #include "commands/event_trigger.h"[m
 #include "commands/trigger.h"[m
[32m+[m[32m#include "funcapi.h"[m
 #include "parser/parse_func.h"[m
 #include "pgstat.h"[m
 #include "miscadmin.h"[m
[36m@@ -39,6 +40,10 @@[m
 #include "utils/syscache.h"[m
 #include "tcop/utility.h"[m
 [m
[32m+[m[32m/* Globally visible state variables */[m
[32m+[m[32mbool evtrig_sqldrop_inprogress = false;[m
[32m+[m[32mslist_head	SQLDropList = SLIST_STATIC_INIT(SQLDropList);[m
[32m+[m
 typedef struct[m
 {[m
 	const char	   *obtypename;[m
[36m@@ -88,6 +93,15 @@[m [mstatic event_trigger_support_data event_trigger_support[] = {[m
 	{ NULL, false }[m
 };[m
 [m
[32m+[m[32m/* Support for dropped objects */[m
[32m+[m[32mtypedef struct SQLDropObject[m
[32m+[m[32m{[m
[32m+[m	[32mObjectAddress	address;[m
[32m+[m	[32mchar		   *objname;[m
[32m+[m	[32mchar		   *schemaname;[m
[32m+[m	[32mslist_node		next;[m
[32m+[m[32m} SQLDropObject;[m
[32m+[m
 static void AlterEventTriggerOwner_internal(Relation rel,[m
 											HeapTuple tup,[m
 											Oid newOwnerId);[m
[36m@@ -150,8 +164,12 @@[m [mCreateEventTrigger(CreateEventTrigStmt *stmt)[m
 	}[m
 [m
 	/* Validate tag list, if any. */[m
[31m-	if (strcmp(stmt->eventname, "ddl_command_start") == 0 && tags != NULL)[m
[32m+[m	[32mif ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||[m
[32m+[m		[32m strcmp(stmt->eventname, "ddl_command_end") == 0)[m
[32m+[m		[32m&& tags != NULL)[m
[32m+[m	[32m{[m
 		validate_ddl_tags("tag", tags);[m
[32m+[m	[32m}[m
 [m
 	/*[m
 	 * Give user a nice error message if an event trigger of the same name[m
[36m@@ -218,7 +236,8 @@[m [mcheck_ddl_tag(const char *tag)[m
 	if (pg_strcasecmp(tag, "CREATE TABLE AS") == 0 ||[m
 		pg_strcasecmp(tag, "SELECT INTO") == 0 ||[m
 		pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||[m
[31m-		pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0)[m
[32m+[m		[32mpg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||[m
[32m+[m		[32mpg_strcasecmp(tag, "DROP OWNED") == 0)[m
 		return EVENT_TRIGGER_COMMAND_TAG_OK;[m
 [m
 	/*[m
[36m@@ -825,3 +844,202 @@[m [mEventTriggerSupportsObjectType(ObjectType obtype)[m
 	}[m
 	return true;[m
 }[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * Support for dropped objects information on event trigger functions.[m
[32m+[m[32m *[m
[32m+[m[32m * We keep the list of objects dropped by the current command in a list of[m
[32m+[m[32m * these structs.  Each command that might drop objects saves the current[m
[32m+[m[32m * list in a local variable, initialize a new empty list and do the dependency.c[m
[32m+[m[32m * dance to drop objects, which populates the list; when the event triggers are[m
[32m+[m[32m * invoked they can consume the list via pg_event_trigger_dropped_objects().[m
[32m+[m[32m * When the command finishes, the list is cleared and the original list is[m
[32m+[m[32m * restored.  This is to support the case that an event trigger function drops[m
[32m+[m[32m * objects "reentrantly".[m
[32m+[m[32m *[m
[32m+[m[32m * For each object dropped, we save the below info, which can be obtained as a[m
[32m+[m[32m * set via the pg_event_trigger_dropped_objects() SQL-callable function.[m
[32m+[m[32m */[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * Initialize state of objects dropped[m
[32m+[m[32m */[m
[32m+[m[32mvoid[m
[32m+[m[32mEventTriggerInitializeDrop(bool *save_inprogress, slist_head *save_objlist)[m
[32m+[m[32m{[m
[32m+[m	[32m/* save previous state in local vars of caller, for later restore */[m
[32m+[m	[32m*save_inprogress = evtrig_sqldrop_inprogress;[m
[32m+[m	[32m*save_objlist = SQLDropList;[m
[32m+[m
[32m+[m	[32mevtrig_sqldrop_inprogress = true;[m
[32m+[m	[32mslist_init(&SQLDropList);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * Restore state after running a command that drops objects; free memory from a[m
[32m+[m[32m * list we may have created.[m
[32m+[m[32m */[m
[32m+[m[32mvoid[m
[32m+[m[32mEventTriggerFinalizeDrop(bool save_inprogress, slist_head save_objlist)[m
[32m+[m[32m{[m
[32m+[m	[32mslist_mutable_iter	iter;[m
[32m+[m
[32m+[m	[32mslist_foreach_modify(iter, &SQLDropList)[m
[32m+[m	[32m{[m
[32m+[m		[32mSQLDropObject  *obj = slist_container(SQLDropObject, next, iter.cur);[m
[32m+[m
[32m+[m		[32mif (obj->objname)[m
[32m+[m			[32mpfree(obj->objname);[m
[32m+[m		[32mif (obj->schemaname)[m
[32m+[m			[32mpfree(obj->schemaname);[m
[32m+[m		[32mpfree(obj);[m
[32m+[m	[32m}[m
[32m+[m
[32m+[m	[32mevtrig_sqldrop_inprogress = save_inprogress;[m
[32m+[m	[32mSQLDropList = save_objlist;[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * Register one object as being dropped by the current command.[m
[32m+[m[32m *[m
[32m+[m[32m * XXX do we need to think about memory context these things are stored in?[m
[32m+[m[32m */[m
[32m+[m[32mvoid[m
[32m+[m[32mevtrig_sqldrop_add_object(ObjectAddress *object)[m
[32m+[m[32m{[m
[32m+[m	[32mSQLDropObject  *obj;[m
[32m+[m	[32mHeapTuple	tuple;[m
[32m+[m	[32mRelation	catalog;[m
[32m+[m
[32m+[m	[32mAssert(EventTriggerSupportsObjectType(getObjectClass(object)));[m
[32m+[m
[32m+[m	[32mobj = palloc0(sizeof(SQLDropObject));[m
[32m+[m	[32mobj->address = *object;[m
[32m+[m
[32m+[m	[32m/*[m
[32m+[m	[32m * Obtain object and schema names from the object's catalog tuple, if one[m
[32m+[m	[32m * exists.[m
[32m+[m	[32m */[m
[32m+[m	[32mcatalog = heap_open(obj->address.classId, AccessShareLock);[m
[32m+[m	[32mtuple = get_catalog_object_by_oid(catalog, obj->address.objectId);[m
[32m+[m	[32mif (tuple)[m
[32m+[m	[32m{[m
[32m+[m		[32mAttrNumber	attnum;[m
[32m+[m		[32mDatum		datum;[m
[32m+[m		[32mbool		isnull;[m
[32m+[m
[32m+[m		[32mattnum = get_object_attnum_name(obj->address.classId);[m
[32m+[m		[32mif (attnum != InvalidAttrNumber)[m
[32m+[m		[32m{[m
[32m+[m			[32mdatum = heap_getattr(tuple, attnum,[m
[32m+[m								[32m RelationGetDescr(catalog), &isnull);[m
[32m+[m			[32mif (!isnull)[m
[32m+[m				[32mobj->objname = pstrdup(NameStr(*DatumGetName(datum)));[m
[32m+[m		[32m}[m
[32m+[m
[32m+[m		[32mattnum = get_object_attnum_namespace(obj->address.classId);[m
[32m+[m		[32mif (attnum != InvalidAttrNumber)[m
[32m+[m		[32m{[m
[32m+[m			[32mdatum = heap_getattr(tuple, attnum,[m
[32m+[m								[32m RelationGetDescr(catalog), &isnull);[m
[32m+[m			[32mif (!isnull)[m
[32m+[m				[32mobj->schemaname = get_namespace_name(DatumGetObjectId(datum));[m
[32m+[m		[32m}[m
[32m+[m	[32m}[m
[32m+[m
[32m+[m	[32mheap_close(catalog, AccessShareLock);[m
[32m+[m
[32m+[m	[32mslist_push_head(&SQLDropList, &obj->next);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * pg_event_trigger_dropped_objects[m
[32m+[m[32m *[m
[32m+[m[32m * Make the list of dropped objects available to the user function run by the[m
[32m+[m[32m * Event Trigger.[m
[32m+[m[32m */[m
[32m+[m[32mDatum[m
[32m+[m[32mpg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)[m
[32m+[m[32m{[m
[32m+[m	[32mReturnSetInfo	   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;[m
[32m+[m	[32mTupleDesc			tupdesc;[m
[32m+[m	[32mTuplestorestate	   *tupstore;[m
[32m+[m	[32mMemoryContext		per_query_ctx;[m
[32m+[m	[32mMemoryContext		oldcontext;[m
[32m+[m	[32mslist_iter			iter;[m
[32m+[m
[32m+[m	[32m/*[m
[32m+[m	[32m * This function is meant to be called from within an event trigger in[m
[32m+[m	[32m * order to get the list of objects dropped, if any.[m
[32m+[m	[32m */[m
[32m+[m	[32mif (!evtrig_sqldrop_inprogress)[m
[32m+[m		[32mereport(ERROR,[m
[32m+[m				[32m(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),[m
[32m+[m				[32m errmsg("%s can only be called from an event trigger function",[m
[32m+[m						[32m"pg_event_trigger_dropped_objects()")));[m
[32m+[m
[32m+[m	[32m/* check to see if caller supports us returning a tuplestore */[m
[32m+[m	[32mif (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))[m
[32m+[m		[32mereport(ERROR,[m
[32m+[m				[32m(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),[m
[32m+[m				[32m errmsg("set-valued function called in context that cannot accept a set")));[m
[32m+[m	[32mif (!(rsinfo->allowedModes & SFRM_Materialize))[m
[32m+[m		[32mereport(ERROR,[m
[32m+[m				[32m(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),[m
[32m+[m				[32m errmsg("materialize mode required, but it is not allowed in this context")));[m
[32m+[m
[32m+[m	[32m/* Build a tuple descriptor for our result type */[m
[32m+[m	[32mif (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)[m
[32m+[m		[32melog(ERROR, "return type must be a row type");[m
[32m+[m
[32m+[m	[32m/* Build tuplestore to hold the result rows */[m
[32m+[m	[32mper_query_ctx = rsinfo->econtext->ecxt_per_query_memory;[m
[32m+[m	[32moldcontext = MemoryContextSwitchTo(per_query_ctx);[m
[32m+[m
[32m+[m	[32mtupstore = tuplestore_begin_heap(true, false, work_mem);[m
[32m+[m	[32mrsinfo->returnMode = SFRM_Materialize;[m
[32m+[m	[32mrsinfo->setResult = tupstore;[m
[32m+[m	[32mrsinfo->setDesc = tupdesc;[m
[32m+[m
[32m+[m	[32mMemoryContextSwitchTo(oldcontext);[m
[32m+[m
[32m+[m	[32mslist_foreach(iter, &SQLDropList)[m
[32m+[m	[32m{[m
[32m+[m		[32mSQLDropObject *obj;[m
[32m+[m		[32mDatum		values[5];[m
[32m+[m		[32mbool		nulls[5];[m
[32m+[m
[32m+[m		[32mobj = slist_container(SQLDropObject, next, iter.cur);[m
[32m+[m
[32m+[m		[32mMemSet(values, 0, sizeof(values));[m
[32m+[m		[32mMemSet(nulls, 0, sizeof(nulls));[m
[32m+[m
[32m+[m		[32m/* classid */[m
[32m+[m		[32mvalues[0] = ObjectIdGetDatum(obj->address.classId);[m
[32m+[m
[32m+[m		[32m/* objid */[m
[32m+[m		[32mvalues[1] = ObjectIdGetDatum(obj->address.objectId);[m
[32m+[m
[32m+[m		[32m/* objsubid */[m
[32m+[m		[32mvalues[2] = Int32GetDatum(obj->address.objectSubId);[m
[32m+[m
[32m+[m		[32m/* objname */[m
[32m+[m		[32mif (obj->objname)[m
[32m+[m			[32mvalues[3] = CStringGetTextDatum(obj->objname);[m
[32m+[m		[32melse[m
[32m+[m			[32mnulls[3] = true;[m
[32m+[m
[32m+[m		[32m/* schemaname */[m
[32m+[m		[32mif (obj->schemaname)[m
[32m+[m			[32mvalues[4] = CStringGetTextDatum(obj->objname);[m
[32m+[m		[32melse[m
[32m+[m			[32mnulls[4] = true;[m
[32m+[m
[32m+[m		[32mtuplestore_putvalues(tupstore, tupdesc, values, nulls);[m
[32m+[m	[32m}[m
[32m+[m
[32m+[m	[32m/* clean up and return the tuplestore */[m
[32m+[m	[32mtuplestore_donestoring(tupstore);[m
[32m+[m
[32m+[m	[32mreturn (Datum) 0;[m
[32m+[m[32m}[m
[1mdiff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c[m
[1mindex 8904c6f..e30fe42 100644[m
[1m--- a/src/backend/tcop/utility.c[m
[1m+++ b/src/backend/tcop/utility.c[m
[36m@@ -697,33 +697,60 @@[m [mstandard_ProcessUtility(Node *parsetree,[m
 		case T_DropStmt:[m
 			{[m
 				DropStmt   *stmt = (DropStmt *) parsetree;[m
[32m+[m				[32mbool		save_inprogress;[m
[32m+[m				[32mslist_head	save_objlist;[m
 [m
[31m-				if (isCompleteQuery[m
[31m-					&& EventTriggerSupportsObjectType(stmt->removeType))[m
[32m+[m				[32m/*[m
[32m+[m				[32m * don't run any event trigger when we require not to have open[m
[32m+[m				[32m * a transaction[m
[32m+[m				[32m */[m
[32m+[m				[32mif (stmt->removeType == OBJECT_INDEX && stmt->concurrent)[m
[32m+[m					[32mPreventTransactionChain(isTopLevel,[m
[32m+[m											[32m"DROP INDEX CONCURRENTLY");[m
[32m+[m
[32m+[m				[32mif (isCompleteQuery &&[m
[32m+[m					[32mEventTriggerSupportsObjectType(stmt->removeType))[m
[32m+[m				[32m{[m
 					EventTriggerDDLCommandStart(parsetree);[m
 [m
[31m-				switch (stmt->removeType)[m
[32m+[m					[32mEventTriggerInitializeDrop(&save_inprogress, &save_objlist);[m
[32m+[m				[32m}[m
[32m+[m
[32m+[m				[32mPG_TRY();[m
 				{[m
[31m-					case OBJECT_INDEX:[m
[31m-						if (stmt->concurrent)[m
[31m-							PreventTransactionChain(isTopLevel,[m
[31m-													"DROP INDEX CONCURRENTLY");[m
[31m-						/* fall through */[m
[32m+[m					[32mswitch (stmt->removeType)[m
[32m+[m					[32m{[m
[32m+[m						[32mcase OBJECT_INDEX:[m
[32m+[m						[32mcase OBJECT_TABLE:[m
[32m+[m						[32mcase OBJECT_SEQUENCE:[m
[32m+[m						[32mcase OBJECT_VIEW:[m
[32m+[m						[32mcase OBJECT_FOREIGN_TABLE:[m
[32m+[m							[32mRemoveRelations((DropStmt *) parsetree);[m
[32m+[m							[32mbreak;[m
[32m+[m						[32mdefault:[m
[32m+[m							[32mRemoveObjects((DropStmt *) parsetree);[m
[32m+[m							[32mbreak;[m
[32m+[m					[32m}[m
 [m
[31m-					case OBJECT_TABLE:[m
[31m-					case OBJECT_SEQUENCE:[m
[31m-					case OBJECT_VIEW:[m
[31m-					case OBJECT_FOREIGN_TABLE:[m
[31m-						RemoveRelations((DropStmt *) parsetree);[m
[31m-						break;[m
[31m-					default:[m
[31m-						RemoveObjects((DropStmt *) parsetree);[m
[31m-						break;[m
[32m+[m					[32mif (isCompleteQuery[m
[32m+[m						[32m&& EventTriggerSupportsObjectType(stmt->removeType))[m
[32m+[m					[32m{[m
[32m+[m						[32mEventTriggerDDLCommandEnd(parsetree);[m
[32m+[m					[32m}[m
[32m+[m				[32m}[m
[32m+[m				[32mPG_CATCH();[m
[32m+[m				[32m{[m
[32m+[m					[32mif (isCompleteQuery[m
[32m+[m						[32m&& EventTriggerSupportsObjectType(stmt->removeType))[m
[32m+[m						[32mEventTriggerFinalizeDrop(save_inprogress, save_objlist);[m
[32m+[m
[32m+[m					[32mPG_RE_THROW();[m
 				}[m
[32m+[m				[32mPG_END_TRY();[m
 [m
 				if (isCompleteQuery[m
 					&& EventTriggerSupportsObjectType(stmt->removeType))[m
[31m-					EventTriggerDDLCommandEnd(parsetree);[m
[32m+[m					[32mEventTriggerFinalizeDrop(save_inprogress, save_objlist);[m
 [m
 				break;[m
 			}[m
[36m@@ -1238,9 +1265,37 @@[m [mstandard_ProcessUtility(Node *parsetree,[m
 			break;[m
 [m
 		case T_DropOwnedStmt:[m
[31m-			/* no event triggers for global objects */[m
[31m-			DropOwnedObjects((DropOwnedStmt *) parsetree);[m
[31m-			break;[m
[32m+[m			[32m{[m
[32m+[m				[32mbool	save_inprogress;[m
[32m+[m				[32mslist_head save_objlist;[m
[32m+[m
[32m+[m				[32mif (isCompleteQuery)[m
[32m+[m				[32m{[m
[32m+[m					[32mEventTriggerDDLCommandStart(parsetree);[m
[32m+[m
[32m+[m					[32mEventTriggerInitializeDrop(&save_inprogress, &save_objlist);[m
[32m+[m				[32m}[m
[32m+[m
[32m+[m				[32mPG_TRY();[m
[32m+[m				[32m{[m
[32m+[m					[32mDropOwnedObjects((DropOwnedStmt *) parsetree);[m
[32m+[m
[32m+[m					[32mif (isCompleteQuery)[m
[32m+[m						[32mEventTriggerDDLCommandEnd(parsetree);[m
[32m+[m				[32m}[m
[32m+[m				[32mPG_CATCH();[m
[32m+[m				[32m{[m
[32m+[m					[32mif (isCompleteQuery)[m
[32m+[m						[32mEventTriggerFinalizeDrop(save_inprogress, save_objlist);[m
[32m+[m					[32mPG_RE_THROW();[m
[32m+[m				[32m}[m
[32m+[m				[32mPG_END_TRY();[m
[32m+[m
[32m+[m				[32mif (isCompleteQuery)[m
[32m+[m					[32mEventTriggerFinalizeDrop(save_inprogress, save_objlist);[m
[32m+[m
[32m+[m				[32mbreak;[m
[32m+[m			[32m}[m
 [m
 		case T_ReassignOwnedStmt:[m
 			/* no event triggers for global objects */[m
[1mdiff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c[m
[1mindex 5865962..7f25de4 100644[m
[1m--- a/src/backend/utils/cache/lsyscache.c[m
[1m+++ b/src/backend/utils/cache/lsyscache.c[m
[36m@@ -18,6 +18,7 @@[m
 #include "access/hash.h"[m
 #include "access/htup_details.h"[m
 #include "access/nbtree.h"[m
[32m+[m[32m#include "access/sysattr.h"[m
 #include "bootstrap/bootstrap.h"[m
 #include "catalog/pg_amop.h"[m
 #include "catalog/pg_amproc.h"[m
[36m@@ -40,6 +41,7 @@[m
 #include "utils/lsyscache.h"[m
 #include "utils/rel.h"[m
 #include "utils/syscache.h"[m
[32m+[m[32m#include "utils/tqual.h"[m
 #include "utils/typcache.h"[m
 [m
 /* Hook for plugins to get control in get_attavgwidth() */[m
[36m@@ -2926,3 +2928,54 @@[m [mget_range_subtype(Oid rangeOid)[m
 	else[m
 		return InvalidOid;[m
 }[m
[32m+[m
[32m+[m[32m/*				------------- GENERIC --------------				 */[m
[32m+[m
[32m+[m[32m/*[m
[32m+[m[32m * Return a copy of the tuple for the object with the given object OID, from[m
[32m+[m[32m * the given catalog (which must have been opened by the caller and suitably[m
[32m+[m[32m * locked).  NULL is returned if the OID is not found.[m
[32m+[m[32m *[m
[32m+[m[32m * We try a syscache first, if available.[m
[32m+[m[32m */[m
[32m+[m[32mHeapTuple[m
[32m+[m[32mget_catalog_object_by_oid(Relation catalog, Oid objectId)[m
[32m+[m[32m{[m
[32m+[m	[32mHeapTuple	tuple;[m
[32m+[m	[32mOid			classId = RelationGetRelid(catalog);[m
[32m+[m	[32mint			oidCacheId = get_object_catcache_oid(classId);[m
[32m+[m
[32m+[m	[32mif (oidCacheId > 0)[m
[32m+[m	[32m{[m
[32m+[m		[32mtuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));[m
[32m+[m		[32mif (!HeapTupleIsValid(tuple))  /* should not happen */[m
[32m+[m			[32mreturn NULL;[m
[32m+[m	[32m}[m
[32m+[m	[32melse[m
[32m+[m	[32m{[m
[32m+[m		[32mOid			oidIndexId = get_object_oid_index(classId);[m
[32m+[m		[32mSysScanDesc	scan;[m
[32m+[m		[32mScanKeyData	skey;[m
[32m+[m
[32m+[m		[32mAssert(OidIsValid(oidIndexId));[m
[32m+[m
[32m+[m		[32mScanKeyInit(&skey,[m
[32m+[m					[32mObjectIdAttributeNumber,[m
[32m+[m					[32mBTEqualStrategyNumber, F_OIDEQ,[m
[32m+[m					[32mObjectIdGetDatum(objectId));[m
[32m+[m
[32m+[m		[32mscan = systable_beginscan(catalog, oidIndexId, true,[m
[32m+[m								[32m  SnapshotNow, 1, &skey);[m
[32m+[m		[32mtuple = systable_getnext(scan);[m
[32m+[m		[32mif (!HeapTupleIsValid(tuple))[m
[32m+[m		[32m{[m
[32m+[m			[32msystable_endscan(scan);[m
[32m+[m			[32mreturn NULL;[m
[32m+[m		[32m}[m
[32m+[m		[32mtuple = heap_copytuple(tuple);[m
[32m+[m
[32m+[m		[32msystable_endscan(scan);[m
[32m+[m	[32m}[m
[32m+[m
[32m+[m	[32mreturn tuple;[m
[32m+[m[32m}[m
[1mdiff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h[m
[1mindex d9f50d2..6b7d4a6 100644[m
[1m--- a/src/include/catalog/pg_proc.h[m
[1m+++ b/src/include/catalog/pg_proc.h[m
[36m@@ -4679,7 +4679,9 @@[m [mDESCR("SP-GiST support for quad tree over range");[m
 DATA(insert OID = 3473 (  spg_range_quad_leaf_consistent	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_  spg_range_quad_leaf_consistent _null_ _null_ _null_ ));[m
 DESCR("SP-GiST support for quad tree over range");[m
 [m
[31m-[m
[32m+[m[32m/* event triggers */[m
[32m+[m[32mDATA(insert OID = 3566 (  pg_event_trigger_dropped_objects		PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,26,25,25}" "{o,o,o,o,0}" "{classid, objid, objsubid, objname, schemaname}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));[m
[32m+[m[32mDESCR("list an extension's version update paths");[m
 /*[m
  * Symbolic values for provolatile column: these indicate whether the result[m
  * of a function is dependent *only* on the values of its explicit arguments,[m
[1mdiff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h[m
[1mindex 74c150b..2e7d815 100644[m
[1m--- a/src/include/commands/event_trigger.h[m
[1m+++ b/src/include/commands/event_trigger.h[m
[36m@@ -13,7 +13,10 @@[m
 #ifndef EVENT_TRIGGER_H[m
 #define EVENT_TRIGGER_H[m
 [m
[32m+[m[32m#include "catalog/dependency.h"[m
[32m+[m[32m#include "catalog/objectaddress.h"[m
 #include "catalog/pg_event_trigger.h"[m
[32m+[m[32m#include "lib/ilist.h"[m
 #include "nodes/parsenodes.h"[m
 [m
 typedef struct EventTriggerData[m
[36m@@ -43,4 +46,10 @@[m [mextern bool EventTriggerSupportsObjectType(ObjectType obtype);[m
 extern void EventTriggerDDLCommandStart(Node *parsetree);[m
 extern void EventTriggerDDLCommandEnd(Node *parsetree);[m
 [m
[32m+[m[32mextern void EventTriggerInitializeDrop(bool *save_inprogress,[m
[32m+[m						[32m   slist_head *save_objlist);[m
[32m+[m[32mextern void EventTriggerFinalizeDrop(bool save_inprogress,[m
[32m+[m						[32m slist_head save_objlist);[m
[32m+[m[32mextern void evtrig_sqldrop_add_object(ObjectAddress *object);[m
[32m+[m
 #endif   /* EVENT_TRIGGER_H */[m
[1mdiff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h[m
[1mindex 533539c..d51b829 100644[m
[1m--- a/src/include/utils/builtins.h[m
[1m+++ b/src/include/utils/builtins.h[m
[36m@@ -1146,6 +1146,9 @@[m [mextern Datum pg_describe_object(PG_FUNCTION_ARGS);[m
 /* commands/constraint.c */[m
 extern Datum unique_key_recheck(PG_FUNCTION_ARGS);[m
 [m
[32m+[m[32m/* commands/event_trigger.c */[m
[32m+[m[32mextern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS);[m
[32m+[m
 /* commands/extension.c */[m
 extern Datum pg_available_extensions(PG_FUNCTION_ARGS);[m
 extern Datum pg_available_extension_versions(PG_FUNCTION_ARGS);[m
[1mdiff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h[m
[1mindex 49f459a..dfa6eb7 100644[m
[1m--- a/src/include/utils/lsyscache.h[m
[1m+++ b/src/include/utils/lsyscache.h[m
[36m@@ -16,6 +16,7 @@[m
 #include "access/attnum.h"[m
 #include "access/htup.h"[m
 #include "nodes/pg_list.h"[m
[32m+[m[32m#include "utils/relcache.h"[m
 [m
 /* Result list element for get_op_btree_interpretation */[m
 typedef struct OpBtreeInterpretation[m
[36m@@ -152,6 +153,7 @@[m [mextern void free_attstatsslot(Oid atttype,[m
 				  float4 *numbers, int nnumbers);[m
 extern char *get_namespace_name(Oid nspid);[m
 extern Oid	get_range_subtype(Oid rangeOid);[m
[32m+[m[32mextern HeapTuple get_catalog_object_by_oid(Relation catalog, Oid objectId);[m
 [m
 #define type_is_array(typid)  (get_element_type(typid) != InvalidOid)[m
 /* type_is_array_domain accepts both plain arrays and domains over arrays */[m
