diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index a3aeabb0ea..9f7adbf83b 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -225,6 +225,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); @@ -246,7 +252,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); @@ -327,6 +353,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); @@ -358,7 +390,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 322a3c7e3b..b77e1b4140 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3376,12 +3376,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); @@ -3424,6 +3446,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); @@ -3432,10 +3460,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 9bca4402f6..4795c83c9b 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; @@ -937,21 +935,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; @@ -980,18 +978,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;