1#include <Common/typeid_cast.h>
2
3#include <Interpreters/IdentifierSemantic.h>
4
5namespace DB
6{
7
8namespace ErrorCodes
9{
10 extern const int AMBIGUOUS_COLUMN_NAME;
11}
12
13namespace
14{
15
16const DatabaseAndTableWithAlias & extractTable(const DatabaseAndTableWithAlias & table)
17{
18 return table;
19}
20
21const DatabaseAndTableWithAlias & extractTable(const TableWithColumnNames & table)
22{
23 return table.table;
24}
25
26template <typename T>
27IdentifierSemantic::ColumnMatch tryChooseTable(const ASTIdentifier & identifier, const std::vector<T> & tables,
28 size_t & best_table_pos, bool allow_ambiguous)
29{
30 using ColumnMatch = IdentifierSemantic::ColumnMatch;
31
32 best_table_pos = 0;
33 auto best_match = ColumnMatch::NoMatch;
34 size_t same_match = 0;
35
36 for (size_t i = 0; i < tables.size(); ++i)
37 {
38 auto match = IdentifierSemantic::canReferColumnToTable(identifier, extractTable(tables[i]));
39 if (match != ColumnMatch::NoMatch)
40 {
41 if (match > best_match)
42 {
43 best_match = match;
44 best_table_pos = i;
45 same_match = 0;
46 }
47 else if (match == best_match)
48 ++same_match;
49 }
50 }
51
52 if ((best_match != ColumnMatch::NoMatch) && same_match)
53 {
54 if (!allow_ambiguous)
55 throw Exception("Ambiguous column '" + identifier.name + "'", ErrorCodes::AMBIGUOUS_COLUMN_NAME);
56 return ColumnMatch::Ambiguous;
57 }
58 return best_match;
59}
60
61}
62
63std::optional<String> IdentifierSemantic::getColumnName(const ASTIdentifier & node)
64{
65 if (!node.semantic->special)
66 return node.name;
67 return {};
68}
69
70std::optional<String> IdentifierSemantic::getColumnName(const ASTPtr & ast)
71{
72 if (ast)
73 if (const auto * id = ast->as<ASTIdentifier>())
74 if (!id->semantic->special)
75 return id->name;
76 return {};
77}
78
79std::optional<String> IdentifierSemantic::getTableName(const ASTIdentifier & node)
80{
81 if (node.semantic->special)
82 return node.name;
83 return {};
84}
85
86std::optional<String> IdentifierSemantic::getTableName(const ASTPtr & ast)
87{
88 if (ast)
89 if (const auto * id = ast->as<ASTIdentifier>())
90 if (id->semantic->special)
91 return id->name;
92 return {};
93}
94
95std::optional<ASTIdentifier> IdentifierSemantic::uncover(const ASTIdentifier & identifier)
96{
97 if (identifier.semantic->covered)
98 {
99 std::vector<String> name_parts = identifier.name_parts;
100 return ASTIdentifier(std::move(name_parts));
101 }
102 return {};
103}
104
105void IdentifierSemantic::coverName(ASTIdentifier & identifier, const String & alias)
106{
107 identifier.setShortName(alias);
108 identifier.semantic->covered = true;
109}
110
111bool IdentifierSemantic::canBeAlias(const ASTIdentifier & identifier)
112{
113 return identifier.semantic->can_be_alias;
114}
115
116void IdentifierSemantic::setMembership(ASTIdentifier & identifier, size_t table_pos)
117{
118 identifier.semantic->membership = table_pos;
119 identifier.semantic->can_be_alias = false;
120}
121
122std::optional<size_t> IdentifierSemantic::getMembership(const ASTIdentifier & identifier)
123{
124 return identifier.semantic->membership;
125}
126
127bool IdentifierSemantic::chooseTable(const ASTIdentifier & identifier, const std::vector<DatabaseAndTableWithAlias> & tables,
128 size_t & best_table_pos, bool ambiguous)
129{
130 static constexpr auto no_match = IdentifierSemantic::ColumnMatch::NoMatch;
131 return tryChooseTable<DatabaseAndTableWithAlias>(identifier, tables, best_table_pos, ambiguous) != no_match;
132}
133
134bool IdentifierSemantic::chooseTable(const ASTIdentifier & identifier, const std::vector<TableWithColumnNames> & tables,
135 size_t & best_table_pos, bool ambiguous)
136{
137 static constexpr auto no_match = IdentifierSemantic::ColumnMatch::NoMatch;
138 return tryChooseTable<TableWithColumnNames>(identifier, tables, best_table_pos, ambiguous) != no_match;
139}
140
141std::pair<String, String> IdentifierSemantic::extractDatabaseAndTable(const ASTIdentifier & identifier)
142{
143 if (identifier.name_parts.size() > 2)
144 throw Exception("Logical error: more than two components in table expression", ErrorCodes::LOGICAL_ERROR);
145
146 if (identifier.name_parts.size() == 2)
147 return { identifier.name_parts[0], identifier.name_parts[1] };
148 return { "", identifier.name };
149}
150
151std::optional<String> IdentifierSemantic::extractNestedName(const ASTIdentifier & identifier, const String & table_name)
152{
153 if (identifier.name_parts.size() == 3 && table_name == identifier.name_parts[0])
154 return identifier.name_parts[1] + '.' + identifier.name_parts[2];
155 else if (identifier.name_parts.size() == 2)
156 return identifier.name_parts[0] + '.' + identifier.name_parts[1];
157 return {};
158}
159
160bool IdentifierSemantic::doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & database, const String & table)
161{
162 size_t num_components = identifier.name_parts.size();
163 if (num_components >= 3)
164 return identifier.name_parts[0] == database &&
165 identifier.name_parts[1] == table;
166 return false;
167}
168
169bool IdentifierSemantic::doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & table)
170{
171 size_t num_components = identifier.name_parts.size();
172 if (num_components >= 2)
173 return identifier.name_parts[0] == table;
174 return false;
175}
176
177IdentifierSemantic::ColumnMatch IdentifierSemantic::canReferColumnToTable(const ASTIdentifier & identifier,
178 const DatabaseAndTableWithAlias & db_and_table)
179{
180 /// database.table.column
181 if (doesIdentifierBelongTo(identifier, db_and_table.database, db_and_table.table))
182 return ColumnMatch::DbAndTable;
183
184 /// alias.column
185 if (doesIdentifierBelongTo(identifier, db_and_table.alias))
186 return ColumnMatch::TableAlias;
187
188 /// table.column
189 if (doesIdentifierBelongTo(identifier, db_and_table.table))
190 {
191 if (!db_and_table.alias.empty())
192 return ColumnMatch::AliasedTableName;
193 else
194 return ColumnMatch::TableName;
195 }
196
197 return ColumnMatch::NoMatch;
198}
199
200/// Strip qualificators from left side of column name.
201/// Example: 'database.table.name' -> 'name'.
202void IdentifierSemantic::setColumnShortName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
203{
204 auto match = IdentifierSemantic::canReferColumnToTable(identifier, db_and_table);
205 size_t to_strip = 0;
206 switch (match)
207 {
208 case ColumnMatch::TableName:
209 case ColumnMatch::AliasedTableName:
210 case ColumnMatch::TableAlias:
211 to_strip = 1;
212 break;
213 case ColumnMatch::DbAndTable:
214 to_strip = 2;
215 break;
216 default:
217 break;
218 }
219
220 if (!to_strip)
221 return;
222
223 std::vector<String> stripped(identifier.name_parts.begin() + to_strip, identifier.name_parts.end());
224
225 DB::String new_name;
226 for (const auto & part : stripped)
227 {
228 if (!new_name.empty())
229 new_name += '.';
230 new_name += part;
231 }
232 identifier.name.swap(new_name);
233}
234
235void IdentifierSemantic::setColumnLongName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table)
236{
237 String prefix = db_and_table.getQualifiedNamePrefix();
238 if (!prefix.empty())
239 {
240 String short_name = identifier.shortName();
241 identifier.name = prefix + short_name;
242 prefix.resize(prefix.size() - 1); /// crop dot
243 identifier.name_parts = {prefix, short_name};
244 }
245}
246
247}
248