summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2025-07-03 17:46:07 +0000
committerTom Lane2025-07-03 17:46:07 +0000
commitd36980b7159a343ec56baca40bfe6c67765095b7 (patch)
treec96aeb75016614e8fa6402979178b36297f0a79c
parentdb51bdf975e28003f08013a12bc46c0848533edc (diff)
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 <[email protected]> Author: jian he <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: CACJufxGKJtGNRRSXfwMW9SqVOPEMdP17BJ7DsBf=tNsv9pWU9g@mail.gmail.com Backpatch-through: 13
-rw-r--r--src/backend/commands/tablecmds.c22
-rw-r--r--src/test/regress/expected/alter_table.out8
-rw-r--r--src/test/regress/sql/alter_table.sql8
3 files changed, 38 insertions, 0 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 5252c971eec..016ae0a65f9 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13561,6 +13561,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);
@@ -13577,6 +13585,20 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
Oid relid;
relid = StatisticsGetRelation(oldId, false);
+
+ /*
+ * As above, make sure we have lock on the statistics object's table
+ * if it's not the same table. However, we take
+ * ShareUpdateExclusiveLock here, aligning with the lock level used in
+ * CreateStatistics and RemoveStatisticsById.
+ *
+ * CAUTION: this should be done after all cases that grab
+ * AccessExclusiveLock, else we risk causing deadlock due to needing
+ * to promote our table lock.
+ */
+ if (relid != tab->relid)
+ LockRelationOid(relid, ShareUpdateExclusiveLock);
+
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 de757a94dab..29b7c305789 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4588,6 +4588,14 @@ 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 statistics atref_stat on ((b).a is not null) from atref;
+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 statistics atref_stat;
+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 b4380ca4b9c..c45f9af17d0 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -3025,6 +3025,14 @@ drop table attbl, atref;
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 statistics atref_stat on ((b).a is not null) from atref;
+alter table attbl alter column a type numeric; -- someday this should work
+drop statistics atref_stat;
+
+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 */