/src/duckdb/src/planner/expression_binder/having_binder.cpp
Line | Count | Source |
1 | | #include "duckdb/planner/expression_binder/having_binder.hpp" |
2 | | |
3 | | #include "duckdb/parser/expression/columnref_expression.hpp" |
4 | | #include "duckdb/parser/expression/window_expression.hpp" |
5 | | #include "duckdb/planner/binder.hpp" |
6 | | #include "duckdb/common/string_util.hpp" |
7 | | #include "duckdb/planner/query_node/bound_select_node.hpp" |
8 | | #include "duckdb/planner/column_qualifier.hpp" |
9 | | |
10 | | namespace duckdb { |
11 | | |
12 | | HavingBinder::HavingBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, |
13 | | AggregateHandling aggregate_handling) |
14 | 0 | : BaseSelectBinder(binder, context, node), column_alias_binder(node.bind_state), |
15 | 0 | aggregate_handling(aggregate_handling) { |
16 | 0 | target_type = LogicalType(LogicalTypeId::BOOLEAN); |
17 | 0 | } |
18 | | |
19 | 0 | BindResult HavingBinder::BindLambdaReference(LambdaRefExpression &expr, idx_t depth) { |
20 | 0 | D_ASSERT(lambda_bindings && expr.LambdaIndex() < lambda_bindings->size()); |
21 | 0 | auto &lambda_ref = expr.Cast<LambdaRefExpression>(); |
22 | 0 | return (*lambda_bindings)[expr.LambdaIndex()].Bind(lambda_ref, depth); |
23 | 0 | } |
24 | | |
25 | 0 | BindResult HavingBinder::BindColumnRef(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth, bool root_expression) { |
26 | | // Keep the original column name to return a meaningful error message. |
27 | 0 | auto col_ref = expr_ptr->Cast<ColumnRefExpression>(); |
28 | 0 | const auto &column_name = col_ref.GetColumnName(); |
29 | |
|
30 | 0 | if (!col_ref.IsQualified()) { |
31 | | // Try binding as a lambda parameter. |
32 | 0 | auto lambda_ref = LambdaRefExpression::FindMatchingBinding(lambda_bindings, col_ref.GetColumnName()); |
33 | 0 | if (lambda_ref) { |
34 | 0 | return BindLambdaReference(lambda_ref->Cast<LambdaRefExpression>(), depth); |
35 | 0 | } |
36 | | // column was not found - check if it is a SQL value function |
37 | 0 | auto value_function = GetSQLValueFunction(col_ref.GetColumnName()); |
38 | 0 | if (value_function) { |
39 | 0 | return BindExpression(value_function, depth); |
40 | 0 | } |
41 | 0 | } |
42 | | |
43 | | // Bind the alias. |
44 | 0 | BindResult alias_result; |
45 | 0 | auto found_alias = column_alias_binder.BindAlias(*this, expr_ptr, depth, root_expression, alias_result); |
46 | 0 | if (found_alias) { |
47 | 0 | if (depth > 0) { |
48 | 0 | throw BinderException("Having clause cannot reference alias \"%s\" in correlated subquery", column_name); |
49 | 0 | } |
50 | 0 | return alias_result; |
51 | 0 | } |
52 | | |
53 | 0 | if (aggregate_handling != AggregateHandling::FORCE_AGGREGATES) { |
54 | 0 | return BindResult(StringUtil::Format( |
55 | 0 | "column %s must appear in the GROUP BY clause or be used in an aggregate function", column_name)); |
56 | 0 | } |
57 | | |
58 | 0 | if (depth > 0) { |
59 | 0 | throw BinderException("Having clause cannot reference column \"%s\" in correlated subquery and group by all", |
60 | 0 | column_name); |
61 | 0 | } |
62 | | |
63 | 0 | auto expr = duckdb::BaseSelectBinder::BindColumnRef(expr_ptr, depth, root_expression); |
64 | 0 | if (expr.HasError()) { |
65 | 0 | return expr; |
66 | 0 | } |
67 | | |
68 | | // Return a GROUP BY column reference expression. |
69 | 0 | auto return_type = expr.expression->GetReturnType(); |
70 | 0 | auto group_idx = ColumnBinding::PushExpression(node.groups.group_expressions, std::move(expr.expression)); |
71 | 0 | auto column_binding = ColumnBinding(node.group_index, group_idx); |
72 | 0 | auto group_ref = make_uniq<BoundColumnRefExpression>(return_type, column_binding); |
73 | 0 | return BindResult(std::move(group_ref)); |
74 | 0 | } |
75 | | |
76 | 0 | BindResult HavingBinder::BindWindowExpression(WindowExpression &expr, idx_t depth) { |
77 | 0 | throw BinderException::Unsupported(expr, "HAVING clause cannot contain window functions!"); |
78 | 0 | } |
79 | | |
80 | 0 | void ExpressionBinder::QualifyColumnNames(HavingBinder &having_binder, unique_ptr<ParsedExpression> &expr) { |
81 | 0 | ColumnQualifier qualifier(having_binder.binder, having_binder.lambda_bindings, nullptr, having_binder); |
82 | 0 | vector<identifier_set_t> lambda_params; |
83 | 0 | qualifier.QualifyColumnNames(expr, lambda_params); |
84 | 0 | } |
85 | | |
86 | | } // namespace duckdb |