1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/planner/bind_context.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/catalog/catalog.hpp"
12#include "duckdb/common/case_insensitive_map.hpp"
13#include "duckdb/common/reference_map.hpp"
14#include "duckdb/parser/expression/columnref_expression.hpp"
15#include "duckdb/parser/parsed_expression.hpp"
16#include "duckdb/parser/qualified_name_set.hpp"
17#include "duckdb/planner/expression.hpp"
18#include "duckdb/planner/expression_binder.hpp"
19#include "duckdb/planner/table_binding.hpp"
20
21namespace duckdb {
22class Binder;
23class LogicalGet;
24class BoundQueryNode;
25
26class StarExpression;
27
28class TableCatalogEntry;
29class TableFunctionCatalogEntry;
30
31struct UsingColumnSet {
32 string primary_binding;
33 unordered_set<string> bindings;
34};
35
36//! The BindContext object keeps track of all the tables and columns that are
37//! encountered during the binding process.
38class BindContext {
39public:
40 //! Keep track of recursive CTE references
41 case_insensitive_map_t<std::shared_ptr<idx_t>> cte_references;
42
43public:
44 //! Given a column name, find the matching table it belongs to. Throws an
45 //! exception if no table has a column of the given name.
46 string GetMatchingBinding(const string &column_name);
47 //! Like GetMatchingBinding, but instead of throwing an error if multiple tables have the same binding it will
48 //! return a list of all the matching ones
49 unordered_set<string> GetMatchingBindings(const string &column_name);
50 //! Like GetMatchingBindings, but returns the top 3 most similar bindings (in levenshtein distance) instead of the
51 //! matching ones
52 vector<string> GetSimilarBindings(const string &column_name);
53
54 optional_ptr<Binding> GetCTEBinding(const string &ctename);
55 //! Binds a column expression to the base table. Returns the bound expression
56 //! or throws an exception if the column could not be bound.
57 BindResult BindColumn(ColumnRefExpression &colref, idx_t depth);
58 string BindColumn(PositionalReferenceExpression &ref, string &table_name, string &column_name);
59 unique_ptr<ColumnRefExpression> PositionToColumn(PositionalReferenceExpression &ref);
60
61 unique_ptr<ParsedExpression> ExpandGeneratedColumn(const string &table_name, const string &column_name);
62
63 unique_ptr<ParsedExpression> CreateColumnReference(const string &table_name, const string &column_name);
64 unique_ptr<ParsedExpression> CreateColumnReference(const string &schema_name, const string &table_name,
65 const string &column_name);
66 unique_ptr<ParsedExpression> CreateColumnReference(const string &catalog_name, const string &schema_name,
67 const string &table_name, const string &column_name);
68
69 //! Generate column expressions for all columns that are present in the
70 //! referenced tables. This is used to resolve the * expression in a
71 //! selection list.
72 void GenerateAllColumnExpressions(StarExpression &expr, vector<unique_ptr<ParsedExpression>> &new_select_list);
73 //! Check if the given (binding, column_name) is in the exclusion/replacement lists.
74 //! Returns true if it is in one of these lists, and should therefore be skipped.
75 bool CheckExclusionList(StarExpression &expr, const string &column_name,
76 vector<unique_ptr<ParsedExpression>> &new_select_list,
77 case_insensitive_set_t &excluded_columns);
78
79 const vector<reference<Binding>> &GetBindingsList() {
80 return bindings_list;
81 }
82
83 void GetTypesAndNames(vector<string> &result_names, vector<LogicalType> &result_types);
84
85 //! Adds a base table with the given alias to the BindContext.
86 void AddBaseTable(idx_t index, const string &alias, const vector<string> &names, const vector<LogicalType> &types,
87 vector<column_t> &bound_column_ids, StandardEntry *entry, bool add_row_id = true);
88 //! Adds a call to a table function with the given alias to the BindContext.
89 void AddTableFunction(idx_t index, const string &alias, const vector<string> &names,
90 const vector<LogicalType> &types, vector<column_t> &bound_column_ids, StandardEntry *entry);
91 //! Adds a table view with a given alias to the BindContext.
92 void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry *view);
93 //! Adds a subquery with a given alias to the BindContext.
94 void AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery);
95 //! Adds a subquery with a given alias to the BindContext.
96 void AddSubquery(idx_t index, const string &alias, TableFunctionRef &ref, BoundQueryNode &subquery);
97 //! Adds a binding to a catalog entry with a given alias to the BindContext.
98 void AddEntryBinding(idx_t index, const string &alias, const vector<string> &names,
99 const vector<LogicalType> &types, StandardEntry &entry);
100 //! Adds a base table with the given alias to the BindContext.
101 void AddGenericBinding(idx_t index, const string &alias, const vector<string> &names,
102 const vector<LogicalType> &types);
103
104 //! Adds a base table with the given alias to the CTE BindContext.
105 //! We need this to correctly bind recursive CTEs with multiple references.
106 void AddCTEBinding(idx_t index, const string &alias, const vector<string> &names, const vector<LogicalType> &types);
107
108 //! Add an implicit join condition (e.g. USING (x))
109 void AddUsingBinding(const string &column_name, UsingColumnSet &set);
110
111 void AddUsingBindingSet(unique_ptr<UsingColumnSet> set);
112
113 //! Returns any using column set for the given column name, or nullptr if there is none. On conflict (multiple using
114 //! column sets with the same name) throw an exception.
115 optional_ptr<UsingColumnSet> GetUsingBinding(const string &column_name);
116 //! Returns any using column set for the given column name, or nullptr if there is none
117 optional_ptr<UsingColumnSet> GetUsingBinding(const string &column_name, const string &binding_name);
118 //! Erase a using binding from the set of using bindings
119 void RemoveUsingBinding(const string &column_name, UsingColumnSet &set);
120 //! Transfer a using binding from one bind context to this bind context
121 void TransferUsingBinding(BindContext &current_context, optional_ptr<UsingColumnSet> current_set,
122 UsingColumnSet &new_set, const string &binding, const string &using_column);
123
124 //! Fetch the actual column name from the given binding, or throws if none exists
125 //! This can be different from "column_name" because of case insensitivity
126 //! (e.g. "column_name" might return "COLUMN_NAME")
127 string GetActualColumnName(const string &binding, const string &column_name);
128
129 case_insensitive_map_t<std::shared_ptr<Binding>> GetCTEBindings() {
130 return cte_bindings;
131 }
132 void SetCTEBindings(case_insensitive_map_t<std::shared_ptr<Binding>> bindings) {
133 cte_bindings = bindings;
134 }
135
136 //! Alias a set of column names for the specified table, using the original names if there are not enough aliases
137 //! specified.
138 static vector<string> AliasColumnNames(const string &table_name, const vector<string> &names,
139 const vector<string> &column_aliases);
140
141 //! Add all the bindings from a BindContext to this BindContext. The other BindContext is destroyed in the process.
142 void AddContext(BindContext other);
143 //! For semi and anti joins we remove the binding context of the right table after binding the condition.
144 void RemoveContext(vector<reference<Binding>> &other_bindings_list);
145
146 //! Gets a binding of the specified name. Returns a nullptr and sets the out_error if the binding could not be
147 //! found.
148 optional_ptr<Binding> GetBinding(const string &name, string &out_error);
149
150private:
151 void AddBinding(const string &alias, unique_ptr<Binding> binding);
152
153private:
154 //! The set of bindings
155 case_insensitive_map_t<unique_ptr<Binding>> bindings;
156 //! The list of bindings in insertion order
157 vector<reference<Binding>> bindings_list;
158 //! The set of columns used in USING join conditions
159 case_insensitive_map_t<reference_set_t<UsingColumnSet>> using_columns;
160 //! Using column sets
161 vector<unique_ptr<UsingColumnSet>> using_column_sets;
162
163 //! The set of CTE bindings
164 case_insensitive_map_t<std::shared_ptr<Binding>> cte_bindings;
165};
166} // namespace duckdb
167