*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 198,203 **** static bool stack_address_present_add_flags(const ObjectAddress *object,
--- 198,204 ----
ObjectAddressStack *stack);
static void getRelationDescription(StringInfo buffer, Oid relid);
static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
+ static void getRelationTypeDescription(StringInfo buffer, Oid relid);
/*
***************
*** 267,272 **** performDeletion(const ObjectAddress *object,
--- 268,279 ----
{
ObjectAddress *thisobj = targetObjects->refs + i;
+ if ((!(flags & PERFORM_DELETION_INTERNAL)) &&
+ EventTriggerSupportsObjectType(getObjectClass(thisobj)))
+ {
+ evtrig_sqldrop_add_object(thisobj);
+ }
+
deleteOneObject(thisobj, &depRel, flags);
}
***************
*** 349,354 **** performMultipleDeletions(const ObjectAddresses *objects,
--- 356,367 ----
{
ObjectAddress *thisobj = targetObjects->refs + i;
+ if ((!(flags & PERFORM_DELETION_INTERNAL)) &&
+ EventTriggerSupportsObjectType(getObjectClass(thisobj)))
+ {
+ evtrig_sqldrop_add_object(thisobj);
+ }
+
deleteOneObject(thisobj, &depRel, flags);
}
***************
*** 366,371 **** performMultipleDeletions(const ObjectAddresses *objects,
--- 379,388 ----
* This is currently used only to clean out the contents of a schema
* (namespace): the passed object is a namespace. We normally want this
* to be done silently, so there's an option to suppress NOTICE messages.
+ *
+ * Note we don't fire object drop event triggers here; it would be wrong to do
+ * so for the current only use of this function, but if more callers are added
+ * this might need to be reconsidered.
*/
void
deleteWhatDependsOn(const ObjectAddress *object,
***************
*** 3107,3109 **** pg_describe_object(PG_FUNCTION_ARGS)
--- 3124,3318 ----
description = getObjectDescription(&address);
PG_RETURN_TEXT_P(cstring_to_text(description));
}
+
+ char *
+ getObjectTypeDescription(const ObjectAddress *object)
+ {
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationTypeDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_PROC:
+ appendStringInfo(&buffer, "function");
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, "type");
+ break;
+
+ case OCLASS_CAST:
+ appendStringInfo(&buffer, "cast");
+ break;
+
+ case OCLASS_COLLATION:
+ appendStringInfo(&buffer, "collation");
+ break;
+
+ case OCLASS_CONSTRAINT:
+ appendStringInfo(&buffer, "constraint");
+ break;
+
+ case OCLASS_CONVERSION:
+ appendStringInfo(&buffer, "conversion");
+ break;
+
+ case OCLASS_DEFAULT:
+ appendStringInfo(&buffer, "default value");
+ break;
+
+ case OCLASS_LANGUAGE:
+ appendStringInfo(&buffer, "language");
+ break;
+
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, "large object");
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, "operator");
+ break;
+
+ case OCLASS_OPCLASS:
+ appendStringInfo(&buffer, "operator class");
+ break;
+
+ case OCLASS_OPFAMILY:
+ appendStringInfo(&buffer, "operator family");
+ break;
+
+ case OCLASS_AMOP:
+ appendStringInfo(&buffer, "operator of access method");
+ break;
+
+ case OCLASS_AMPROC:
+ appendStringInfo(&buffer, "function of access method");
+ break;
+
+ case OCLASS_REWRITE:
+ appendStringInfo(&buffer, "rule");
+ break;
+
+ case OCLASS_TRIGGER:
+ appendStringInfo(&buffer, "trigger");
+ break;
+
+ case OCLASS_SCHEMA:
+ appendStringInfo(&buffer, "schema");
+ break;
+
+ case OCLASS_TSPARSER:
+ appendStringInfo(&buffer, "text search parser");
+ break;
+
+ case OCLASS_TSDICT:
+ appendStringInfo(&buffer, "text search dictionary");
+ break;
+
+ case OCLASS_TSTEMPLATE:
+ appendStringInfo(&buffer, "text search template");
+ break;
+
+ case OCLASS_TSCONFIG:
+ appendStringInfo(&buffer, "text search configuration");
+ break;
+
+ case OCLASS_ROLE:
+ appendStringInfo(&buffer, "role");
+ break;
+
+ case OCLASS_DATABASE:
+ appendStringInfo(&buffer, "database");
+ break;
+
+ case OCLASS_TBLSPACE:
+ appendStringInfo(&buffer, "tablespace");
+ break;
+
+ case OCLASS_FDW:
+ appendStringInfo(&buffer, "foreign-data wrapper");
+ break;
+
+ case OCLASS_FOREIGN_SERVER:
+ appendStringInfo(&buffer, "server");
+ break;
+
+ case OCLASS_USER_MAPPING:
+ appendStringInfo(&buffer, "user mapping");
+ break;
+
+ case OCLASS_DEFACL:
+ /* XXX do we need more detail here? */
+ appendStringInfo(&buffer, "default ACL");
+ break;
+
+ case OCLASS_EXTENSION:
+ appendStringInfo(&buffer, "extension");
+ break;
+
+ case OCLASS_EVENT_TRIGGER:
+ appendStringInfo(&buffer, "event trigger");
+ break;
+
+ default:
+ appendStringInfo(&buffer, "unrecognized object type");
+ break;
+ }
+
+ return buffer.data;
+ }
+
+ /*
+ * subroutine for getObjectTypeDescription: describe a relation type
+ */
+ static void
+ getRelationTypeDescription(StringInfo buffer, Oid relid)
+ {
+ HeapTuple relTup;
+ Form_pg_class relForm;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ switch (relForm->relkind)
+ {
+ case RELKIND_RELATION:
+ appendStringInfo(buffer, "table");
+ break;
+ case RELKIND_INDEX:
+ appendStringInfo(buffer, "index");
+ break;
+ case RELKIND_SEQUENCE:
+ appendStringInfo(buffer, "sequence");
+ break;
+ case RELKIND_TOASTVALUE:
+ appendStringInfo(buffer, "toast table");
+ break;
+ case RELKIND_VIEW:
+ appendStringInfo(buffer, "view");
+ break;
+ case RELKIND_MATVIEW:
+ appendStringInfo(buffer, "materialized view");
+ break;
+ case RELKIND_COMPOSITE_TYPE:
+ appendStringInfo(buffer, "composite type");
+ break;
+ case RELKIND_FOREIGN_TABLE:
+ appendStringInfo(buffer, "foreign table");
+ break;
+ default:
+ /* shouldn't get here */
+ appendStringInfo(buffer, "relation");
+ break;
+ }
+
+ ReleaseSysCache(relTup);
+ }
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 748,805 **** ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
}
/*
- * Return a copy of the tuple for the object with the given object OID, from
- * the given catalog (which must have been opened by the caller and suitably
- * locked). NULL is returned if the OID is not found.
- *
- * We try a syscache first, if available.
- *
- * XXX this function seems general in possible usage. Given sufficient callers
- * elsewhere, we should consider moving it to a more appropriate place.
- */
- static HeapTuple
- get_catalog_object_by_oid(Relation catalog, Oid objectId)
- {
- HeapTuple tuple;
- Oid classId = RelationGetRelid(catalog);
- int oidCacheId = get_object_catcache_oid(classId);
-
- if (oidCacheId > 0)
- {
- tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
- if (!HeapTupleIsValid(tuple)) /* should not happen */
- return NULL;
- }
- else
- {
- Oid oidIndexId = get_object_oid_index(classId);
- SysScanDesc scan;
- ScanKeyData skey;
-
- Assert(OidIsValid(oidIndexId));
-
- ScanKeyInit(&skey,
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(objectId));
-
- scan = systable_beginscan(catalog, oidIndexId, true,
- SnapshotNow, 1, &skey);
- tuple = systable_getnext(scan);
- if (!HeapTupleIsValid(tuple))
- {
- systable_endscan(scan);
- return NULL;
- }
- tuple = heap_copytuple(tuple);
-
- systable_endscan(scan);
- }
-
- return tuple;
- }
-
- /*
* Generic function to change the ownership of a given object, for simple
* cases (won't work for tables, nor other cases where we need to do more than
* change the ownership column of a single catalog entry).
--- 748,753 ----
*** a/src/backend/commands/event_trigger.c
--- b/src/backend/commands/event_trigger.c
***************
*** 25,30 ****
--- 25,31 ----
#include "commands/dbcommands.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
+ #include "funcapi.h"
#include "parser/parse_func.h"
#include "pgstat.h"
#include "miscadmin.h"
***************
*** 39,44 ****
--- 40,49 ----
#include "utils/syscache.h"
#include "tcop/utility.h"
+ /* Globally visible state variables */
+ bool evtrig_sqldrop_inprogress = false;
+ slist_head SQLDropList = SLIST_STATIC_INIT(SQLDropList);
+
typedef struct
{
const char *obtypename;
***************
*** 89,94 **** static event_trigger_support_data event_trigger_support[] = {
--- 94,109 ----
{ NULL, false }
};
+ /* Support for dropped objects */
+ typedef struct SQLDropObject
+ {
+ ObjectAddress address;
+ char *objname;
+ char *schemaname;
+ char *objecttype;
+ slist_node next;
+ } SQLDropObject;
+
static void AlterEventTriggerOwner_internal(Relation rel,
HeapTuple tup,
Oid newOwnerId);
***************
*** 151,158 **** CreateEventTrigger(CreateEventTrigStmt *stmt)
}
/* Validate tag list, if any. */
! if (strcmp(stmt->eventname, "ddl_command_start") == 0 && tags != NULL)
validate_ddl_tags("tag", tags);
/*
* Give user a nice error message if an event trigger of the same name
--- 166,177 ----
}
/* Validate tag list, if any. */
! if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
! strcmp(stmt->eventname, "ddl_command_end") == 0)
! && tags != NULL)
! {
validate_ddl_tags("tag", tags);
+ }
/*
* Give user a nice error message if an event trigger of the same name
***************
*** 220,226 **** check_ddl_tag(const char *tag)
pg_strcasecmp(tag, "SELECT INTO") == 0 ||
pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
! pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0)
return EVENT_TRIGGER_COMMAND_TAG_OK;
/*
--- 239,246 ----
pg_strcasecmp(tag, "SELECT INTO") == 0 ||
pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
! pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
! pg_strcasecmp(tag, "DROP OWNED") == 0)
return EVENT_TRIGGER_COMMAND_TAG_OK;
/*
***************
*** 827,829 **** EventTriggerSupportsObjectType(ObjectType obtype)
--- 847,1054 ----
}
return true;
}
+
+ /*
+ * Support for dropped objects information on event trigger functions.
+ *
+ * We keep the list of objects dropped by the current command in a list of
+ * these structs. Each command that might drop objects saves the current
+ * list in a local variable, initialize a new empty list and do the dependency.c
+ * dance to drop objects, which populates the list; when the event triggers are
+ * invoked they can consume the list via pg_event_trigger_dropped_objects().
+ * When the command finishes, the list is cleared and the original list is
+ * restored. This is to support the case that an event trigger function drops
+ * objects "reentrantly".
+ *
+ * For each object dropped, we save the below info, which can be obtained as a
+ * set via the pg_event_trigger_dropped_objects() SQL-callable function.
+ */
+
+ /*
+ * Initialize state of objects dropped
+ */
+ void
+ EventTriggerInitializeDrop(bool *save_inprogress, slist_head *save_objlist)
+ {
+ /* save previous state in local vars of caller, for later restore */
+ *save_inprogress = evtrig_sqldrop_inprogress;
+ *save_objlist = SQLDropList;
+
+ evtrig_sqldrop_inprogress = true;
+ slist_init(&SQLDropList);
+ }
+
+ /*
+ * Restore state after running a command that drops objects; free memory from a
+ * list we may have created.
+ */
+ void
+ EventTriggerFinalizeDrop(bool save_inprogress, slist_head save_objlist)
+ {
+ slist_mutable_iter iter;
+
+ slist_foreach_modify(iter, &SQLDropList)
+ {
+ SQLDropObject *obj = slist_container(SQLDropObject, next, iter.cur);
+
+ if (obj->objname)
+ pfree(obj->objname);
+ if (obj->schemaname)
+ pfree(obj->schemaname);
+ pfree(obj);
+ }
+
+ evtrig_sqldrop_inprogress = save_inprogress;
+ SQLDropList = save_objlist;
+ }
+
+ /*
+ * Register one object as being dropped by the current command.
+ *
+ * XXX do we need to think about memory context these things are stored in?
+ */
+ void
+ evtrig_sqldrop_add_object(ObjectAddress *object)
+ {
+ SQLDropObject *obj;
+ HeapTuple tuple;
+ Relation catalog;
+
+ Assert(EventTriggerSupportsObjectType(getObjectClass(object)));
+
+ obj = palloc0(sizeof(SQLDropObject));
+ obj->address = *object;
+
+ /*
+ * Obtain object and schema names from the object's catalog tuple, if one
+ * exists.
+ */
+ catalog = heap_open(obj->address.classId, AccessShareLock);
+ tuple = get_catalog_object_by_oid(catalog, obj->address.objectId);
+ if (tuple)
+ {
+ AttrNumber attnum;
+ Datum datum;
+ bool isnull;
+
+ attnum = get_object_attnum_name(obj->address.classId);
+ if (attnum != InvalidAttrNumber)
+ {
+ datum = heap_getattr(tuple, attnum,
+ RelationGetDescr(catalog), &isnull);
+ if (!isnull)
+ obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
+ }
+
+ attnum = get_object_attnum_namespace(obj->address.classId);
+ if (attnum != InvalidAttrNumber)
+ {
+ datum = heap_getattr(tuple, attnum,
+ RelationGetDescr(catalog), &isnull);
+ if (!isnull)
+ obj->schemaname = get_namespace_name(DatumGetObjectId(datum));
+ }
+ }
+
+ /* and object type, too */
+ obj->objecttype = getObjectTypeDescription(&obj->address);
+
+ heap_close(catalog, AccessShareLock);
+
+ slist_push_head(&SQLDropList, &obj->next);
+ }
+
+ /*
+ * pg_event_trigger_dropped_objects
+ *
+ * Make the list of dropped objects available to the user function run by the
+ * Event Trigger.
+ */
+ Datum
+ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
+ {
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+ slist_iter iter;
+
+ /*
+ * This function is meant to be called from within an event trigger in
+ * order to get the list of objects dropped, if any.
+ */
+ if (!evtrig_sqldrop_inprogress)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("%s can only be called from an event trigger function",
+ "pg_event_trigger_dropped_objects()")));
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not allowed in this context")));
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ /* Build tuplestore to hold the result rows */
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ MemoryContextSwitchTo(oldcontext);
+
+ slist_foreach(iter, &SQLDropList)
+ {
+ SQLDropObject *obj;
+ Datum values[6];
+ bool nulls[6];
+
+ obj = slist_container(SQLDropObject, next, iter.cur);
+
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, 0, sizeof(nulls));
+
+ /* classid */
+ values[0] = ObjectIdGetDatum(obj->address.classId);
+
+ /* objid */
+ values[1] = ObjectIdGetDatum(obj->address.objectId);
+
+ /* objsubid */
+ values[2] = Int32GetDatum(obj->address.objectSubId);
+
+ /* object type */
+ values[3] = CStringGetTextDatum(obj->objecttype);
+
+ /* objname */
+ if (obj->objname)
+ values[4] = CStringGetTextDatum(obj->objname);
+ else
+ nulls[4] = true;
+
+ /* schemaname */
+ if (obj->schemaname)
+ values[5] = CStringGetTextDatum(obj->schemaname);
+ else
+ nulls[5] = true;
+
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
+
+ /* clean up and return the tuplestore */
+ tuplestore_donestoring(tupstore);
+
+ return (Datum) 0;
+ }
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 699,732 **** standard_ProcessUtility(Node *parsetree,
case T_DropStmt:
{
DropStmt *stmt = (DropStmt *) parsetree;
! if (isCompleteQuery
! && EventTriggerSupportsObjectType(stmt->removeType))
EventTriggerDDLCommandStart(parsetree);
! switch (stmt->removeType)
{
! case OBJECT_INDEX:
! if (stmt->concurrent)
! PreventTransactionChain(isTopLevel,
! "DROP INDEX CONCURRENTLY");
! /* fall through */
! case OBJECT_TABLE:
! case OBJECT_SEQUENCE:
! case OBJECT_VIEW:
! case OBJECT_MATVIEW:
! case OBJECT_FOREIGN_TABLE:
! RemoveRelations((DropStmt *) parsetree);
! break;
! default:
! RemoveObjects((DropStmt *) parsetree);
! break;
}
if (isCompleteQuery
&& EventTriggerSupportsObjectType(stmt->removeType))
! EventTriggerDDLCommandEnd(parsetree);
break;
}
--- 699,759 ----
case T_DropStmt:
{
DropStmt *stmt = (DropStmt *) parsetree;
+ bool save_inprogress;
+ slist_head save_objlist;
! /*
! * don't run any event trigger when we require not to have open
! * a transaction
! */
! if (stmt->removeType == OBJECT_INDEX && stmt->concurrent)
! PreventTransactionChain(isTopLevel,
! "DROP INDEX CONCURRENTLY");
!
! if (isCompleteQuery &&
! EventTriggerSupportsObjectType(stmt->removeType))
! {
EventTriggerDDLCommandStart(parsetree);
! EventTriggerInitializeDrop(&save_inprogress, &save_objlist);
! }
!
! PG_TRY();
{
! switch (stmt->removeType)
! {
! case OBJECT_INDEX:
! case OBJECT_TABLE:
! case OBJECT_SEQUENCE:
! case OBJECT_VIEW:
! case OBJECT_MATVIEW:
! case OBJECT_FOREIGN_TABLE:
! RemoveRelations((DropStmt *) parsetree);
! break;
! default:
! RemoveObjects((DropStmt *) parsetree);
! break;
! }
! if (isCompleteQuery
! && EventTriggerSupportsObjectType(stmt->removeType))
! {
! EventTriggerDDLCommandEnd(parsetree);
! }
! }
! PG_CATCH();
! {
! if (isCompleteQuery
! && EventTriggerSupportsObjectType(stmt->removeType))
! EventTriggerFinalizeDrop(save_inprogress, save_objlist);
!
! PG_RE_THROW();
}
+ PG_END_TRY();
if (isCompleteQuery
&& EventTriggerSupportsObjectType(stmt->removeType))
! EventTriggerFinalizeDrop(save_inprogress, save_objlist);
break;
}
***************
*** 1248,1256 **** standard_ProcessUtility(Node *parsetree,
break;
case T_DropOwnedStmt:
! /* no event triggers for global objects */
! DropOwnedObjects((DropOwnedStmt *) parsetree);
! break;
case T_ReassignOwnedStmt:
/* no event triggers for global objects */
--- 1275,1311 ----
break;
case T_DropOwnedStmt:
! {
! bool save_inprogress;
! slist_head save_objlist;
!
! if (isCompleteQuery)
! {
! EventTriggerDDLCommandStart(parsetree);
!
! EventTriggerInitializeDrop(&save_inprogress, &save_objlist);
! }
!
! PG_TRY();
! {
! DropOwnedObjects((DropOwnedStmt *) parsetree);
!
! if (isCompleteQuery)
! EventTriggerDDLCommandEnd(parsetree);
! }
! PG_CATCH();
! {
! if (isCompleteQuery)
! EventTriggerFinalizeDrop(save_inprogress, save_objlist);
! PG_RE_THROW();
! }
! PG_END_TRY();
!
! if (isCompleteQuery)
! EventTriggerFinalizeDrop(save_inprogress, save_objlist);
!
! break;
! }
case T_ReassignOwnedStmt:
/* no event triggers for global objects */
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
***************
*** 18,23 ****
--- 18,24 ----
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
+ #include "access/sysattr.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
***************
*** 40,45 ****
--- 41,47 ----
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
+ #include "utils/tqual.h"
#include "utils/typcache.h"
/* Hook for plugins to get control in get_attavgwidth() */
***************
*** 2926,2928 **** get_range_subtype(Oid rangeOid)
--- 2928,2981 ----
else
return InvalidOid;
}
+
+ /* ------------- GENERIC -------------- */
+
+ /*
+ * Return a copy of the tuple for the object with the given object OID, from
+ * the given catalog (which must have been opened by the caller and suitably
+ * locked). NULL is returned if the OID is not found.
+ *
+ * We try a syscache first, if available.
+ */
+ HeapTuple
+ get_catalog_object_by_oid(Relation catalog, Oid objectId)
+ {
+ HeapTuple tuple;
+ Oid classId = RelationGetRelid(catalog);
+ int oidCacheId = get_object_catcache_oid(classId);
+
+ if (oidCacheId > 0)
+ {
+ tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
+ if (!HeapTupleIsValid(tuple)) /* should not happen */
+ return NULL;
+ }
+ else
+ {
+ Oid oidIndexId = get_object_oid_index(classId);
+ SysScanDesc scan;
+ ScanKeyData skey;
+
+ Assert(OidIsValid(oidIndexId));
+
+ ScanKeyInit(&skey,
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+
+ scan = systable_beginscan(catalog, oidIndexId, true,
+ SnapshotNow, 1, &skey);
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ return NULL;
+ }
+ tuple = heap_copytuple(tuple);
+
+ systable_endscan(scan);
+ }
+
+ return tuple;
+ }
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 179,184 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 179,186 ----
extern char *getObjectDescription(const ObjectAddress *object);
extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ extern char *getObjectTypeDescription(const ObjectAddress *object);
+
extern ObjectAddresses *new_object_addresses(void);
extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 4682,4687 **** DATA(insert OID = 3473 ( spg_range_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0
--- 4682,4690 ----
DESCR("SP-GiST support for quad tree over range");
+ /* event triggers */
+ DATA(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,25}" "{o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, object_name, schema_name}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
+ DESCR("list objects dropped by the current command");
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
*** a/src/include/commands/event_trigger.h
--- b/src/include/commands/event_trigger.h
***************
*** 13,19 ****
--- 13,22 ----
#ifndef EVENT_TRIGGER_H
#define EVENT_TRIGGER_H
+ #include "catalog/dependency.h"
+ #include "catalog/objectaddress.h"
#include "catalog/pg_event_trigger.h"
+ #include "lib/ilist.h"
#include "nodes/parsenodes.h"
typedef struct EventTriggerData
***************
*** 43,46 **** extern bool EventTriggerSupportsObjectType(ObjectType obtype);
--- 46,55 ----
extern void EventTriggerDDLCommandStart(Node *parsetree);
extern void EventTriggerDDLCommandEnd(Node *parsetree);
+ extern void EventTriggerInitializeDrop(bool *save_inprogress,
+ slist_head *save_objlist);
+ extern void EventTriggerFinalizeDrop(bool save_inprogress,
+ slist_head save_objlist);
+ extern void evtrig_sqldrop_add_object(ObjectAddress *object);
+
#endif /* EVENT_TRIGGER_H */
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 1147,1152 **** extern Datum pg_describe_object(PG_FUNCTION_ARGS);
--- 1147,1155 ----
/* commands/constraint.c */
extern Datum unique_key_recheck(PG_FUNCTION_ARGS);
+ /* commands/event_trigger.c */
+ extern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS);
+
/* commands/extension.c */
extern Datum pg_available_extensions(PG_FUNCTION_ARGS);
extern Datum pg_available_extension_versions(PG_FUNCTION_ARGS);
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
***************
*** 16,21 ****
--- 16,22 ----
#include "access/attnum.h"
#include "access/htup.h"
#include "nodes/pg_list.h"
+ #include "utils/relcache.h"
/* Result list element for get_op_btree_interpretation */
typedef struct OpBtreeInterpretation
***************
*** 152,157 **** extern void free_attstatsslot(Oid atttype,
--- 153,159 ----
float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
+ extern HeapTuple get_catalog_object_by_oid(Relation catalog, Oid objectId);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
/* type_is_array_domain accepts both plain arrays and domains over arrays */