v3-0001-disallow-altering-column-if-partition-key-contains-wholerow-refer.patch
text/x-patch
Filename: v3-0001-disallow-altering-column-if-partition-key-contains-wholerow-refer.patch
Type: text/x-patch
Part: 0
From 8eee74af121b2a9cc8f72111f15d94c3086138a2 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Wed, 31 Dec 2025 10:54:54 +0800
Subject: [PATCH v3 1/1] disallow altering column if partition key contains
wholerow reference
For partition key expressions containing whole-row reference, we cannot rely on
pg_depend lookups to determine whether an individual column can be altered
(drop, set data type).
As noted in the comments for find_expr_references_walker, no dependency entries
are recorded for whole-row expressions. Therefore whole-row reference check is
needed in has_partition_attrs.
Partition key expressions contain whole-row reference, it is effectively
equivalent to all user columns being indirectly associated with that expression.
Since columns that in a partition key cannot be altered in any way, the same
restriction should be applied to whole-row reference expressions in the
partition key.
Author: jian he <jian.universality@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Matt Dailis <dwehttam@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
discussion: https://postgr.es/m/CACJufxG5wLiATocRTaC=z+kw4mUaasC-50+q9K=fOdAr3=OGRw@mail.gmail.com
---
src/backend/catalog/partition.c | 14 ++++++++++++++
src/test/regress/expected/alter_table.out | 16 ++++++++++++++++
src/test/regress/sql/alter_table.sql | 9 +++++++++
3 files changed, 39 insertions(+)
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 93d72157a46..5d5fdf5dd77 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -290,6 +290,20 @@ has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
/* Find all attributes referenced */
pull_varattnos(expr, 1, &expr_attrs);
+
+ /*
+ * If the partition expression contains a whole-row reference,
+ * then all columns are indirectly associated with that
+ * expression.
+ */
+ if (bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
+ expr_attrs))
+ {
+ if (used_in_expr)
+ *used_in_expr = true;
+ return true;
+ }
+
partexprs_item = lnext(partexprs, partexprs_item);
if (bms_overlap(attnums, expr_attrs))
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 5e98bbf2425..e740f178c11 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3988,6 +3988,22 @@ LINE 1: ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
ALTER TABLE partitioned SET (fillfactor=100);
ERROR: cannot specify storage parameters for a partitioned table
HINT: Specify storage parameters for its leaf partitions instead.
+-- If the partition expression contains a whole-row reference, altering a
+-- column’s data type or dropping the column is not allowed.
+CREATE TABLE partitioned1(a int, b int) PARTITION BY list((partitioned1));
+ALTER TABLE partitioned1 DROP COLUMN a; --error
+ERROR: cannot drop column "a" because it is part of the partition key of relation "partitioned1"
+ALTER TABLE partitioned1 DROP COLUMN b; --error
+ERROR: cannot drop column "b" because it is part of the partition key of relation "partitioned1"
+ALTER TABLE partitioned1 ALTER COLUMN a TYPE text; --error
+ERROR: cannot alter column "a" because it is part of the partition key of relation "partitioned1"
+LINE 1: ALTER TABLE partitioned1 ALTER COLUMN a TYPE text;
+ ^
+ALTER TABLE partitioned1 ALTER COLUMN b TYPE text; --error
+ERROR: cannot alter column "b" because it is part of the partition key of relation "partitioned1"
+LINE 1: ALTER TABLE partitioned1 ALTER COLUMN b TYPE text;
+ ^
+DROP TABLE partitioned1;
-- partitioned table cannot participate in regular inheritance
CREATE TABLE nonpartitioned (
a int,
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 417202430a5..cce2ac8ea57 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2392,6 +2392,15 @@ ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
-- specifying storage parameters for partitioned tables is not supported
ALTER TABLE partitioned SET (fillfactor=100);
+-- If the partition expression contains a whole-row reference, altering a
+-- column’s data type or dropping the column is not allowed.
+CREATE TABLE partitioned1(a int, b int) PARTITION BY list((partitioned1));
+ALTER TABLE partitioned1 DROP COLUMN a; --error
+ALTER TABLE partitioned1 DROP COLUMN b; --error
+ALTER TABLE partitioned1 ALTER COLUMN a TYPE text; --error
+ALTER TABLE partitioned1 ALTER COLUMN b TYPE text; --error
+DROP TABLE partitioned1;
+
-- partitioned table cannot participate in regular inheritance
CREATE TABLE nonpartitioned (
a int,
--
2.34.1