v3_ignore_contradictory_where_clauses_at_partprune_step.patch

application/octet-stream

Filename: v3_ignore_contradictory_where_clauses_at_partprune_step.patch
Type: application/octet-stream
Part: 0
Message: RE: Problem with default partition pruning

Patch

Format: unified
Series: patch v3
File+
src/backend/partitioning/partprune.c 24 19
src/test/regress/expected/partition_prune.out 18 0
src/test/regress/sql/partition_prune.sql 4 0
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 5cd740a..f360d82 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -783,11 +783,35 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
 	{
 		Expr	   *clause = (Expr *) lfirst(lc);
 		int			i;
+		List	   *partconstr = rel->partition_qual;
 
 		/* Look through RestrictInfo, if any */
 		if (IsA(clause, RestrictInfo))
 			clause = ((RestrictInfo *) clause)->clause;
 
+		/*
+		 * If this clause can be proved false for this partition,
+		 * given its partition constraint, we can ignore it,
+		 * that is not try to pass it to the pruning code.
+		 * We should do that especially to avoid pruning code
+		 * wrongly failing to prune the default partition.
+		 */
+		if (partconstr)
+		{
+			partconstr = (List *)
+				expression_planner((Expr *) partconstr);
+			if (rel->relid != 1)
+				ChangeVarNodes((Node *) partconstr, 1,
+							   rel->relid, 0);
+			if (predicate_refuted_by(partconstr,
+									 list_make1(clause),
+									 false))
+			{
+				*contradictory = true;
+				return NIL;
+			}
+		}
+
 		/* Constant-false-or-null is contradictory */
 		if (IsA(clause, Const) &&
 			(((Const *) clause)->constisnull ||
@@ -850,32 +874,13 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
 						 * an arg.  To indicate that to the pruning code, we
 						 * must construct a dummy PartitionPruneStepCombine
 						 * whose source_stepids is set to an empty List.
-						 * However, if we can prove using constraint exclusion
-						 * that the clause refutes the table's partition
-						 * constraint (if it's sub-partitioned), we need not
-						 * bother with that.  That is, we effectively ignore
-						 * this OR arm.
 						 */
-						List	   *partconstr = rel->partition_qual;
 						PartitionPruneStep *orstep;
 
 						/* Just ignore this argument. */
 						if (arg_contradictory)
 							continue;
 
-						if (partconstr)
-						{
-							partconstr = (List *)
-								expression_planner((Expr *) partconstr);
-							if (rel->relid != 1)
-								ChangeVarNodes((Node *) partconstr, 1,
-											   rel->relid, 0);
-							if (predicate_refuted_by(partconstr,
-													 list_make1(arg),
-													 false))
-								continue;
-						}
-
 						orstep = gen_prune_step_combine(context, NIL,
 														PARTPRUNE_COMBINE_UNION);
 						arg_stepids = lappend_int(arg_stepids, orstep->step_id);
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index b46951c..716155d 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -592,6 +592,24 @@ explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25);
          Filter: ((a < 1) OR ((a > 20) AND (a < 25)))
 (5 rows)
 
+-- where clause contradicts sub-partition's constraint 
+explain (costs off) select * from rlp where a = 20 or a = 40;
+               QUERY PLAN               
+----------------------------------------
+ Append
+   ->  Seq Scan on rlp4_1
+         Filter: ((a = 20) OR (a = 40))
+   ->  Seq Scan on rlp5_default
+         Filter: ((a = 20) OR (a = 40))
+(5 rows)
+
+explain (costs off) select * from rlp3 where a = 20;   /* empty */
+        QUERY PLAN        
+--------------------------
+ Result
+   One-Time Filter: false
+(2 rows)
+
 -- redundant clauses are eliminated
 explain (costs off) select * from rlp where a > 1 and a = 10;	/* only default */
             QUERY PLAN            
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index abc6d9e..a5e8109 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -85,6 +85,10 @@ explain (costs off) select * from rlp where a = 29;
 explain (costs off) select * from rlp where a >= 29;
 explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25);
 
+-- where clause contradicts sub-partition's constraint
+explain (costs off) select * from rlp where a = 20 or a = 40;
+explain (costs off) select * from rlp3 where a = 20;   /* empty */
+
 -- redundant clauses are eliminated
 explain (costs off) select * from rlp where a > 1 and a = 10;	/* only default */
 explain (costs off) select * from rlp where a > 1 and a >=15;	/* rlp3 onwards, including default */