Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e8b6598

Browse files
committed
After a MINVALUE/MAXVALUE bound, allow only more of the same.
In the old syntax, which used UNBOUNDED, we had a similar restriction, but commit d363d42, which changed the syntax, eliminated it. Put it back. Patch by me, reviewed by Dean Rasheed. Discussion: http://postgr.es/m/CA+Tgmobs+pLPC27tS3gOpEAxAffHrq5w509cvkwTf9pF6cWYbg@mail.gmail.com
1 parent f830183 commit e8b6598

File tree

8 files changed

+102
-37
lines changed

8 files changed

+102
-37
lines changed

doc/src/sgml/ref/create_table.sgml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,10 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
322322
</para>
323323

324324
<para>
325-
Note that any values after <literal>MINVALUE</> or
326-
<literal>MAXVALUE</> in a partition bound are ignored; so the bound
327-
<literal>(10, MINVALUE, 0)</> is equivalent to
328-
<literal>(10, MINVALUE, 10)</> and <literal>(10, MINVALUE, MINVALUE)</>
329-
and <literal>(10, MINVALUE, MAXVALUE)</>.
325+
Note that if <literal>MINVALUE</> or <literal>MAXVALUE</> is used for
326+
one column of a partitioning bound, the same value must be used for all
327+
subsequent columns. For example, <literal>(10, MINVALUE, 0)</> is not
328+
a valid bound; you should write <literal>(10, MINVALUE, MINVALUE)</>.
330329
</para>
331330

332331
<para>
@@ -1643,7 +1642,7 @@ CREATE TABLE measurement_y2016m07
16431642
<programlisting>
16441643
CREATE TABLE measurement_ym_older
16451644
PARTITION OF measurement_year_month
1646-
FOR VALUES FROM (MINVALUE, 0) TO (2016, 11);
1645+
FOR VALUES FROM (MINVALUE, MINVALUE) TO (2016, 11);
16471646

16481647
CREATE TABLE measurement_ym_y2016m11
16491648
PARTITION OF measurement_year_month

src/backend/parser/parse_utilcmd.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ static void transformConstraintAttrs(CreateStmtContext *cxt,
135135
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
136136
static void setSchemaName(char *context_schema, char **stmt_schema_name);
137137
static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
138+
static void validateInfiniteBounds(ParseState *pstate, List *blist);
138139
static Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
139140
const char *colName, Oid colType, int32 colTypmod);
140141

@@ -3382,6 +3383,13 @@ transformPartitionBound(ParseState *pstate, Relation parent,
33823383
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
33833384
errmsg("TO must specify exactly one value per partitioning column")));
33843385

3386+
/*
3387+
* Once we see MINVALUE or MAXVALUE for one column, the remaining
3388+
* columns must be the same.
3389+
*/
3390+
validateInfiniteBounds(pstate, spec->lowerdatums);
3391+
validateInfiniteBounds(pstate, spec->upperdatums);
3392+
33853393
/* Transform all the constants */
33863394
i = j = 0;
33873395
result_spec->lowerdatums = result_spec->upperdatums = NIL;
@@ -3453,6 +3461,46 @@ transformPartitionBound(ParseState *pstate, Relation parent,
34533461
return result_spec;
34543462
}
34553463

3464+
/*
3465+
* validateInfiniteBounds
3466+
*
3467+
* Check that a MAXVALUE or MINVALUE specification in a partition bound is
3468+
* followed only by more of the same.
3469+
*/
3470+
static void
3471+
validateInfiniteBounds(ParseState *pstate, List *blist)
3472+
{
3473+
ListCell *lc;
3474+
PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
3475+
3476+
foreach(lc, blist)
3477+
{
3478+
PartitionRangeDatum *prd = castNode(PartitionRangeDatum, lfirst(lc));
3479+
3480+
if (kind == prd->kind)
3481+
continue;
3482+
3483+
switch (kind)
3484+
{
3485+
case PARTITION_RANGE_DATUM_VALUE:
3486+
kind = prd->kind;
3487+
break;
3488+
3489+
case PARTITION_RANGE_DATUM_MAXVALUE:
3490+
ereport(ERROR,
3491+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3492+
errmsg("every bound following MAXVALUE must also be MAXVALUE"),
3493+
parser_errposition(pstate, exprLocation((Node *) prd))));
3494+
3495+
case PARTITION_RANGE_DATUM_MINVALUE:
3496+
ereport(ERROR,
3497+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3498+
errmsg("every bound following MINVALUE must also be MINVALUE"),
3499+
parser_errposition(pstate, exprLocation((Node *) prd))));
3500+
}
3501+
}
3502+
}
3503+
34563504
/*
34573505
* Transform one constant in a partition bound spec
34583506
*/

src/test/regress/expected/create_table.out

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -703,27 +703,27 @@ Number of partitions: 3 (Use \d+ to list them.)
703703

704704
-- check that we get the expected partition constraints
705705
CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
706-
CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
706+
CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE);
707707
\d+ unbounded_range_part
708708
Table "public.unbounded_range_part"
709709
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
710710
--------+---------+-----------+----------+---------+---------+--------------+-------------
711711
a | integer | | | | plain | |
712712
b | integer | | | | plain | |
713713
c | integer | | | | plain | |
714-
Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0)
714+
Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE)
715715
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL))
716716

717717
DROP TABLE unbounded_range_part;
718-
CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
718+
CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE);
719719
\d+ range_parted4_1
720720
Table "public.range_parted4_1"
721721
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
722722
--------+---------+-----------+----------+---------+---------+--------------+-------------
723723
a | integer | | | | plain | |
724724
b | integer | | | | plain | |
725725
c | integer | | | | plain | |
726-
Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0)
726+
Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE)
727727
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND (abs(a) <= 1))
728728

729729
CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
@@ -737,15 +737,15 @@ CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5
737737
Partition of: range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE)
738738
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 3) OR ((abs(a) = 3) AND (abs(b) > 4)) OR ((abs(a) = 3) AND (abs(b) = 4) AND (c >= 5))) AND ((abs(a) < 6) OR ((abs(a) = 6) AND (abs(b) <= 7))))
739739

740-
CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
740+
CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE);
741741
\d+ range_parted4_3
742742
Table "public.range_parted4_3"
743743
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
744744
--------+---------+-----------+----------+---------+---------+--------------+-------------
745745
a | integer | | | | plain | |
746746
b | integer | | | | plain | |
747747
c | integer | | | | plain | |
748-
Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0)
748+
Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE)
749749
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 6) OR ((abs(a) = 6) AND (abs(b) >= 8))) AND (abs(a) <= 9))
750750

751751
DROP TABLE range_parted4;

src/test/regress/expected/inherit.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,12 +1831,12 @@ drop table range_list_parted;
18311831
-- check that constraint exclusion is able to cope with the partition
18321832
-- constraint emitted for multi-column range partitioned tables
18331833
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
1834-
create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
1834+
create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
18351835
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
18361836
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
18371837
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
18381838
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
1839-
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
1839+
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
18401840
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
18411841
QUERY PLAN
18421842
------------------------------

src/test/regress/expected/insert.out

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -451,15 +451,28 @@ revoke all on key_desc from someone_else;
451451
revoke all on key_desc_1 from someone_else;
452452
drop role someone_else;
453453
drop table key_desc, key_desc_1;
454+
-- test minvalue/maxvalue restrictions
455+
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
456+
create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, maxvalue);
457+
ERROR: every bound following MINVALUE must also be MINVALUE
458+
LINE 1: ...partition of mcrparted for values from (minvalue, 0, 0) to (...
459+
^
460+
create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, minvalue);
461+
ERROR: every bound following MAXVALUE must also be MAXVALUE
462+
LINE 1: ...r values from (10, 6, minvalue) to (10, maxvalue, minvalue);
463+
^
464+
create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, minvalue);
465+
ERROR: every bound following MINVALUE must also be MINVALUE
466+
LINE 1: ...ition of mcrparted for values from (21, minvalue, 0) to (30,...
467+
^
454468
-- check multi-column range partitioning expression enforces the same
455469
-- constraint as what tuple-routing would determine it to be
456-
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
457-
create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, 0);
470+
create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, maxvalue, maxvalue);
458471
create table mcrparted1 partition of mcrparted for values from (2, 1, minvalue) to (10, 5, 10);
459-
create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, 0);
472+
create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, maxvalue);
460473
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
461-
create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, maxvalue);
462-
create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, 0, 0);
474+
create table mcrparted4 partition of mcrparted for values from (21, minvalue, minvalue) to (30, 20, maxvalue);
475+
create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, maxvalue, maxvalue);
463476
-- routed to mcrparted0
464477
insert into mcrparted values (0, 1, 1);
465478
insert into mcrparted0 values (0, 1, 1);
@@ -543,37 +556,37 @@ drop table brtrigpartcon;
543556
drop function brtrigpartcon1trigf();
544557
-- check multi-column range partitioning with minvalue/maxvalue constraints
545558
create table mcrparted (a text, b int) partition by range(a, b);
546-
create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
559+
create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, minvalue) to ('b', minvalue);
547560
create table mcrparted2_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
548561
create table mcrparted3_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
549562
create table mcrparted4_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
550563
create table mcrparted5_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
551564
create table mcrparted6_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
552565
create table mcrparted7_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
553-
create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
566+
create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, maxvalue);
554567
\d+ mcrparted
555568
Table "public.mcrparted"
556569
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
557570
--------+---------+-----------+----------+---------+----------+--------------+-------------
558571
a | text | | | | extended | |
559572
b | integer | | | | plain | |
560573
Partition key: RANGE (a, b)
561-
Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE),
574+
Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, MINVALUE) TO ('b', MINVALUE),
562575
mcrparted2_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
563576
mcrparted3_c_to_common FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE),
564577
mcrparted4_common_lt_0 FOR VALUES FROM ('common', MINVALUE) TO ('common', 0),
565578
mcrparted5_common_0_to_10 FOR VALUES FROM ('common', 0) TO ('common', 10),
566579
mcrparted6_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE),
567580
mcrparted7_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE),
568-
mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
581+
mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
569582

570583
\d+ mcrparted1_lt_b
571584
Table "public.mcrparted1_lt_b"
572585
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
573586
--------+---------+-----------+----------+---------+----------+--------------+-------------
574587
a | text | | | | extended | |
575588
b | integer | | | | plain | |
576-
Partition of: mcrparted FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
589+
Partition of: mcrparted FOR VALUES FROM (MINVALUE, MINVALUE) TO ('b', MINVALUE)
577590
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
578591

579592
\d+ mcrparted2_b
@@ -636,7 +649,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::te
636649
--------+---------+-----------+----------+---------+----------+--------------+-------------
637650
a | text | | | | extended | |
638651
b | integer | | | | plain | |
639-
Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
652+
Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
640653
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'd'::text))
641654

642655
insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),

src/test/regress/sql/create_table.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -621,14 +621,14 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
621621

622622
-- check that we get the expected partition constraints
623623
CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
624-
CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
624+
CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE);
625625
\d+ unbounded_range_part
626626
DROP TABLE unbounded_range_part;
627-
CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
627+
CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE);
628628
\d+ range_parted4_1
629629
CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
630630
\d+ range_parted4_2
631-
CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
631+
CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE);
632632
\d+ range_parted4_3
633633
DROP TABLE range_parted4;
634634

src/test/regress/sql/inherit.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,12 +647,12 @@ drop table range_list_parted;
647647
-- check that constraint exclusion is able to cope with the partition
648648
-- constraint emitted for multi-column range partitioned tables
649649
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
650-
create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
650+
create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
651651
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
652652
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
653653
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
654654
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
655-
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
655+
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
656656
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
657657
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1
658658
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2

0 commit comments

Comments
 (0)