1#include "duckdb/optimizer/rule/conjunction_simplification.hpp"
2
3#include "duckdb/execution/expression_executor.hpp"
4#include "duckdb/planner/expression/bound_conjunction_expression.hpp"
5#include "duckdb/planner/expression/bound_constant_expression.hpp"
6
7using namespace duckdb;
8using namespace std;
9
10ConjunctionSimplificationRule::ConjunctionSimplificationRule(ExpressionRewriter &rewriter) : Rule(rewriter) {
11 // match on a ComparisonExpression that has a ConstantExpression as a check
12 auto op = make_unique<ConjunctionExpressionMatcher>();
13 op->matchers.push_back(make_unique<FoldableConstantMatcher>());
14 op->policy = SetMatcher::Policy::SOME;
15 root = move(op);
16}
17
18unique_ptr<Expression> ConjunctionSimplificationRule::RemoveExpression(BoundConjunctionExpression &conj,
19 Expression *expr) {
20 for (idx_t i = 0; i < conj.children.size(); i++) {
21 if (conj.children[i].get() == expr) {
22 // erase the expression
23 conj.children.erase(conj.children.begin() + i);
24 break;
25 }
26 }
27 if (conj.children.size() == 1) {
28 // one expression remaining: simply return that expression and erase the conjunction
29 return move(conj.children[0]);
30 }
31 return nullptr;
32}
33
34unique_ptr<Expression> ConjunctionSimplificationRule::Apply(LogicalOperator &op, vector<Expression *> &bindings,
35 bool &changes_made) {
36 auto conjunction = (BoundConjunctionExpression *)bindings[0];
37 auto constant_expr = bindings[1];
38 // the constant_expr is a scalar expression that we have to fold
39 // use an ExpressionExecutor to execute the expression
40 assert(constant_expr->IsFoldable());
41 auto constant_value = ExpressionExecutor::EvaluateScalar(*constant_expr).CastAs(TypeId::BOOL);
42 if (constant_value.is_null) {
43 // we can't simplify conjunctions with a constant NULL
44 return nullptr;
45 }
46 if (conjunction->type == ExpressionType::CONJUNCTION_AND) {
47 if (!constant_value.value_.boolean) {
48 // FALSE in AND, result of expression is false
49 return make_unique<BoundConstantExpression>(Value::BOOLEAN(false));
50 } else {
51 // TRUE in AND, remove the expression from the set
52 return RemoveExpression(*conjunction, constant_expr);
53 }
54 } else {
55 assert(conjunction->type == ExpressionType::CONJUNCTION_OR);
56 if (!constant_value.value_.boolean) {
57 // FALSE in OR, remove the expression from the set
58 return RemoveExpression(*conjunction, constant_expr);
59 } else {
60 // TRUE in OR, result of expression is true
61 return make_unique<BoundConstantExpression>(Value::BOOLEAN(true));
62 }
63 }
64}
65