1 | #include "duckdb/optimizer/statistics_propagator.hpp" |
2 | #include "duckdb/planner/expression/bound_between_expression.hpp" |
3 | #include "duckdb/planner/expression/bound_comparison_expression.hpp" |
4 | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
5 | #include "duckdb/optimizer/expression_rewriter.hpp" |
6 | |
7 | namespace duckdb { |
8 | |
9 | unique_ptr<BaseStatistics> StatisticsPropagator::PropagateExpression(BoundBetweenExpression &between, |
10 | unique_ptr<Expression> *expr_ptr) { |
11 | // propagate in all the children |
12 | auto input_stats = PropagateExpression(expr&: between.input); |
13 | auto lower_stats = PropagateExpression(expr&: between.lower); |
14 | auto upper_stats = PropagateExpression(expr&: between.upper); |
15 | if (!input_stats) { |
16 | return nullptr; |
17 | } |
18 | auto lower_comparison = between.LowerComparisonType(); |
19 | auto upper_comparison = between.UpperComparisonType(); |
20 | // propagate the comparisons |
21 | auto lower_prune = FilterPropagateResult::NO_PRUNING_POSSIBLE; |
22 | auto upper_prune = FilterPropagateResult::NO_PRUNING_POSSIBLE; |
23 | if (lower_stats) { |
24 | lower_prune = PropagateComparison(left&: *input_stats, right&: *lower_stats, comparison: lower_comparison); |
25 | } |
26 | if (upper_stats) { |
27 | upper_prune = PropagateComparison(left&: *input_stats, right&: *upper_stats, comparison: upper_comparison); |
28 | } |
29 | if (lower_prune == FilterPropagateResult::FILTER_ALWAYS_TRUE && |
30 | upper_prune == FilterPropagateResult::FILTER_ALWAYS_TRUE) { |
31 | // both filters are always true: replace the between expression with a constant true |
32 | *expr_ptr = make_uniq<BoundConstantExpression>(args: Value::BOOLEAN(value: true)); |
33 | } else if (lower_prune == FilterPropagateResult::FILTER_ALWAYS_FALSE || |
34 | upper_prune == FilterPropagateResult::FILTER_ALWAYS_FALSE) { |
35 | // either one of the filters is always false: replace the between expression with a constant false |
36 | *expr_ptr = make_uniq<BoundConstantExpression>(args: Value::BOOLEAN(value: false)); |
37 | } else if (lower_prune == FilterPropagateResult::FILTER_FALSE_OR_NULL || |
38 | upper_prune == FilterPropagateResult::FILTER_FALSE_OR_NULL) { |
39 | // either one of the filters is false or null: replace with a constant or null (false) |
40 | vector<unique_ptr<Expression>> children; |
41 | children.push_back(x: std::move(between.input)); |
42 | children.push_back(x: std::move(between.lower)); |
43 | children.push_back(x: std::move(between.upper)); |
44 | *expr_ptr = ExpressionRewriter::ConstantOrNull(children: std::move(children), value: Value::BOOLEAN(value: false)); |
45 | } else if (lower_prune == FilterPropagateResult::FILTER_TRUE_OR_NULL && |
46 | upper_prune == FilterPropagateResult::FILTER_TRUE_OR_NULL) { |
47 | // both filters are true or null: replace with a true or null |
48 | vector<unique_ptr<Expression>> children; |
49 | children.push_back(x: std::move(between.input)); |
50 | children.push_back(x: std::move(between.lower)); |
51 | children.push_back(x: std::move(between.upper)); |
52 | *expr_ptr = ExpressionRewriter::ConstantOrNull(children: std::move(children), value: Value::BOOLEAN(value: true)); |
53 | } else if (lower_prune == FilterPropagateResult::FILTER_ALWAYS_TRUE) { |
54 | // lower filter is always true: replace with upper comparison |
55 | *expr_ptr = |
56 | make_uniq<BoundComparisonExpression>(args&: upper_comparison, args: std::move(between.input), args: std::move(between.upper)); |
57 | } else if (upper_prune == FilterPropagateResult::FILTER_ALWAYS_TRUE) { |
58 | // upper filter is always true: replace with lower comparison |
59 | *expr_ptr = |
60 | make_uniq<BoundComparisonExpression>(args&: lower_comparison, args: std::move(between.input), args: std::move(between.lower)); |
61 | } |
62 | return nullptr; |
63 | } |
64 | |
65 | } // namespace duckdb |
66 | |