After a MINVALUE/MAXVALUE bound, allow only more of the same.
authorRobert Haas <rhaas@postgresql.org>
Sat, 16 Sep 2017 01:15:55 +0000 (21:15 -0400)
committerRobert Haas <rhaas@postgresql.org>
Sat, 16 Sep 2017 01:15:55 +0000 (21:15 -0400)
In the old syntax, which used UNBOUNDED, we had a similar restriction,
but commit d363d42bb9a4399a0207bd3b371c966e22e06bd3, 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

doc/src/sgml/ref/create_table.sgml
src/backend/parser/parse_utilcmd.c
src/test/regress/expected/create_table.out
src/test/regress/expected/inherit.out
src/test/regress/expected/insert.out
src/test/regress/sql/create_table.sql
src/test/regress/sql/inherit.sql
src/test/regress/sql/insert.sql

index 824253de404feb09272fcd9399d63a5ecd7c527b..1477288851929c7449544a2b8b9b34a91a79f077 100644 (file)
@@ -324,11 +324,10 @@ FROM ( { <replaceable class="PARAMETER">numeric_literal</replaceable> | <replace
      </para>
 
      <para>
-      Note that any values after <literal>MINVALUE</> or
-      <literal>MAXVALUE</> in a partition bound are ignored; so the bound
-      <literal>(10, MINVALUE, 0)</> is equivalent to
-      <literal>(10, MINVALUE, 10)</> and <literal>(10, MINVALUE, MINVALUE)</>
-      and <literal>(10, MINVALUE, MAXVALUE)</>.
+      Note that if <literal>MINVALUE</> or <literal>MAXVALUE</> is used for
+      one column of a partitioning bound, the same value must be used for all
+      subsequent columns.  For example, <literal>(10, MINVALUE, 0)</> is not
+      a valid bound; you should write <literal>(10, MINVALUE, MINVALUE)</>.
      </para>
 
      <para>
@@ -1665,7 +1664,7 @@ CREATE TABLE measurement_y2016m07
 <programlisting>
 CREATE TABLE measurement_ym_older
     PARTITION OF measurement_year_month
-    FOR VALUES FROM (MINVALUE, 0) TO (2016, 11);
+    FOR VALUES FROM (MINVALUE, MINVALUE) TO (2016, 11);
 
 CREATE TABLE measurement_ym_y2016m11
     PARTITION OF measurement_year_month
index 655da02c10952f36ee7c454b3ee4d961edca7d87..27e568fc626bff9715f9025de3df66af5363cede 100644 (file)
@@ -135,6 +135,7 @@ static void transformConstraintAttrs(CreateStmtContext *cxt,
 static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
 static void setSchemaName(char *context_schema, char **stmt_schema_name);
 static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
+static void validateInfiniteBounds(ParseState *pstate, List *blist);
 static Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
                             const char *colName, Oid colType, int32 colTypmod);
 
@@ -3397,6 +3398,13 @@ transformPartitionBound(ParseState *pstate, Relation parent,
                    (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                     errmsg("TO must specify exactly one value per partitioning column")));
 
+       /*
+        * Once we see MINVALUE or MAXVALUE for one column, the remaining
+        * columns must be the same.
+        */
+       validateInfiniteBounds(pstate, spec->lowerdatums);
+       validateInfiniteBounds(pstate, spec->upperdatums);
+
        /* Transform all the constants */
        i = j = 0;
        result_spec->lowerdatums = result_spec->upperdatums = NIL;
@@ -3468,6 +3476,46 @@ transformPartitionBound(ParseState *pstate, Relation parent,
    return result_spec;
 }
 
+/*
+ * validateInfiniteBounds
+ *
+ * Check that a MAXVALUE or MINVALUE specification in a partition bound is
+ * followed only by more of the same.
+ */
+static void
+validateInfiniteBounds(ParseState *pstate, List *blist)
+{
+   ListCell *lc;
+   PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
+
+   foreach(lc, blist)
+   {
+       PartitionRangeDatum *prd = castNode(PartitionRangeDatum, lfirst(lc));
+
+       if (kind == prd->kind)
+           continue;
+
+       switch (kind)
+       {
+           case PARTITION_RANGE_DATUM_VALUE:
+               kind = prd->kind;
+               break;
+
+           case PARTITION_RANGE_DATUM_MAXVALUE:
+               ereport(ERROR,
+                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                        errmsg("every bound following MAXVALUE must also be MAXVALUE"),
+                        parser_errposition(pstate, exprLocation((Node *) prd))));
+
+           case PARTITION_RANGE_DATUM_MINVALUE:
+               ereport(ERROR,
+                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                        errmsg("every bound following MINVALUE must also be MINVALUE"),
+                        parser_errposition(pstate, exprLocation((Node *) prd))));
+       }
+   }
+}
+
 /*
  * Transform one constant in a partition bound spec
  */
index 58c755be505d1157ceb1337afc428ecb64c3bac0..60ab28a96ad42f29a987c038406c5618c66cbe12 100644 (file)
@@ -723,7 +723,7 @@ Number of partitions: 3 (Use \d+ to list them.)
 
 -- check that we get the expected partition constraints
 CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
-CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
+CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE);
 \d+ unbounded_range_part
                            Table "public.unbounded_range_part"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -731,11 +731,11 @@ CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MI
  a      | integer |           |          |         | plain   |              | 
  b      | integer |           |          |         | plain   |              | 
  c      | integer |           |          |         | plain   |              | 
-Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0)
+Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL))
 
 DROP TABLE unbounded_range_part;
-CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
+CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE);
 \d+ range_parted4_1
                               Table "public.range_parted4_1"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -743,7 +743,7 @@ CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALU
  a      | integer |           |          |         | plain   |              | 
  b      | integer |           |          |         | plain   |              | 
  c      | integer |           |          |         | plain   |              | 
-Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0)
+Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND (abs(a) <= 1))
 
 CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
@@ -757,7 +757,7 @@ CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5
 Partition of: range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE)
 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))))
 
-CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
+CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE);
 \d+ range_parted4_3
                               Table "public.range_parted4_3"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -765,7 +765,7 @@ CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, M
  a      | integer |           |          |         | plain   |              | 
  b      | integer |           |          |         | plain   |              | 
  c      | integer |           |          |         | plain   |              | 
-Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0)
+Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE)
 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))
 
 DROP TABLE range_parted4;
index 2fb0b4d86ec935f7d812c28e6e6774d40acc3075..c698faff2f168e53240aa0b42b35ef2d8273768b 100644 (file)
@@ -1853,12 +1853,12 @@ drop table range_list_parted;
 -- check that constraint exclusion is able to cope with the partition
 -- constraint emitted for multi-column range partitioned tables
 create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
+create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
 create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
 create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
 create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
 create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
-create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
+create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
 explain (costs off) select * from mcrparted where a = 0;   -- scans mcrparted0
           QUERY PLAN          
 ------------------------------
index 73a5600f19c4859f9d51b12b8d8c0b4637151d90..b715619313a05aa8144d51e08454d947684de903 100644 (file)
@@ -574,15 +574,28 @@ revoke all on key_desc from someone_else;
 revoke all on key_desc_1 from someone_else;
 drop role someone_else;
 drop table key_desc, key_desc_1;
+-- test minvalue/maxvalue restrictions
+create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, maxvalue);
+ERROR:  every bound following MINVALUE must also be MINVALUE
+LINE 1: ...partition of mcrparted for values from (minvalue, 0, 0) to (...
+                                                             ^
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, minvalue);
+ERROR:  every bound following MAXVALUE must also be MAXVALUE
+LINE 1: ...r values from (10, 6, minvalue) to (10, maxvalue, minvalue);
+                                                             ^
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, minvalue);
+ERROR:  every bound following MINVALUE must also be MINVALUE
+LINE 1: ...ition of mcrparted for values from (21, minvalue, 0) to (30,...
+                                                             ^
 -- check multi-column range partitioning expression enforces the same
 -- constraint as what tuple-routing would determine it to be
-create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, 0);
+create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, maxvalue, maxvalue);
 create table mcrparted1 partition of mcrparted for values from (2, 1, minvalue) to (10, 5, 10);
-create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, 0);
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, maxvalue);
 create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
-create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, maxvalue);
-create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, 0, 0);
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, minvalue) to (30, 20, maxvalue);
+create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, maxvalue, maxvalue);
 -- routed to mcrparted0
 insert into mcrparted values (0, 1, 1);
 insert into mcrparted0 values (0, 1, 1);
@@ -666,14 +679,14 @@ drop table brtrigpartcon;
 drop function brtrigpartcon1trigf();
 -- check multi-column range partitioning with minvalue/maxvalue constraints
 create table mcrparted (a text, b int) partition by range(a, b);
-create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, minvalue) to ('b', minvalue);
 create table mcrparted2_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
 create table mcrparted3_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
 create table mcrparted4_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
 create table mcrparted5_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
 create table mcrparted6_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
 create table mcrparted7_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
-create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, maxvalue);
 \d+ mcrparted
                                  Table "public.mcrparted"
  Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
@@ -681,14 +694,14 @@ create table mcrparted8_ge_d partition of mcrparted for values from ('d', minval
  a      | text    |           |          |         | extended |              | 
  b      | integer |           |          |         | plain    |              | 
 Partition key: RANGE (a, b)
-Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE),
+Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, MINVALUE) TO ('b', MINVALUE),
             mcrparted2_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
             mcrparted3_c_to_common FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE),
             mcrparted4_common_lt_0 FOR VALUES FROM ('common', MINVALUE) TO ('common', 0),
             mcrparted5_common_0_to_10 FOR VALUES FROM ('common', 0) TO ('common', 10),
             mcrparted6_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE),
             mcrparted7_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE),
-            mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
+            mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
 
 \d+ mcrparted1_lt_b
                               Table "public.mcrparted1_lt_b"
@@ -696,7 +709,7 @@ Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE),
 --------+---------+-----------+----------+---------+----------+--------------+-------------
  a      | text    |           |          |         | extended |              | 
  b      | integer |           |          |         | plain    |              | 
-Partition of: mcrparted FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
+Partition of: mcrparted FOR VALUES FROM (MINVALUE, MINVALUE) TO ('b', MINVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
 
 \d+ mcrparted2_b
@@ -759,7 +772,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::te
 --------+---------+-----------+----------+---------+----------+--------------+-------------
  a      | text    |           |          |         | extended |              | 
  b      | integer |           |          |         | plain    |              | 
-Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
+Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'd'::text))
 
 insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
index eeab5d91ffb44ba670686f9df36819d4660192ae..df6a6d732678c6084af26ba74b4ac7a3c9a73f98 100644 (file)
@@ -641,14 +641,14 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
 
 -- check that we get the expected partition constraints
 CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
-CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
+CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE);
 \d+ unbounded_range_part
 DROP TABLE unbounded_range_part;
-CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
+CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE);
 \d+ range_parted4_1
 CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
 \d+ range_parted4_2
-CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
+CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE);
 \d+ range_parted4_3
 DROP TABLE range_parted4;
 
index 01780d497734ccc2f23e12d87acf76bad497deb1..169d0dc0f567e1dfae8920a377688e6c9cd27ebc 100644 (file)
@@ -664,12 +664,12 @@ drop table range_list_parted;
 -- check that constraint exclusion is able to cope with the partition
 -- constraint emitted for multi-column range partitioned tables
 create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
+create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
 create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
 create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
 create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
 create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
-create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
+create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
 explain (costs off) select * from mcrparted where a = 0;   -- scans mcrparted0
 explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5;   -- scans mcrparted1
 explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5;   -- scans mcrparted1, mcrparted2
index a2948e4dd0ced3119816e3f13fe707f9fafebba4..d74151441413f1387844775d436223e906ec0453 100644 (file)
@@ -369,15 +369,20 @@ revoke all on key_desc_1 from someone_else;
 drop role someone_else;
 drop table key_desc, key_desc_1;
 
+-- test minvalue/maxvalue restrictions
+create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, maxvalue);
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, minvalue);
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, minvalue);
+
 -- check multi-column range partitioning expression enforces the same
 -- constraint as what tuple-routing would determine it to be
-create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, 0);
+create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, maxvalue, maxvalue);
 create table mcrparted1 partition of mcrparted for values from (2, 1, minvalue) to (10, 5, 10);
-create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, 0);
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, maxvalue);
 create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
-create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, maxvalue);
-create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, 0, 0);
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, minvalue) to (30, 20, maxvalue);
+create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, maxvalue, maxvalue);
 
 -- routed to mcrparted0
 insert into mcrparted values (0, 1, 1);
@@ -442,14 +447,14 @@ drop function brtrigpartcon1trigf();
 
 -- check multi-column range partitioning with minvalue/maxvalue constraints
 create table mcrparted (a text, b int) partition by range(a, b);
-create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, minvalue) to ('b', minvalue);
 create table mcrparted2_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
 create table mcrparted3_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
 create table mcrparted4_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
 create table mcrparted5_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
 create table mcrparted6_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
 create table mcrparted7_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
-create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, maxvalue);
 
 \d+ mcrparted
 \d+ mcrparted1_lt_b