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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs