From f9ba071cc5bdd2a98c361b5a75e995ffaa0ec787 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 3 Jul 2025 13:46:07 -0400 Subject: [PATCH] Obtain required table lock during cross-table updates, redux. Commits 8319e5cb5 et al missed the fact that ATPostAlterTypeCleanup contains three calls to ATPostAlterTypeParse, and the other two also need protection against passing a relid that we don't yet have lock on. Add similar logic to those code paths, and add some test cases demonstrating the need for it. In v18 and master, the test cases demonstrate that there's a behavioral discrepancy between stored generated columns and virtual generated columns: we disallow changing the expression of a stored column if it's used in any composite-type columns, but not that of a virtual column. Since the expression isn't actually relevant to either sort of composite-type usage, this prohibition seems unnecessary; but changing it is a matter for separate discussion. For now we are just documenting the existing behavior. Reported-by: jian he Author: jian he Reviewed-by: Tom Lane Discussion: CACJufxGKJtGNRRSXfwMW9SqVOPEMdP17BJ7DsBf=tNsv9pWU9g@mail.gmail.com Backpatch-through: 13 --- src/backend/commands/tablecmds.c | 8 ++++++++ src/test/regress/expected/alter_table.out | 4 ++++ src/test/regress/sql/alter_table.sql | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3c680fade2b..6b33b46d518 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12632,6 +12632,14 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) Oid relid; relid = IndexGetRelation(oldId, false); + + /* + * As above, make sure we have lock on the index's table if it's not + * the same table. + */ + if (relid != tab->relid) + LockRelationOid(relid, AccessExclusiveLock); + ATPostAlterTypeParse(oldId, relid, InvalidOid, (char *) lfirst(def_item), wqueue, lockmode, tab->rewrite); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index fe3f2f009dc..a33ee26f293 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4513,6 +4513,10 @@ create table attbl(a int); create table atref(b attbl check ((b).a is not null)); alter table attbl alter column a type numeric; -- someday this should work ERROR: cannot alter table "attbl" because column "atref.b" uses its row type +alter table atref drop constraint atref_b_check; +create index atref_idx on atref (((b).a)); +alter table attbl alter column a type numeric; -- someday this should work +ERROR: cannot alter table "attbl" because column "atref.b" uses its row type drop table attbl, atref; /* End test case for bug #18970 */ -- Test that ALTER TABLE rewrite preserves a clustered index diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 06bcbb04c46..e72f02fedeb 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2983,6 +2983,10 @@ update bar1 set a = a + 1; create table attbl(a int); create table atref(b attbl check ((b).a is not null)); alter table attbl alter column a type numeric; -- someday this should work +alter table atref drop constraint atref_b_check; + +create index atref_idx on atref (((b).a)); +alter table attbl alter column a type numeric; -- someday this should work drop table attbl, atref; /* End test case for bug #18970 */ -- 2.39.5