1#include "duckdb/planner/table_binding.hpp"
2
3#include "duckdb/common/string_util.hpp"
4#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
5#include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp"
6#include "duckdb/parser/expression/columnref_expression.hpp"
7#include "duckdb/parser/tableref/subqueryref.hpp"
8#include "duckdb/planner/bind_context.hpp"
9#include "duckdb/planner/bound_query_node.hpp"
10#include "duckdb/planner/expression/bound_columnref_expression.hpp"
11#include "duckdb/planner/expression/bound_lambdaref_expression.hpp"
12#include "duckdb/parser/parsed_expression_iterator.hpp"
13
14#include <algorithm>
15
16namespace duckdb {
17
18Binding::Binding(BindingType binding_type, const string &alias, vector<LogicalType> coltypes, vector<string> colnames,
19 idx_t index)
20 : binding_type(binding_type), alias(alias), index(index), types(std::move(coltypes)), names(std::move(colnames)) {
21 D_ASSERT(types.size() == names.size());
22 for (idx_t i = 0; i < names.size(); i++) {
23 auto &name = names[i];
24 D_ASSERT(!name.empty());
25 if (name_map.find(x: name) != name_map.end()) {
26 throw BinderException("table \"%s\" has duplicate column name \"%s\"", alias, name);
27 }
28 name_map[name] = i;
29 }
30}
31
32bool Binding::TryGetBindingIndex(const string &column_name, column_t &result) {
33 auto entry = name_map.find(x: column_name);
34 if (entry == name_map.end()) {
35 return false;
36 }
37 auto column_info = entry->second;
38 result = column_info;
39 return true;
40}
41
42column_t Binding::GetBindingIndex(const string &column_name) {
43 column_t result;
44 if (!TryGetBindingIndex(column_name, result)) {
45 throw InternalException("Binding index for column \"%s\" not found", column_name);
46 }
47 return result;
48}
49
50bool Binding::HasMatchingBinding(const string &column_name) {
51 column_t result;
52 return TryGetBindingIndex(column_name, result);
53}
54
55string Binding::ColumnNotFoundError(const string &column_name) const {
56 return StringUtil::Format(fmt_str: "Values list \"%s\" does not have a column named \"%s\"", params: alias, params: column_name);
57}
58
59BindResult Binding::Bind(ColumnRefExpression &colref, idx_t depth) {
60 column_t column_index;
61 bool success = false;
62 success = TryGetBindingIndex(column_name: colref.GetColumnName(), result&: column_index);
63 if (!success) {
64 return BindResult(ColumnNotFoundError(column_name: colref.GetColumnName()));
65 }
66 ColumnBinding binding;
67 binding.table_index = index;
68 binding.column_index = column_index;
69 LogicalType sql_type = types[column_index];
70 if (colref.alias.empty()) {
71 colref.alias = names[column_index];
72 }
73 return BindResult(make_uniq<BoundColumnRefExpression>(args: colref.GetName(), args&: sql_type, args&: binding, args&: depth));
74}
75
76optional_ptr<StandardEntry> Binding::GetStandardEntry() {
77 return nullptr;
78}
79
80EntryBinding::EntryBinding(const string &alias, vector<LogicalType> types_p, vector<string> names_p, idx_t index,
81 StandardEntry &entry)
82 : Binding(BindingType::CATALOG_ENTRY, alias, std::move(types_p), std::move(names_p), index), entry(entry) {
83}
84
85optional_ptr<StandardEntry> EntryBinding::GetStandardEntry() {
86 return &entry;
87}
88
89TableBinding::TableBinding(const string &alias, vector<LogicalType> types_p, vector<string> names_p,
90 vector<column_t> &bound_column_ids, optional_ptr<StandardEntry> entry, idx_t index,
91 bool add_row_id)
92 : Binding(BindingType::TABLE, alias, std::move(types_p), std::move(names_p), index),
93 bound_column_ids(bound_column_ids), entry(entry) {
94 if (add_row_id) {
95 if (name_map.find(x: "rowid") == name_map.end()) {
96 name_map["rowid"] = COLUMN_IDENTIFIER_ROW_ID;
97 }
98 }
99}
100
101static void ReplaceAliases(ParsedExpression &expr, const ColumnList &list,
102 const unordered_map<idx_t, string> &alias_map) {
103 if (expr.type == ExpressionType::COLUMN_REF) {
104 auto &colref = expr.Cast<ColumnRefExpression>();
105 D_ASSERT(!colref.IsQualified());
106 auto &col_names = colref.column_names;
107 D_ASSERT(col_names.size() == 1);
108 auto idx_entry = list.GetColumnIndex(column_name&: col_names[0]);
109 auto &alias = alias_map.at(k: idx_entry.index);
110 col_names = {alias};
111 }
112 ParsedExpressionIterator::EnumerateChildren(
113 expr, callback: [&](const ParsedExpression &child) { ReplaceAliases(expr&: (ParsedExpression &)child, list, alias_map); });
114}
115
116static void BakeTableName(ParsedExpression &expr, const string &table_name) {
117 if (expr.type == ExpressionType::COLUMN_REF) {
118 auto &colref = expr.Cast<ColumnRefExpression>();
119 D_ASSERT(!colref.IsQualified());
120 auto &col_names = colref.column_names;
121 col_names.insert(position: col_names.begin(), x: table_name);
122 }
123 ParsedExpressionIterator::EnumerateChildren(
124 expr, callback: [&](const ParsedExpression &child) { BakeTableName(expr&: (ParsedExpression &)child, table_name); });
125}
126
127unique_ptr<ParsedExpression> TableBinding::ExpandGeneratedColumn(const string &column_name) {
128 auto catalog_entry = GetStandardEntry();
129 D_ASSERT(catalog_entry); // Should only be called on a TableBinding
130
131 D_ASSERT(catalog_entry->type == CatalogType::TABLE_ENTRY);
132 auto &table_entry = catalog_entry->Cast<TableCatalogEntry>();
133
134 // Get the index of the generated column
135 auto column_index = GetBindingIndex(column_name);
136 D_ASSERT(table_entry.GetColumn(LogicalIndex(column_index)).Generated());
137 // Get a copy of the generated column
138 auto expression = table_entry.GetColumn(idx: LogicalIndex(column_index)).GeneratedExpression().Copy();
139 unordered_map<idx_t, string> alias_map;
140 for (auto &entry : name_map) {
141 alias_map[entry.second] = entry.first;
142 }
143 ReplaceAliases(expr&: *expression, list: table_entry.GetColumns(), alias_map);
144 BakeTableName(expr&: *expression, table_name: alias);
145 return (expression);
146}
147
148const vector<column_t> &TableBinding::GetBoundColumnIds() const {
149#ifdef DEBUG
150 unordered_set<column_t> column_ids;
151 for (auto &id : bound_column_ids) {
152 auto result = column_ids.insert(id);
153 // assert that all entries in the bound_column_ids are unique
154 D_ASSERT(result.second);
155 auto it = std::find_if(name_map.begin(), name_map.end(),
156 [&](const std::pair<const string, column_t> &it) { return it.second == id; });
157 // assert that every id appears in the name_map
158 D_ASSERT(it != name_map.end());
159 // the order that they appear in is not guaranteed to be sequential
160 }
161#endif
162 return bound_column_ids;
163}
164
165ColumnBinding TableBinding::GetColumnBinding(column_t column_index) {
166 auto &column_ids = bound_column_ids;
167 ColumnBinding binding;
168
169 // Locate the column_id that matches the 'column_index'
170 auto it = std::find_if(first: column_ids.begin(), last: column_ids.end(),
171 pred: [&](const column_t &id) -> bool { return id == column_index; });
172 // Get the index of it
173 binding.column_index = std::distance(first: column_ids.begin(), last: it);
174 // If it wasn't found, add it
175 if (it == column_ids.end()) {
176 column_ids.push_back(x: column_index);
177 }
178
179 binding.table_index = index;
180 return binding;
181}
182
183BindResult TableBinding::Bind(ColumnRefExpression &colref, idx_t depth) {
184 auto &column_name = colref.GetColumnName();
185 column_t column_index;
186 bool success = false;
187 success = TryGetBindingIndex(column_name, result&: column_index);
188 if (!success) {
189 return BindResult(ColumnNotFoundError(column_name));
190 }
191 auto entry = GetStandardEntry();
192 if (entry && column_index != COLUMN_IDENTIFIER_ROW_ID) {
193 D_ASSERT(entry->type == CatalogType::TABLE_ENTRY);
194 // Either there is no table, or the columns category has to be standard
195 auto &table_entry = entry->Cast<TableCatalogEntry>();
196 auto &column_entry = table_entry.GetColumn(idx: LogicalIndex(column_index));
197 (void)table_entry;
198 (void)column_entry;
199 D_ASSERT(column_entry.Category() == TableColumnType::STANDARD);
200 }
201 // fetch the type of the column
202 LogicalType col_type;
203 if (column_index == COLUMN_IDENTIFIER_ROW_ID) {
204 // row id: BIGINT type
205 col_type = LogicalType::BIGINT;
206 } else {
207 // normal column: fetch type from base column
208 col_type = types[column_index];
209 if (colref.alias.empty()) {
210 colref.alias = names[column_index];
211 }
212 }
213 ColumnBinding binding = GetColumnBinding(column_index);
214 return BindResult(make_uniq<BoundColumnRefExpression>(args: colref.GetName(), args&: col_type, args&: binding, args&: depth));
215}
216
217optional_ptr<StandardEntry> TableBinding::GetStandardEntry() {
218 return entry;
219}
220
221string TableBinding::ColumnNotFoundError(const string &column_name) const {
222 return StringUtil::Format(fmt_str: "Table \"%s\" does not have a column named \"%s\"", params: alias, params: column_name);
223}
224
225DummyBinding::DummyBinding(vector<LogicalType> types_p, vector<string> names_p, string dummy_name_p)
226 : Binding(BindingType::DUMMY, DummyBinding::DUMMY_NAME + dummy_name_p, std::move(types_p), std::move(names_p),
227 DConstants::INVALID_INDEX),
228 dummy_name(std::move(dummy_name_p)) {
229}
230
231BindResult DummyBinding::Bind(ColumnRefExpression &colref, idx_t depth) {
232 column_t column_index;
233 if (!TryGetBindingIndex(column_name: colref.GetColumnName(), result&: column_index)) {
234 throw InternalException("Column %s not found in bindings", colref.GetColumnName());
235 }
236 ColumnBinding binding(index, column_index);
237
238 // we are binding a parameter to create the dummy binding, no arguments are supplied
239 return BindResult(make_uniq<BoundColumnRefExpression>(args: colref.GetName(), args&: types[column_index], args&: binding, args&: depth));
240}
241
242BindResult DummyBinding::Bind(ColumnRefExpression &colref, idx_t lambda_index, idx_t depth) {
243 column_t column_index;
244 if (!TryGetBindingIndex(column_name: colref.GetColumnName(), result&: column_index)) {
245 throw InternalException("Column %s not found in bindings", colref.GetColumnName());
246 }
247 ColumnBinding binding(index, column_index);
248 return BindResult(
249 make_uniq<BoundLambdaRefExpression>(args: colref.GetName(), args&: types[column_index], args&: binding, args&: lambda_index, args&: depth));
250}
251
252unique_ptr<ParsedExpression> DummyBinding::ParamToArg(ColumnRefExpression &colref) {
253 column_t column_index;
254 if (!TryGetBindingIndex(column_name: colref.GetColumnName(), result&: column_index)) {
255 throw InternalException("Column %s not found in macro", colref.GetColumnName());
256 }
257 auto arg = (*arguments)[column_index]->Copy();
258 arg->alias = colref.alias;
259 return arg;
260}
261
262} // namespace duckdb
263