| 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 |