1#include "duckdb/common/limits.hpp"
2#include "duckdb/common/string_util.hpp"
3#include "duckdb/execution/expression_executor.hpp"
4#include "duckdb/main/config.hpp"
5#include "duckdb/parser/expression/columnref_expression.hpp"
6#include "duckdb/parser/expression/comparison_expression.hpp"
7#include "duckdb/parser/expression/constant_expression.hpp"
8#include "duckdb/parser/expression/subquery_expression.hpp"
9#include "duckdb/parser/expression/star_expression.hpp"
10#include "duckdb/parser/query_node/select_node.hpp"
11#include "duckdb/parser/tableref/joinref.hpp"
12#include "duckdb/planner/binder.hpp"
13#include "duckdb/planner/expression_binder/column_alias_binder.hpp"
14#include "duckdb/planner/expression_binder/constant_binder.hpp"
15#include "duckdb/planner/expression_binder/group_binder.hpp"
16#include "duckdb/planner/expression_binder/having_binder.hpp"
17#include "duckdb/planner/expression_binder/qualify_binder.hpp"
18#include "duckdb/planner/expression_binder/order_binder.hpp"
19#include "duckdb/planner/expression_binder/select_binder.hpp"
20#include "duckdb/planner/expression_binder/where_binder.hpp"
21#include "duckdb/planner/query_node/bound_select_node.hpp"
22#include "duckdb/parser/expression/conjunction_expression.hpp"
23
24namespace duckdb {
25
26unique_ptr<Expression> Binder::BindOrderExpression(OrderBinder &order_binder, unique_ptr<ParsedExpression> expr) {
27 // we treat the Distinct list as a order by
28 auto bound_expr = order_binder.Bind(expr: std::move(expr));
29 if (!bound_expr) {
30 // DISTINCT ON non-integer constant
31 // remove the expression from the DISTINCT ON list
32 return nullptr;
33 }
34 D_ASSERT(bound_expr->type == ExpressionType::BOUND_COLUMN_REF);
35 return bound_expr;
36}
37
38unique_ptr<Expression> Binder::BindDelimiter(ClientContext &context, OrderBinder &order_binder,
39 unique_ptr<ParsedExpression> delimiter, const LogicalType &type,
40 Value &delimiter_value) {
41 auto new_binder = Binder::CreateBinder(context, parent: this, inherit_ctes: true);
42 if (delimiter->HasSubquery()) {
43 if (!order_binder.HasExtraList()) {
44 throw BinderException("Subquery in LIMIT/OFFSET not supported in set operation");
45 }
46 return order_binder.CreateExtraReference(expr: std::move(delimiter));
47 }
48 ExpressionBinder expr_binder(*new_binder, context);
49 expr_binder.target_type = type;
50 auto expr = expr_binder.Bind(expr&: delimiter);
51 if (expr->IsFoldable()) {
52 //! this is a constant
53 delimiter_value = ExpressionExecutor::EvaluateScalar(context, expr: *expr).CastAs(context, target_type: type);
54 return nullptr;
55 }
56 if (!new_binder->correlated_columns.empty()) {
57 throw BinderException("Correlated columns not supported in LIMIT/OFFSET");
58 }
59 // move any correlated columns to this binder
60 MoveCorrelatedExpressions(other&: *new_binder);
61 return expr;
62}
63
64duckdb::unique_ptr<BoundResultModifier> Binder::BindLimit(OrderBinder &order_binder, LimitModifier &limit_mod) {
65 auto result = make_uniq<BoundLimitModifier>();
66 if (limit_mod.limit) {
67 Value val;
68 result->limit = BindDelimiter(context, order_binder, delimiter: std::move(limit_mod.limit), type: LogicalType::BIGINT, delimiter_value&: val);
69 if (!result->limit) {
70 result->limit_val = val.IsNull() ? NumericLimits<int64_t>::Maximum() : val.GetValue<int64_t>();
71 if (result->limit_val < 0) {
72 throw BinderException("LIMIT cannot be negative");
73 }
74 }
75 }
76 if (limit_mod.offset) {
77 Value val;
78 result->offset = BindDelimiter(context, order_binder, delimiter: std::move(limit_mod.offset), type: LogicalType::BIGINT, delimiter_value&: val);
79 if (!result->offset) {
80 result->offset_val = val.IsNull() ? 0 : val.GetValue<int64_t>();
81 if (result->offset_val < 0) {
82 throw BinderException("OFFSET cannot be negative");
83 }
84 }
85 }
86 return std::move(result);
87}
88
89unique_ptr<BoundResultModifier> Binder::BindLimitPercent(OrderBinder &order_binder, LimitPercentModifier &limit_mod) {
90 auto result = make_uniq<BoundLimitPercentModifier>();
91 if (limit_mod.limit) {
92 Value val;
93 result->limit = BindDelimiter(context, order_binder, delimiter: std::move(limit_mod.limit), type: LogicalType::DOUBLE, delimiter_value&: val);
94 if (!result->limit) {
95 result->limit_percent = val.IsNull() ? 100 : val.GetValue<double>();
96 if (result->limit_percent < 0.0) {
97 throw Exception("Limit percentage can't be negative value");
98 }
99 }
100 }
101 if (limit_mod.offset) {
102 Value val;
103 result->offset = BindDelimiter(context, order_binder, delimiter: std::move(limit_mod.offset), type: LogicalType::BIGINT, delimiter_value&: val);
104 if (!result->offset) {
105 result->offset_val = val.IsNull() ? 0 : val.GetValue<int64_t>();
106 }
107 }
108 return std::move(result);
109}
110
111void Binder::BindModifiers(OrderBinder &order_binder, QueryNode &statement, BoundQueryNode &result) {
112 for (auto &mod : statement.modifiers) {
113 unique_ptr<BoundResultModifier> bound_modifier;
114 switch (mod->type) {
115 case ResultModifierType::DISTINCT_MODIFIER: {
116 auto &distinct = mod->Cast<DistinctModifier>();
117 auto bound_distinct = make_uniq<BoundDistinctModifier>();
118 bound_distinct->distinct_type =
119 distinct.distinct_on_targets.empty() ? DistinctType::DISTINCT : DistinctType::DISTINCT_ON;
120 if (distinct.distinct_on_targets.empty()) {
121 for (idx_t i = 0; i < result.names.size(); i++) {
122 distinct.distinct_on_targets.push_back(x: make_uniq<ConstantExpression>(args: Value::INTEGER(value: 1 + i)));
123 }
124 }
125 for (auto &distinct_on_target : distinct.distinct_on_targets) {
126 auto expr = BindOrderExpression(order_binder, expr: std::move(distinct_on_target));
127 if (!expr) {
128 continue;
129 }
130 bound_distinct->target_distincts.push_back(x: std::move(expr));
131 }
132 bound_modifier = std::move(bound_distinct);
133 break;
134 }
135 case ResultModifierType::ORDER_MODIFIER: {
136 auto &order = mod->Cast<OrderModifier>();
137 auto bound_order = make_uniq<BoundOrderModifier>();
138 auto &config = DBConfig::GetConfig(context);
139 D_ASSERT(!order.orders.empty());
140 auto &order_binders = order_binder.GetBinders();
141 if (order.orders.size() == 1 && order.orders[0].expression->type == ExpressionType::STAR) {
142 auto &star = order.orders[0].expression->Cast<StarExpression>();
143 if (star.exclude_list.empty() && star.replace_list.empty() && !star.expr) {
144 // ORDER BY ALL
145 // replace the order list with the all elements in the SELECT list
146 auto order_type = order.orders[0].type;
147 auto null_order = order.orders[0].null_order;
148
149 vector<OrderByNode> new_orders;
150 for (idx_t i = 0; i < order_binder.MaxCount(); i++) {
151 new_orders.emplace_back(args&: order_type, args&: null_order,
152 args: make_uniq<ConstantExpression>(args: Value::INTEGER(value: i + 1)));
153 }
154 order.orders = std::move(new_orders);
155 }
156 }
157 for (auto &order_node : order.orders) {
158 vector<unique_ptr<ParsedExpression>> order_list;
159 order_binders[0]->ExpandStarExpression(expr: std::move(order_node.expression), new_select_list&: order_list);
160
161 auto type = config.ResolveOrder(order_type: order_node.type);
162 auto null_order = config.ResolveNullOrder(order_type: type, null_type: order_node.null_order);
163 for (auto &order_expr : order_list) {
164 auto bound_expr = BindOrderExpression(order_binder, expr: std::move(order_expr));
165 if (!bound_expr) {
166 continue;
167 }
168 bound_order->orders.emplace_back(args&: type, args&: null_order, args: std::move(bound_expr));
169 }
170 }
171 if (!bound_order->orders.empty()) {
172 bound_modifier = std::move(bound_order);
173 }
174 break;
175 }
176 case ResultModifierType::LIMIT_MODIFIER:
177 bound_modifier = BindLimit(order_binder, limit_mod&: mod->Cast<LimitModifier>());
178 break;
179 case ResultModifierType::LIMIT_PERCENT_MODIFIER:
180 bound_modifier = BindLimitPercent(order_binder, limit_mod&: mod->Cast<LimitPercentModifier>());
181 break;
182 default:
183 throw Exception("Unsupported result modifier");
184 }
185 if (bound_modifier) {
186 result.modifiers.push_back(x: std::move(bound_modifier));
187 }
188 }
189}
190
191static void AssignReturnType(unique_ptr<Expression> &expr, const vector<LogicalType> &sql_types) {
192 if (!expr) {
193 return;
194 }
195 if (expr->type != ExpressionType::BOUND_COLUMN_REF) {
196 return;
197 }
198 auto &bound_colref = expr->Cast<BoundColumnRefExpression>();
199 bound_colref.return_type = sql_types[bound_colref.binding.column_index];
200}
201
202void Binder::BindModifierTypes(BoundQueryNode &result, const vector<LogicalType> &sql_types, idx_t projection_index) {
203 for (auto &bound_mod : result.modifiers) {
204 switch (bound_mod->type) {
205 case ResultModifierType::DISTINCT_MODIFIER: {
206 auto &distinct = bound_mod->Cast<BoundDistinctModifier>();
207 D_ASSERT(!distinct.target_distincts.empty());
208 // set types of distinct targets
209 for (auto &expr : distinct.target_distincts) {
210 D_ASSERT(expr->type == ExpressionType::BOUND_COLUMN_REF);
211 auto &bound_colref = expr->Cast<BoundColumnRefExpression>();
212 if (bound_colref.binding.column_index == DConstants::INVALID_INDEX) {
213 throw BinderException("Ambiguous name in DISTINCT ON!");
214 }
215 D_ASSERT(bound_colref.binding.column_index < sql_types.size());
216 bound_colref.return_type = sql_types[bound_colref.binding.column_index];
217 }
218 for (auto &target_distinct : distinct.target_distincts) {
219 auto &bound_colref = target_distinct->Cast<BoundColumnRefExpression>();
220 const auto &sql_type = sql_types[bound_colref.binding.column_index];
221 if (sql_type.id() == LogicalTypeId::VARCHAR) {
222 target_distinct = ExpressionBinder::PushCollation(context, source: std::move(target_distinct),
223 collation: StringType::GetCollation(type: sql_type), equality_only: true);
224 }
225 }
226 break;
227 }
228 case ResultModifierType::LIMIT_MODIFIER: {
229 auto &limit = bound_mod->Cast<BoundLimitModifier>();
230 AssignReturnType(expr&: limit.limit, sql_types);
231 AssignReturnType(expr&: limit.offset, sql_types);
232 break;
233 }
234 case ResultModifierType::LIMIT_PERCENT_MODIFIER: {
235 auto &limit = bound_mod->Cast<BoundLimitPercentModifier>();
236 AssignReturnType(expr&: limit.limit, sql_types);
237 AssignReturnType(expr&: limit.offset, sql_types);
238 break;
239 }
240 case ResultModifierType::ORDER_MODIFIER: {
241 auto &order = bound_mod->Cast<BoundOrderModifier>();
242 for (auto &order_node : order.orders) {
243 auto &expr = order_node.expression;
244 D_ASSERT(expr->type == ExpressionType::BOUND_COLUMN_REF);
245 auto &bound_colref = expr->Cast<BoundColumnRefExpression>();
246 if (bound_colref.binding.column_index == DConstants::INVALID_INDEX) {
247 throw BinderException("Ambiguous name in ORDER BY!");
248 }
249 D_ASSERT(bound_colref.binding.column_index < sql_types.size());
250 const auto &sql_type = sql_types[bound_colref.binding.column_index];
251 bound_colref.return_type = sql_types[bound_colref.binding.column_index];
252 if (sql_type.id() == LogicalTypeId::VARCHAR) {
253 order_node.expression = ExpressionBinder::PushCollation(context, source: std::move(order_node.expression),
254 collation: StringType::GetCollation(type: sql_type));
255 }
256 }
257 break;
258 }
259 default:
260 break;
261 }
262 }
263}
264
265unique_ptr<BoundQueryNode> Binder::BindNode(SelectNode &statement) {
266 D_ASSERT(statement.from_table);
267 // first bind the FROM table statement
268 auto from = std::move(statement.from_table);
269 auto from_table = Bind(ref&: *from);
270 return BindSelectNode(statement, from_table: std::move(from_table));
271}
272
273void Binder::BindWhereStarExpression(unique_ptr<ParsedExpression> &expr) {
274 // expand any expressions in the upper AND recursively
275 if (expr->type == ExpressionType::CONJUNCTION_AND) {
276 auto &conj = expr->Cast<ConjunctionExpression>();
277 for (auto &child : conj.children) {
278 BindWhereStarExpression(expr&: child);
279 }
280 return;
281 }
282 if (expr->type == ExpressionType::STAR) {
283 auto &star = expr->Cast<StarExpression>();
284 if (!star.columns) {
285 throw ParserException("STAR expression is not allowed in the WHERE clause. Use COLUMNS(*) instead.");
286 }
287 }
288 // expand the stars for this expression
289 vector<unique_ptr<ParsedExpression>> new_conditions;
290 ExpandStarExpression(expr: std::move(expr), new_select_list&: new_conditions);
291 if (new_conditions.empty()) {
292 throw ParserException("COLUMNS expansion resulted in empty set of columns");
293 }
294
295 // set up an AND conjunction between the expanded conditions
296 expr = std::move(new_conditions[0]);
297 for (idx_t i = 1; i < new_conditions.size(); i++) {
298 auto and_conj = make_uniq<ConjunctionExpression>(args: ExpressionType::CONJUNCTION_AND, args: std::move(expr),
299 args: std::move(new_conditions[i]));
300 expr = std::move(and_conj);
301 }
302}
303
304unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_ptr<BoundTableRef> from_table) {
305 D_ASSERT(from_table);
306 D_ASSERT(!statement.from_table);
307 auto result = make_uniq<BoundSelectNode>();
308 result->projection_index = GenerateTableIndex();
309 result->group_index = GenerateTableIndex();
310 result->aggregate_index = GenerateTableIndex();
311 result->groupings_index = GenerateTableIndex();
312 result->window_index = GenerateTableIndex();
313 result->prune_index = GenerateTableIndex();
314
315 result->from_table = std::move(from_table);
316 // bind the sample clause
317 if (statement.sample) {
318 result->sample_options = std::move(statement.sample);
319 }
320
321 // visit the select list and expand any "*" statements
322 vector<unique_ptr<ParsedExpression>> new_select_list;
323 ExpandStarExpressions(select_list&: statement.select_list, new_select_list);
324
325 if (new_select_list.empty()) {
326 throw BinderException("SELECT list is empty after resolving * expressions!");
327 }
328 statement.select_list = std::move(new_select_list);
329
330 // create a mapping of (alias -> index) and a mapping of (Expression -> index) for the SELECT list
331 case_insensitive_map_t<idx_t> alias_map;
332 parsed_expression_map_t<idx_t> projection_map;
333 for (idx_t i = 0; i < statement.select_list.size(); i++) {
334 auto &expr = statement.select_list[i];
335 result->names.push_back(x: expr->GetName());
336 ExpressionBinder::QualifyColumnNames(binder&: *this, expr);
337 if (!expr->alias.empty()) {
338 alias_map[expr->alias] = i;
339 result->names[i] = expr->alias;
340 }
341 projection_map[*expr] = i;
342 result->original_expressions.push_back(x: expr->Copy());
343 }
344 result->column_count = statement.select_list.size();
345
346 // first visit the WHERE clause
347 // the WHERE clause happens before the GROUP BY, PROJECTION or HAVING clauses
348 if (statement.where_clause) {
349 // bind any star expressions in the WHERE clause
350 BindWhereStarExpression(expr&: statement.where_clause);
351
352 ColumnAliasBinder alias_binder(*result, alias_map);
353 WhereBinder where_binder(*this, context, &alias_binder);
354 unique_ptr<ParsedExpression> condition = std::move(statement.where_clause);
355 result->where_clause = where_binder.Bind(expr&: condition);
356 }
357
358 // now bind all the result modifiers; including DISTINCT and ORDER BY targets
359 OrderBinder order_binder({this}, result->projection_index, statement, alias_map, projection_map);
360 BindModifiers(order_binder, statement, result&: *result);
361
362 vector<unique_ptr<ParsedExpression>> unbound_groups;
363 BoundGroupInformation info;
364 auto &group_expressions = statement.groups.group_expressions;
365 if (!group_expressions.empty()) {
366 // the statement has a GROUP BY clause, bind it
367 unbound_groups.resize(new_size: group_expressions.size());
368 GroupBinder group_binder(*this, context, statement, result->group_index, alias_map, info.alias_map);
369 for (idx_t i = 0; i < group_expressions.size(); i++) {
370
371 // we keep a copy of the unbound expression;
372 // we keep the unbound copy around to check for group references in the SELECT and HAVING clause
373 // the reason we want the unbound copy is because we want to figure out whether an expression
374 // is a group reference BEFORE binding in the SELECT/HAVING binder
375 group_binder.unbound_expression = group_expressions[i]->Copy();
376 group_binder.bind_index = i;
377
378 // bind the groups
379 LogicalType group_type;
380 auto bound_expr = group_binder.Bind(expr&: group_expressions[i], result_type: &group_type);
381 D_ASSERT(bound_expr->return_type.id() != LogicalTypeId::INVALID);
382
383 // push a potential collation, if necessary
384 bound_expr = ExpressionBinder::PushCollation(context, source: std::move(bound_expr),
385 collation: StringType::GetCollation(type: group_type), equality_only: true);
386 result->groups.group_expressions.push_back(x: std::move(bound_expr));
387
388 // in the unbound expression we DO bind the table names of any ColumnRefs
389 // we do this to make sure that "table.a" and "a" are treated the same
390 // if we wouldn't do this then (SELECT test.a FROM test GROUP BY a) would not work because "test.a" <> "a"
391 // hence we convert "a" -> "test.a" in the unbound expression
392 unbound_groups[i] = std::move(group_binder.unbound_expression);
393 ExpressionBinder::QualifyColumnNames(binder&: *this, expr&: unbound_groups[i]);
394 info.map[*unbound_groups[i]] = i;
395 }
396 }
397 result->groups.grouping_sets = std::move(statement.groups.grouping_sets);
398
399 // bind the HAVING clause, if any
400 if (statement.having) {
401 HavingBinder having_binder(*this, context, *result, info, alias_map, statement.aggregate_handling);
402 ExpressionBinder::QualifyColumnNames(binder&: *this, expr&: statement.having);
403 result->having = having_binder.Bind(expr&: statement.having);
404 }
405
406 // bind the QUALIFY clause, if any
407 unique_ptr<QualifyBinder> qualify_binder;
408 if (statement.qualify) {
409 if (statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES) {
410 throw BinderException("Combining QUALIFY with GROUP BY ALL is not supported yet");
411 }
412 qualify_binder = make_uniq<QualifyBinder>(args&: *this, args&: context, args&: *result, args&: info, args&: alias_map);
413 ExpressionBinder::QualifyColumnNames(binder&: *this, expr&: statement.qualify);
414 result->qualify = qualify_binder->Bind(expr&: statement.qualify);
415 if (qualify_binder->HasBoundColumns() && qualify_binder->BoundAggregates()) {
416 throw BinderException("Cannot mix aggregates with non-aggregated columns!");
417 }
418 }
419
420 // after that, we bind to the SELECT list
421 SelectBinder select_binder(*this, context, *result, info, alias_map);
422 vector<LogicalType> internal_sql_types;
423 vector<idx_t> group_by_all_indexes;
424 vector<string> new_names;
425 for (idx_t i = 0; i < statement.select_list.size(); i++) {
426 bool is_window = statement.select_list[i]->IsWindow();
427 idx_t unnest_count = result->unnests.size();
428 LogicalType result_type;
429 auto expr = select_binder.Bind(expr&: statement.select_list[i], result_type: &result_type, root_expression: true);
430 bool is_original_column = i < result->column_count;
431 bool can_group_by_all =
432 statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES && is_original_column;
433 if (select_binder.HasExpandedExpressions()) {
434 if (!is_original_column) {
435 throw InternalException("Only original columns can have expanded expressions");
436 }
437 if (statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES) {
438 throw BinderException("UNNEST of struct cannot be combined with GROUP BY ALL");
439 }
440 auto &struct_expressions = select_binder.ExpandedExpressions();
441 D_ASSERT(!struct_expressions.empty());
442 for (auto &struct_expr : struct_expressions) {
443 new_names.push_back(x: struct_expr->GetName());
444 result->types.push_back(x: struct_expr->return_type);
445 result->select_list.push_back(x: std::move(struct_expr));
446 }
447 struct_expressions.clear();
448 continue;
449 }
450 if (can_group_by_all && select_binder.HasBoundColumns()) {
451 if (select_binder.BoundAggregates()) {
452 throw BinderException("Cannot mix aggregates with non-aggregated columns!");
453 }
454 if (is_window) {
455 throw BinderException("Cannot group on a window clause");
456 }
457 if (result->unnests.size() > unnest_count) {
458 throw BinderException("Cannot group on an UNNEST or UNLIST clause");
459 }
460 // we are forcing aggregates, and the node has columns bound
461 // this entry becomes a group
462 group_by_all_indexes.push_back(x: i);
463 }
464 result->select_list.push_back(x: std::move(expr));
465 if (is_original_column) {
466 new_names.push_back(x: std::move(result->names[i]));
467 result->types.push_back(x: result_type);
468 }
469 internal_sql_types.push_back(x: result_type);
470 if (can_group_by_all) {
471 select_binder.ResetBindings();
472 }
473 }
474 // push the GROUP BY ALL expressions into the group set
475 for (auto &group_by_all_index : group_by_all_indexes) {
476 auto &expr = result->select_list[group_by_all_index];
477 auto group_ref = make_uniq<BoundColumnRefExpression>(
478 args&: expr->return_type, args: ColumnBinding(result->group_index, result->groups.group_expressions.size()));
479 result->groups.group_expressions.push_back(x: std::move(expr));
480 expr = std::move(group_ref);
481 }
482 result->column_count = new_names.size();
483 result->names = std::move(new_names);
484 result->need_prune = result->select_list.size() > result->column_count;
485
486 // in the normal select binder, we bind columns as if there is no aggregation
487 // i.e. in the query [SELECT i, SUM(i) FROM integers;] the "i" will be bound as a normal column
488 // since we have an aggregation, we need to either (1) throw an error, or (2) wrap the column in a FIRST() aggregate
489 // we choose the former one [CONTROVERSIAL: this is the PostgreSQL behavior]
490 if (!result->groups.group_expressions.empty() || !result->aggregates.empty() || statement.having ||
491 !result->groups.grouping_sets.empty()) {
492 if (statement.aggregate_handling == AggregateHandling::NO_AGGREGATES_ALLOWED) {
493 throw BinderException("Aggregates cannot be present in a Project relation!");
494 } else {
495 vector<reference<BaseSelectBinder>> to_check_binders;
496 to_check_binders.push_back(x: select_binder);
497 if (qualify_binder) {
498 to_check_binders.push_back(x: *qualify_binder);
499 }
500 for (auto &binder : to_check_binders) {
501 auto &sel_binder = binder.get();
502 if (!sel_binder.HasBoundColumns()) {
503 continue;
504 }
505 auto &bound_columns = sel_binder.GetBoundColumns();
506 string error;
507 error = "column \"%s\" must appear in the GROUP BY clause or must be part of an aggregate function.";
508 if (statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES) {
509 error += "\nGROUP BY ALL will only group entries in the SELECT list. Add it to the SELECT list or "
510 "GROUP BY this entry explicitly.";
511 } else {
512 error +=
513 "\nEither add it to the GROUP BY list, or use \"ANY_VALUE(%s)\" if the exact value of \"%s\" "
514 "is not important.";
515 }
516 throw BinderException(FormatError(query_location: bound_columns[0].query_location, msg: error, params: bound_columns[0].name,
517 params: bound_columns[0].name, params: bound_columns[0].name));
518 }
519 }
520 }
521
522 // QUALIFY clause requires at least one window function to be specified in at least one of the SELECT column list or
523 // the filter predicate of the QUALIFY clause
524 if (statement.qualify && result->windows.empty()) {
525 throw BinderException("at least one window function must appear in the SELECT column or QUALIFY clause");
526 }
527
528 // now that the SELECT list is bound, we set the types of DISTINCT/ORDER BY expressions
529 BindModifierTypes(result&: *result, sql_types: internal_sql_types, projection_index: result->projection_index);
530 return std::move(result);
531}
532
533} // namespace duckdb
534