1#include "duckdb/planner/expression_binder/base_select_binder.hpp"
2
3#include "duckdb/parser/expression/columnref_expression.hpp"
4#include "duckdb/parser/expression/window_expression.hpp"
5#include "duckdb/parser/parsed_expression_iterator.hpp"
6#include "duckdb/planner/expression/bound_columnref_expression.hpp"
7#include "duckdb/planner/expression/bound_window_expression.hpp"
8#include "duckdb/planner/expression_binder/aggregate_binder.hpp"
9#include "duckdb/planner/query_node/bound_select_node.hpp"
10#include "duckdb/parser/expression/operator_expression.hpp"
11#include "duckdb/common/string_util.hpp"
12#include "duckdb/planner/binder.hpp"
13
14namespace duckdb {
15
16BaseSelectBinder::BaseSelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node,
17 BoundGroupInformation &info, case_insensitive_map_t<idx_t> alias_map)
18 : ExpressionBinder(binder, context), inside_window(false), node(node), info(info), alias_map(std::move(alias_map)) {
19}
20
21BaseSelectBinder::BaseSelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node,
22 BoundGroupInformation &info)
23 : BaseSelectBinder(binder, context, node, info, case_insensitive_map_t<idx_t>()) {
24}
25
26BindResult BaseSelectBinder::BindExpression(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth, bool root_expression) {
27 auto &expr = *expr_ptr;
28 // check if the expression binds to one of the groups
29 auto group_index = TryBindGroup(expr, depth);
30 if (group_index != DConstants::INVALID_INDEX) {
31 return BindGroup(expr, depth, group_index);
32 }
33 switch (expr.expression_class) {
34 case ExpressionClass::COLUMN_REF:
35 return BindColumnRef(expr_ptr, depth);
36 case ExpressionClass::DEFAULT:
37 return BindResult("SELECT clause cannot contain DEFAULT clause");
38 case ExpressionClass::WINDOW:
39 return BindWindow(expr&: expr.Cast<WindowExpression>(), depth);
40 default:
41 return ExpressionBinder::BindExpression(expr_ptr, depth, root_expression);
42 }
43}
44
45idx_t BaseSelectBinder::TryBindGroup(ParsedExpression &expr, idx_t depth) {
46 // first check the group alias map, if expr is a ColumnRefExpression
47 if (expr.type == ExpressionType::COLUMN_REF) {
48 auto &colref = expr.Cast<ColumnRefExpression>();
49 if (!colref.IsQualified()) {
50 auto alias_entry = info.alias_map.find(x: colref.column_names[0]);
51 if (alias_entry != info.alias_map.end()) {
52 // found entry!
53 return alias_entry->second;
54 }
55 }
56 }
57 // no alias reference found
58 // check the list of group columns for a match
59 auto entry = info.map.find(x: expr);
60 if (entry != info.map.end()) {
61 return entry->second;
62 }
63#ifdef DEBUG
64 for (auto entry : info.map) {
65 D_ASSERT(!entry.first.get().Equals(expr));
66 D_ASSERT(!expr.Equals(entry.first.get()));
67 }
68#endif
69 return DConstants::INVALID_INDEX;
70}
71
72BindResult BaseSelectBinder::BindColumnRef(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth) {
73 // first try to bind the column reference regularly
74 auto result = ExpressionBinder::BindExpression(expr_ptr, depth);
75 if (!result.HasError()) {
76 return result;
77 }
78 // binding failed
79 // check in the alias map
80 auto &colref = (expr_ptr.get())->Cast<ColumnRefExpression>();
81 if (!colref.IsQualified()) {
82 auto alias_entry = alias_map.find(x: colref.column_names[0]);
83 if (alias_entry != alias_map.end()) {
84 // found entry!
85 auto index = alias_entry->second;
86 if (index >= node.select_list.size()) {
87 throw BinderException("Column \"%s\" referenced that exists in the SELECT clause - but this column "
88 "cannot be referenced before it is defined",
89 colref.column_names[0]);
90 }
91 if (node.select_list[index]->HasSideEffects()) {
92 throw BinderException("Alias \"%s\" referenced in a SELECT clause - but the expression has side "
93 "effects. This is not yet supported.",
94 colref.column_names[0]);
95 }
96 if (node.select_list[index]->HasSubquery()) {
97 throw BinderException("Alias \"%s\" referenced in a SELECT clause - but the expression has a subquery."
98 " This is not yet supported.",
99 colref.column_names[0]);
100 }
101 auto result = BindResult(node.select_list[index]->Copy());
102 if (result.expression->type == ExpressionType::BOUND_COLUMN_REF) {
103 auto &result_expr = result.expression->Cast<BoundColumnRefExpression>();
104 result_expr.depth = depth;
105 }
106 return result;
107 }
108 }
109 // entry was not found in the alias map: return the original error
110 return result;
111}
112
113BindResult BaseSelectBinder::BindGroupingFunction(OperatorExpression &op, idx_t depth) {
114 if (op.children.empty()) {
115 throw InternalException("GROUPING requires at least one child");
116 }
117 if (node.groups.group_expressions.empty()) {
118 return BindResult(binder.FormatError(expr_context&: op, message: "GROUPING statement cannot be used without groups"));
119 }
120 if (op.children.size() >= 64) {
121 return BindResult(binder.FormatError(expr_context&: op, message: "GROUPING statement cannot have more than 64 groups"));
122 }
123 vector<idx_t> group_indexes;
124 group_indexes.reserve(n: op.children.size());
125 for (auto &child : op.children) {
126 ExpressionBinder::QualifyColumnNames(binder, expr&: child);
127 auto idx = TryBindGroup(expr&: *child, depth);
128 if (idx == DConstants::INVALID_INDEX) {
129 return BindResult(binder.FormatError(
130 expr_context&: op, message: StringUtil::Format(fmt_str: "GROUPING child \"%s\" must be a grouping column", params: child->GetName())));
131 }
132 group_indexes.push_back(x: idx);
133 }
134 auto col_idx = node.grouping_functions.size();
135 node.grouping_functions.push_back(x: std::move(group_indexes));
136 return BindResult(make_uniq<BoundColumnRefExpression>(args: op.GetName(), args: LogicalType::BIGINT,
137 args: ColumnBinding(node.groupings_index, col_idx), args&: depth));
138}
139
140BindResult BaseSelectBinder::BindGroup(ParsedExpression &expr, idx_t depth, idx_t group_index) {
141 auto &group = node.groups.group_expressions[group_index];
142 return BindResult(make_uniq<BoundColumnRefExpression>(args: expr.GetName(), args&: group->return_type,
143 args: ColumnBinding(node.group_index, group_index), args&: depth));
144}
145
146bool BaseSelectBinder::QualifyColumnAlias(const ColumnRefExpression &colref) {
147 if (!colref.IsQualified()) {
148 return alias_map.find(x: colref.column_names[0]) != alias_map.end() ? true : false;
149 }
150 return false;
151}
152
153} // namespace duckdb
154