1 | #include "duckdb/planner/expression_binder/having_binder.hpp" |
2 | |
3 | #include "duckdb/parser/expression/columnref_expression.hpp" |
4 | #include "duckdb/planner/binder.hpp" |
5 | #include "duckdb/planner/expression_binder/aggregate_binder.hpp" |
6 | #include "duckdb/common/string_util.hpp" |
7 | #include "duckdb/planner/query_node/bound_select_node.hpp" |
8 | |
9 | namespace duckdb { |
10 | |
11 | HavingBinder::HavingBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info, |
12 | case_insensitive_map_t<idx_t> &alias_map, AggregateHandling aggregate_handling) |
13 | : BaseSelectBinder(binder, context, node, info), column_alias_binder(node, alias_map), |
14 | aggregate_handling(aggregate_handling) { |
15 | target_type = LogicalType(LogicalTypeId::BOOLEAN); |
16 | } |
17 | |
18 | BindResult HavingBinder::BindColumnRef(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth, bool root_expression) { |
19 | auto &expr = expr_ptr->Cast<ColumnRefExpression>(); |
20 | auto alias_result = column_alias_binder.BindAlias(enclosing_binder&: *this, expr, depth, root_expression); |
21 | if (!alias_result.HasError()) { |
22 | if (depth > 0) { |
23 | throw BinderException("Having clause cannot reference alias in correlated subquery" ); |
24 | } |
25 | return alias_result; |
26 | } |
27 | if (aggregate_handling == AggregateHandling::FORCE_AGGREGATES) { |
28 | if (depth > 0) { |
29 | throw BinderException("Having clause cannot reference column in correlated subquery and group by all" ); |
30 | } |
31 | auto expr = duckdb::BaseSelectBinder::BindExpression(expr_ptr, depth); |
32 | if (expr.HasError()) { |
33 | return expr; |
34 | } |
35 | auto group_ref = make_uniq<BoundColumnRefExpression>( |
36 | args&: expr.expression->return_type, args: ColumnBinding(node.group_index, node.groups.group_expressions.size())); |
37 | node.groups.group_expressions.push_back(x: std::move(expr.expression)); |
38 | return BindResult(std::move(group_ref)); |
39 | } |
40 | return BindResult(StringUtil::Format( |
41 | fmt_str: "column %s must appear in the GROUP BY clause or be used in an aggregate function" , params: expr.ToString())); |
42 | } |
43 | |
44 | BindResult HavingBinder::BindExpression(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth, bool root_expression) { |
45 | auto &expr = *expr_ptr; |
46 | // check if the expression binds to one of the groups |
47 | auto group_index = TryBindGroup(expr, depth); |
48 | if (group_index != DConstants::INVALID_INDEX) { |
49 | return BindGroup(expr, depth, group_index); |
50 | } |
51 | switch (expr.expression_class) { |
52 | case ExpressionClass::WINDOW: |
53 | return BindResult("HAVING clause cannot contain window functions!" ); |
54 | case ExpressionClass::COLUMN_REF: |
55 | return BindColumnRef(expr_ptr, depth, root_expression); |
56 | default: |
57 | return duckdb::BaseSelectBinder::BindExpression(expr_ptr, depth); |
58 | } |
59 | } |
60 | |
61 | } // namespace duckdb |
62 | |