From 2bca3f25e5ac17631200fb5d76684d5805a76d77 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 8 May 2017 13:29:19 +0900
Subject: [PATCH 1/3] Disallow finite value after UNBOUNDED in range bounds

It does not make sense to have a finite lower or upper bound value
for a column, if an earlier column is unconstrained, i.e., has
UNBOUNDED specified.
---
 src/backend/parser/parse_utilcmd.c         | 34 ++++++++++++++++++++++++++++--
 src/test/regress/expected/create_table.out |  7 ++++++
 src/test/regress/sql/create_table.sql      |  5 +++++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index e187409f6f..3abb655ea6 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3358,6 +3358,9 @@ transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
 		int			i,
 					j;
 		char	   *colname;
+		PartitionRangeDatum *ldatum,
+					   *rdatum;
+		bool		seen_unbounded;
 
 		if (spec->strategy != PARTITION_STRATEGY_RANGE)
 			ereport(ERROR,
@@ -3376,12 +3379,39 @@ transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 					 errmsg("TO must specify exactly one value per partitioning column")));
 
+		/*
+		 * Check that no finite value follows a UNBOUNDED literal in either of
+		 * lower and upper bound lists.
+		 */
+		seen_unbounded = false;
+		foreach(cell1, spec->lowerdatums)
+		{
+			ldatum = (PartitionRangeDatum *) lfirst(cell1);
+			if (ldatum->infinite)
+				seen_unbounded = true;
+			else if (seen_unbounded)
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("cannot specify finite value after UNBOUNDED"),
+						 parser_errposition(pstate, exprLocation((Node *) ldatum))));
+		}
+		seen_unbounded = false;
+		foreach(cell1, spec->upperdatums)
+		{
+			rdatum = (PartitionRangeDatum *) lfirst(cell1);
+			if (rdatum->infinite)
+				seen_unbounded = true;
+			else if (seen_unbounded)
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("cannot specify finite value after UNBOUNDED"),
+						 parser_errposition(pstate, exprLocation((Node *) rdatum))));
+		}
+
 		i = j = 0;
 		result_spec->lowerdatums = result_spec->upperdatums = NIL;
 		forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
 		{
-			PartitionRangeDatum *ldatum,
-					   *rdatum;
 			Node	   *value;
 			A_Const    *lcon = NULL,
 					   *rcon = NULL;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index dda0d7ee5d..15d4ce591c 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -505,6 +505,13 @@ ERROR:  TO must specify exactly one value per partitioning column
 -- cannot specify null values in range bounds
 CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded);
 ERROR:  cannot specify NULL in range bound
+-- cannot specify finite values after UNBOUNDED has been specified
+CREATE TABLE range_parted_multicol (a int, b int, c int) PARTITION BY RANGE (a, b, c);
+CREATE TABLE fail_part PARTITION OF range_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNBOUNDED, 1, 1);
+ERROR:  cannot specify finite value after UNBOUNDED
+LINE 1: ...ge_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNB...
+                                                             ^
+DROP TABLE range_parted_multicol;
 -- check if compatible with the specified parent
 -- cannot create as partition of a non-partitioned table
 CREATE TABLE unparted (
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index caf5ddb58b..95035c5947 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -473,6 +473,11 @@ CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z',
 -- cannot specify null values in range bounds
 CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded);
 
+-- cannot specify finite values after UNBOUNDED has been specified
+CREATE TABLE range_parted_multicol (a int, b int, c int) PARTITION BY RANGE (a, b, c);
+CREATE TABLE fail_part PARTITION OF range_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNBOUNDED, 1, 1);
+DROP TABLE range_parted_multicol;
+
 -- check if compatible with the specified parent
 
 -- cannot create as partition of a non-partitioned table
-- 
2.11.0

