static PartClauseMatchStatus match_boolean_partition_clause(Oid partopfamily,
Expr *clause,
Expr *partkey,
- Expr **outconst);
+ Expr **outconst,
+ bool *noteq);
static void partkey_datum_from_expr(PartitionPruneContext *context,
Expr *expr, int stateidx,
Datum *value, bool *isnull);
Oid partopfamily = part_scheme->partopfamily[partkeyidx],
partcoll = part_scheme->partcollation[partkeyidx];
Expr *expr;
+ bool noteq;
/*
* Recognize specially shaped clauses that match a Boolean partition key.
*/
boolmatchstatus = match_boolean_partition_clause(partopfamily, clause,
- partkey, &expr);
+ partkey, &expr, ¬eq);
if (boolmatchstatus == PARTCLAUSE_MATCH_CLAUSE)
{
partclause->keyno = partkeyidx;
/* Do pruning with the Boolean equality operator. */
partclause->opno = BooleanEqualOperator;
- partclause->op_is_ne = false;
+ partclause->op_is_ne = noteq;
partclause->expr = expr;
/* We know that expr is of Boolean type. */
partclause->cmpfn = part_scheme->partsupfunc[partkeyidx].fn_oid;
* match_boolean_partition_clause
*
* If we're able to match the clause to the partition key as specially-shaped
- * boolean clause, set *outconst to a Const containing a true or false value
- * and return PARTCLAUSE_MATCH_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 it's a bool quals but
- * just does not match this partition key. *outconst is set to NULL in the
- * latter two cases.
+ * boolean clause, set *outconst to a Const containing a true or false value,
+ * set *noteq according to if the clause was in the "not" form, i.e. "is not
+ * true" or "is not false", and return PARTCLAUSE_MATCH_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 it's a bool quals but just does not match this
+ * partition key. *outconst is set to NULL in the latter two cases.
*/
static PartClauseMatchStatus
match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
- Expr **outconst)
+ Expr **outconst, bool *noteq)
{
Expr *leftop;
*outconst = NULL;
+ *noteq = false;
/*
* Partitioning currently can only use built-in AMs, so checking for
leftop = ((RelabelType *) leftop)->arg;
if (equal(leftop, partkey))
- *outconst = (btest->booltesttype == IS_TRUE ||
- btest->booltesttype == IS_NOT_FALSE)
- ? (Expr *) makeBoolConst(true, false)
- : (Expr *) makeBoolConst(false, false);
-
+ {
+ switch (btest->booltesttype)
+ {
+ case IS_NOT_TRUE:
+ *noteq = true;
+ /* fall through */
+ case IS_TRUE:
+ *outconst = (Expr *) makeBoolConst(true, false);
+ break;
+ case IS_NOT_FALSE:
+ *noteq = true;
+ /* fall through */
+ case IS_FALSE:
+ *outconst = (Expr *) makeBoolConst(false, false);
+ break;
+ default:
+ return PARTCLAUSE_UNSUPPORTED;
+ }
+ }
if (*outconst)
return PARTCLAUSE_MATCH_CLAUSE;
}
/* Compare to the partition key, and make up a clause ... */
if (equal(leftop, partkey))
- *outconst = is_not_clause ?
- (Expr *) makeBoolConst(false, false) :
- (Expr *) makeBoolConst(true, false);
+ *outconst = (Expr *) makeBoolConst(!is_not_clause, false);
else if (equal(negate_clause((Node *) leftop), partkey))
- *outconst = (Expr *) makeBoolConst(false, false);
+ *outconst = (Expr *) makeBoolConst(is_not_clause, false);
if (*outconst)
return PARTCLAUSE_MATCH_CLAUSE;
create table boolpart_default partition of boolpart default;
create table boolpart_t partition of boolpart for values in ('true');
create table boolpart_f partition of boolpart for values in ('false');
+insert into boolpart values (true), (false), (null);
explain (costs off) select * from boolpart where a in (true, false);
QUERY PLAN
------------------------------------------------
Filter: ((a IS TRUE) OR (a IS NOT TRUE))
-> Seq Scan on boolpart_t boolpart_2
Filter: ((a IS TRUE) OR (a IS NOT TRUE))
-(5 rows)
+ -> Seq Scan on boolpart_default boolpart_3
+ Filter: ((a IS TRUE) OR (a IS NOT TRUE))
+(7 rows)
explain (costs off) select * from boolpart where a is not true;
- QUERY PLAN
----------------------------------
- Seq Scan on boolpart_f boolpart
- Filter: (a IS NOT TRUE)
-(2 rows)
+ QUERY PLAN
+-----------------------------------------------
+ Append
+ -> Seq Scan on boolpart_f boolpart_1
+ Filter: (a IS NOT TRUE)
+ -> Seq Scan on boolpart_default boolpart_2
+ Filter: (a IS NOT TRUE)
+(5 rows)
explain (costs off) select * from boolpart where a is not true and a is not false;
- QUERY PLAN
---------------------------
- Result
- One-Time Filter: false
+ QUERY PLAN
+--------------------------------------------------
+ Seq Scan on boolpart_default boolpart
+ Filter: ((a IS NOT TRUE) AND (a IS NOT FALSE))
(2 rows)
explain (costs off) select * from boolpart where a is unknown;
Filter: (a IS NOT UNKNOWN)
(7 rows)
+select * from boolpart where a in (true, false);
+ a
+---
+ f
+ t
+(2 rows)
+
+select * from boolpart where a = false;
+ a
+---
+ f
+(1 row)
+
+select * from boolpart where not a = false;
+ a
+---
+ t
+(1 row)
+
+select * from boolpart where a is true or a is not true;
+ a
+---
+ f
+ t
+
+(3 rows)
+
+select * from boolpart where a is not true;
+ a
+---
+ f
+
+(2 rows)
+
+select * from boolpart where a is not true and a is not false;
+ a
+---
+
+(1 row)
+
+select * from boolpart where a is unknown;
+ a
+---
+
+(1 row)
+
+select * from boolpart where a is not unknown;
+ a
+---
+ f
+ t
+(2 rows)
+
+-- inverse boolean partitioning - a seemingly unlikely design, but we've got
+-- code for it, so we'd better test it.
+create table iboolpart (a bool) partition by list ((not a));
+create table iboolpart_default partition of iboolpart default;
+create table iboolpart_f partition of iboolpart for values in ('true');
+create table iboolpart_t partition of iboolpart for values in ('false');
+insert into iboolpart values (true), (false), (null);
+explain (costs off) select * from iboolpart where a in (true, false);
+ QUERY PLAN
+-------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: (a = ANY ('{t,f}'::boolean[]))
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: (a = ANY ('{t,f}'::boolean[]))
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: (a = ANY ('{t,f}'::boolean[]))
+(7 rows)
+
+explain (costs off) select * from iboolpart where a = false;
+ QUERY PLAN
+-----------------------------------
+ Seq Scan on iboolpart_f iboolpart
+ Filter: (NOT a)
+(2 rows)
+
+explain (costs off) select * from iboolpart where not a = false;
+ QUERY PLAN
+-----------------------------------
+ Seq Scan on iboolpart_t iboolpart
+ Filter: a
+(2 rows)
+
+explain (costs off) select * from iboolpart where a is true or a is not true;
+ QUERY PLAN
+--------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: ((a IS TRUE) OR (a IS NOT TRUE))
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: ((a IS TRUE) OR (a IS NOT TRUE))
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: ((a IS TRUE) OR (a IS NOT TRUE))
+(7 rows)
+
+explain (costs off) select * from iboolpart where a is not true;
+ QUERY PLAN
+-------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: (a IS NOT TRUE)
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: (a IS NOT TRUE)
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: (a IS NOT TRUE)
+(7 rows)
+
+explain (costs off) select * from iboolpart where a is not true and a is not false;
+ QUERY PLAN
+--------------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: ((a IS NOT TRUE) AND (a IS NOT FALSE))
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: ((a IS NOT TRUE) AND (a IS NOT FALSE))
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: ((a IS NOT TRUE) AND (a IS NOT FALSE))
+(7 rows)
+
+explain (costs off) select * from iboolpart where a is unknown;
+ QUERY PLAN
+-------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: (a IS UNKNOWN)
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: (a IS UNKNOWN)
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: (a IS UNKNOWN)
+(7 rows)
+
+explain (costs off) select * from iboolpart where a is not unknown;
+ QUERY PLAN
+-------------------------------------------------
+ Append
+ -> Seq Scan on iboolpart_t iboolpart_1
+ Filter: (a IS NOT UNKNOWN)
+ -> Seq Scan on iboolpart_f iboolpart_2
+ Filter: (a IS NOT UNKNOWN)
+ -> Seq Scan on iboolpart_default iboolpart_3
+ Filter: (a IS NOT UNKNOWN)
+(7 rows)
+
+select * from iboolpart where a in (true, false);
+ a
+---
+ t
+ f
+(2 rows)
+
+select * from iboolpart where a = false;
+ a
+---
+ f
+(1 row)
+
+select * from iboolpart where not a = false;
+ a
+---
+ t
+(1 row)
+
+select * from iboolpart where a is true or a is not true;
+ a
+---
+ t
+ f
+
+(3 rows)
+
+select * from iboolpart where a is not true;
+ a
+---
+ f
+
+(2 rows)
+
+select * from iboolpart where a is not true and a is not false;
+ a
+---
+
+(1 row)
+
+select * from iboolpart where a is unknown;
+ a
+---
+
+(1 row)
+
+select * from iboolpart where a is not unknown;
+ a
+---
+ t
+ f
+(2 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);
Filter: (a > '100000000000000'::bigint)
(2 rows)
-drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
+drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, iboolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
--
-- Test Partition pruning for HASH partitioning
--
create table boolpart_default partition of boolpart default;
create table boolpart_t partition of boolpart for values in ('true');
create table boolpart_f partition of boolpart for values in ('false');
+insert into boolpart values (true), (false), (null);
explain (costs off) select * from boolpart where a in (true, false);
explain (costs off) select * from boolpart where a = false;
explain (costs off) select * from boolpart where a is unknown;
explain (costs off) select * from boolpart where a is not unknown;
+select * from boolpart where a in (true, false);
+select * from boolpart where a = false;
+select * from boolpart where not a = false;
+select * from boolpart where a is true or a is not true;
+select * from boolpart where a is not true;
+select * from boolpart where a is not true and a is not false;
+select * from boolpart where a is unknown;
+select * from boolpart where a is not unknown;
+
+-- inverse boolean partitioning - a seemingly unlikely design, but we've got
+-- code for it, so we'd better test it.
+create table iboolpart (a bool) partition by list ((not a));
+create table iboolpart_default partition of iboolpart default;
+create table iboolpart_f partition of iboolpart for values in ('true');
+create table iboolpart_t partition of iboolpart for values in ('false');
+insert into iboolpart values (true), (false), (null);
+
+explain (costs off) select * from iboolpart where a in (true, false);
+explain (costs off) select * from iboolpart where a = false;
+explain (costs off) select * from iboolpart where not a = false;
+explain (costs off) select * from iboolpart where a is true or a is not true;
+explain (costs off) select * from iboolpart where a is not true;
+explain (costs off) select * from iboolpart where a is not true and a is not false;
+explain (costs off) select * from iboolpart where a is unknown;
+explain (costs off) select * from iboolpart where a is not unknown;
+
+select * from iboolpart where a in (true, false);
+select * from iboolpart where a = false;
+select * from iboolpart where not a = false;
+select * from iboolpart where a is true or a is not true;
+select * from iboolpart where a is not true;
+select * from iboolpart where a is not true and a is not false;
+select * from iboolpart where a is unknown;
+select * from iboolpart 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);
-- all partitions but rparted_by_int2_maxvalue pruned
explain (costs off) select * from rparted_by_int2 where a > 100_000_000_000_000;
-drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
+drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, iboolpart, boolrangep, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
--
-- Test Partition pruning for HASH partitioning