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
9namespace duckdb {
10
11BindResult 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