Dimitri Fontaine escribió: > The good news is that the patch to do that has already been sent on this > list, and got reviewed in details by Álvaro who did offer incremental > changes. Version 3 of that patch is to be found in: > > http://www.postgresql.org/message-id/m2fw19n1hr....@2ndquadrant.fr
Here's a v4 of that patch. I added support for DROP OWNED, and added object name and schema name available to the pg_dropped_objects function. Since we're now in agreement that this is the way to go, I think this only needs a few more tweaks to get to a committable state, as well as some useful tests and doc changes. (v3 has docs which I didn't include here but are probably useful almost verbatim.) Do we want some more stuff provided by pg_dropped_objects? We now have classId, objectId, objectSubId, object name, schema name. One further thing I think we need is the object's type, i.e. a simple untranslated string "table", "view", "operator" and so on. AFAICT this requires a nearly-duplicate of getObjectDescription. -- Álvaro Herrera http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
[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
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers