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
8namespace duckdb {
9
10unique_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