/* * recordSharedDependencyOn * * Record a dependency between 2 objects via their respective ObjectAddresses. * The first argument is the dependent object, the second the one it * references (which must be a shared object). * * This locks the referenced object and makes sure it still exists. * Then it creates an entry in pg_shdepend. The lock is kept until * the end of the transaction. * * Dependencies on pinned objects are not recorded. */ void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype) { Relation sdepRel; /* * Objects in pg_shdepend can't have SubIds. */ Assert(depender->objectSubId == 0); Assert(referenced->objectSubId == 0); /* * During bootstrap, do nothing since pg_shdepend may not exist yet. * initdb will fill in appropriate pg_shdepend entries after bootstrap. */ if (IsBootstrapProcessingMode()) return; sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* If the referenced object is pinned, do nothing. */ if (!isSharedObjectPinned(referenced->classId, referenced->objectId, sdepRel)) { shdepAddDependency(sdepRel, depender->classId, depender->objectId, depender->objectSubId, referenced->classId, referenced->objectId, deptype); } heap_close(sdepRel, RowExclusiveLock); }
/* * updateAclDependencies * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE. * * classId, objectId: 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 * nnewmembers, newmembers: array of roleids appearing in new ACL * * We calculate the difference between the new and old lists of roles, * and then insert (if it's a grant) or delete (if it's a revoke) from * pg_shdepend as appropiate. * * Note that we can't insert blindly at grant, because we would end up with * duplicate registered dependencies. We could check for existence of the * tuple before inserting, but that seems to be more expensive than what we are * doing now. On the other hand, we can't just delete the tuples blindly at * revoke, because the user may still have other privileges. * * NOTE: Both input arrays must be sorted and de-duped. They are pfreed * before return. */ void updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers) { Relation sdepRel; Oid *diff; int ndiff, i; /* * Calculate the differences between the old and new lists. */ if (isGrant) ndiff = getOidListDiff(newmembers, nnewmembers, oldmembers, noldmembers, &diff); else ndiff = getOidListDiff(oldmembers, noldmembers, newmembers, nnewmembers, &diff); if (ndiff > 0) { sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* Add or drop the respective dependency */ for (i = 0; i < ndiff; i++) { Oid roleid = diff[i]; /* * Skip the owner: he has an OWNER shdep entry instead. (This is * not just a space optimization; it makes ALTER OWNER easier. See * notes in changeDependencyOnOwner.) */ if (roleid == ownerId) continue; /* Skip pinned roles */ if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) continue; if (isGrant) shdepAddDependency(sdepRel, classId, objectId, AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); else shdepDropDependency(sdepRel, classId, objectId, AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } heap_close(sdepRel, RowExclusiveLock); } pfree(diff); }
/* * updateAclDependencies * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE. * * classId, objectId, objsubId: identify the object whose ACL this is * ownerId: role owning the object * noldmembers, oldmembers: array of roleids appearing in old ACL * nnewmembers, newmembers: array of roleids appearing in new ACL * * We calculate the differences between the new and old lists of roles, * and then insert or delete from pg_shdepend as appropriate. * * Note that we can't just insert all referenced roles blindly during GRANT, * because we would end up with duplicate registered dependencies. We could * check for existence of the tuples before inserting, but that seems to be * more expensive than what we are doing here. Likewise we can't just delete * blindly during REVOKE, because the user may still have other privileges. * It is also possible that REVOKE actually adds dependencies, due to * instantiation of a formerly implicit default ACL (although at present, * all such dependencies should be for the owning role, which we ignore here). * * NOTE: Both input arrays must be sorted and de-duped. (Typically they * are extracted from an ACL array by aclmembers(), which takes care of * both requirements.) The arrays are pfreed before return. */ void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers) { Relation sdepRel; int i; /* * Remove entries that are common to both lists; those represent existing * dependencies we don't need to change. * * OK to overwrite the inputs since we'll pfree them anyway. */ getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers); if (noldmembers > 0 || nnewmembers > 0) { sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* Add new dependencies that weren't already present */ for (i = 0; i < nnewmembers; i++) { Oid roleid = newmembers[i]; /* * Skip the owner: he has an OWNER shdep entry instead. (This is * not just a space optimization; it makes ALTER OWNER easier. See * notes in changeDependencyOnOwner.) */ if (roleid == ownerId) continue; /* Skip pinned roles; they don't need dependency entries */ if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) continue; shdepAddDependency(sdepRel, classId, objectId, objsubId, AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } /* Drop no-longer-used old dependencies */ for (i = 0; i < noldmembers; i++) { Oid roleid = oldmembers[i]; /* Skip the owner, same as above */ if (roleid == ownerId) continue; /* Skip pinned roles */ if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) continue; shdepDropDependency(sdepRel, classId, objectId, objsubId, false, /* exact match on objsubId */ AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } heap_close(sdepRel, RowExclusiveLock); } if (oldmembers) pfree(oldmembers); if (newmembers) pfree(newmembers); }