1 | |
---|---|
2 | #include "duckdb/optimizer/statistics_propagator.hpp" |
3 | #include "duckdb/planner/expression/bound_conjunction_expression.hpp" |
4 | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
5 | #include "duckdb/optimizer/expression_rewriter.hpp" |
6 | #include "duckdb/execution/expression_executor.hpp" |
7 | |
8 | namespace duckdb { |
9 | |
10 | unique_ptr<BaseStatistics> StatisticsPropagator::PropagateExpression(BoundConjunctionExpression &expr, |
11 | unique_ptr<Expression> *expr_ptr) { |
12 | auto is_and = expr.type == ExpressionType::CONJUNCTION_AND; |
13 | for (idx_t expr_idx = 0; expr_idx < expr.children.size(); expr_idx++) { |
14 | auto &child = expr.children[expr_idx]; |
15 | auto stats = PropagateExpression(expr&: child); |
16 | if (!child->IsFoldable()) { |
17 | continue; |
18 | } |
19 | // we have a constant in a conjunction |
20 | // we (1) either prune the child |
21 | // or (2) replace the entire conjunction with a constant |
22 | auto constant = ExpressionExecutor::EvaluateScalar(context, expr: *child); |
23 | if (constant.IsNull()) { |
24 | continue; |
25 | } |
26 | auto b = BooleanValue::Get(value: constant); |
27 | bool prune_child = false; |
28 | bool constant_value = true; |
29 | if (b) { |
30 | // true |
31 | if (is_and) { |
32 | // true in and: prune child |
33 | prune_child = true; |
34 | } else { |
35 | // true in OR: replace with TRUE |
36 | constant_value = true; |
37 | } |
38 | } else { |
39 | // false |
40 | if (is_and) { |
41 | // false in AND: replace with FALSE |
42 | constant_value = false; |
43 | } else { |
44 | // false in OR: prune child |
45 | prune_child = true; |
46 | } |
47 | } |
48 | if (prune_child) { |
49 | expr.children.erase(position: expr.children.begin() + expr_idx); |
50 | expr_idx--; |
51 | continue; |
52 | } |
53 | *expr_ptr = make_uniq<BoundConstantExpression>(args: Value::BOOLEAN(value: constant_value)); |
54 | return PropagateExpression(expr&: *expr_ptr); |
55 | } |
56 | if (expr.children.empty()) { |
57 | // if there are no children left, replace the conjunction with TRUE (for AND) or FALSE (for OR) |
58 | *expr_ptr = make_uniq<BoundConstantExpression>(args: Value::BOOLEAN(value: is_and)); |
59 | return PropagateExpression(expr&: *expr_ptr); |
60 | } else if (expr.children.size() == 1) { |
61 | // if there is one child left, replace the conjunction with that one child |
62 | *expr_ptr = std::move(expr.children[0]); |
63 | } |
64 | return nullptr; |
65 | } |
66 | |
67 | } // namespace duckdb |
68 |