fix_boolean_partition_pruning.patch
application/octet-stream
Filename: fix_boolean_partition_pruning.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/partitioning/partprune.c | 24 | 13 |
| src/test/regress/expected/partition_prune.out | 14 | 1 |
| src/test/regress/sql/partition_prune.sql | 10 | 1 |
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 5982af4de1..2c6e97ac16 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -194,8 +194,10 @@ static PruneStepResult *perform_pruning_base_step(PartitionPruneContext *context
static PruneStepResult *perform_pruning_combine_step(PartitionPruneContext *context,
PartitionPruneStepCombine *cstep,
PruneStepResult **step_results);
-static bool match_boolean_partition_clause(Oid partopfamily, Expr *clause,
- Expr *partkey, Expr **outconst);
+static PartClauseMatchStatus match_boolean_partition_clause(Oid partopfamily,
+ Expr *clause,
+ Expr *partkey,
+ Expr **outconst);
static void partkey_datum_from_expr(PartitionPruneContext *context,
Expr *expr, int stateidx,
Datum *value, bool *isnull);
@@ -1623,6 +1625,7 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
bool *clause_is_not_null, PartClauseInfo **pc,
List **clause_steps)
{
+ PartClauseMatchStatus boolmatchstatus;
PartitionScheme part_scheme = context->rel->part_scheme;
Oid partopfamily = part_scheme->partopfamily[partkeyidx],
partcoll = part_scheme->partcollation[partkeyidx];
@@ -1631,7 +1634,10 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
/*
* Recognize specially shaped clauses that match a Boolean partition key.
*/
- if (match_boolean_partition_clause(partopfamily, clause, partkey, &expr))
+ boolmatchstatus = match_boolean_partition_clause(partopfamily, clause,
+ partkey, &expr);
+
+ if (boolmatchstatus == PARTCLAUSE_MATCH_CLAUSE)
{
PartClauseInfo *partclause;
@@ -2147,7 +2153,8 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
return PARTCLAUSE_MATCH_NULLNESS;
}
- return PARTCLAUSE_UNSUPPORTED;
+ /* return the value from the match_boolean_partition_clause call */
+ return boolmatchstatus;
}
/*
@@ -3395,11 +3402,15 @@ perform_pruning_combine_step(PartitionPruneContext *context,
/*
* match_boolean_partition_clause
*
- * Sets *outconst to a Const containing true or false value and returns true if
- * we're able to match the clause to the partition key as specially-shaped
- * Boolean clause. Returns false otherwise with *outconst set to NULL.
+ * Sets *outconst to a Const containing a true or false value and returns
+ * PARTCLAUSE_MATCH_CLAUSE if we're able to match the clause to the partition
+ * key as specially-shaped Boolean clause. Returns PARTCLAUSE_UNSUPPORTED if
+ * the clause is not a boolean clause or if the boolean clause is unsuitable
+ * for partition pruning. Returns PARTCLAUSE_NOMATCH if we're unable to match
+ * the clause up to the partition key. *outconst is set to NULL in the latter
+ * two cases.
*/
-static bool
+static PartClauseMatchStatus
match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
Expr **outconst)
{
@@ -3408,7 +3419,7 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
*outconst = NULL;
if (!IsBooleanOpfamily(partopfamily))
- return false;
+ return PARTCLAUSE_UNSUPPORTED;
if (IsA(clause, BooleanTest))
{
@@ -3417,7 +3428,7 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
/* Only IS [NOT] TRUE/FALSE are any good to us */
if (btest->booltesttype == IS_UNKNOWN ||
btest->booltesttype == IS_NOT_UNKNOWN)
- return false;
+ return PARTCLAUSE_UNSUPPORTED;
leftop = btest->arg;
if (IsA(leftop, RelabelType))
@@ -3430,7 +3441,7 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
: (Expr *) makeBoolConst(false, false);
if (*outconst)
- return true;
+ return PARTCLAUSE_MATCH_CLAUSE;
}
else
{
@@ -3450,10 +3461,10 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
*outconst = (Expr *) makeBoolConst(false, false);
if (*outconst)
- return true;
+ return PARTCLAUSE_MATCH_CLAUSE;
}
- return false;
+ return PARTCLAUSE_NOMATCH;
}
/*
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 841bd8bc67..604375e787 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -1086,6 +1086,19 @@ explain (costs off) select * from boolpart where a is not unknown;
Filter: (a IS NOT UNKNOWN)
(7 rows)
+create table boolrangep (a bool, b bool, c int) partition by range (a,b,c);
+create table boolrangep_tf partition of boolrangep for values from ('true', 'false', 0) to ('true', 'false', 100);
+create table boolrangep_ft partition of boolrangep for values from ('false', 'true', 0) to ('false', 'true', 100);
+create table boolrangep_ff1 partition of boolrangep for values from ('false', 'false', 0) to ('false', 'false', 50);
+create table boolrangep_ff2 partition of boolrangep for values from ('false', 'false', 50) to ('false', 'false', 100);
+-- try a more complex boolean case that's been known to trip up pruning in the past
+explain (costs off) select * from boolrangep where not a and not b and c = 25;
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on boolrangep_ff1
+ Filter: ((NOT a) AND (NOT b) AND (c = 25))
+(2 rows)
+
-- test scalar-to-array operators
create table coercepart (a varchar) partition by list (a);
create table coercepart_ab partition of coercepart for values in ('ab');
@@ -1420,7 +1433,7 @@ explain (costs off) select * from rparted_by_int2 where a > 100000000000000;
Filter: (a > '100000000000000'::bigint)
(2 rows)
-drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
+drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
--
-- Test Partition pruning for HASH partitioning
--
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index 071e28dce8..f8a3cf53db 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -159,6 +159,15 @@ explain (costs off) select * from boolpart where a is not true and a is not fals
explain (costs off) select * from boolpart where a is unknown;
explain (costs off) select * from boolpart where a is not unknown;
+create table boolrangep (a bool, b bool, c int) partition by range (a,b,c);
+create table boolrangep_tf partition of boolrangep for values from ('true', 'false', 0) to ('true', 'false', 100);
+create table boolrangep_ft partition of boolrangep for values from ('false', 'true', 0) to ('false', 'true', 100);
+create table boolrangep_ff1 partition of boolrangep for values from ('false', 'false', 0) to ('false', 'false', 50);
+create table boolrangep_ff2 partition of boolrangep for values from ('false', 'false', 50) to ('false', 'false', 100);
+
+-- try a more complex boolean case that's been known to trip up pruning in the past
+explain (costs off) select * from boolrangep where not a and not b and c = 25;
+
-- test scalar-to-array operators
create table coercepart (a varchar) partition by list (a);
create table coercepart_ab partition of coercepart for values in ('ab');
@@ -264,7 +273,7 @@ create table rparted_by_int2_maxvalue partition of rparted_by_int2 for values fr
-- all partitions but rparted_by_int2_maxvalue pruned
explain (costs off) select * from rparted_by_int2 where a > 100000000000000;
-drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
+drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
--
-- Test Partition pruning for HASH partitioning