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/[email protected]
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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers