From 200879e5edfc1ce93b7af3cbfafc1f618626cbe9 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 2 Dec 2022 08:16:53 +0100 Subject: [PATCH] Refactor ExecGrant_*() functions Instead of half a dozen of mostly-duplicate ExecGrant_Foo() functions, write one common function ExecGrant_generic() that can handle most of them. We already have all the information we need, such as which system catalog corresponds to which catalog table and which column is the ACL column. --- src/backend/catalog/aclchk.c | 662 ++--------------------------------- 1 file changed, 34 insertions(+), 628 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 8d84a7b056..612ef1a666 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -106,14 +106,9 @@ bool binary_upgrade_record_init_privs = false; static void ExecGrantStmt_oids(InternalGrant *istmt); static void ExecGrant_Relation(InternalGrant *istmt); -static void ExecGrant_Database(InternalGrant *istmt); -static void ExecGrant_Fdw(InternalGrant *istmt); -static void ExecGrant_ForeignServer(InternalGrant *istmt); -static void ExecGrant_Function(InternalGrant *istmt); +static void ExecGrant_generic(InternalGrant *istmt, Oid classid, AclMode default_privs); static void ExecGrant_Language(InternalGrant *istmt); static void ExecGrant_Largeobject(InternalGrant *istmt); -static void ExecGrant_Namespace(InternalGrant *istmt); -static void ExecGrant_Tablespace(InternalGrant *istmt); static void ExecGrant_Type(InternalGrant *istmt); static void ExecGrant_Parameter(InternalGrant *istmt); @@ -602,22 +597,22 @@ ExecGrantStmt_oids(InternalGrant *istmt) ExecGrant_Relation(istmt); break; case OBJECT_DATABASE: - ExecGrant_Database(istmt); + ExecGrant_generic(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE); break; case OBJECT_DOMAIN: case OBJECT_TYPE: ExecGrant_Type(istmt); break; case OBJECT_FDW: - ExecGrant_Fdw(istmt); + ExecGrant_generic(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW); break; case OBJECT_FOREIGN_SERVER: - ExecGrant_ForeignServer(istmt); + ExecGrant_generic(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: - ExecGrant_Function(istmt); + ExecGrant_generic(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION); break; case OBJECT_LANGUAGE: ExecGrant_Language(istmt); @@ -626,10 +621,10 @@ ExecGrantStmt_oids(InternalGrant *istmt) ExecGrant_Largeobject(istmt); break; case OBJECT_SCHEMA: - ExecGrant_Namespace(istmt); + ExecGrant_generic(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA); break; case OBJECT_TABLESPACE: - ExecGrant_Tablespace(istmt); + ExecGrant_generic(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE); break; case OBJECT_PARAMETER_ACL: ExecGrant_Parameter(istmt); @@ -2132,380 +2127,22 @@ ExecGrant_Relation(InternalGrant *istmt) } static void -ExecGrant_Database(InternalGrant *istmt) -{ - Relation relation; - ListCell *cell; - - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_DATABASE; - - relation = table_open(DatabaseRelationId, RowExclusiveLock); - - foreach(cell, istmt->objects) - { - Oid datId = lfirst_oid(cell); - Form_pg_database pg_database_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple newtuple; - Datum values[Natts_pg_database] = {0}; - bool nulls[Natts_pg_database] = {0}; - bool replaces[Natts_pg_database] = {0}; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - HeapTuple tuple; - - tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for database %u", datId); - - pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple); - - /* - * Get owner ID and working copy of existing ACL. If there's no ACL, - * substitute the proper default. - */ - ownerId = pg_database_tuple->datdba; - aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, - RelationGetDescr(relation), &isNull); - if (isNull) - { - old_acl = acldefault(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, - old_acl, ownerId, - &grantorId, &avail_goptions); - - /* - * Restrict the privileges to what we can actually grant, and emit the - * standards-mandated warning and error messages. - */ - this_privileges = - restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - datId, grantorId, OBJECT_DATABASE, - NameStr(pg_database_tuple->datname), - 0, NULL); - - /* - * Generate new ACL. - */ - 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 */ - replaces[Anum_pg_database_datacl - 1] = true; - values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); - - /* Update the shared dependency ACL info */ - updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0, - ownerId, - noldmembers, oldmembers, - nnewmembers, newmembers); - - ReleaseSysCache(tuple); - - pfree(new_acl); - - /* prevent error when processing duplicate objects */ - CommandCounterIncrement(); - } - - table_close(relation, RowExclusiveLock); -} - -static void -ExecGrant_Fdw(InternalGrant *istmt) -{ - Relation relation; - ListCell *cell; - - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_FDW; - - relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock); - - foreach(cell, istmt->objects) - { - Oid fdwid = lfirst_oid(cell); - Form_pg_foreign_data_wrapper pg_fdw_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple tuple; - HeapTuple newtuple; - Datum values[Natts_pg_foreign_data_wrapper] = {0}; - bool nulls[Natts_pg_foreign_data_wrapper] = {0}; - bool replaces[Natts_pg_foreign_data_wrapper] = {0}; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - - tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, - ObjectIdGetDatum(fdwid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid); - - pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); - - /* - * Get owner ID and working copy of existing ACL. If there's no ACL, - * substitute the proper default. - */ - ownerId = pg_fdw_tuple->fdwowner; - aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple, - Anum_pg_foreign_data_wrapper_fdwacl, - &isNull); - if (isNull) - { - old_acl = acldefault(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, - old_acl, ownerId, - &grantorId, &avail_goptions); - - /* - * Restrict the privileges to what we can actually grant, and emit the - * standards-mandated warning and error messages. - */ - this_privileges = - restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - fdwid, grantorId, OBJECT_FDW, - NameStr(pg_fdw_tuple->fdwname), - 0, NULL); - - /* - * Generate new ACL. - */ - 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 */ - replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; - values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); - - /* Update initial privileges for extensions */ - recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0, - new_acl); - - /* Update the shared dependency ACL info */ - updateAclDependencies(ForeignDataWrapperRelationId, - pg_fdw_tuple->oid, 0, - ownerId, - noldmembers, oldmembers, - nnewmembers, newmembers); - - ReleaseSysCache(tuple); - - pfree(new_acl); - - /* prevent error when processing duplicate objects */ - CommandCounterIncrement(); - } - - table_close(relation, RowExclusiveLock); -} - -static void -ExecGrant_ForeignServer(InternalGrant *istmt) +ExecGrant_generic(InternalGrant *istmt, Oid classid, AclMode default_privs) { + int cacheid; Relation relation; ListCell *cell; if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER; - - relation = table_open(ForeignServerRelationId, RowExclusiveLock); - - foreach(cell, istmt->objects) - { - Oid srvid = lfirst_oid(cell); - Form_pg_foreign_server pg_server_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple tuple; - HeapTuple newtuple; - Datum values[Natts_pg_foreign_server] = {0}; - bool nulls[Natts_pg_foreign_server] = {0}; - bool replaces[Natts_pg_foreign_server] = {0}; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - - tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for foreign server %u", srvid); - - pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple); - - /* - * Get owner ID and working copy of existing ACL. If there's no ACL, - * substitute the proper default. - */ - ownerId = pg_server_tuple->srvowner; - aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple, - Anum_pg_foreign_server_srvacl, - &isNull); - if (isNull) - { - old_acl = acldefault(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, - old_acl, ownerId, - &grantorId, &avail_goptions); - - /* - * Restrict the privileges to what we can actually grant, and emit the - * standards-mandated warning and error messages. - */ - this_privileges = - restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - srvid, grantorId, OBJECT_FOREIGN_SERVER, - NameStr(pg_server_tuple->srvname), - 0, NULL); - - /* - * Generate new ACL. - */ - 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 */ - replaces[Anum_pg_foreign_server_srvacl - 1] = true; - values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); - - /* Update initial privileges for extensions */ - recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl); - - /* Update the shared dependency ACL info */ - updateAclDependencies(ForeignServerRelationId, - pg_server_tuple->oid, 0, - ownerId, - noldmembers, oldmembers, - nnewmembers, newmembers); - - ReleaseSysCache(tuple); + istmt->privileges = default_privs; - pfree(new_acl); - - /* prevent error when processing duplicate objects */ - CommandCounterIncrement(); - } - - table_close(relation, RowExclusiveLock); -} - -static void -ExecGrant_Function(InternalGrant *istmt) -{ - Relation relation; - ListCell *cell; - - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_FUNCTION; + cacheid = get_object_catcache_oid(classid); - relation = table_open(ProcedureRelationId, RowExclusiveLock); + relation = table_open(classid, RowExclusiveLock); foreach(cell, istmt->objects) { - Oid funcId = lfirst_oid(cell); - Form_pg_proc pg_proc_tuple; + Oid objectid = lfirst_oid(cell); Datum aclDatum; bool isNull; AclMode avail_goptions; @@ -2516,30 +2153,34 @@ ExecGrant_Function(InternalGrant *istmt) Oid ownerId; HeapTuple tuple; HeapTuple newtuple; - Datum values[Natts_pg_proc] = {0}; - bool nulls[Natts_pg_proc] = {0}; - bool replaces[Natts_pg_proc] = {0}; + Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts); + bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts); + bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts); int noldmembers; int nnewmembers; Oid *oldmembers; Oid *newmembers; - tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId)); + tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid)); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for function %u", funcId); - - pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); + elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid); /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. */ - ownerId = pg_proc_tuple->proowner; - aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + ownerId = DatumGetObjectId(SysCacheGetAttr(cacheid, + tuple, + get_object_attnum_owner(classid), + &isNull)); + Assert(!isNull); + aclDatum = SysCacheGetAttr(cacheid, + tuple, + get_object_attnum_acl(classid), &isNull); if (isNull) { - old_acl = acldefault(OBJECT_FUNCTION, ownerId); + old_acl = acldefault(get_object_type(classid, objectid), ownerId); /* There are no old member roles according to the catalogs */ noldmembers = 0; oldmembers = NULL; @@ -2563,8 +2204,8 @@ ExecGrant_Function(InternalGrant *istmt) this_privileges = restrict_and_check_grant(istmt->is_grant, avail_goptions, istmt->all_privs, istmt->privileges, - funcId, grantorId, OBJECT_FUNCTION, - NameStr(pg_proc_tuple->proname), + objectid, grantorId, get_object_type(classid, objectid), + NameStr(*DatumGetName(SysCacheGetAttr(cacheid, tuple, get_object_attnum_name(classid), &isNull))), 0, NULL); /* @@ -2582,8 +2223,8 @@ ExecGrant_Function(InternalGrant *istmt) nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ - replaces[Anum_pg_proc_proacl - 1] = true; - values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl); + replaces[get_object_attnum_acl(classid) - 1] = true; + values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl); newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces); @@ -2591,10 +2232,11 @@ ExecGrant_Function(InternalGrant *istmt) CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); /* Update initial privileges for extensions */ - recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl); + recordExtensionInitPriv(objectid, classid, 0, new_acl); /* Update the shared dependency ACL info */ - updateAclDependencies(ProcedureRelationId, funcId, 0, + updateAclDependencies(classid, + objectid, 0, ownerId, noldmembers, oldmembers, nnewmembers, newmembers); @@ -2873,242 +2515,6 @@ ExecGrant_Largeobject(InternalGrant *istmt) table_close(relation, RowExclusiveLock); } -static void -ExecGrant_Namespace(InternalGrant *istmt) -{ - Relation relation; - ListCell *cell; - - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_SCHEMA; - - relation = table_open(NamespaceRelationId, RowExclusiveLock); - - foreach(cell, istmt->objects) - { - Oid nspid = lfirst_oid(cell); - Form_pg_namespace pg_namespace_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple tuple; - HeapTuple newtuple; - Datum values[Natts_pg_namespace] = {0}; - bool nulls[Natts_pg_namespace] = {0}; - bool replaces[Natts_pg_namespace] = {0}; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - - tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for namespace %u", nspid); - - pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); - - /* - * Get owner ID and working copy of existing ACL. If there's no ACL, - * substitute the proper default. - */ - ownerId = pg_namespace_tuple->nspowner; - aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple, - Anum_pg_namespace_nspacl, - &isNull); - if (isNull) - { - old_acl = acldefault(OBJECT_SCHEMA, 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, - old_acl, ownerId, - &grantorId, &avail_goptions); - - /* - * Restrict the privileges to what we can actually grant, and emit the - * standards-mandated warning and error messages. - */ - this_privileges = - restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - nspid, grantorId, OBJECT_SCHEMA, - NameStr(pg_namespace_tuple->nspname), - 0, NULL); - - /* - * Generate new ACL. - */ - 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 */ - replaces[Anum_pg_namespace_nspacl - 1] = true; - values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); - - /* Update initial privileges for extensions */ - recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl); - - /* Update the shared dependency ACL info */ - updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0, - ownerId, - noldmembers, oldmembers, - nnewmembers, newmembers); - - ReleaseSysCache(tuple); - - pfree(new_acl); - - /* prevent error when processing duplicate objects */ - CommandCounterIncrement(); - } - - table_close(relation, RowExclusiveLock); -} - -static void -ExecGrant_Tablespace(InternalGrant *istmt) -{ - Relation relation; - ListCell *cell; - - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE; - - relation = table_open(TableSpaceRelationId, RowExclusiveLock); - - foreach(cell, istmt->objects) - { - Oid tblId = lfirst_oid(cell); - Form_pg_tablespace pg_tablespace_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple newtuple; - Datum values[Natts_pg_tablespace] = {0}; - bool nulls[Natts_pg_tablespace] = {0}; - bool replaces[Natts_pg_tablespace] = {0}; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - HeapTuple tuple; - - /* Search syscache for pg_tablespace */ - tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for tablespace %u", tblId); - - pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple); - - /* - * Get owner ID and working copy of existing ACL. If there's no ACL, - * substitute the proper default. - */ - ownerId = pg_tablespace_tuple->spcowner; - aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl, - RelationGetDescr(relation), &isNull); - if (isNull) - { - old_acl = acldefault(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, - old_acl, ownerId, - &grantorId, &avail_goptions); - - /* - * Restrict the privileges to what we can actually grant, and emit the - * standards-mandated warning and error messages. - */ - this_privileges = - restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - tblId, grantorId, OBJECT_TABLESPACE, - NameStr(pg_tablespace_tuple->spcname), - 0, NULL); - - /* - * Generate new ACL. - */ - 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 */ - replaces[Anum_pg_tablespace_spcacl - 1] = true; - values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); - - /* Update the shared dependency ACL info */ - updateAclDependencies(TableSpaceRelationId, tblId, 0, - ownerId, - noldmembers, oldmembers, - nnewmembers, newmembers); - - ReleaseSysCache(tuple); - pfree(new_acl); - - /* prevent error when processing duplicate objects */ - CommandCounterIncrement(); - } - - table_close(relation, RowExclusiveLock); -} - static void ExecGrant_Type(InternalGrant *istmt) { -- 2.38.1