1 | #include <Poco/String.h> |
2 | #include <Core/Names.h> |
3 | #include <Interpreters/QueryNormalizer.h> |
4 | #include <Interpreters/IdentifierSemantic.h> |
5 | #include <Interpreters/Context.h> |
6 | #include <Parsers/ASTFunction.h> |
7 | #include <Parsers/ASTIdentifier.h> |
8 | #include <Parsers/ASTSelectQuery.h> |
9 | #include <Parsers/ASTQueryParameter.h> |
10 | #include <Parsers/ASTTablesInSelectQuery.h> |
11 | #include <Common/StringUtils/StringUtils.h> |
12 | #include <Common/quoteString.h> |
13 | |
14 | namespace DB |
15 | { |
16 | |
17 | namespace ErrorCodes |
18 | { |
19 | extern const int TOO_DEEP_AST; |
20 | extern const int CYCLIC_ALIASES; |
21 | extern const int UNKNOWN_QUERY_PARAMETER; |
22 | } |
23 | |
24 | |
25 | class CheckASTDepth |
26 | { |
27 | public: |
28 | CheckASTDepth(QueryNormalizer::Data & data_) |
29 | : data(data_) |
30 | { |
31 | if (data.level > data.settings.max_ast_depth) |
32 | throw Exception("Normalized AST is too deep. Maximum: " + toString(data.settings.max_ast_depth), ErrorCodes::TOO_DEEP_AST); |
33 | ++data.level; |
34 | } |
35 | |
36 | ~CheckASTDepth() |
37 | { |
38 | --data.level; |
39 | } |
40 | |
41 | private: |
42 | QueryNormalizer::Data & data; |
43 | }; |
44 | |
45 | |
46 | class RestoreAliasOnExitScope |
47 | { |
48 | public: |
49 | RestoreAliasOnExitScope(String & alias_) |
50 | : alias(alias_) |
51 | , copy(alias_) |
52 | {} |
53 | |
54 | ~RestoreAliasOnExitScope() |
55 | { |
56 | alias = copy; |
57 | } |
58 | |
59 | private: |
60 | String & alias; |
61 | const String copy; |
62 | }; |
63 | |
64 | |
65 | void QueryNormalizer::visit(ASTIdentifier & node, ASTPtr & ast, Data & data) |
66 | { |
67 | auto & current_asts = data.current_asts; |
68 | String & current_alias = data.current_alias; |
69 | |
70 | if (!IdentifierSemantic::getColumnName(node)) |
71 | return; |
72 | |
73 | /// If it is an alias, but not a parent alias (for constructs like "SELECT column + 1 AS column"). |
74 | auto it_alias = data.aliases.find(node.name); |
75 | if (it_alias != data.aliases.end() && current_alias != node.name) |
76 | { |
77 | if (!IdentifierSemantic::canBeAlias(node)) |
78 | { |
79 | /// This means that column had qualified name, which was translated (so, canBeAlias() returns false). |
80 | /// But there is an alias with the same name. So, let's use original name for that column. |
81 | /// If alias wasn't set, use original column name as alias. |
82 | /// That helps to avoid result set with columns which have same names but different values. |
83 | if (node.alias.empty()) |
84 | { |
85 | node.name.swap(node.alias); |
86 | node.restoreCompoundName(); |
87 | node.name.swap(node.alias); |
88 | } |
89 | |
90 | return; |
91 | } |
92 | |
93 | auto & alias_node = it_alias->second; |
94 | |
95 | /// Let's replace it with the corresponding tree node. |
96 | if (current_asts.count(alias_node.get())) |
97 | throw Exception("Cyclic aliases" , ErrorCodes::CYCLIC_ALIASES); |
98 | |
99 | String my_alias = ast->tryGetAlias(); |
100 | if (!my_alias.empty() && my_alias != alias_node->getAliasOrColumnName()) |
101 | { |
102 | /// Avoid infinite recursion here |
103 | auto opt_name = IdentifierSemantic::getColumnName(alias_node); |
104 | bool is_cycle = opt_name && *opt_name == node.name; |
105 | |
106 | if (!is_cycle) |
107 | { |
108 | /// In a construct like "a AS b", where a is an alias, you must set alias b to the result of substituting alias a. |
109 | ast = alias_node->clone(); |
110 | ast->setAlias(my_alias); |
111 | } |
112 | } |
113 | else |
114 | ast = alias_node; |
115 | } |
116 | } |
117 | |
118 | void QueryNormalizer::visit(ASTTablesInSelectQueryElement & node, const ASTPtr &, Data & data) |
119 | { |
120 | /// normalize JOIN ON section |
121 | if (node.table_join) |
122 | { |
123 | auto & join = node.table_join->as<ASTTableJoin &>(); |
124 | if (join.on_expression) |
125 | visit(join.on_expression, data); |
126 | } |
127 | } |
128 | |
129 | static bool needVisitChild(const ASTPtr & child) |
130 | { |
131 | if (child->as<ASTSelectQuery>() || child->as<ASTTableExpression>()) |
132 | return false; |
133 | return true; |
134 | } |
135 | |
136 | /// special visitChildren() for ASTSelectQuery |
137 | void QueryNormalizer::visit(ASTSelectQuery & select, const ASTPtr &, Data & data) |
138 | { |
139 | for (auto & child : select.children) |
140 | if (needVisitChild(child)) |
141 | visit(child, data); |
142 | |
143 | /// If the WHERE clause or HAVING consists of a single alias, the reference must be replaced not only in children, |
144 | /// but also in where_expression and having_expression. |
145 | if (select.prewhere()) |
146 | visit(select.refPrewhere(), data); |
147 | if (select.where()) |
148 | visit(select.refWhere(), data); |
149 | if (select.having()) |
150 | visit(select.refHaving(), data); |
151 | } |
152 | |
153 | /// Don't go into subqueries. |
154 | /// Don't go into select query. It processes children itself. |
155 | /// Do not go to the left argument of lambda expressions, so as not to replace the formal parameters |
156 | /// on aliases in expressions of the form 123 AS x, arrayMap(x -> 1, [2]). |
157 | void QueryNormalizer::visitChildren(const ASTPtr & node, Data & data) |
158 | { |
159 | if (const auto * func_node = node->as<ASTFunction>()) |
160 | { |
161 | /// We skip the first argument. We also assume that the lambda function can not have parameters. |
162 | size_t first_pos = 0; |
163 | if (func_node->name == "lambda" ) |
164 | first_pos = 1; |
165 | |
166 | auto & func_children = func_node->arguments->children; |
167 | |
168 | for (size_t i = first_pos; i < func_children.size(); ++i) |
169 | { |
170 | auto & child = func_children[i]; |
171 | |
172 | if (needVisitChild(child)) |
173 | visit(child, data); |
174 | } |
175 | } |
176 | else if (!node->as<ASTSelectQuery>()) |
177 | { |
178 | for (auto & child : node->children) |
179 | if (needVisitChild(child)) |
180 | visit(child, data); |
181 | } |
182 | } |
183 | |
184 | void QueryNormalizer::visit(ASTPtr & ast, Data & data) |
185 | { |
186 | CheckASTDepth scope1(data); |
187 | RestoreAliasOnExitScope scope2(data.current_alias); |
188 | |
189 | auto & finished_asts = data.finished_asts; |
190 | auto & current_asts = data.current_asts; |
191 | |
192 | if (finished_asts.count(ast)) |
193 | { |
194 | ast = finished_asts[ast]; |
195 | return; |
196 | } |
197 | |
198 | ASTPtr initial_ast = ast; |
199 | current_asts.insert(initial_ast.get()); |
200 | |
201 | { |
202 | String my_alias = ast->tryGetAlias(); |
203 | if (!my_alias.empty()) |
204 | data.current_alias = my_alias; |
205 | } |
206 | |
207 | if (auto * node_id = ast->as<ASTIdentifier>()) |
208 | visit(*node_id, ast, data); |
209 | else if (auto * node_tables = ast->as<ASTTablesInSelectQueryElement>()) |
210 | visit(*node_tables, ast, data); |
211 | else if (auto * node_select = ast->as<ASTSelectQuery>()) |
212 | visit(*node_select, ast, data); |
213 | else if (auto * node_param = ast->as<ASTQueryParameter>()) |
214 | throw Exception("Query parameter " + backQuote(node_param->name) + " was not set" , ErrorCodes::UNKNOWN_QUERY_PARAMETER); |
215 | |
216 | /// If we replace the root of the subtree, we will be called again for the new root, in case the alias is replaced by an alias. |
217 | if (ast.get() != initial_ast.get()) |
218 | visit(ast, data); |
219 | else |
220 | visitChildren(ast, data); |
221 | |
222 | current_asts.erase(initial_ast.get()); |
223 | current_asts.erase(ast.get()); |
224 | finished_asts[initial_ast] = ast; |
225 | |
226 | /// @note can not place it in CheckASTDepth dtor cause of exception. |
227 | if (data.level == 1) |
228 | { |
229 | try |
230 | { |
231 | ast->checkSize(data.settings.max_expanded_ast_elements); |
232 | } |
233 | catch (Exception & e) |
234 | { |
235 | e.addMessage("(after expansion of aliases)" ); |
236 | throw; |
237 | } |
238 | } |
239 | } |
240 | |
241 | } |
242 | |