Skip to content

Commit c03911d

Browse files
committed
Simplify the logic checking new range partition bounds.
The previous logic, whilst not actually wrong, was overly complex and involved doing two binary searches, where only one was really necessary. This simplifies that logic and improves the comments. One visible change is that if the new partition overlaps multiple existing partitions, the error message now always reports the overlap with the first existing partition (the one with the lowest bounds). The old code would sometimes report the clash with the first partition and sometimes with the last one. Original patch idea from Amit Langote, substantially rewritten by me. Discussion: https://postgr.es/m/CAAJ_b947mowpLdxL3jo3YLKngRjrq9+Ej4ymduQTfYR+8=YAYQ@mail.gmail.com
1 parent ec86af9 commit c03911d

File tree

2 files changed

+40
-54
lines changed

2 files changed

+40
-54
lines changed

src/backend/catalog/partition.c

+39-53
Original file line numberDiff line numberDiff line change
@@ -745,78 +745,64 @@ check_new_partition_bound(char *relname, Relation parent,
745745
if (partdesc->nparts > 0)
746746
{
747747
PartitionBoundInfo boundinfo = partdesc->boundinfo;
748-
int off1,
749-
off2;
750-
bool equal = false;
748+
int offset;
749+
bool equal;
751750

752751
Assert(boundinfo && boundinfo->ndatums > 0 &&
753752
boundinfo->strategy == PARTITION_STRATEGY_RANGE);
754753

755754
/*
756-
* Firstly, find the greatest range bound that is less
757-
* than or equal to the new lower bound.
755+
* Test whether the new lower bound (which is treated
756+
* inclusively as part of the new partition) lies inside an
757+
* existing partition, or in a gap.
758+
*
759+
* If it's inside an existing partition, the bound at
760+
* offset + 1 will be the upper bound of that partition,
761+
* and its index will be >= 0.
762+
*
763+
* If it's in a gap, the bound at offset + 1 will be the
764+
* lower bound of the next partition, and its index will be
765+
* -1. This is also true if there is no next partition,
766+
* since the index array is initialised with an extra -1 at
767+
* the end.
758768
*/
759-
off1 = partition_bound_bsearch(key, boundinfo, lower, true,
760-
&equal);
769+
offset = partition_bound_bsearch(key, boundinfo, lower,
770+
true, &equal);
761771

762-
/*
763-
* off1 == -1 means that all existing bounds are greater
764-
* than the new lower bound. In that case and the case
765-
* where no partition is defined between the bounds at
766-
* off1 and off1 + 1, we have a "gap" in the range that
767-
* could be occupied by the new partition. We confirm if
768-
* so by checking whether the new upper bound is confined
769-
* within the gap.
770-
*/
771-
if (!equal && boundinfo->indexes[off1 + 1] < 0)
772+
if (boundinfo->indexes[offset + 1] < 0)
772773
{
773-
off2 = partition_bound_bsearch(key, boundinfo, upper,
774-
true, &equal);
775-
776774
/*
777-
* If the new upper bound is returned to be equal to
778-
* the bound at off2, the latter must be the upper
779-
* bound of some partition with which the new
780-
* partition clearly overlaps.
781-
*
782-
* Also, if bound at off2 is not same as the one
783-
* returned for the new lower bound (IOW, off1 !=
784-
* off2), then the new partition overlaps at least one
785-
* partition.
775+
* Check that the new partition will fit in the gap.
776+
* For it to fit, the new upper bound must be less than
777+
* or equal to the lower bound of the next partition,
778+
* if there is one.
786779
*/
787-
if (equal || off1 != off2)
780+
if (offset + 1 < boundinfo->ndatums)
788781
{
789-
overlap = true;
782+
int32 cmpval;
790783

791-
/*
792-
* The bound at off2 could be the lower bound of
793-
* the partition with which the new partition
794-
* overlaps. In that case, use the upper bound
795-
* (that is, the bound at off2 + 1) to get the
796-
* index of that partition.
797-
*/
798-
if (boundinfo->indexes[off2] < 0)
799-
with = boundinfo->indexes[off2 + 1];
800-
else
801-
with = boundinfo->indexes[off2];
784+
cmpval = partition_bound_cmp(key, boundinfo,
785+
offset + 1, upper,
786+
true);
787+
if (cmpval < 0)
788+
{
789+
/*
790+
* The new partition overlaps with the existing
791+
* partition between offset + 1 and offset + 2.
792+
*/
793+
overlap = true;
794+
with = boundinfo->indexes[offset + 2];
795+
}
802796
}
803797
}
804798
else
805799
{
806800
/*
807-
* Equal has been set to true and there is no "gap"
808-
* between the bound at off1 and that at off1 + 1, so
809-
* the new partition will overlap some partition. In
810-
* the former case, the new lower bound is found to be
811-
* equal to the bound at off1, which could only ever
812-
* be true if the latter is the lower bound of some
813-
* partition. It's clear in such a case that the new
814-
* partition overlaps that partition, whose index we
815-
* get using its upper bound (that is, using the bound
816-
* at off1 + 1).
801+
* The new partition overlaps with the existing
802+
* partition between offset and offset + 1.
817803
*/
818804
overlap = true;
819-
with = boundinfo->indexes[off1 + 1];
805+
with = boundinfo->indexes[offset + 1];
820806
}
821807
}
822808

src/test/regress/expected/create_table.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40);
589589
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30);
590590
ERROR: partition "fail_part" would overlap partition "part2"
591591
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (50);
592-
ERROR: partition "fail_part" would overlap partition "part3"
592+
ERROR: partition "fail_part" would overlap partition "part2"
593593
-- now check for multi-column range partition key
594594
CREATE TABLE range_parted3 (
595595
a int,

0 commit comments

Comments
 (0)