hi.

while reviewing disallow generated column as partition key in [1],
I found out this bug.

demo:
drop table if exists t4;
CREATE TABLE t4(f1 int, f2 bigint) PARTITION BY list ((t4));
create table t4_1 partition of t4 for values in ((1,2));
alter table t4 alter column f2 set data type text using f2;

insert into t4 select 1, '2';
ERROR: invalid memory alloc request size 18446744073709551615

turns out the fix seems pretty simple, mainly on has_partition_attrs.
has_partition_attrs is used to
Checks if any of the 'attnums' is a partition key attribute for rel.
if partition keys have column references, then has_partition_attrs
should return true.

[1]: 
https://postgr.es/m/CACJufxF=wdgthxsaqr9thyusfx_1_t9e6n8te3b8eqxcvov...@mail.gmail.com
From 7a4c9bc1cb65c3aedc92a4bf31352ba19f1135b9 Mon Sep 17 00:00:00 2001
From: jian he <jian.universal...@gmail.com>
Date: Tue, 22 Apr 2025 19:37:24 +0800
Subject: [PATCH v1 1/1] fix wholerow as partition key reference.

If the partition key contains wholerow reference, individual columns cannot be altered.

discussion: https://postgr.es/m/
---
 src/backend/catalog/partition.c           | 12 ++++++++++++
 src/test/regress/expected/alter_table.out | 14 ++++++++++++++
 src/test/regress/sql/alter_table.sql      |  7 +++++++
 3 files changed, 33 insertions(+)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 93d72157a46..e0ae3d2abe1 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -290,6 +290,18 @@ has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
 
 			/* Find all attributes referenced */
 			pull_varattnos(expr, 1, &expr_attrs);
+
+			/*
+			 * If this is a wholerow reference, then assume unconditionally that
+			 * 'attnums' is included as part of the partition key attributes.
+			*/
+			if (bms_is_member(0 - 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 476266e3f4b..fef20e5ae7c 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3984,6 +3984,20 @@ 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.
+-- partition expression is whole row
+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;
+                                              ^
 -- 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 5ce9d1e429f..f5745f448ae 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2390,6 +2390,13 @@ ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
 -- specifying storage parameters for partitioned tables is not supported
 ALTER TABLE partitioned SET (fillfactor=100);
 
+-- partition expression is whole row
+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
+
 -- partitioned table cannot participate in regular inheritance
 CREATE TABLE nonpartitioned (
 	a int,
-- 
2.34.1

Reply via email to