1#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp"
2#include "duckdb/common/string_util.hpp"
3#include "duckdb/function/scalar/nested_functions.hpp"
4#include "duckdb/parser/expression/columnref_expression.hpp"
5#include "duckdb/parser/expression/constant_expression.hpp"
6#include "duckdb/parser/expression/function_expression.hpp"
7#include "duckdb/parser/expression/operator_expression.hpp"
8#include "duckdb/parser/expression/positional_reference_expression.hpp"
9#include "duckdb/parser/expression/subquery_expression.hpp"
10#include "duckdb/parser/parsed_expression_iterator.hpp"
11#include "duckdb/planner/binder.hpp"
12#include "duckdb/planner/expression/bound_columnref_expression.hpp"
13#include "duckdb/planner/expression/bound_lambdaref_expression.hpp"
14#include "duckdb/planner/expression/bound_constant_expression.hpp"
15#include "duckdb/planner/expression_binder.hpp"
16#include "duckdb/planner/expression_binder/where_binder.hpp"
17
18namespace duckdb {
19
20string GetSQLValueFunctionName(const string &column_name) {
21 auto lcase = StringUtil::Lower(str: column_name);
22 if (lcase == "current_catalog") {
23 return "current_catalog";
24 } else if (lcase == "current_date") {
25 return "current_date";
26 } else if (lcase == "current_schema") {
27 return "current_schema";
28 } else if (lcase == "current_role") {
29 return "current_role";
30 } else if (lcase == "current_time") {
31 return "get_current_time";
32 } else if (lcase == "current_timestamp") {
33 return "get_current_timestamp";
34 } else if (lcase == "current_user") {
35 return "current_user";
36 } else if (lcase == "localtime") {
37 return "current_localtime";
38 } else if (lcase == "localtimestamp") {
39 return "current_localtimestamp";
40 } else if (lcase == "session_user") {
41 return "session_user";
42 } else if (lcase == "user") {
43 return "user";
44 }
45 return string();
46}
47
48unique_ptr<ParsedExpression> ExpressionBinder::GetSQLValueFunction(const string &column_name) {
49 auto value_function = GetSQLValueFunctionName(column_name);
50 if (value_function.empty()) {
51 return nullptr;
52 }
53
54 vector<unique_ptr<ParsedExpression>> children;
55 return make_uniq<FunctionExpression>(args&: value_function, args: std::move(children));
56}
57
58unique_ptr<ParsedExpression> ExpressionBinder::QualifyColumnName(const string &column_name, string &error_message) {
59 auto using_binding = binder.bind_context.GetUsingBinding(column_name);
60 if (using_binding) {
61 // we are referencing a USING column
62 // check if we can refer to one of the base columns directly
63 unique_ptr<Expression> expression;
64 if (!using_binding->primary_binding.empty()) {
65 // we can! just assign the table name and re-bind
66 return binder.bind_context.CreateColumnReference(table_name: using_binding->primary_binding, column_name);
67 } else {
68 // // we cannot! we need to bind this as a coalesce between all the relevant columns
69 auto coalesce = make_uniq<OperatorExpression>(args: ExpressionType::OPERATOR_COALESCE);
70 coalesce->children.reserve(n: using_binding->bindings.size());
71 for (auto &entry : using_binding->bindings) {
72 coalesce->children.push_back(x: make_uniq<ColumnRefExpression>(args: column_name, args: entry));
73 }
74 return std::move(coalesce);
75 }
76 }
77
78 // find a binding that contains this
79 string table_name = binder.bind_context.GetMatchingBinding(column_name);
80
81 // throw an error if a macro conflicts with a column name
82 auto is_macro_column = false;
83 if (binder.macro_binding != nullptr && binder.macro_binding->HasMatchingBinding(column_name)) {
84 is_macro_column = true;
85 if (!table_name.empty()) {
86 throw BinderException("Conflicting column names for column " + column_name + "!");
87 }
88 }
89
90 if (lambda_bindings) {
91 for (idx_t i = 0; i < lambda_bindings->size(); i++) {
92 if ((*lambda_bindings)[i].HasMatchingBinding(column_name)) {
93
94 // throw an error if a lambda conflicts with a column name or a macro
95 if (!table_name.empty() || is_macro_column) {
96 throw BinderException("Conflicting column names for column " + column_name + "!");
97 }
98
99 D_ASSERT(!(*lambda_bindings)[i].alias.empty());
100 return make_uniq<ColumnRefExpression>(args: column_name, args&: (*lambda_bindings)[i].alias);
101 }
102 }
103 }
104
105 if (is_macro_column) {
106 D_ASSERT(!binder.macro_binding->alias.empty());
107 return make_uniq<ColumnRefExpression>(args: column_name, args&: binder.macro_binding->alias);
108 }
109 // see if it's a column
110 if (table_name.empty()) {
111 // column was not found - check if it is a SQL value function
112 auto value_function = GetSQLValueFunction(column_name);
113 if (value_function) {
114 return value_function;
115 }
116 // it's not, find candidates and error
117 auto similar_bindings = binder.bind_context.GetSimilarBindings(column_name);
118 string candidate_str = StringUtil::CandidatesMessage(candidates: similar_bindings, candidate: "Candidate bindings");
119 error_message =
120 StringUtil::Format(fmt_str: "Referenced column \"%s\" not found in FROM clause!%s", params: column_name, params: candidate_str);
121 return nullptr;
122 }
123 return binder.bind_context.CreateColumnReference(table_name, column_name);
124}
125
126void ExpressionBinder::QualifyColumnNames(unique_ptr<ParsedExpression> &expr) {
127 switch (expr->type) {
128 case ExpressionType::COLUMN_REF: {
129 auto &colref = expr->Cast<ColumnRefExpression>();
130 string error_message;
131 auto new_expr = QualifyColumnName(colref, error_message);
132 if (new_expr) {
133 if (!expr->alias.empty()) {
134 new_expr->alias = expr->alias;
135 }
136 new_expr->query_location = colref.query_location;
137 expr = std::move(new_expr);
138 }
139 break;
140 }
141 case ExpressionType::POSITIONAL_REFERENCE: {
142 auto &ref = expr->Cast<PositionalReferenceExpression>();
143 if (ref.alias.empty()) {
144 string table_name, column_name;
145 auto error = binder.bind_context.BindColumn(ref, table_name, column_name);
146 if (error.empty()) {
147 ref.alias = column_name;
148 }
149 }
150 break;
151 }
152 default:
153 break;
154 }
155 ParsedExpressionIterator::EnumerateChildren(
156 expr&: *expr, callback: [&](unique_ptr<ParsedExpression> &child) { QualifyColumnNames(expr&: child); });
157}
158
159void ExpressionBinder::QualifyColumnNames(Binder &binder, unique_ptr<ParsedExpression> &expr) {
160 WhereBinder where_binder(binder, binder.context);
161 where_binder.QualifyColumnNames(expr);
162}
163
164unique_ptr<ParsedExpression> ExpressionBinder::CreateStructExtract(unique_ptr<ParsedExpression> base,
165 string field_name) {
166
167 // we need to transform the struct extract if it is inside a lambda expression
168 // because we cannot bind to an existing table, so we remove the dummy table also
169 if (lambda_bindings && base->type == ExpressionType::COLUMN_REF) {
170 auto &lambda_column_ref = base->Cast<ColumnRefExpression>();
171 D_ASSERT(!lambda_column_ref.column_names.empty());
172
173 if (lambda_column_ref.column_names[0].find(s: DummyBinding::DUMMY_NAME) != string::npos) {
174 D_ASSERT(lambda_column_ref.column_names.size() == 2);
175 auto lambda_param_name = lambda_column_ref.column_names.back();
176 lambda_column_ref.column_names.clear();
177 lambda_column_ref.column_names.push_back(x: lambda_param_name);
178 }
179 }
180
181 vector<unique_ptr<ParsedExpression>> children;
182 children.push_back(x: std::move(base));
183 children.push_back(x: make_uniq_base<ParsedExpression, ConstantExpression>(args: Value(std::move(field_name))));
184 auto extract_fun = make_uniq<OperatorExpression>(args: ExpressionType::STRUCT_EXTRACT, args: std::move(children));
185 return std::move(extract_fun);
186}
187
188unique_ptr<ParsedExpression> ExpressionBinder::CreateStructPack(ColumnRefExpression &colref) {
189 D_ASSERT(colref.column_names.size() <= 3);
190 string error_message;
191 auto &table_name = colref.column_names.back();
192 auto binding = binder.bind_context.GetBinding(name: table_name, out_error&: error_message);
193 if (!binding) {
194 return nullptr;
195 }
196 if (colref.column_names.size() >= 2) {
197 // "schema_name.table_name"
198 auto catalog_entry = binding->GetStandardEntry();
199 if (!catalog_entry) {
200 return nullptr;
201 }
202 if (catalog_entry->name != table_name) {
203 return nullptr;
204 }
205 if (colref.column_names.size() == 2) {
206 auto &qualifier = colref.column_names[0];
207 if (catalog_entry->catalog.GetName() != qualifier && catalog_entry->schema.name != qualifier) {
208 return nullptr;
209 }
210 } else if (colref.column_names.size() == 3) {
211 auto &catalog_name = colref.column_names[0];
212 auto &schema_name = colref.column_names[1];
213 if (catalog_entry->catalog.GetName() != catalog_name || catalog_entry->schema.name != schema_name) {
214 return nullptr;
215 }
216 } else {
217 throw InternalException("Expected 2 or 3 column names for CreateStructPack");
218 }
219 }
220 // We found the table, now create the struct_pack expression
221 vector<unique_ptr<ParsedExpression>> child_expressions;
222 child_expressions.reserve(n: binding->names.size());
223 for (const auto &column_name : binding->names) {
224 child_expressions.push_back(x: make_uniq<ColumnRefExpression>(args: column_name, args&: table_name));
225 }
226 return make_uniq<FunctionExpression>(args: "struct_pack", args: std::move(child_expressions));
227}
228
229unique_ptr<ParsedExpression> ExpressionBinder::QualifyColumnName(ColumnRefExpression &colref, string &error_message) {
230 idx_t column_parts = colref.column_names.size();
231 // column names can have an arbitrary amount of dots
232 // here is how the resolution works:
233 if (column_parts == 1) {
234 // no dots (i.e. "part1")
235 // -> part1 refers to a column
236 // check if we can qualify the column name with the table name
237 auto qualified_colref = QualifyColumnName(column_name: colref.GetColumnName(), error_message);
238 if (qualified_colref) {
239 // we could: return it
240 return qualified_colref;
241 }
242 // we could not! Try creating an implicit struct_pack
243 return CreateStructPack(colref);
244 } else if (column_parts == 2) {
245 // one dot (i.e. "part1.part2")
246 // EITHER:
247 // -> part1 is a table, part2 is a column
248 // -> part1 is a column, part2 is a property of that column (i.e. struct_extract)
249
250 // first check if part1 is a table, and part2 is a standard column
251 if (binder.HasMatchingBinding(table_name: colref.column_names[0], column_name: colref.column_names[1], error_message)) {
252 // it is! return the colref directly
253 return binder.bind_context.CreateColumnReference(table_name: colref.column_names[0], column_name: colref.column_names[1]);
254 } else {
255 // otherwise check if we can turn this into a struct extract
256 auto new_colref = make_uniq<ColumnRefExpression>(args&: colref.column_names[0]);
257 string other_error;
258 auto qualified_colref = QualifyColumnName(column_name: colref.column_names[0], error_message&: other_error);
259 if (qualified_colref) {
260 // we could: create a struct extract
261 return CreateStructExtract(base: std::move(qualified_colref), field_name: colref.column_names[1]);
262 }
263 // we could not! Try creating an implicit struct_pack
264 return CreateStructPack(colref);
265 }
266 } else {
267 // two or more dots (i.e. "part1.part2.part3.part4...")
268 // -> part1 is a catalog, part2 is a schema, part3 is a table, part4 is a column name, part 5 and beyond are
269 // struct fields
270 // -> part1 is a catalog, part2 is a table, part3 is a column name, part4 and beyond are struct fields
271 // -> part1 is a schema, part2 is a table, part3 is a column name, part4 and beyond are struct fields
272 // -> part1 is a table, part2 is a column name, part3 and beyond are struct fields
273 // -> part1 is a column, part2 and beyond are struct fields
274
275 // we always prefer the most top-level view
276 // i.e. in case of multiple resolution options, we resolve in order:
277 // -> 1. resolve "part1" as a catalog
278 // -> 2. resolve "part1" as a schema
279 // -> 3. resolve "part1" as a table
280 // -> 4. resolve "part1" as a column
281
282 unique_ptr<ParsedExpression> result_expr;
283 idx_t struct_extract_start;
284 // first check if part1 is a catalog
285 if (colref.column_names.size() > 3 &&
286 binder.HasMatchingBinding(catalog_name: colref.column_names[0], schema_name: colref.column_names[1], table_name: colref.column_names[2],
287 column_name: colref.column_names[3], error_message)) {
288 // part1 is a catalog - the column reference is "catalog.schema.table.column"
289 result_expr = binder.bind_context.CreateColumnReference(catalog_name: colref.column_names[0], schema_name: colref.column_names[1],
290 table_name: colref.column_names[2], column_name: colref.column_names[3]);
291 struct_extract_start = 4;
292 } else if (binder.HasMatchingBinding(catalog_name: colref.column_names[0], INVALID_SCHEMA, table_name: colref.column_names[1],
293 column_name: colref.column_names[2], error_message)) {
294 // part1 is a catalog - the column reference is "catalog.table.column"
295 result_expr = binder.bind_context.CreateColumnReference(catalog_name: colref.column_names[0], INVALID_SCHEMA,
296 table_name: colref.column_names[1], column_name: colref.column_names[2]);
297 struct_extract_start = 3;
298 } else if (binder.HasMatchingBinding(schema_name: colref.column_names[0], table_name: colref.column_names[1], column_name: colref.column_names[2],
299 error_message)) {
300 // part1 is a schema - the column reference is "schema.table.column"
301 // any additional fields are turned into struct_extract calls
302 result_expr = binder.bind_context.CreateColumnReference(schema_name: colref.column_names[0], table_name: colref.column_names[1],
303 column_name: colref.column_names[2]);
304 struct_extract_start = 3;
305 } else if (binder.HasMatchingBinding(table_name: colref.column_names[0], column_name: colref.column_names[1], error_message)) {
306 // part1 is a table
307 // the column reference is "table.column"
308 // any additional fields are turned into struct_extract calls
309 result_expr = binder.bind_context.CreateColumnReference(table_name: colref.column_names[0], column_name: colref.column_names[1]);
310 struct_extract_start = 2;
311 } else {
312 // part1 could be a column
313 string col_error;
314 result_expr = QualifyColumnName(column_name: colref.column_names[0], error_message&: col_error);
315 if (!result_expr) {
316 // it is not! Try creating an implicit struct_pack
317 return CreateStructPack(colref);
318 }
319 // it is! add the struct extract calls
320 struct_extract_start = 1;
321 }
322 for (idx_t i = struct_extract_start; i < colref.column_names.size(); i++) {
323 result_expr = CreateStructExtract(base: std::move(result_expr), field_name: colref.column_names[i]);
324 }
325 return result_expr;
326 }
327}
328
329BindResult ExpressionBinder::BindExpression(ColumnRefExpression &colref_p, idx_t depth) {
330 if (binder.GetBindingMode() == BindingMode::EXTRACT_NAMES) {
331 return BindResult(make_uniq<BoundConstantExpression>(args: Value(LogicalType::SQLNULL)));
332 }
333 string error_message;
334 auto expr = QualifyColumnName(colref&: colref_p, error_message);
335 if (!expr) {
336 return BindResult(binder.FormatError(expr_context&: colref_p, message: error_message));
337 }
338 expr->query_location = colref_p.query_location;
339
340 // a generated column returns a generated expression, a struct on a column returns a struct extract
341 if (expr->type != ExpressionType::COLUMN_REF) {
342 auto alias = expr->alias;
343 auto result = BindExpression(expr_ptr&: expr, depth);
344 if (result.expression) {
345 result.expression->alias = std::move(alias);
346 }
347 return result;
348 }
349
350 auto &colref = expr->Cast<ColumnRefExpression>();
351 D_ASSERT(colref.IsQualified());
352 auto &table_name = colref.GetTableName();
353
354 // individual column reference
355 // resolve to either a base table or a subquery expression
356 // if it was a macro parameter, let macro_binding bind it to the argument
357 // if it was a lambda parameter, let lambda_bindings bind it to the argument
358
359 BindResult result;
360
361 auto found_lambda_binding = false;
362 if (lambda_bindings) {
363 for (idx_t i = 0; i < lambda_bindings->size(); i++) {
364 if (table_name == (*lambda_bindings)[i].alias) {
365 result = (*lambda_bindings)[i].Bind(colref, lambda_index: i, depth);
366 found_lambda_binding = true;
367 break;
368 }
369 }
370 }
371
372 if (!found_lambda_binding) {
373 if (binder.macro_binding && table_name == binder.macro_binding->alias) {
374 result = binder.macro_binding->Bind(colref, depth);
375 } else {
376 result = binder.bind_context.BindColumn(colref, depth);
377 }
378 }
379
380 if (!result.HasError()) {
381 BoundColumnReferenceInfo ref;
382 ref.name = colref.column_names.back();
383 ref.query_location = colref.query_location;
384 bound_columns.push_back(x: std::move(ref));
385 } else {
386 result.error = binder.FormatError(expr_context&: colref_p, message: result.error);
387 }
388 return result;
389}
390
391bool ExpressionBinder::QualifyColumnAlias(const ColumnRefExpression &colref) {
392 // Only BaseSelectBinder will have a valid col alias map,
393 // otherwise just return false
394 return false;
395}
396
397} // namespace duckdb
398