]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix SPLIT PARTITION range bound validation with DEFAULT
authorAlexander Korotkov <akorotkov@postgresql.org>
Tue, 19 May 2026 10:38:55 +0000 (13:38 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Tue, 19 May 2026 10:54:55 +0000 (13:54 +0300)
When splitting a range partition and defining a new DEFAULT partition, the
validation checked the lower bound of the first explicit partition and the
upper bound of explicit partitions only when they were not first.  If there
was exactly one explicit non-DEFAULT partition, its upper bound was therefore
not checked.

This could allow the replacement partition to extend beyond the upper bound
of the partition being split, potentially overlapping another existing
partition.

Fix this by checking the upper bound whenever the explicit partition is the
last one.  Add a regression test covering the single explicit partition plus
DEFAULT case.

Author: Chao Li <lic@highgo.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Zhenwei Shang <a934172442@gmail.com>
Reviewed-by: Dmitry Koval <d.koval@postgrespro.ru>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/C18878AB-DEB2-4A61-9995-A035DD644B81@gmail.com

src/backend/partitioning/partbounds.c
src/test/regress/expected/partition_split.out
src/test/regress/sql/partition_split.sql

index a09beec34d895f663d06bd793a00af9622cd6e14..73dea0375be0ffce7c8cb4ce96f0a645ed5636d8 100644 (file)
@@ -5419,7 +5419,8 @@ check_partition_bounds_for_split_range(Relation parent,
                                                                "ALTER TABLE ... SPLIT PARTITION"),
                                                parser_errposition(pstate, exprLocation((Node *) datum)));
                }
-               else
+
+               if (last)
                {
                        PartitionRangeBound *split_upper;
 
index 961b37953c8bf909a5c7c920780cb4b624d663f3..a2ccbe5138be371264c486ee0900c3c7539e1bd5 100644 (file)
@@ -1188,6 +1188,22 @@ SELECT tableoid::regclass, * FROM sales_range ORDER BY tableoid::regclass::text
 
 DROP TABLE sales_range;
 --
+-- Test that the explicit partition bound cannot extend outside the split
+-- partition's bound when a DEFAULT partition is specified.
+--
+CREATE TABLE t (i int) PARTITION BY RANGE (i);
+CREATE TABLE tp_0_51 PARTITION OF t FOR VALUES FROM (0) TO (51);
+CREATE TABLE tp_51_100 PARTITION OF t FOR VALUES FROM (51) TO (100);
+-- ERROR
+ALTER TABLE t SPLIT PARTITION tp_0_51 INTO
+  (PARTITION tp_0_51 FOR VALUES FROM (0) TO (53),
+   PARTITION tp_default DEFAULT);
+ERROR:  upper bound of partition "tp_0_51" is greater than upper bound of split partition "tp_0_51"
+LINE 2:   (PARTITION tp_0_51 FOR VALUES FROM (0) TO (53),
+                                                     ^
+HINT:  ALTER TABLE ... SPLIT PARTITION require combined bounds of new partitions must exactly match the bound of the split partition.
+DROP TABLE t;
+--
 -- Try to SPLIT partition of another table.
 --
 CREATE TABLE t1(i int, t text) PARTITION BY LIST (t);
index a110fc8786792940d5c46ee23e9b922048b2b25d..d9821c5e2a34a1c4a7a6310afe3f71fa1357f2eb 100644 (file)
@@ -834,6 +834,21 @@ SELECT tableoid::regclass, * FROM sales_range ORDER BY tableoid::regclass::text
 
 DROP TABLE sales_range;
 
+--
+-- Test that the explicit partition bound cannot extend outside the split
+-- partition's bound when a DEFAULT partition is specified.
+--
+CREATE TABLE t (i int) PARTITION BY RANGE (i);
+CREATE TABLE tp_0_51 PARTITION OF t FOR VALUES FROM (0) TO (51);
+CREATE TABLE tp_51_100 PARTITION OF t FOR VALUES FROM (51) TO (100);
+
+-- ERROR
+ALTER TABLE t SPLIT PARTITION tp_0_51 INTO
+  (PARTITION tp_0_51 FOR VALUES FROM (0) TO (53),
+   PARTITION tp_default DEFAULT);
+
+DROP TABLE t;
+
 --
 -- Try to SPLIT partition of another table.
 --