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