adjust ACL owners for REASSIGN and ALTER OWNER TO

When REASSIGN and ALTER OWNER TO are used, both the object owner and ACL
list should be changed from the old owner to the new owner. This patch
fixes types, foreign data wrappers, and foreign servers to change their
ACL list properly;  they already changed owners properly.

BACKWARD INCOMPATIBILITY?

Report by Alexey Bashtanov
This commit is contained in:
Bruce Momjian 2015-01-22 12:36:34 -05:00
parent b181a91981
commit 59367fdf97
3 changed files with 161 additions and 64 deletions

View File

@ -225,6 +225,12 @@ static void
AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
{ {
Form_pg_foreign_data_wrapper form; 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); form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);
@ -246,7 +252,27 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
if (form->fdwowner != newOwnerId) 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); simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup); CatalogUpdateIndexes(rel, tup);
@ -327,6 +353,12 @@ static void
AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
{ {
Form_pg_foreign_server form; 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); 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); simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup); CatalogUpdateIndexes(rel, tup);

View File

@ -3376,12 +3376,34 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock); ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
else else
{ {
/* Datum repl_val[Natts_pg_type];
* We can just apply the modification directly. bool repl_null[Natts_pg_type];
* bool repl_repl[Natts_pg_type];
* okay to scribble on typTup because it's a copy Acl *newAcl;
*/ Datum aclDatum;
typTup->typowner = newOwnerId; 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); simple_heap_update(rel, &tup->t_self, tup);
@ -3424,6 +3446,12 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
Relation rel; Relation rel;
HeapTuple tup; HeapTuple tup;
Form_pg_type typTup; 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); rel = heap_open(TypeRelationId, RowExclusiveLock);
@ -3432,10 +3460,27 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
elog(ERROR, "cache lookup failed for type %u", typeOid); elog(ERROR, "cache lookup failed for type %u", typeOid);
typTup = (Form_pg_type) GETSTRUCT(tup); typTup = (Form_pg_type) GETSTRUCT(tup);
/* memset(repl_null, false, sizeof(repl_null));
* Modify the owner --- okay to scribble on typTup because it's a copy memset(repl_repl, false, sizeof(repl_repl));
*/
typTup->typowner = newOwnerId; 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); simple_heap_update(rel, &tup->t_self, tup);

View File

@ -422,40 +422,38 @@ ERROR: role "regress_test_indirect" cannot be dropped because some objects depe
DETAIL: owner of server s1 DETAIL: owner of server s1
privileges for foreign-data wrapper foo privileges for foreign-data wrapper foo
\des+ \des+
List of foreign servers List of foreign servers
Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description 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') | s1 | regress_test_indirect | foo | regress_test_indirect=U/regress_test_indirect | | 1.1 | (servername 's1') |
| | | regress_test_role=U/foreign_data_user | | | | s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') |
s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') |
s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') |
s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | s5 | foreign_data_user | foo | | | 15.0 | |
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') |
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 | | | |
| | | regress_test_role2=U*/foreign_data_user | | | | s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') |
s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | s8 | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') |
s8 | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | t1 | regress_test_role | foo | | | | |
t1 | regress_test_role | foo | | | | | t2 | regress_test_role | foo | | | | |
t2 | regress_test_role | foo | | | | |
(10 rows) (10 rows)
ALTER SERVER s8 RENAME to s8new; ALTER SERVER s8 RENAME to s8new;
\des+ \des+
List of foreign servers List of foreign servers
Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description 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') | s1 | regress_test_indirect | foo | regress_test_indirect=U/regress_test_indirect | | 1.1 | (servername 's1') |
| | | regress_test_role=U/foreign_data_user | | | | s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') |
s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') | s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') |
s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') | s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') |
s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | s5 | foreign_data_user | foo | | | 15.0 | |
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') |
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 | | | |
| | | regress_test_role2=U*/foreign_data_user | | | | s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') |
s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | s8new | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') |
s8new | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') | t1 | regress_test_role | foo | | | | |
t1 | regress_test_role | foo | | | | | t2 | regress_test_role | foo | | | | |
t2 | regress_test_role | foo | | | | |
(10 rows) (10 rows)
ALTER SERVER s8new RENAME to s8; ALTER SERVER s8new RENAME to s8;
@ -937,21 +935,21 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY lower(authorizati
(7 rows) (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; 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 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 | | 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_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(4 rows) (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; 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 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 | | 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_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(4 rows) (4 rows)
SELECT * FROM information_schema.foreign_tables ORDER BY 1, 2, 3; 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) (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; 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 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_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES
(2 rows) 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; 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 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_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES regress_test_indirect | regress_test_indirect | regression | | s6 | FOREIGN SERVER | USAGE | YES
(2 rows) regress_test_indirect | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(3 rows)
DROP USER MAPPING FOR current_user SERVER t1; DROP USER MAPPING FOR current_user SERVER t1;
SET ROLE regress_test_role2; SET ROLE regress_test_role2;