It seems that ALTER TABLE ... OWNER TO does not change the ownership of any inheriting tables. The documentation states:
> If ONLY is specified, only that table is altered. If ONLY is not > specified, the table and any descendant tables are altered. Which to me indicates that ownership should be altered on the target table and any descendant tables as well. Here is a small test case to reproduce the problem: create table parent (id int); create table child () inherits (parent); create role new_owner; alter table parent owner to new_owner; After performing this sequence of commands, \d looks like: Schema | Name | Type | Owner --------+---------------+----------+----------- public | child | table | ryan public | parent | table | new_owner But I would expect that without specifying only, I would get: Schema | Name | Type | Owner --------+---------------+----------+----------- public | child | table | new_owner public | parent | table | new_owner Attached is a patch which fixes this issue. It is based off of REL8_4_11. Version: PostgreSQL 8.4.11 on i386-apple-darwin10.8.0, compiled by GCC i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3), 64-bit -Ryan Kelly
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 963f6b4..ba97baf 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -312,7 +312,7 @@ static void ATPostAlterTypeParse(char *cmd, List **wqueue); static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId); static void change_owner_recurse_to_sequences(Oid relationOid, - Oid newOwnerId); + Oid newOwnerId, bool isOnly); static void ATExecClusterOn(Relation rel, const char *indexName); static void ATExecDropCluster(Relation rel); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, @@ -2457,8 +2457,10 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_ALTER_TYPE; break; case AT_ChangeOwner: /* ALTER OWNER */ - /* This command never recurses */ - /* No command-specific prep needed */ + /* Recursion occurs during execution phase */ + /* No command-specific prep needed except saving recurse flag */ + if (recurse) + cmd->subtype = AT_ChangeOwnerRecurse; pass = AT_PASS_MISC; break; case AT_ClusterOn: /* CLUSTER ON */ @@ -2663,6 +2665,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, case AT_ChangeOwner: /* ALTER OWNER */ ATExecChangeOwner(RelationGetRelid(rel), get_roleid_checked(cmd->name), + false, + true); + break; + case AT_ChangeOwnerRecurse: /* ALTER OWNER with recursion */ + ATExecChangeOwner(RelationGetRelid(rel), + get_roleid_checked(cmd->name), + false, false); break; case AT_ClusterOn: /* CLUSTER ON */ @@ -6217,9 +6226,13 @@ ATPostAlterTypeParse(char *cmd, List **wqueue) * * recursing is also true if ALTER TYPE OWNER is calling us to fix up a * free-standing composite type. + * + * isOnly is true if we are altering this table only (including any sequences + * and indexes). If it is false, this means we should recurse to any tables + * which inherit from this one. */ void -ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) +ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, bool isOnly) { Relation target_rel; Relation class_rel; @@ -6310,8 +6323,10 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. + * However, if we are potentially altering any child tables, we need + * to keep going. */ - if (tuple_class->relowner != newOwnerId) + if (tuple_class->relowner != newOwnerId || !isOnly) { Datum repl_val[Natts_pg_class]; bool repl_null[Natts_pg_class]; @@ -6417,7 +6432,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) /* For each index, recursively change its ownership */ foreach(i, index_oid_list) - ATExecChangeOwner(lfirst_oid(i), newOwnerId, true); + ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, isOnly); list_free(index_oid_list); } @@ -6427,10 +6442,26 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) /* If it has a toast table, recurse to change its ownership */ if (tuple_class->reltoastrelid != InvalidOid) ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId, - true); + true, isOnly); /* If it has dependent sequences, recurse to change them too */ - change_owner_recurse_to_sequences(relationOid, newOwnerId); + change_owner_recurse_to_sequences(relationOid, newOwnerId, isOnly); + + /* If it has child tables, recurse to change them too */ + if (!isOnly) { + List *inheritingOidList; + ListCell *i; + + /* Find all the inheriting children of this relation */ + inheritingOidList = find_inheritance_children(relationOid, + AccessExclusiveLock); + + /* For each child, recursively change its ownership */ + foreach(i, inheritingOidList) + ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, isOnly); + + list_free(inheritingOidList); + } } } @@ -6512,7 +6543,7 @@ change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId) * ownership. */ static void -change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId) +change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, bool isOnly) { Relation depRel; SysScanDesc scan; @@ -6562,7 +6593,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId) } /* We don't need to close the sequence while we alter it. */ - ATExecChangeOwner(depForm->objid, newOwnerId, true); + ATExecChangeOwner(depForm->objid, newOwnerId, true, isOnly); /* Now we can close it. Keep the lock till end of transaction. */ relation_close(seqRel, NoLock); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 82c9813..33e7891 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -24,7 +24,8 @@ extern void RemoveRelations(DropStmt *drop); extern void AlterTable(AlterTableStmt *stmt); -extern void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing); +extern void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, + bool isOnly); extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f27d9a2..78254e1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1131,7 +1131,8 @@ typedef enum AlterTableType AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */ AT_DisableRule, /* DISABLE RULE name */ AT_AddInherit, /* INHERIT parent */ - AT_DropInherit /* NO INHERIT parent */ + AT_DropInherit, /* NO INHERIT parent */ + AT_ChangeOwnerRecurse /* internal to commands/tablecmds.c */ } AlterTableType; typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
-- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs