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 | |
7 | using namespace duckdb; |
8 | using namespace std; |
9 | |
10 | ConjunctionSimplificationRule::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 | |
18 | unique_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 | |
34 | unique_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 |