From 192d1bbf99699de76473184c57fff9ff4b4246f4 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Mon, 30 Jul 2018 17:18:42 -0400
Subject: [PATCH] Change bms_add_range to be a no-op for empty ranges

In commit 84940644de93, bms_add_range was added with an API to fail with
an error if an empty range was specified.  This seems arbitrary and
unhelpful, so turn that case into a no-op instead.  Callers that require
further verification on the arguments or result can apply them by
themselves.

This fixes the bug that partition pruning throws an API error for a case
involving the default partition of a default partition, as in the
included test case.

Reported-by: Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com>
Diagnosed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/16590.1532622503@sss.pgh.pa.us
---
 src/backend/nodes/bitmapset.c                 |  7 +++++--
 src/test/regress/expected/partition_prune.out | 15 +++++++++++++++
 src/test/regress/sql/partition_prune.sql      |  7 +++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 9bf9a29d6b1..6208f4ed936 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -867,6 +867,10 @@ bms_add_range(Bitmapset *a, int lower, int upper)
 				ushiftbits,
 				wordnum;
 
+	/* do nothing if nothing is called for, without further checking */
+	if (upper < lower)
+		return a;
+
 	if (lower < 0 || upper < 0)
 		elog(ERROR, "negative bitmapset member not allowed");
 	if (lower > upper)
@@ -878,13 +882,12 @@ bms_add_range(Bitmapset *a, int lower, int upper)
 		a = (Bitmapset *) palloc0(BITMAPSET_SIZE(uwordnum + 1));
 		a->nwords = uwordnum + 1;
 	}
-
-	/* ensure we have enough words to store the upper bit */
 	else if (uwordnum >= a->nwords)
 	{
 		int			oldnwords = a->nwords;
 		int			i;
 
+		/* ensure we have enough words to store the upper bit */
 		a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1));
 		a->nwords = uwordnum + 1;
 		/* zero out the enlarged portion */
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 022b7c55c7d..cd0d044a0b0 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -1180,6 +1180,21 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}');
 (7 rows)
 
 drop table coercepart;
+CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a);
+CREATE TABLE part_p1 PARTITION OF part FOR VALUES IN (-2,-1,0,1,2);
+CREATE TABLE part_p2 PARTITION OF part DEFAULT PARTITION BY RANGE(a);
+CREATE TABLE part_p2_p1 PARTITION OF part_p2 DEFAULT;
+INSERT INTO part VALUES (-1,-1), (1,1), (2,NULL), (NULL,-2),(NULL,NULL);
+EXPLAIN (COSTS OFF) SELECT tableoid::regclass as part, a, b FROM part WHERE a IS NULL ORDER BY 1, 2, 3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Sort
+   Sort Key: ((part_p2_p1.tableoid)::regclass), part_p2_p1.a, part_p2_p1.b
+   ->  Append
+         ->  Seq Scan on part_p2_p1
+               Filter: (a IS NULL)
+(5 rows)
+
 --
 -- some more cases
 --
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index 2357f02cde9..f0f62f6543f 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -173,6 +173,13 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}');
 
 drop table coercepart;
 
+CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a);
+CREATE TABLE part_p1 PARTITION OF part FOR VALUES IN (-2,-1,0,1,2);
+CREATE TABLE part_p2 PARTITION OF part DEFAULT PARTITION BY RANGE(a);
+CREATE TABLE part_p2_p1 PARTITION OF part_p2 DEFAULT;
+INSERT INTO part VALUES (-1,-1), (1,1), (2,NULL), (NULL,-2),(NULL,NULL);
+EXPLAIN (COSTS OFF) SELECT tableoid::regclass as part, a, b FROM part WHERE a IS NULL ORDER BY 1, 2, 3;
+
 --
 -- some more cases
 --
-- 
GitLab