| 1 | #include "duckdb/parser/expression/between_expression.hpp" |
| 2 | #include "duckdb/planner/expression/bound_between_expression.hpp" |
| 3 | #include "duckdb/planner/expression/bound_cast_expression.hpp" |
| 4 | #include "duckdb/planner/expression/bound_comparison_expression.hpp" |
| 5 | #include "duckdb/planner/expression/bound_conjunction_expression.hpp" |
| 6 | #include "duckdb/planner/expression/bound_parameter_expression.hpp" |
| 7 | #include "duckdb/planner/expression_binder.hpp" |
| 8 | |
| 9 | namespace duckdb { |
| 10 | |
| 11 | BindResult ExpressionBinder::BindExpression(BetweenExpression &expr, idx_t depth) { |
| 12 | // first try to bind the children of the case expression |
| 13 | string error; |
| 14 | BindChild(expr&: expr.input, depth, error); |
| 15 | BindChild(expr&: expr.lower, depth, error); |
| 16 | BindChild(expr&: expr.upper, depth, error); |
| 17 | if (!error.empty()) { |
| 18 | return BindResult(error); |
| 19 | } |
| 20 | // the children have been successfully resolved |
| 21 | auto &input = BoundExpression::GetExpression(expr&: *expr.input); |
| 22 | auto &lower = BoundExpression::GetExpression(expr&: *expr.lower); |
| 23 | auto &upper = BoundExpression::GetExpression(expr&: *expr.upper); |
| 24 | |
| 25 | auto input_sql_type = input->return_type; |
| 26 | auto lower_sql_type = lower->return_type; |
| 27 | auto upper_sql_type = upper->return_type; |
| 28 | |
| 29 | // cast the input types to the same type |
| 30 | // now obtain the result type of the input types |
| 31 | auto input_type = BoundComparisonExpression::BindComparison(left_type: input_sql_type, right_type: lower_sql_type); |
| 32 | input_type = BoundComparisonExpression::BindComparison(left_type: input_type, right_type: upper_sql_type); |
| 33 | // add casts (if necessary) |
| 34 | input = BoundCastExpression::AddCastToType(context, expr: std::move(input), target_type: input_type); |
| 35 | lower = BoundCastExpression::AddCastToType(context, expr: std::move(lower), target_type: input_type); |
| 36 | upper = BoundCastExpression::AddCastToType(context, expr: std::move(upper), target_type: input_type); |
| 37 | if (input_type.id() == LogicalTypeId::VARCHAR) { |
| 38 | // handle collation |
| 39 | auto collation = StringType::GetCollation(type: input_type); |
| 40 | input = PushCollation(context, source: std::move(input), collation, equality_only: false); |
| 41 | lower = PushCollation(context, source: std::move(lower), collation, equality_only: false); |
| 42 | upper = PushCollation(context, source: std::move(upper), collation, equality_only: false); |
| 43 | } |
| 44 | if (!input->HasSideEffects() && !input->HasParameter() && !input->HasSubquery()) { |
| 45 | // the expression does not have side effects and can be copied: create two comparisons |
| 46 | // the reason we do this is that individual comparisons are easier to handle in optimizers |
| 47 | // if both comparisons remain they will be folded together again into a single BETWEEN in the optimizer |
| 48 | auto left_compare = make_uniq<BoundComparisonExpression>(args: ExpressionType::COMPARE_GREATERTHANOREQUALTO, |
| 49 | args: input->Copy(), args: std::move(lower)); |
| 50 | auto right_compare = make_uniq<BoundComparisonExpression>(args: ExpressionType::COMPARE_LESSTHANOREQUALTO, |
| 51 | args: std::move(input), args: std::move(upper)); |
| 52 | return BindResult(make_uniq<BoundConjunctionExpression>(args: ExpressionType::CONJUNCTION_AND, |
| 53 | args: std::move(left_compare), args: std::move(right_compare))); |
| 54 | } else { |
| 55 | // expression has side effects: we cannot duplicate it |
| 56 | // create a bound_between directly |
| 57 | return BindResult( |
| 58 | make_uniq<BoundBetweenExpression>(args: std::move(input), args: std::move(lower), args: std::move(upper), args: true, args: true)); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | } // namespace duckdb |
| 63 | |