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