diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 5151d7bbceab564f0e25a19421440ed57195cef0..f61add142aaa2e36d4b10bb811b5fd58e9f5d400 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.164 2010/03/06 23:10:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.165 2010/04/05 01:09:52 tgl Exp $ * * NOTES * See acl.h. @@ -1142,7 +1142,16 @@ SetDefaultACL(InternalDefaultACL *iacls) isNew = true; } - if (old_acl == NULL) + if (old_acl != NULL) + { + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. Collect data before + * merge_acl_with_grant throws away old_acl. + */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + else { /* * If we are creating a global entry, start with the hard-wired @@ -1154,14 +1163,11 @@ SetDefaultACL(InternalDefaultACL *iacls) old_acl = acldefault(iacls->objtype, iacls->roleid); else old_acl = make_empty_acl(); - } - /* - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. Collect data before - * merge_acl_with_grant throws away old_acl. - */ - noldmembers = aclmembers(old_acl, &oldmembers); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } /* * Generate new ACL. Grantor of rights is always the same as the target @@ -1236,7 +1242,7 @@ SetDefaultACL(InternalDefaultACL *iacls) nnewmembers = aclmembers(new_acl, &newmembers); updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0, - iacls->roleid, iacls->is_grant, + iacls->roleid, noldmembers, oldmembers, nnewmembers, newmembers); @@ -1526,9 +1532,18 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* * In select_best_grantor we should consider existing table-level ACL bits @@ -1563,18 +1578,17 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, col_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -1613,7 +1627,7 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, attnum, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); } @@ -1648,6 +1662,8 @@ ExecGrant_Relation(InternalGrant *istmt) bool have_col_privileges; Acl *old_acl; Acl *old_rel_acl; + int noldmembers; + Oid *oldmembers; Oid ownerId; HeapTuple tuple; ListCell *cell_colprivs; @@ -1770,11 +1786,20 @@ ExecGrant_Relation(InternalGrant *istmt) aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull); if (isNull) + { old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ? ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Need an extra copy of original rel ACL for column handling */ old_rel_acl = aclcopy(old_acl); @@ -1791,9 +1816,7 @@ ExecGrant_Relation(InternalGrant *istmt) Datum values[Natts_pg_class]; bool nulls[Natts_pg_class]; bool replaces[Natts_pg_class]; - int noldmembers; int nnewmembers; - Oid *oldmembers; Oid *newmembers; /* Determine ID to do the grant as, and available grant options */ @@ -1816,12 +1839,7 @@ ExecGrant_Relation(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct - * the shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, @@ -1831,6 +1849,10 @@ ExecGrant_Relation(InternalGrant *istmt) grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct + * the shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -1851,7 +1873,7 @@ ExecGrant_Relation(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -1980,9 +2002,18 @@ ExecGrant_Database(InternalGrant *istmt) aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, RelationGetDescr(relation), &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2002,17 +2033,16 @@ ExecGrant_Database(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2033,7 +2063,7 @@ ExecGrant_Database(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2097,9 +2127,18 @@ ExecGrant_Fdw(InternalGrant *istmt) Anum_pg_foreign_data_wrapper_fdwacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_FDW, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2119,17 +2158,16 @@ ExecGrant_Fdw(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2151,7 +2189,7 @@ ExecGrant_Fdw(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(ForeignDataWrapperRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2214,9 +2252,18 @@ ExecGrant_ForeignServer(InternalGrant *istmt) Anum_pg_foreign_server_srvacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2236,17 +2283,16 @@ ExecGrant_ForeignServer(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2268,7 +2314,7 @@ ExecGrant_ForeignServer(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(ForeignServerRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2330,9 +2376,18 @@ ExecGrant_Function(InternalGrant *istmt) aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2352,17 +2407,16 @@ ExecGrant_Function(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2383,7 +2437,7 @@ ExecGrant_Function(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(ProcedureRelationId, funcId, 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2452,9 +2506,18 @@ ExecGrant_Language(InternalGrant *istmt) aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2474,17 +2537,16 @@ ExecGrant_Language(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2505,7 +2567,7 @@ ExecGrant_Language(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2582,9 +2644,18 @@ ExecGrant_Largeobject(InternalGrant *istmt) Anum_pg_largeobject_metadata_lomacl, RelationGetDescr(relation), &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2604,17 +2675,16 @@ ExecGrant_Largeobject(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2637,7 +2707,7 @@ ExecGrant_Largeobject(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(LargeObjectRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2700,9 +2770,18 @@ ExecGrant_Namespace(InternalGrant *istmt) Anum_pg_namespace_nspacl, &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2722,17 +2801,16 @@ ExecGrant_Namespace(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2753,7 +2831,7 @@ ExecGrant_Namespace(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2816,9 +2894,18 @@ ExecGrant_Tablespace(InternalGrant *istmt) aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl, RelationGetDescr(relation), &isNull); if (isNull) + { old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } else + { old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), istmt->privileges, @@ -2838,17 +2925,16 @@ ExecGrant_Tablespace(InternalGrant *istmt) /* * Generate new ACL. - * - * We need the members of both old and new ACLs so we can correct the - * shared dependency information. */ - noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, istmt->grant_option, istmt->behavior, istmt->grantees, this_privileges, grantorId, ownerId); + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ @@ -2869,7 +2955,7 @@ ExecGrant_Tablespace(InternalGrant *istmt) /* Update the shared dependency ACL info */ updateAclDependencies(TableSpaceRelationId, tblId, 0, - ownerId, istmt->is_grant, + ownerId, noldmembers, oldmembers, nnewmembers, newmembers); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 39aec680c086926ba232082a07ad58e83cf8536a..47e0c9b9cf5df0eb69a8ffa863a888f5fb991c4a 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.372 2010/02/26 02:00:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.373 2010/04/05 01:09:52 tgl Exp $ * * * INTERFACE ROUTINES @@ -1160,7 +1160,7 @@ heap_create_with_catalog(const char *relname, nnewmembers = aclmembers(relacl, &newmembers); updateAclDependencies(RelationRelationId, relid, 0, - ownerid, true, + ownerid, 0, NULL, nnewmembers, newmembers); } diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index f97641d55556377cb28f1861c0f034160063c48c..64b8872706354a1cf912b83e6e942810e8bd2335 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.173 2010/03/19 22:54:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.174 2010/04/05 01:09:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -609,7 +609,7 @@ ProcedureCreate(const char *procedureName, nnewmembers = aclmembers(proacl, &newmembers); updateAclDependencies(ProcedureRelationId, retval, 0, - proowner, true, + proowner, 0, NULL, nnewmembers, newmembers); } diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index df65e1086ee57a65c05587c4b0f62d1e0a1e01fa..c7a5e86c58340f768115c0d51f8fa0478272dcde 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); } /* diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 6d39ecee507f434ae11ec262535d9435cdbfbabb..d8a0e0aa639e60b4901cc3cf532c81981704f196 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.44 2010/01/02 16:58:01 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.45 2010/04/05 01:09:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -232,7 +232,7 @@ extern void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId); extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId, - Oid ownerId, bool isGrant, + Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers);