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
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 */