1 | #include <ostream> |
2 | #include <sstream> |
3 | |
4 | #include <Common/typeid_cast.h> |
5 | #include <Interpreters/QueryAliasesVisitor.h> |
6 | #include <Parsers/ASTTablesInSelectQuery.h> |
7 | #include <Parsers/ASTSelectWithUnionQuery.h> |
8 | #include <Parsers/ASTSelectQuery.h> |
9 | #include <Parsers/formatAST.h> |
10 | #include <Parsers/ASTSubquery.h> |
11 | #include <Common/quoteString.h> |
12 | |
13 | namespace DB |
14 | { |
15 | |
16 | namespace ErrorCodes |
17 | { |
18 | extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; |
19 | } |
20 | |
21 | static String wrongAliasMessage(const ASTPtr & ast, const ASTPtr & prev_ast, const String & alias) |
22 | { |
23 | std::stringstream message; |
24 | message << "Different expressions with the same alias " << backQuoteIfNeed(alias) << ":" << std::endl; |
25 | formatAST(*ast, message, false, true); |
26 | message << std::endl << "and" << std::endl; |
27 | formatAST(*prev_ast, message, false, true); |
28 | message << std::endl; |
29 | return message.str(); |
30 | } |
31 | |
32 | |
33 | bool QueryAliasesMatcher::needChildVisit(ASTPtr & node, const ASTPtr &) |
34 | { |
35 | /// Don't descent into table functions and subqueries and special case for ArrayJoin. |
36 | if (node->as<ASTTableExpression>() || node->as<ASTSelectWithUnionQuery>() || node->as<ASTArrayJoin>()) |
37 | return false; |
38 | return true; |
39 | } |
40 | |
41 | void QueryAliasesMatcher::visit(ASTPtr & ast, Data & data) |
42 | { |
43 | if (auto * s = ast->as<ASTSubquery>()) |
44 | visit(*s, ast, data); |
45 | else if (auto * q = ast->as<ASTSelectQuery>()) |
46 | visit(*q, ast, data); |
47 | else if (auto * aj = ast->as<ASTArrayJoin>()) |
48 | visit(*aj, ast, data); |
49 | else |
50 | visitOther(ast, data); |
51 | } |
52 | |
53 | void QueryAliasesMatcher::visit(const ASTSelectQuery & select, const ASTPtr &, Data &) |
54 | { |
55 | ASTPtr with = select.with(); |
56 | if (!with) |
57 | return; |
58 | |
59 | for (auto & child : with->children) |
60 | if (auto * ast_with_alias = dynamic_cast<ASTWithAlias *>(child.get())) |
61 | ast_with_alias->prefer_alias_to_column_name = true; |
62 | } |
63 | |
64 | /// The top-level aliases in the ARRAY JOIN section have a special meaning, we will not add them |
65 | /// (skip the expression list itself and its children). |
66 | void QueryAliasesMatcher::visit(const ASTArrayJoin &, const ASTPtr & ast, Data & data) |
67 | { |
68 | visitOther(ast, data); |
69 | |
70 | std::vector<ASTPtr> grand_children; |
71 | for (auto & child1 : ast->children) |
72 | for (auto & child2 : child1->children) |
73 | for (auto & child3 : child2->children) |
74 | grand_children.push_back(child3); |
75 | |
76 | /// create own visitor to run bottom to top |
77 | for (auto & child : grand_children) |
78 | Visitor(data).visit(child); |
79 | } |
80 | |
81 | /// set unique aliases for all subqueries. this is needed, because: |
82 | /// 1) content of subqueries could change after recursive analysis, and auto-generated column names could become incorrect |
83 | /// 2) result of different scalar subqueries can be cached inside expressions compilation cache and must have different names |
84 | void QueryAliasesMatcher::visit(ASTSubquery & subquery, const ASTPtr & ast, Data & data) |
85 | { |
86 | Aliases & aliases = data.aliases; |
87 | |
88 | static std::atomic_uint64_t subquery_index = 0; |
89 | |
90 | if (subquery.alias.empty()) |
91 | { |
92 | String alias; |
93 | do |
94 | { |
95 | alias = "_subquery" + std::to_string(++subquery_index); |
96 | } |
97 | while (aliases.count(alias)); |
98 | |
99 | subquery.setAlias(alias); |
100 | aliases[alias] = ast; |
101 | } |
102 | else |
103 | visitOther(ast, data); |
104 | |
105 | subquery.prefer_alias_to_column_name = true; |
106 | } |
107 | |
108 | void QueryAliasesMatcher::visitOther(const ASTPtr & ast, Data & data) |
109 | { |
110 | Aliases & aliases = data.aliases; |
111 | |
112 | String alias = ast->tryGetAlias(); |
113 | if (!alias.empty()) |
114 | { |
115 | if (aliases.count(alias) && ast->getTreeHash() != aliases[alias]->getTreeHash()) |
116 | throw Exception(wrongAliasMessage(ast, aliases[alias], alias), ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS); |
117 | |
118 | aliases[alias] = ast; |
119 | } |
120 | } |
121 | |
122 | } |
123 | |