diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index bf57a1c793bf4cd548564bd2b8a45c4842567559..6bcd5e01cc34cafdf1d302e3c6753a1f9359eed8 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -286,6 +286,12 @@ static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_foreign_data_wrapper form; + Datum repl_val[Natts_pg_foreign_data_wrapper]; + bool repl_null[Natts_pg_foreign_data_wrapper]; + bool repl_repl[Natts_pg_foreign_data_wrapper]; + Acl *newAcl; + Datum aclDatum; + bool isNull; form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup); @@ -307,7 +313,27 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI if (form->fdwowner != newOwnerId) { - form->fdwowner = newOwnerId; + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_repl[Anum_pg_foreign_data_wrapper_fdwowner - 1] = true; + repl_val[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(newOwnerId); + + aclDatum = heap_getattr(tup, + Anum_pg_foreign_data_wrapper_fdwacl, + RelationGetDescr(rel), + &isNull); + /* Null ACLs do not require changes */ + if (!isNull) + { + newAcl = aclnewowner(DatumGetAclP(aclDatum), + form->fdwowner, newOwnerId); + repl_repl[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; + repl_val[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(newAcl); + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, + repl_repl); simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); @@ -380,6 +406,12 @@ static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_foreign_server form; + Datum repl_val[Natts_pg_foreign_server]; + bool repl_null[Natts_pg_foreign_server]; + bool repl_repl[Natts_pg_foreign_server]; + Acl *newAcl; + Datum aclDatum; + bool isNull; form = (Form_pg_foreign_server) GETSTRUCT(tup); @@ -411,7 +443,27 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) } } - form->srvowner = newOwnerId; + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_repl[Anum_pg_foreign_server_srvowner - 1] = true; + repl_val[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(newOwnerId); + + aclDatum = heap_getattr(tup, + Anum_pg_foreign_server_srvacl, + RelationGetDescr(rel), + &isNull); + /* Null ACLs do not require changes */ + if (!isNull) + { + newAcl = aclnewowner(DatumGetAclP(aclDatum), + form->srvowner, newOwnerId); + repl_repl[Anum_pg_foreign_server_srvacl - 1] = true; + repl_val[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(newAcl); + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, + repl_repl); simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 0169a5122ec9e3342dbe7ecdf6d1568d21b01ac7..0a12442ccbea443a99d0ce4e8ad0ed6713a86f81 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3263,12 +3263,34 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype) ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock); else { - /* - * We can just apply the modification directly. - * - * okay to scribble on typTup because it's a copy - */ - typTup->typowner = newOwnerId; + Datum repl_val[Natts_pg_type]; + bool repl_null[Natts_pg_type]; + bool repl_repl[Natts_pg_type]; + Acl *newAcl; + Datum aclDatum; + bool isNull; + + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_repl[Anum_pg_type_typowner - 1] = true; + repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId); + + aclDatum = heap_getattr(tup, + Anum_pg_type_typacl, + RelationGetDescr(rel), + &isNull); + /* Null ACLs do not require changes */ + if (!isNull) + { + newAcl = aclnewowner(DatumGetAclP(aclDatum), + typTup->typowner, newOwnerId); + repl_repl[Anum_pg_type_typacl - 1] = true; + repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl); + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, + repl_repl); simple_heap_update(rel, &tup->t_self, tup); @@ -3305,6 +3327,12 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId, Relation rel; HeapTuple tup; Form_pg_type typTup; + Datum repl_val[Natts_pg_type]; + bool repl_null[Natts_pg_type]; + bool repl_repl[Natts_pg_type]; + Acl *newAcl; + Datum aclDatum; + bool isNull; rel = heap_open(TypeRelationId, RowExclusiveLock); @@ -3313,10 +3341,27 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId, elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); - /* - * Modify the owner --- okay to scribble on typTup because it's a copy - */ - typTup->typowner = newOwnerId; + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_repl[Anum_pg_type_typowner - 1] = true; + repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId); + + aclDatum = heap_getattr(tup, + Anum_pg_type_typacl, + RelationGetDescr(rel), + &isNull); + /* Null ACLs do not require changes */ + if (!isNull) + { + newAcl = aclnewowner(DatumGetAclP(aclDatum), + typTup->typowner, newOwnerId); + repl_repl[Anum_pg_type_typacl - 1] = true; + repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl); + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, + repl_repl); simple_heap_update(rel, &tup->t_self, tup); diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index e06dc3de7ddc926fcae107c79ba9c92b1c44da5f..0706593db414313235fbaea5d820783ae8c6e408 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -422,40 +422,38 @@ ERROR: role "regress_test_indirect" cannot be dropped because some objects depe DETAIL: owner of server s1 privileges for foreign-data wrapper foo \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description -------+-----------------------+----------------------+-----------------------------------------+--------+---------+--------------------------------------+------------- - s1 | regress_test_indirect | foo | foreign_data_user=U/foreign_data_user +| | 1.1 | (servername 's1') | - | | | regress_test_role=U/foreign_data_user | | | | - s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | - s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | - s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | - s5 | foreign_data_user | foo | | | 15.0 | | - s6 | foreign_data_user | foo | foreign_data_user=U/foreign_data_user +| | 16.0 | (host 'a', dbname 'b') | - | | | regress_test_role2=U*/foreign_data_user | | | | - s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | - s8 | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | - t1 | regress_test_role | foo | | | | | - t2 | regress_test_role | foo | | | | | + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +------+-----------------------+----------------------+-----------------------------------------------+--------+---------+--------------------------------------+------------- + s1 | regress_test_indirect | foo | regress_test_indirect=U/regress_test_indirect | | 1.1 | (servername 's1') | + s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | + s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | + s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | + s5 | foreign_data_user | foo | | | 15.0 | | + s6 | foreign_data_user | foo | foreign_data_user=U/foreign_data_user +| | 16.0 | (host 'a', dbname 'b') | + | | | regress_test_role2=U*/foreign_data_user | | | | + s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | + s8 | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | + t1 | regress_test_role | foo | | | | | + t2 | regress_test_role | foo | | | | | (10 rows) ALTER SERVER s8 RENAME to s8new; \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description --------+-----------------------+----------------------+-----------------------------------------+--------+---------+--------------------------------------+------------- - s1 | regress_test_indirect | foo | foreign_data_user=U/foreign_data_user +| | 1.1 | (servername 's1') | - | | | regress_test_role=U/foreign_data_user | | | | - s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | - s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | - s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | - s5 | foreign_data_user | foo | | | 15.0 | | - s6 | foreign_data_user | foo | foreign_data_user=U/foreign_data_user +| | 16.0 | (host 'a', dbname 'b') | - | | | regress_test_role2=U*/foreign_data_user | | | | - s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | - s8new | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | - t1 | regress_test_role | foo | | | | | - t2 | regress_test_role | foo | | | | | + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +-------+-----------------------+----------------------+-----------------------------------------------+--------+---------+--------------------------------------+------------- + s1 | regress_test_indirect | foo | regress_test_indirect=U/regress_test_indirect | | 1.1 | (servername 's1') | + s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | + s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | + s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | + s5 | foreign_data_user | foo | | | 15.0 | | + s6 | foreign_data_user | foo | foreign_data_user=U/foreign_data_user +| | 16.0 | (host 'a', dbname 'b') | + | | | regress_test_role2=U*/foreign_data_user | | | | + s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | + s8new | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | + t1 | regress_test_role | foo | | | | | + t2 | regress_test_role | foo | | | | | (10 rows) ALTER SERVER s8new RENAME to s8; @@ -900,21 +898,21 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY lower(authorizati (7 rows) SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5; - grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable --------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- - foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES - foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | YES - foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO - foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES + grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable +-----------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- + foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES + foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO + regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES + regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES (4 rows) SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5; - grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable --------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- - foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES - foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | YES - foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO - foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES + grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable +-----------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- + foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES + foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO + regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES + regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES (4 rows) SELECT * FROM information_schema.foreign_tables ORDER BY 1, 2, 3; @@ -943,18 +941,20 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4; (5 rows) SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5; - grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable --------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- - foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO - foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES -(2 rows) + grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable +-----------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- + foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO + regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES + regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES +(3 rows) SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5; - grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable --------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- - foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO - foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES -(2 rows) + grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable +-----------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+-------------- + foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO + regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES + regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES +(3 rows) DROP USER MAPPING FOR current_user SERVER t1; SET ROLE regress_test_role2;