X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_shdepend.c;h=19cfe08f4f818db4e8fb295964a51754afc5f6d6;hb=76d4abf2d974ffa578ddc7ff40984cc05c1d48b1;hp=e57a22858fc659a5db8de4f8d8b2011845c1cd99;hpb=4789e9880148660c7126aef4fbaf5563be6ff167;p=postgresql diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index e57a22858f..19cfe08f4f 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -3,12 +3,12 @@ * pg_shdepend.c * routines to support manipulation of the pg_shdepend relation * - * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.7 2006/01/21 02:16:18 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.33 2009/06/04 18:33:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,8 @@ #include "access/genam.h" #include "access/heapam.h" -#include "utils/acl.h" +#include "access/xact.h" +#include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_authid.h" @@ -31,14 +32,16 @@ #include "catalog/pg_type.h" #include "commands/conversioncmds.h" #include "commands/defrem.h" +#include "commands/proclang.h" #include "commands/schemacmds.h" #include "commands/tablecmds.h" #include "commands/typecmds.h" -#include "lib/stringinfo.h" +#include "storage/lmgr.h" #include "miscadmin.h" +#include "utils/acl.h" #include "utils/fmgroids.h" -#include "utils/inval.h" #include "utils/syscache.h" +#include "utils/tqual.h" typedef enum @@ -52,15 +55,19 @@ static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff); static Oid classIdGetDbId(Oid classId); static void shdepLockAndCheckObject(Oid classId, Oid objectId); -static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, - Oid refclassid, Oid refobjid, - SharedDependencyType deptype); -static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, - Oid refclassId, Oid refobjId, - SharedDependencyType deptype); -static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, - Oid refclassId, Oid refobjId, - SharedDependencyType deptype); +static void shdepChangeDep(Relation sdepRel, + Oid classid, Oid objid, int32 objsubid, + Oid refclassid, Oid refobjid, + SharedDependencyType deptype); +static void shdepAddDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype); +static void shdepDropDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + bool drop_subobjects, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype); static void storeObjectDescription(StringInfo descs, objectType type, ObjectAddress *object, SharedDependencyType deptype, @@ -108,6 +115,7 @@ recordSharedDependencyOn(ObjectAddress *depender, sdepRel)) { shdepAddDependency(sdepRel, depender->classId, depender->objectId, + depender->objectSubId, referenced->classId, referenced->objectId, deptype); } @@ -160,14 +168,15 @@ recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner) * locked. */ static void -shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, +shdepChangeDep(Relation sdepRel, + Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype) { Oid dbid = classIdGetDbId(classid); HeapTuple oldtup = NULL; HeapTuple scantup; - ScanKeyData key[3]; + ScanKeyData key[4]; SysScanDesc scan; /* @@ -191,9 +200,13 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, Anum_pg_shdepend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objid)); + ScanKeyInit(&key[3], + Anum_pg_shdepend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubid)); scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, - SnapshotNow, 3, key); + SnapshotNow, 4, key); while ((scantup = systable_getnext(scan)) != NULL) { @@ -203,8 +216,8 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, /* Caller screwed up if multiple matches */ if (oldtup) elog(ERROR, - "multiple pg_shdepend entries for object %u/%u deptype %c", - classid, objid, deptype); + "multiple pg_shdepend entries for object %u/%u/%d deptype %c", + classid, objid, objsubid, deptype); oldtup = heap_copytuple(scantup); } @@ -236,11 +249,12 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, Datum values[Natts_pg_shdepend]; bool nulls[Natts_pg_shdepend]; - memset(nulls, 0, sizeof(nulls)); + memset(nulls, false, sizeof(nulls)); values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid); values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid); values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid); + values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid); values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid); values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid); @@ -265,6 +279,9 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, * changeDependencyOnOwner * * Update the shared dependencies to account for the new owner. + * + * Note: we don't need an objsubid argument because only whole objects + * have owners. */ void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) @@ -274,7 +291,8 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* Adjust the SHARED_DEPENDENCY_OWNER entry */ - shdepChangeDep(sdepRel, classId, objectId, + shdepChangeDep(sdepRel, + classId, objectId, 0, AuthIdRelationId, newOwnerId, SHARED_DEPENDENCY_OWNER); @@ -297,7 +315,7 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) * to make the various ALTER OWNER routines each know about it. *---------- */ - shdepDropDependency(sdepRel, classId, objectId, + shdepDropDependency(sdepRel, classId, objectId, 0, true, AuthIdRelationId, newOwnerId, SHARED_DEPENDENCY_ACL); @@ -365,7 +383,7 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff) * updateAclDependencies * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE. * - * classId, objectId: identify the object whose ACL this is + * classId, objectId, objsubId: identify the object whose ACL this is * ownerId: role owning the object * isGrant: are we adding or removing ACL entries? * noldmembers, oldmembers: array of roleids appearing in old ACL @@ -385,7 +403,8 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff) * before return. */ void -updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant, +updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, + Oid ownerId, bool isGrant, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers) { @@ -426,11 +445,12 @@ updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant, continue; if (isGrant) - shdepAddDependency(sdepRel, classId, objectId, + shdepAddDependency(sdepRel, classId, objectId, objsubId, AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); else - shdepDropDependency(sdepRel, classId, objectId, + shdepDropDependency(sdepRel, classId, objectId, objsubId, + false, /* exact match on objsubId */ AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } @@ -454,8 +474,14 @@ typedef struct * checkSharedDependencies * * Check whether there are shared dependency entries for a given shared - * object. Returns a string containing a newline-separated list of object + * object; return true if so. + * + * In addition, return a string containing a newline-separated list of object * descriptions that depend on the shared object, or NULL if none is found. + * We actually return two such strings; the "detail" result is suitable for + * returning to the client as an errdetail() string, and is limited in size. + * The "detail_log" string is potentially much longer, and should be emitted + * to the server log only. * * We can find three different kinds of dependencies: dependencies on objects * of the current database; dependencies on shared objects; and dependencies @@ -465,28 +491,32 @@ typedef struct * * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early. */ -char * -checkSharedDependencies(Oid classId, Oid objectId) +bool +checkSharedDependencies(Oid classId, Oid objectId, + char **detail_msg, char **detail_log_msg) { Relation sdepRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; - int totalDeps = 0; - int numLocalDeps = 0; - int numSharedDeps = 0; + int numReportedDeps = 0; + int numNotReportedDeps = 0; + int numNotReportedDbs = 0; List *remDeps = NIL; ListCell *cell; ObjectAddress object; StringInfoData descs; + StringInfoData alldescs; /* - * We try to limit the number of reported dependencies to something sane, - * both for the user's sake and to avoid blowing out memory. + * We limit the number of dependencies reported to the client to + * MAX_REPORTED_DEPS, since client software may not deal well with + * enormous error strings. The server log always gets a full report. */ #define MAX_REPORTED_DEPS 100 initStringInfo(&descs); + initStringInfo(&alldescs); sdepRel = heap_open(SharedDependRelationId, AccessShareLock); @@ -520,7 +550,7 @@ checkSharedDependencies(Oid classId, Oid objectId) object.classId = sdepForm->classid; object.objectId = sdepForm->objid; - object.objectSubId = 0; + object.objectSubId = sdepForm->objsubid; /* * If it's a dependency local to this database or it's a shared @@ -531,17 +561,29 @@ checkSharedDependencies(Oid classId, Oid objectId) */ if (sdepForm->dbid == MyDatabaseId) { - numLocalDeps++; - if (++totalDeps <= MAX_REPORTED_DEPS) + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; storeObjectDescription(&descs, LOCAL_OBJECT, &object, sdepForm->deptype, 0); + } + else + numNotReportedDeps++; + storeObjectDescription(&alldescs, LOCAL_OBJECT, &object, + sdepForm->deptype, 0); } else if (sdepForm->dbid == InvalidOid) { - numSharedDeps++; - if (++totalDeps <= MAX_REPORTED_DEPS) + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; storeObjectDescription(&descs, SHARED_OBJECT, &object, sdepForm->deptype, 0); + } + else + numNotReportedDeps++; + storeObjectDescription(&alldescs, SHARED_OBJECT, &object, + sdepForm->deptype, 0); } else { @@ -571,7 +613,6 @@ checkSharedDependencies(Oid classId, Oid objectId) dep->dbOid = sdepForm->dbid; dep->count = 1; remDeps = lappend(remDeps, dep); - totalDeps++; } } } @@ -580,29 +621,9 @@ checkSharedDependencies(Oid classId, Oid objectId) heap_close(sdepRel, AccessShareLock); - if (totalDeps > MAX_REPORTED_DEPS) - { - /* - * Report seems unreasonably long, so reduce it to per-database info - * - * Note: we don't ever suppress per-database totals, which should be - * OK as long as there aren't too many databases ... - */ - descs.len = 0; /* reset to empty */ - descs.data[0] = '\0'; - - if (numLocalDeps > 0) - { - appendStringInfo(&descs, _("%d objects in this database"), - numLocalDeps); - if (numSharedDeps > 0) - appendStringInfoChar(&descs, '\n'); - } - if (numSharedDeps > 0) - appendStringInfo(&descs, _("%d shared objects"), - numSharedDeps); - } - + /* + * Summarize dependencies in remote databases. + */ foreach(cell, remDeps) { remoteDep *dep = lfirst(cell); @@ -611,7 +632,15 @@ checkSharedDependencies(Oid classId, Oid objectId) object.objectId = dep->dbOid; object.objectSubId = 0; - storeObjectDescription(&descs, REMOTE_OBJECT, &object, + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; + storeObjectDescription(&descs, REMOTE_OBJECT, &object, + SHARED_DEPENDENCY_INVALID, dep->count); + } + else + numNotReportedDbs++; + storeObjectDescription(&alldescs, REMOTE_OBJECT, &object, SHARED_DEPENDENCY_INVALID, dep->count); } @@ -620,10 +649,29 @@ checkSharedDependencies(Oid classId, Oid objectId) if (descs.len == 0) { pfree(descs.data); - return NULL; + pfree(alldescs.data); + *detail_msg = *detail_log_msg = NULL; + return false; } - return descs.data; + if (numNotReportedDeps > 0) + appendStringInfo(&descs, ngettext("\nand %d other object " + "(see server log for list)", + "\nand %d other objects " + "(see server log for list)", + numNotReportedDeps), + numNotReportedDeps); + if (numNotReportedDbs > 0) + appendStringInfo(&descs, ngettext("\nand objects in %d other database " + "(see server log for list)", + "\nand objects in %d other databases " + "(see server log for list)", + numNotReportedDbs), + numNotReportedDbs); + + *detail_msg = descs.data; + *detail_log_msg = alldescs.data; + return true; } /* @@ -730,7 +778,7 @@ dropDatabaseDependencies(Oid databaseId) systable_endscan(scan); /* Now delete all entries corresponding to the database itself */ - shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, + shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true, InvalidOid, InvalidOid, SHARED_DEPENDENCY_INVALID); @@ -743,15 +791,19 @@ dropDatabaseDependencies(Oid databaseId) * Delete all pg_shdepend entries corresponding to an object that's being * dropped or modified. The object is assumed to be either a shared object * or local to the current database (the classId tells us which). + * + * If objectSubId is zero, we are deleting a whole object, so get rid of + * pg_shdepend entries for subobjects as well. */ void -deleteSharedDependencyRecordsFor(Oid classId, Oid objectId) +deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId) { Relation sdepRel; sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); - shdepDropDependency(sdepRel, classId, objectId, + shdepDropDependency(sdepRel, classId, objectId, objectSubId, + (objectSubId == 0), InvalidOid, InvalidOid, SHARED_DEPENDENCY_INVALID); @@ -766,7 +818,8 @@ deleteSharedDependencyRecordsFor(Oid classId, Oid objectId) * locked. */ static void -shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, +shdepAddDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype) { @@ -789,6 +842,7 @@ shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId)); values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId); values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId); + values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId); values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId); values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId); @@ -810,20 +864,26 @@ shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, * Internal workhorse for deleting entries from pg_shdepend. * * We drop entries having the following properties: - * dependent object is the one identified by classId/objectId + * dependent object is the one identified by classId/objectId/objsubId * if refclassId isn't InvalidOid, it must match the entry's refclassid * if refobjId isn't InvalidOid, it must match the entry's refobjid * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype * + * If drop_subobjects is true, we ignore objsubId and consider all entries + * matching classId/objectId. + * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. */ static void -shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, +shdepDropDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + bool drop_subobjects, Oid refclassId, Oid refobjId, SharedDependencyType deptype) { - ScanKeyData key[3]; + ScanKeyData key[4]; + int nkeys; SysScanDesc scan; HeapTuple tup; @@ -840,9 +900,19 @@ shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, Anum_pg_shdepend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); + if (drop_subobjects) + nkeys = 3; + else + { + ScanKeyInit(&key[3], + Anum_pg_shdepend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubId)); + nkeys = 4; + } scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, - SnapshotNow, 3, key); + SnapshotNow, nkeys, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { @@ -870,30 +940,17 @@ shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, * Get the database Id that should be used in pg_shdepend, given the OID * of the catalog containing the object. For shared objects, it's 0 * (InvalidOid); for all other objects, it's the current database Id. - * - * XXX it's awfully tempting to hard-wire this instead of doing a syscache - * lookup ... but resist the temptation, unless you can prove it's a - * bottleneck. */ static Oid classIdGetDbId(Oid classId) { Oid dbId; - HeapTuple tup; - tup = SearchSysCache(RELOID, - ObjectIdGetDatum(classId), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for relation %u", classId); - - if (((Form_pg_class) GETSTRUCT(tup))->relisshared) + if (IsSharedRelation(classId)) dbId = InvalidOid; else dbId = MyDatabaseId; - ReleaseSysCache(tup); - return dbId; } @@ -911,12 +968,6 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) /* AccessShareLock should be OK, since we are not modifying the object */ LockSharedObject(classId, objectId, 0, AccessShareLock); - /* - * We have to recognize sinval updates here, else our local syscache may - * still contain the object even if it was just dropped. - */ - AcceptInvalidationMessages(); - switch (classId) { case AuthIdRelationId: @@ -998,7 +1049,10 @@ storeObjectDescription(StringInfo descs, objectType type, case REMOTE_OBJECT: /* translator: %s will always be "database %s" */ - appendStringInfo(descs, _("%d objects in %s"), count, objdesc); + appendStringInfo(descs, ngettext("%d object in %s", + "%d objects in %s", + count), + count, objdesc); break; default: @@ -1061,15 +1115,28 @@ isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel) * * Drop the objects owned by any one of the given RoleIds. If a role has * access to an object, the grant will be removed as well (but the object - * will not, of course.) + * will not, of course). + * + * We can revoke grants immediately while doing the scan, but drops are + * saved up and done all at once with performMultipleDeletions. This + * is necessary so that we don't get failures from trying to delete + * interdependent objects in the wrong order. */ void shdepDropOwned(List *roleids, DropBehavior behavior) { Relation sdepRel; ListCell *cell; + ObjectAddresses *deleteobjs; - sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock); + deleteobjs = new_object_addresses(); + + /* + * We don't need this strong a lock here, but we'll call routines that + * acquire RowExclusiveLock. Better get that right now to avoid potential + * deadlock failures. + */ + sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* * For each role, find the dependent objects and drop them using the @@ -1113,17 +1180,15 @@ shdepDropOwned(List *roleids, DropBehavior behavior) while ((tuple = systable_getnext(scan)) != NULL) { Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); + InternalGrant istmt; + ObjectAddress obj; - /* We only operate on objects on the current database */ + /* We only operate on objects in the current database */ if (sdepForm->dbid != MyDatabaseId) continue; switch (sdepForm->deptype) { - ObjectAddress obj; - GrantObjectType objtype; - InternalGrant istmt; - /* Shouldn't happen */ case SHARED_DEPENDENCY_PIN: case SHARED_DEPENDENCY_INVALID: @@ -1133,25 +1198,9 @@ shdepDropOwned(List *roleids, DropBehavior behavior) switch (sdepForm->classid) { case RelationRelationId: - { - /* is it a sequence or non-sequence? */ - Form_pg_class pg_class_tuple; - HeapTuple tuple; - - tuple = SearchSysCache(RELOID, - ObjectIdGetDatum(sdepForm->objid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", - sdepForm->objid); - pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); - if (pg_class_tuple->relkind == RELKIND_SEQUENCE) - istmt.objtype = ACL_OBJECT_SEQUENCE; - else - istmt.objtype = ACL_OBJECT_RELATION; - ReleaseSysCache(tuple); + /* it's OK to use RELATION for a sequence */ + istmt.objtype = ACL_OBJECT_RELATION; break; - } case DatabaseRelationId: istmt.objtype = ACL_OBJECT_DATABASE; break; @@ -1170,14 +1219,13 @@ shdepDropOwned(List *roleids, DropBehavior behavior) default: elog(ERROR, "unexpected object type %d", sdepForm->classid); - /* keep compiler quiet */ - objtype = (GrantObjectType) 0; break; } istmt.is_grant = false; istmt.objects = list_make1_oid(sdepForm->objid); istmt.all_privs = true; istmt.privileges = ACL_NO_RIGHTS; + istmt.col_privs = NIL; istmt.grantees = list_make1_oid(roleid); istmt.grant_option = false; istmt.behavior = DROP_CASCADE; @@ -1185,20 +1233,11 @@ shdepDropOwned(List *roleids, DropBehavior behavior) ExecGrantStmt_oids(&istmt); break; case SHARED_DEPENDENCY_OWNER: - - /* - * If there's a regular (non-shared) dependency on this - * object marked with DEPENDENCY_INTERNAL, skip this - * object. We will drop the referencer object instead. - */ - if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid)) - continue; - - /* Drop the object */ + /* Save it for deletion below */ obj.classId = sdepForm->classid; obj.objectId = sdepForm->objid; - obj.objectSubId = 0; - performDeletion(&obj, behavior); + obj.objectSubId = sdepForm->objsubid; + add_exact_object_address(&obj, deleteobjs); break; } } @@ -1206,7 +1245,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior) systable_endscan(scan); } - heap_close(sdepRel, AccessExclusiveLock); + /* the dependency mechanism does the actual work */ + performMultipleDeletions(deleteobjs, behavior); + + heap_close(sdepRel, RowExclusiveLock); + + free_object_addresses(deleteobjs); } /* @@ -1221,7 +1265,12 @@ shdepReassignOwned(List *roleids, Oid newrole) Relation sdepRel; ListCell *cell; - sdepRel = heap_open(SharedDependRelationId, AccessShareLock); + /* + * We don't need this strong a lock here, but we'll call routines that + * acquire RowExclusiveLock. Better get that right now to avoid potential + * deadlock problems. + */ + sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); foreach(cell, roleids) { @@ -1267,7 +1316,7 @@ shdepReassignOwned(List *roleids, Oid newrole) { Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); - /* We only operate on objects on the current database */ + /* We only operate on objects in the current database */ if (sdepForm->dbid != MyDatabaseId) continue; @@ -1279,15 +1328,7 @@ shdepReassignOwned(List *roleids, Oid newrole) if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER) continue; - /* - * If there's a regular (non-shared) dependency on this object - * marked with DEPENDENCY_INTERNAL, skip this object. We will - * alter the referencer object instead. - */ - if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid)) - continue; - - /* Issue the appropiate ALTER OWNER call */ + /* Issue the appropriate ALTER OWNER call */ switch (sdepForm->classid) { case ConversionRelationId: @@ -1295,7 +1336,7 @@ shdepReassignOwned(List *roleids, Oid newrole) break; case TypeRelationId: - AlterTypeOwnerInternal(sdepForm->objid, newrole); + AlterTypeOwnerInternal(sdepForm->objid, newrole, true); break; case OperatorRelationId: @@ -1307,13 +1348,23 @@ shdepReassignOwned(List *roleids, Oid newrole) break; case RelationRelationId: - ATExecChangeOwner(sdepForm->objid, newrole, false); + + /* + * Pass recursing = true so that we don't fail on indexes, + * owned sequences, etc when we happen to visit them + * before their parent table. + */ + ATExecChangeOwner(sdepForm->objid, newrole, true); break; case ProcedureRelationId: AlterFunctionOwner_oid(sdepForm->objid, newrole); break; + case LanguageRelationId: + AlterLanguageOwner_oid(sdepForm->objid, newrole); + break; + default: elog(ERROR, "unexpected classid %d", sdepForm->classid); break; @@ -1325,5 +1376,5 @@ shdepReassignOwned(List *roleids, Oid newrole) systable_endscan(scan); } - heap_close(sdepRel, AccessShareLock); + heap_close(sdepRel, RowExclusiveLock); }