From bd5edd67b1e4a15d0c1ff0a58f8b89df8eded3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Thu, 14 May 2026 15:27:30 +0200 Subject: [PATCH v5 1/3] Add regression test to highlight unexpected behavior when running 'safe' alter column types on partitioned tables --- src/test/regress/expected/alter_table.out | 90 +++++++++++++++++++++++ src/test/regress/sql/alter_table.sql | 68 +++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 20707c186b3..0b67306f532 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2351,6 +2351,96 @@ select conname, obj_description(oid, 'pg_constraint') as desc -- Don't remove this DROP, it exposes bug #15672 drop table at_partitioned; +-- Alter column type when no index rewrite is required +-- for partitioned tables. Reindex is required although +-- it shouldn't be. +create table at_idx_part (id int, code varchar(10), + primary key (id, code)) + partition by range (id); +create table at_idx_part_p1 partition of at_idx_part + for values from (0) to (100); +create table at_idx_part_p2 partition of at_idx_part + for values from (100) to (200); +create index at_idx_part_code_idx on at_idx_part (code); +insert into at_idx_part values (1, 'a'), (101, 'b'); +create temp table at_idx_old as + select relname, oid as oldoid, relfilenode as oldfilenode + from pg_class where relname like 'at_idx_part%'; +alter table at_idx_part alter column code type varchar(20); +select relname, + c.oid = oldoid as same_oid, + case relfilenode + when 0 then 'none' + when c.oid then 'own' + when oldfilenode then 'orig' + else 'OTHER' + end as storage + from pg_class c join at_idx_old using (relname) + where relname like 'at_idx_part%' + order by relname; + relname | same_oid | storage +-------------------------+----------+--------- + at_idx_part | t | none + at_idx_part_code_idx | f | none + at_idx_part_p1 | t | own + at_idx_part_p1_code_idx | f | own + at_idx_part_p1_pkey | f | own + at_idx_part_p2 | t | own + at_idx_part_p2_code_idx | f | own + at_idx_part_p2_pkey | f | own + at_idx_part_pkey | f | none +(9 rows) + +drop table at_idx_part; +-- Same, but with two levels of partitioning. +create table at_idx_part2 (id int, code varchar(10), + primary key (id, code)) + partition by range (id); +create table at_idx_part2_p1 partition of at_idx_part2 + for values from (0) to (100) partition by range (id); +create table at_idx_part2_p1_1 partition of at_idx_part2_p1 + for values from (0) to (50); +create table at_idx_part2_p1_2 partition of at_idx_part2_p1 + for values from (50) to (100); +create table at_idx_part2_p2 partition of at_idx_part2 + for values from (100) to (200); +create index at_idx_part2_code_idx on at_idx_part2 (code); +insert into at_idx_part2 values (1, 'a'), (51, 'b'), (101, 'c'); +create temp table at_idx_old2 as + select relname, oid as oldoid, relfilenode as oldfilenode + from pg_class where relname like 'at_idx_part2%'; +alter table at_idx_part2 alter column code type varchar(20); +select relname, + c.oid = oldoid as same_oid, + case relfilenode + when 0 then 'none' + when c.oid then 'own' + when oldfilenode then 'orig' + else 'OTHER' + end as storage + from pg_class c join at_idx_old2 using (relname) + where relname like 'at_idx_part2%' + order by relname; + relname | same_oid | storage +----------------------------+----------+--------- + at_idx_part2 | t | none + at_idx_part2_code_idx | f | none + at_idx_part2_p1 | t | none + at_idx_part2_p1_1 | t | own + at_idx_part2_p1_1_code_idx | f | own + at_idx_part2_p1_1_pkey | f | own + at_idx_part2_p1_2 | t | own + at_idx_part2_p1_2_code_idx | f | own + at_idx_part2_p1_2_pkey | f | own + at_idx_part2_p1_code_idx | f | none + at_idx_part2_p1_pkey | f | none + at_idx_part2_p2 | t | own + at_idx_part2_p2_code_idx | f | own + at_idx_part2_p2_pkey | f | own + at_idx_part2_pkey | f | none +(15 rows) + +drop table at_idx_part2; -- disallow recursive containment of row types create temp table recur1 (f1 int); alter table recur1 add column f2 recur1; -- fails diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 18f3fdac57a..5d2098befc4 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1557,6 +1557,74 @@ select conname, obj_description(oid, 'pg_constraint') as desc -- Don't remove this DROP, it exposes bug #15672 drop table at_partitioned; +-- Alter column type when no index rewrite is required +-- for partitioned tables. Reindex is required although +-- it shouldn't be. +create table at_idx_part (id int, code varchar(10), + primary key (id, code)) + partition by range (id); +create table at_idx_part_p1 partition of at_idx_part + for values from (0) to (100); +create table at_idx_part_p2 partition of at_idx_part + for values from (100) to (200); +create index at_idx_part_code_idx on at_idx_part (code); +insert into at_idx_part values (1, 'a'), (101, 'b'); + +create temp table at_idx_old as + select relname, oid as oldoid, relfilenode as oldfilenode + from pg_class where relname like 'at_idx_part%'; + +alter table at_idx_part alter column code type varchar(20); + +select relname, + c.oid = oldoid as same_oid, + case relfilenode + when 0 then 'none' + when c.oid then 'own' + when oldfilenode then 'orig' + else 'OTHER' + end as storage + from pg_class c join at_idx_old using (relname) + where relname like 'at_idx_part%' + order by relname; + +drop table at_idx_part; + +-- Same, but with two levels of partitioning. +create table at_idx_part2 (id int, code varchar(10), + primary key (id, code)) + partition by range (id); +create table at_idx_part2_p1 partition of at_idx_part2 + for values from (0) to (100) partition by range (id); +create table at_idx_part2_p1_1 partition of at_idx_part2_p1 + for values from (0) to (50); +create table at_idx_part2_p1_2 partition of at_idx_part2_p1 + for values from (50) to (100); +create table at_idx_part2_p2 partition of at_idx_part2 + for values from (100) to (200); +create index at_idx_part2_code_idx on at_idx_part2 (code); +insert into at_idx_part2 values (1, 'a'), (51, 'b'), (101, 'c'); + +create temp table at_idx_old2 as + select relname, oid as oldoid, relfilenode as oldfilenode + from pg_class where relname like 'at_idx_part2%'; + +alter table at_idx_part2 alter column code type varchar(20); + +select relname, + c.oid = oldoid as same_oid, + case relfilenode + when 0 then 'none' + when c.oid then 'own' + when oldfilenode then 'orig' + else 'OTHER' + end as storage + from pg_class c join at_idx_old2 using (relname) + where relname like 'at_idx_part2%' + order by relname; + +drop table at_idx_part2; + -- disallow recursive containment of row types create temp table recur1 (f1 int); alter table recur1 add column f2 recur1; -- fails -- 2.52.0