Commit 970c0505 authored by Tom Lane's avatar Tom Lane

Fix assertion failure in check_new_partition_bound().

Commit 6b2c4e59 was overly confident about not being able to see
a negative cmpval result from partition_range_bsearch().  Adjust
the code to cope with that.

Report and patch by Amul Sul; some additional cosmetic changes by me

Discussion: https://postgr.es/m/CAAJ_b97WCO=EyVA7fKzc86kKfojHXLU04_zs7-7+yVzm=-1QkQ@mail.gmail.com
parent 6f0bc5e1
...@@ -2703,10 +2703,10 @@ add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs, ...@@ -2703,10 +2703,10 @@ add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
prev_ub.lower = false; prev_ub.lower = false;
/* /*
* We pass to partition_rbound_cmp() lower1 as false to prevent it * We pass lower1 = false to partition_rbound_cmp() to prevent it from
* from considering the last upper bound to be smaller than the lower * considering the last upper bound to be smaller than the lower bound
* bound of the merged partition when the values of the two range * of the merged partition when the values of the two range bounds
* bounds compare equal. * compare equal.
*/ */
cmpval = partition_rbound_cmp(partnatts, partsupfuncs, partcollations, cmpval = partition_rbound_cmp(partnatts, partsupfuncs, partcollations,
merged_lb->datums, merged_lb->kind, merged_lb->datums, merged_lb->kind,
...@@ -2978,16 +2978,19 @@ check_new_partition_bound(char *relname, Relation parent, ...@@ -2978,16 +2978,19 @@ check_new_partition_bound(char *relname, Relation parent,
/* /*
* First check if the resulting range would be empty with * First check if the resulting range would be empty with
* specified lower and upper bounds * specified lower and upper bounds. partition_rbound_cmp
* cannot return zero here, since the lower-bound flags are
* different.
*/ */
cmpval = partition_rbound_cmp(key->partnatts, cmpval = partition_rbound_cmp(key->partnatts,
key->partsupfunc, key->partsupfunc,
key->partcollation, key->partcollation,
lower->datums, lower->kind, lower->datums, lower->kind,
true, upper); true, upper);
if (cmpval >= 0) Assert(cmpval != 0);
if (cmpval > 0)
{ {
/* Fetch the problematic key from the lower datums list. */ /* Point to problematic key in the lower datums list. */
PartitionRangeDatum *datum = list_nth(spec->lowerdatums, PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
cmpval - 1); cmpval - 1);
...@@ -3057,11 +3060,11 @@ check_new_partition_bound(char *relname, Relation parent, ...@@ -3057,11 +3060,11 @@ check_new_partition_bound(char *relname, Relation parent,
if (cmpval < 0) if (cmpval < 0)
{ {
/* /*
* Fetch the problematic key from the upper * Point to problematic key in the upper
* datums list. * datums list.
*/ */
PartitionRangeDatum *datum = PartitionRangeDatum *datum =
list_nth(spec->upperdatums, -cmpval - 1); list_nth(spec->upperdatums, Abs(cmpval) - 1);
/* /*
* The new partition overlaps with the * The new partition overlaps with the
...@@ -3083,15 +3086,11 @@ check_new_partition_bound(char *relname, Relation parent, ...@@ -3083,15 +3086,11 @@ check_new_partition_bound(char *relname, Relation parent,
PartitionRangeDatum *datum; PartitionRangeDatum *datum;
/* /*
* Fetch the problematic key from the lower datums * Point to problematic key in the lower datums list;
* list. Given the way partition_range_bsearch() * if we have equality, point to the first one.
* works, the new lower bound is certainly >= the
* bound at offset. If the bound matches exactly, we
* flag the 1st key.
*/ */
Assert(cmpval >= 0);
datum = cmpval == 0 ? linitial(spec->lowerdatums) : datum = cmpval == 0 ? linitial(spec->lowerdatums) :
list_nth(spec->lowerdatums, cmpval - 1); list_nth(spec->lowerdatums, Abs(cmpval) - 1);
overlap = true; overlap = true;
overlap_location = datum->location; overlap_location = datum->location;
with = boundinfo->indexes[offset + 1]; with = boundinfo->indexes[offset + 1];
...@@ -3393,13 +3392,14 @@ partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, ...@@ -3393,13 +3392,14 @@ partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
else if (kind1[i] > kind2[i]) else if (kind1[i] > kind2[i])
return colnum; return colnum;
else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE) else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
{
/* /*
* The column bounds are both MINVALUE or both MAXVALUE. No later * The column bounds are both MINVALUE or both MAXVALUE. No later
* columns should be considered, but we still need to compare * columns should be considered, but we still need to compare
* whether they are upper or lower bounds. * whether they are upper or lower bounds.
*/ */
break; break;
}
cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i], cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
partcollation[i], partcollation[i],
...@@ -3692,9 +3692,9 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg) ...@@ -3692,9 +3692,9 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b); PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
PartitionKey key = (PartitionKey) arg; PartitionKey key = (PartitionKey) arg;
return partition_rbound_cmp(key->partnatts, key->partsupfunc, return compare_range_bounds(key->partnatts, key->partsupfunc,
key->partcollation, b1->datums, b1->kind, key->partcollation,
b1->lower, b2); b1, b2);
} }
/* /*
......
...@@ -856,6 +856,10 @@ ERROR: partition "fail_part" would overlap partition "part0" ...@@ -856,6 +856,10 @@ ERROR: partition "fail_part" would overlap partition "part0"
LINE 1: ..._part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) ... LINE 1: ..._part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) ...
^ ^
CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10); CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10);
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (-1) TO (1);
ERROR: partition "fail_part" would overlap partition "part0"
LINE 1: ..._part PARTITION OF range_parted2 FOR VALUES FROM (-1) TO (1)...
^
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue); CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue);
ERROR: partition "fail_part" would overlap partition "part1" ERROR: partition "fail_part" would overlap partition "part1"
LINE 1: ..._part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (max... LINE 1: ..._part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (max...
......
...@@ -687,6 +687,7 @@ CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1); ...@@ -687,6 +687,7 @@ CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1);
CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (1); CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (1);
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (2); CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (2);
CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10); CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10);
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (-1) TO (1);
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue); CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue);
CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30); CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30);
CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40); CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment