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