diff options
Diffstat (limited to 'src/backend/catalog/pg_shdepend.c')
-rw-r--r-- | src/backend/catalog/pg_shdepend.c | 159 |
1 files changed, 84 insertions, 75 deletions
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index df65e1086ee..c7a5e86c583 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.40 2010/02/26 02:00:37 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.41 2010/04/05 01:09:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,8 +54,7 @@ typedef enum REMOTE_OBJECT } objectType; -static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, - Oid **diff); +static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2); static Oid classIdGetDbId(Oid classId); static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, @@ -328,57 +327,53 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) * getOidListDiff * Helper for updateAclDependencies. * - * Takes two Oid arrays and returns elements from the first not found in the - * second. We assume both arrays are sorted and de-duped, and that the - * second array does not contain any values not found in the first. - * - * NOTE: Both input arrays are pfreed. + * Takes two Oid arrays and removes elements that are common to both arrays, + * leaving just those that are in one input but not the other. + * We assume both arrays have been sorted and de-duped. */ -static int -getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff) +static void +getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2) { - Oid *result; - int i, - j, - k = 0; - - AssertArg(nlist1 >= nlist2 && nlist2 >= 0); + int in1, + in2, + out1, + out2; - result = palloc(sizeof(Oid) * (nlist1 - nlist2)); - *diff = result; - - for (i = 0, j = 0; i < nlist1 && j < nlist2;) + in1 = in2 = out1 = out2 = 0; + while (in1 < *nlist1 && in2 < *nlist2) { - if (list1[i] == list2[j]) + if (list1[in1] == list2[in2]) { - i++; - j++; + /* skip over duplicates */ + in1++; + in2++; } - else if (list1[i] < list2[j]) + else if (list1[in1] < list2[in2]) { - result[k++] = list1[i]; - i++; + /* list1[in1] is not in list2 */ + list1[out1++] = list1[in1++]; } else { - /* can't happen */ - elog(WARNING, "invalid element %u in shorter list", list2[j]); - j++; + /* list2[in2] is not in list1 */ + list2[out2++] = list2[in2++]; } } - for (; i < nlist1; i++) - result[k++] = list1[i]; - - /* We should have copied the exact number of elements */ - AssertState(k == (nlist1 - nlist2)); + /* any remaining list1 entries are not in list2 */ + while (in1 < *nlist1) + { + list1[out1++] = list1[in1++]; + } - if (list1) - pfree(list1); - if (list2) - pfree(list2); + /* any remaining list2 entries are not in list1 */ + while (in2 < *nlist2) + { + list2[out2++] = list2[in2++]; + } - return k; + *nlist1 = out1; + *nlist2 = out2; } /* @@ -387,52 +382,50 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff) * * 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 * 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. + * We calculate the differences between the new and old lists of roles, + * and then insert or delete 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 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. They are pfreed - * before return. + * 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, bool isGrant, + Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers) { Relation sdepRel; - Oid *diff; - int ndiff, - i; + int i; /* - * Calculate the differences between the old and new lists. + * 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. */ - if (isGrant) - ndiff = getOidListDiff(newmembers, nnewmembers, - oldmembers, noldmembers, &diff); - else - ndiff = getOidListDiff(oldmembers, noldmembers, - newmembers, nnewmembers, &diff); + getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers); - if (ndiff > 0) + if (noldmembers > 0 || nnewmembers > 0) { sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); - /* Add or drop the respective dependency */ - for (i = 0; i < ndiff; i++) + /* Add new dependencies that weren't already present */ + for (i = 0; i < nnewmembers; i++) { - Oid roleid = diff[i]; + Oid roleid = newmembers[i]; /* * Skip the owner: he has an OWNER shdep entry instead. (This is @@ -442,25 +435,41 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, 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; - if (isGrant) - shdepAddDependency(sdepRel, classId, objectId, objsubId, - AuthIdRelationId, roleid, - SHARED_DEPENDENCY_ACL); - else - shdepDropDependency(sdepRel, classId, objectId, objsubId, - false, /* exact match on objsubId */ - AuthIdRelationId, roleid, - SHARED_DEPENDENCY_ACL); + shdepDropDependency(sdepRel, classId, objectId, objsubId, + false, /* exact match on objsubId */ + AuthIdRelationId, roleid, + SHARED_DEPENDENCY_ACL); } heap_close(sdepRel, RowExclusiveLock); } - pfree(diff); + if (oldmembers) + pfree(oldmembers); + if (newmembers) + pfree(newmembers); } /* |