1#include "duckdb/planner/bind_context.hpp"
2
3#include "duckdb/parser/expression/columnref_expression.hpp"
4#include "duckdb/parser/tableref/subqueryref.hpp"
5#include "duckdb/planner/expression/bound_columnref_expression.hpp"
6#include "duckdb/planner/bound_query_node.hpp"
7
8#include "duckdb/common/string_util.hpp"
9
10#include <algorithm>
11
12using namespace duckdb;
13using namespace std;
14
15string BindContext::GetMatchingBinding(const string &column_name) {
16 string result;
17 for (auto &kv : bindings) {
18 auto binding = kv.second.get();
19 if (binding->HasMatchingBinding(column_name)) {
20 // check if the binding is ignored
21 if (BindingIsHidden(kv.first, column_name)) {
22 continue;
23 }
24
25 if (!result.empty()) {
26 throw BinderException("Ambiguous reference to column name \"%s\" (use: \"%s.%s\" "
27 "or \"%s.%s\")",
28 column_name.c_str(), result.c_str(), column_name.c_str(), kv.first.c_str(),
29 column_name.c_str());
30 }
31 result = kv.first;
32 }
33 }
34 return result;
35}
36
37bool BindContext::BindingIsHidden(const string &binding_name, const string &column_name) {
38 string total_binding = binding_name + "." + column_name;
39 return hidden_columns.find(total_binding) != hidden_columns.end();
40}
41
42unordered_set<string> BindContext::GetMatchingBindings(const string &column_name) {
43 unordered_set<string> result;
44 for (auto &kv : bindings) {
45 auto binding = kv.second.get();
46 if (binding->HasMatchingBinding(column_name)) {
47 result.insert(kv.first);
48 }
49 }
50 return result;
51}
52
53Binding *BindContext::GetCTEBinding(const string &ctename) {
54 auto match = cte_bindings.find(ctename);
55 if (match == cte_bindings.end()) {
56 return nullptr;
57 }
58 return match->second.get();
59}
60
61BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) {
62 if (colref.table_name.empty()) {
63 return BindResult(StringUtil::Format("Could not bind alias \"%s\"!", colref.column_name.c_str()));
64 }
65
66 auto match = bindings.find(colref.table_name);
67 if (match == bindings.end()) {
68 // alias not found in this BindContext
69 return BindResult(StringUtil::Format("Referenced table \"%s\" not found!", colref.table_name.c_str()));
70 }
71 auto binding = match->second.get();
72 return binding->Bind(colref, depth);
73}
74
75void BindContext::GenerateAllColumnExpressions(vector<unique_ptr<ParsedExpression>> &new_select_list,
76 string relation_name) {
77 if (bindings_list.size() == 0) {
78 throw BinderException("SELECT * expression without FROM clause!");
79 }
80 if (relation_name == "") { // SELECT * case
81 // we have to bind the tables and subqueries in order of table_index
82 for (auto &entry : bindings_list) {
83 auto binding = entry.second;
84 binding->GenerateAllColumnExpressions(*this, new_select_list);
85 }
86 } else { // SELECT tbl.* case
87 auto match = bindings.find(relation_name);
88 if (match == bindings.end()) {
89 // alias not found in this BindContext
90 throw BinderException("SELECT table.* expression but can't find table");
91 }
92 auto binding = match->second.get();
93 binding->GenerateAllColumnExpressions(*this, new_select_list);
94 }
95}
96
97void BindContext::AddBinding(const string &alias, unique_ptr<Binding> binding) {
98 if (bindings.find(alias) != bindings.end()) {
99 throw BinderException("Duplicate alias \"%s\" in query!", alias.c_str());
100 }
101 bindings_list.push_back(make_pair(alias, binding.get()));
102 bindings[alias] = move(binding);
103}
104
105void BindContext::AddBaseTable(idx_t index, const string &alias, TableCatalogEntry &table, LogicalGet &get) {
106 AddBinding(alias, make_unique<TableBinding>(alias, table, get, index));
107}
108
109void BindContext::AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery) {
110 vector<string> names;
111 if (ref.column_name_alias.size() > subquery.names.size()) {
112 throw BinderException("table \"%s\" has %lld columns available but %lld columns specified", alias.c_str(),
113 (int64_t)subquery.names.size(), (int64_t)ref.column_name_alias.size());
114 }
115 // use any provided aliases from the subquery
116 for (idx_t i = 0; i < ref.column_name_alias.size(); i++) {
117 names.push_back(ref.column_name_alias[i]);
118 }
119 // if not enough aliases were provided, use the default names for remaining columns
120 for (idx_t i = ref.column_name_alias.size(); i < subquery.names.size(); i++) {
121 names.push_back(subquery.names[i]);
122 }
123 AddGenericBinding(index, alias, names, subquery.types);
124}
125
126void BindContext::AddGenericBinding(idx_t index, const string &alias, vector<string> names, vector<SQLType> types) {
127 AddBinding(alias, make_unique<GenericBinding>(alias, move(types), move(names), index));
128}
129
130void BindContext::AddCTEBinding(idx_t index, const string &alias, vector<string> names, vector<SQLType> types) {
131 auto binding = make_shared<GenericBinding>(alias, move(types), move(names), index);
132
133 if (cte_bindings.find(alias) != cte_bindings.end()) {
134 throw BinderException("Duplicate alias \"%s\" in query!", alias.c_str());
135 }
136 cte_bindings[alias] = move(binding);
137 cte_references[alias] = std::make_shared<idx_t>(0);
138}
139