1#include "duckdb/planner/bind_context.hpp"
2
3#include "duckdb/catalog/catalog_entry/table_column_type.hpp"
4#include "duckdb/catalog/standard_entry.hpp"
5#include "duckdb/common/pair.hpp"
6#include "duckdb/common/string_util.hpp"
7#include "duckdb/parser/expression/columnref_expression.hpp"
8#include "duckdb/parser/expression/operator_expression.hpp"
9#include "duckdb/parser/expression/positional_reference_expression.hpp"
10#include "duckdb/parser/expression/star_expression.hpp"
11#include "duckdb/parser/tableref/subqueryref.hpp"
12#include "duckdb/parser/tableref/table_function_ref.hpp"
13#include "duckdb/planner/bound_query_node.hpp"
14#include "duckdb/planner/expression/bound_columnref_expression.hpp"
15#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp"
16#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
17#include "duckdb/planner/expression_binder/constant_binder.hpp"
18
19#include <algorithm>
20
21namespace duckdb {
22
23string BindContext::GetMatchingBinding(const string &column_name) {
24 string result;
25 for (auto &kv : bindings) {
26 auto binding = kv.second.get();
27 auto is_using_binding = GetUsingBinding(column_name, binding_name: kv.first);
28 if (is_using_binding) {
29 continue;
30 }
31 if (binding->HasMatchingBinding(column_name)) {
32 if (!result.empty() || is_using_binding) {
33 throw BinderException("Ambiguous reference to column name \"%s\" (use: \"%s.%s\" "
34 "or \"%s.%s\")",
35 column_name, result, column_name, kv.first, column_name);
36 }
37 result = kv.first;
38 }
39 }
40 return result;
41}
42
43vector<string> BindContext::GetSimilarBindings(const string &column_name) {
44 vector<pair<string, idx_t>> scores;
45 for (auto &kv : bindings) {
46 auto binding = kv.second.get();
47 for (auto &name : binding->names) {
48 idx_t distance = StringUtil::SimilarityScore(s1: name, s2: column_name);
49 scores.emplace_back(args: binding->alias + "." + name, args&: distance);
50 }
51 }
52 return StringUtil::TopNStrings(scores);
53}
54
55void BindContext::AddUsingBinding(const string &column_name, UsingColumnSet &set) {
56 using_columns[column_name].insert(x: set);
57}
58
59void BindContext::AddUsingBindingSet(unique_ptr<UsingColumnSet> set) {
60 using_column_sets.push_back(x: std::move(set));
61}
62
63optional_ptr<UsingColumnSet> BindContext::GetUsingBinding(const string &column_name) {
64 auto entry = using_columns.find(x: column_name);
65 if (entry == using_columns.end()) {
66 return nullptr;
67 }
68 auto &using_bindings = entry->second;
69 if (using_bindings.size() > 1) {
70 string error = "Ambiguous column reference: column \"" + column_name + "\" can refer to either:\n";
71 for (auto &using_set_ref : using_bindings) {
72 auto &using_set = using_set_ref.get();
73 string result_bindings;
74 for (auto &binding : using_set.bindings) {
75 if (result_bindings.empty()) {
76 result_bindings = "[";
77 } else {
78 result_bindings += ", ";
79 }
80 result_bindings += binding;
81 result_bindings += ".";
82 result_bindings += GetActualColumnName(binding, column_name);
83 }
84 error += result_bindings + "]";
85 }
86 throw BinderException(error);
87 }
88 for (auto &using_set : using_bindings) {
89 return &using_set.get();
90 }
91 throw InternalException("Using binding found but no entries");
92}
93
94optional_ptr<UsingColumnSet> BindContext::GetUsingBinding(const string &column_name, const string &binding_name) {
95 if (binding_name.empty()) {
96 throw InternalException("GetUsingBinding: expected non-empty binding_name");
97 }
98 auto entry = using_columns.find(x: column_name);
99 if (entry == using_columns.end()) {
100 return nullptr;
101 }
102 auto &using_bindings = entry->second;
103 for (auto &using_set_ref : using_bindings) {
104 auto &using_set = using_set_ref.get();
105 auto &bindings = using_set.bindings;
106 if (bindings.find(x: binding_name) != bindings.end()) {
107 return &using_set;
108 }
109 }
110 return nullptr;
111}
112
113void BindContext::RemoveUsingBinding(const string &column_name, UsingColumnSet &set) {
114 auto entry = using_columns.find(x: column_name);
115 if (entry == using_columns.end()) {
116 throw InternalException("Attempting to remove using binding that is not there");
117 }
118 auto &bindings = entry->second;
119 if (bindings.find(x: set) != bindings.end()) {
120 bindings.erase(x: set);
121 }
122 if (bindings.empty()) {
123 using_columns.erase(x: column_name);
124 }
125}
126
127void BindContext::TransferUsingBinding(BindContext &current_context, optional_ptr<UsingColumnSet> current_set,
128 UsingColumnSet &new_set, const string &binding, const string &using_column) {
129 AddUsingBinding(column_name: using_column, set&: new_set);
130 if (current_set) {
131 current_context.RemoveUsingBinding(column_name: using_column, set&: *current_set);
132 }
133}
134
135string BindContext::GetActualColumnName(const string &binding_name, const string &column_name) {
136 string error;
137 auto binding = GetBinding(name: binding_name, out_error&: error);
138 if (!binding) {
139 throw InternalException("No binding with name \"%s\"", binding_name);
140 }
141 column_t binding_index;
142 if (!binding->TryGetBindingIndex(column_name, result&: binding_index)) { // LCOV_EXCL_START
143 throw InternalException("Binding with name \"%s\" does not have a column named \"%s\"", binding_name,
144 column_name);
145 } // LCOV_EXCL_STOP
146 return binding->names[binding_index];
147}
148
149unordered_set<string> BindContext::GetMatchingBindings(const string &column_name) {
150 unordered_set<string> result;
151 for (auto &kv : bindings) {
152 auto binding = kv.second.get();
153 if (binding->HasMatchingBinding(column_name)) {
154 result.insert(x: kv.first);
155 }
156 }
157 return result;
158}
159
160unique_ptr<ParsedExpression> BindContext::ExpandGeneratedColumn(const string &table_name, const string &column_name) {
161 string error_message;
162
163 auto binding = GetBinding(name: table_name, out_error&: error_message);
164 D_ASSERT(binding);
165 auto &table_binding = binding->Cast<TableBinding>();
166 auto result = table_binding.ExpandGeneratedColumn(column_name);
167 result->alias = column_name;
168 return result;
169}
170
171unique_ptr<ParsedExpression> BindContext::CreateColumnReference(const string &table_name, const string &column_name) {
172 string schema_name;
173 return CreateColumnReference(schema_name, table_name, column_name);
174}
175
176static bool ColumnIsGenerated(Binding &binding, column_t index) {
177 if (binding.binding_type != BindingType::TABLE) {
178 return false;
179 }
180 auto &table_binding = binding.Cast<TableBinding>();
181 auto catalog_entry = table_binding.GetStandardEntry();
182 if (!catalog_entry) {
183 return false;
184 }
185 if (index == COLUMN_IDENTIFIER_ROW_ID) {
186 return false;
187 }
188 D_ASSERT(catalog_entry->type == CatalogType::TABLE_ENTRY);
189 auto &table_entry = catalog_entry->Cast<TableCatalogEntry>();
190 return table_entry.GetColumn(idx: LogicalIndex(index)).Generated();
191}
192
193unique_ptr<ParsedExpression> BindContext::CreateColumnReference(const string &catalog_name, const string &schema_name,
194 const string &table_name, const string &column_name) {
195 string error_message;
196 vector<string> names;
197 if (!catalog_name.empty()) {
198 names.push_back(x: catalog_name);
199 }
200 if (!schema_name.empty()) {
201 names.push_back(x: schema_name);
202 }
203 names.push_back(x: table_name);
204 names.push_back(x: column_name);
205
206 auto result = make_uniq<ColumnRefExpression>(args: std::move(names));
207 auto binding = GetBinding(name: table_name, out_error&: error_message);
208 if (!binding) {
209 return std::move(result);
210 }
211 auto column_index = binding->GetBindingIndex(column_name);
212 if (ColumnIsGenerated(binding&: *binding, index: column_index)) {
213 return ExpandGeneratedColumn(table_name, column_name);
214 } else if (column_index < binding->names.size() && binding->names[column_index] != column_name) {
215 // because of case insensitivity in the binder we rename the column to the original name
216 // as it appears in the binding itself
217 result->alias = binding->names[column_index];
218 }
219 return std::move(result);
220}
221
222unique_ptr<ParsedExpression> BindContext::CreateColumnReference(const string &schema_name, const string &table_name,
223 const string &column_name) {
224 string catalog_name;
225 return CreateColumnReference(catalog_name, schema_name, table_name, column_name);
226}
227
228optional_ptr<Binding> BindContext::GetCTEBinding(const string &ctename) {
229 auto match = cte_bindings.find(x: ctename);
230 if (match == cte_bindings.end()) {
231 return nullptr;
232 }
233 return match->second.get();
234}
235
236optional_ptr<Binding> BindContext::GetBinding(const string &name, string &out_error) {
237 auto match = bindings.find(x: name);
238 if (match == bindings.end()) {
239 // alias not found in this BindContext
240 vector<string> candidates;
241 for (auto &kv : bindings) {
242 candidates.push_back(x: kv.first);
243 }
244 string candidate_str =
245 StringUtil::CandidatesMessage(candidates: StringUtil::TopNLevenshtein(strings: candidates, target: name), candidate: "Candidate tables");
246 out_error = StringUtil::Format(fmt_str: "Referenced table \"%s\" not found!%s", params: name, params: candidate_str);
247 return nullptr;
248 }
249 return match->second.get();
250}
251
252BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) {
253 if (!colref.IsQualified()) {
254 throw InternalException("Could not bind alias \"%s\"!", colref.GetColumnName());
255 }
256
257 string error;
258 auto binding = GetBinding(name: colref.GetTableName(), out_error&: error);
259 if (!binding) {
260 return BindResult(error);
261 }
262 return binding->Bind(colref, depth);
263}
264
265string BindContext::BindColumn(PositionalReferenceExpression &ref, string &table_name, string &column_name) {
266 idx_t total_columns = 0;
267 idx_t current_position = ref.index - 1;
268 for (auto &entry : bindings_list) {
269 auto &binding = entry.get();
270 idx_t entry_column_count = binding.names.size();
271 if (ref.index == 0) {
272 // this is a row id
273 table_name = binding.alias;
274 column_name = "rowid";
275 return string();
276 }
277 if (current_position < entry_column_count) {
278 table_name = binding.alias;
279 column_name = binding.names[current_position];
280 return string();
281 } else {
282 total_columns += entry_column_count;
283 current_position -= entry_column_count;
284 }
285 }
286 return StringUtil::Format(fmt_str: "Positional reference %d out of range (total %d columns)", params: ref.index, params: total_columns);
287}
288
289unique_ptr<ColumnRefExpression> BindContext::PositionToColumn(PositionalReferenceExpression &ref) {
290 string table_name, column_name;
291
292 string error = BindColumn(ref, table_name, column_name);
293 if (!error.empty()) {
294 throw BinderException(error);
295 }
296 return make_uniq<ColumnRefExpression>(args&: column_name, args&: table_name);
297}
298
299bool BindContext::CheckExclusionList(StarExpression &expr, const string &column_name,
300 vector<unique_ptr<ParsedExpression>> &new_select_list,
301 case_insensitive_set_t &excluded_columns) {
302 if (expr.exclude_list.find(x: column_name) != expr.exclude_list.end()) {
303 excluded_columns.insert(x: column_name);
304 return true;
305 }
306 auto entry = expr.replace_list.find(x: column_name);
307 if (entry != expr.replace_list.end()) {
308 auto new_entry = entry->second->Copy();
309 new_entry->alias = entry->first;
310 excluded_columns.insert(x: entry->first);
311 new_select_list.push_back(x: std::move(new_entry));
312 return true;
313 }
314 return false;
315}
316
317void BindContext::GenerateAllColumnExpressions(StarExpression &expr,
318 vector<unique_ptr<ParsedExpression>> &new_select_list) {
319 if (bindings_list.empty()) {
320 throw BinderException("* expression without FROM clause!");
321 }
322 case_insensitive_set_t excluded_columns;
323 if (expr.relation_name.empty()) {
324 // SELECT * case
325 // bind all expressions of each table in-order
326 reference_set_t<UsingColumnSet> handled_using_columns;
327 for (auto &entry : bindings_list) {
328 auto &binding = entry.get();
329 for (auto &column_name : binding.names) {
330 if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) {
331 continue;
332 }
333 // check if this column is a USING column
334 auto using_binding_ptr = GetUsingBinding(column_name, binding_name: binding.alias);
335 if (using_binding_ptr) {
336 auto &using_binding = *using_binding_ptr;
337 // it is!
338 // check if we have already emitted the using column
339 if (handled_using_columns.find(x: using_binding) != handled_using_columns.end()) {
340 // we have! bail out
341 continue;
342 }
343 // we have not! output the using column
344 if (using_binding.primary_binding.empty()) {
345 // no primary binding: output a coalesce
346 auto coalesce = make_uniq<OperatorExpression>(args: ExpressionType::OPERATOR_COALESCE);
347 for (auto &child_binding : using_binding.bindings) {
348 coalesce->children.push_back(x: make_uniq<ColumnRefExpression>(args&: column_name, args: child_binding));
349 }
350 coalesce->alias = column_name;
351 new_select_list.push_back(x: std::move(coalesce));
352 } else {
353 // primary binding: output the qualified column ref
354 new_select_list.push_back(
355 x: make_uniq<ColumnRefExpression>(args&: column_name, args&: using_binding.primary_binding));
356 }
357 handled_using_columns.insert(x: using_binding);
358 continue;
359 }
360 new_select_list.push_back(x: make_uniq<ColumnRefExpression>(args&: column_name, args&: binding.alias));
361 }
362 }
363 } else {
364 // SELECT tbl.* case
365 // SELECT struct.* case
366 string error;
367 auto binding = GetBinding(name: expr.relation_name, out_error&: error);
368 bool is_struct_ref = false;
369 if (!binding) {
370 auto binding_name = GetMatchingBinding(column_name: expr.relation_name);
371 if (binding_name.empty()) {
372 throw BinderException(error);
373 }
374 binding = bindings[binding_name].get();
375 is_struct_ref = true;
376 }
377
378 if (is_struct_ref) {
379 auto col_idx = binding->GetBindingIndex(column_name: expr.relation_name);
380 auto col_type = binding->types[col_idx];
381 if (col_type.id() != LogicalTypeId::STRUCT) {
382 throw BinderException(StringUtil::Format(
383 fmt_str: "Cannot extract field from expression \"%s\" because it is not a struct", params: expr.ToString()));
384 }
385 auto &struct_children = StructType::GetChildTypes(type: col_type);
386 vector<string> column_names(3);
387 column_names[0] = binding->alias;
388 column_names[1] = expr.relation_name;
389 for (auto &child : struct_children) {
390 if (CheckExclusionList(expr, column_name: child.first, new_select_list, excluded_columns)) {
391 continue;
392 }
393 column_names[2] = child.first;
394 new_select_list.push_back(x: make_uniq<ColumnRefExpression>(args&: column_names));
395 }
396 } else {
397 for (auto &column_name : binding->names) {
398 if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) {
399 continue;
400 }
401
402 new_select_list.push_back(x: make_uniq<ColumnRefExpression>(args&: column_name, args&: binding->alias));
403 }
404 }
405 }
406 for (auto &excluded : expr.exclude_list) {
407 if (excluded_columns.find(x: excluded) == excluded_columns.end()) {
408 throw BinderException("Column \"%s\" in EXCLUDE list not found in %s", excluded,
409 expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str());
410 }
411 }
412 for (auto &entry : expr.replace_list) {
413 if (excluded_columns.find(x: entry.first) == excluded_columns.end()) {
414 throw BinderException("Column \"%s\" in REPLACE list not found in %s", entry.first,
415 expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str());
416 }
417 }
418}
419
420void BindContext::GetTypesAndNames(vector<string> &result_names, vector<LogicalType> &result_types) {
421 for (auto &binding_entry : bindings_list) {
422 auto &binding = binding_entry.get();
423 D_ASSERT(binding.names.size() == binding.types.size());
424 for (idx_t i = 0; i < binding.names.size(); i++) {
425 result_names.push_back(x: binding.names[i]);
426 result_types.push_back(x: binding.types[i]);
427 }
428 }
429}
430
431void BindContext::AddBinding(const string &alias, unique_ptr<Binding> binding) {
432 if (bindings.find(x: alias) != bindings.end()) {
433 throw BinderException("Duplicate alias \"%s\" in query!", alias);
434 }
435 bindings_list.push_back(x: *binding);
436 bindings[alias] = std::move(binding);
437}
438
439void BindContext::AddBaseTable(idx_t index, const string &alias, const vector<string> &names,
440 const vector<LogicalType> &types, vector<column_t> &bound_column_ids,
441 StandardEntry *entry, bool add_row_id) {
442 AddBinding(alias, binding: make_uniq<TableBinding>(args: alias, args: types, args: names, args&: bound_column_ids, args&: entry, args&: index, args&: add_row_id));
443}
444
445void BindContext::AddTableFunction(idx_t index, const string &alias, const vector<string> &names,
446 const vector<LogicalType> &types, vector<column_t> &bound_column_ids,
447 StandardEntry *entry) {
448 AddBinding(alias, binding: make_uniq<TableBinding>(args: alias, args: types, args: names, args&: bound_column_ids, args&: entry, args&: index));
449}
450
451static string AddColumnNameToBinding(const string &base_name, case_insensitive_set_t &current_names) {
452 idx_t index = 1;
453 string name = base_name;
454 while (current_names.find(x: name) != current_names.end()) {
455 name = base_name + ":" + std::to_string(val: index++);
456 }
457 current_names.insert(x: name);
458 return name;
459}
460
461vector<string> BindContext::AliasColumnNames(const string &table_name, const vector<string> &names,
462 const vector<string> &column_aliases) {
463 vector<string> result;
464 if (column_aliases.size() > names.size()) {
465 throw BinderException("table \"%s\" has %lld columns available but %lld columns specified", table_name,
466 names.size(), column_aliases.size());
467 }
468 case_insensitive_set_t current_names;
469 // use any provided column aliases first
470 for (idx_t i = 0; i < column_aliases.size(); i++) {
471 result.push_back(x: AddColumnNameToBinding(base_name: column_aliases[i], current_names));
472 }
473 // if not enough aliases were provided, use the default names for remaining columns
474 for (idx_t i = column_aliases.size(); i < names.size(); i++) {
475 result.push_back(x: AddColumnNameToBinding(base_name: names[i], current_names));
476 }
477 return result;
478}
479
480void BindContext::AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery) {
481 auto names = AliasColumnNames(table_name: alias, names: subquery.names, column_aliases: ref.column_name_alias);
482 AddGenericBinding(index, alias, names, types: subquery.types);
483}
484
485void BindContext::AddEntryBinding(idx_t index, const string &alias, const vector<string> &names,
486 const vector<LogicalType> &types, StandardEntry &entry) {
487 AddBinding(alias, binding: make_uniq<EntryBinding>(args: alias, args: types, args: names, args&: index, args&: entry));
488}
489
490void BindContext::AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery,
491 ViewCatalogEntry *view) {
492 auto names = AliasColumnNames(table_name: alias, names: subquery.names, column_aliases: ref.column_name_alias);
493 AddEntryBinding(index, alias, names, types: subquery.types, entry&: view->Cast<StandardEntry>());
494}
495
496void BindContext::AddSubquery(idx_t index, const string &alias, TableFunctionRef &ref, BoundQueryNode &subquery) {
497 auto names = AliasColumnNames(table_name: alias, names: subquery.names, column_aliases: ref.column_name_alias);
498 AddGenericBinding(index, alias, names, types: subquery.types);
499}
500
501void BindContext::AddGenericBinding(idx_t index, const string &alias, const vector<string> &names,
502 const vector<LogicalType> &types) {
503 AddBinding(alias, binding: make_uniq<Binding>(args: BindingType::BASE, args: alias, args: types, args: names, args&: index));
504}
505
506void BindContext::AddCTEBinding(idx_t index, const string &alias, const vector<string> &names,
507 const vector<LogicalType> &types) {
508 auto binding = make_shared<Binding>(args: BindingType::BASE, args: alias, args: types, args: names, args&: index);
509
510 if (cte_bindings.find(x: alias) != cte_bindings.end()) {
511 throw BinderException("Duplicate alias \"%s\" in query!", alias);
512 }
513 cte_bindings[alias] = std::move(binding);
514 cte_references[alias] = std::make_shared<idx_t>(args: 0);
515}
516
517void BindContext::AddContext(BindContext other) {
518 for (auto &binding : other.bindings) {
519 if (bindings.find(x: binding.first) != bindings.end()) {
520 throw BinderException("Duplicate alias \"%s\" in query!", binding.first);
521 }
522 bindings[binding.first] = std::move(binding.second);
523 }
524 for (auto &binding : other.bindings_list) {
525 bindings_list.push_back(x: binding);
526 }
527 for (auto &entry : other.using_columns) {
528 for (auto &alias : entry.second) {
529#ifdef DEBUG
530 for (auto &other_alias : using_columns[entry.first]) {
531 for (auto &col : alias.get().bindings) {
532 D_ASSERT(other_alias.get().bindings.find(col) == other_alias.get().bindings.end());
533 }
534 }
535#endif
536 using_columns[entry.first].insert(x: alias);
537 }
538 }
539}
540
541void BindContext::RemoveContext(vector<reference<Binding>> &other_bindings_list) {
542 for (auto &other_binding : other_bindings_list) {
543 auto it = std::remove_if(first: bindings_list.begin(), last: bindings_list.end(), pred: [other_binding](reference<Binding> x) {
544 return x.get().alias == other_binding.get().alias;
545 });
546 bindings_list.erase(first: it, last: bindings_list.end());
547 }
548
549 for (auto &other_binding : other_bindings_list) {
550 auto &alias = other_binding.get().alias;
551 if (bindings.find(x: alias) != bindings.end()) {
552 bindings.erase(x: alias);
553 }
554 }
555}
556
557} // namespace duckdb
558