1#include "duckdb/planner/expression_binder/column_alias_binder.hpp"
2
3#include "duckdb/parser/expression/columnref_expression.hpp"
4#include "duckdb/planner/query_node/bound_select_node.hpp"
5#include "duckdb/common/string_util.hpp"
6#include "duckdb/planner/expression_binder.hpp"
7#include "duckdb/planner/binder.hpp"
8
9namespace duckdb {
10
11ColumnAliasBinder::ColumnAliasBinder(BoundSelectNode &node, const case_insensitive_map_t<idx_t> &alias_map)
12 : node(node), alias_map(alias_map), visited_select_indexes() {
13}
14
15BindResult ColumnAliasBinder::BindAlias(ExpressionBinder &enclosing_binder, ColumnRefExpression &expr, idx_t depth,
16 bool root_expression) {
17 if (expr.IsQualified()) {
18 return BindResult(StringUtil::Format(fmt_str: "Alias %s cannot be qualified.", params: expr.ToString()));
19 }
20
21 auto alias_entry = alias_map.find(x: expr.column_names[0]);
22 if (alias_entry == alias_map.end()) {
23 return BindResult(StringUtil::Format(fmt_str: "Alias %s is not found.", params: expr.ToString()));
24 }
25
26 if (visited_select_indexes.find(x: alias_entry->second) != visited_select_indexes.end()) {
27 return BindResult("Cannot resolve self-referential alias");
28 }
29
30 // found an alias: bind the alias expression
31 auto expression = node.original_expressions[alias_entry->second]->Copy();
32 visited_select_indexes.insert(x: alias_entry->second);
33
34 // since the alias has been found, pass a depth of 0. See Issue 4978 (#16)
35 // ColumnAliasBinders are only in Having, Qualify and Where Binders
36 auto result = enclosing_binder.BindExpression(expr_ptr&: expression, depth: 0, root_expression);
37 visited_select_indexes.erase(x: alias_entry->second);
38 return result;
39}
40
41} // namespace duckdb
42