| 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 | |