1 | #pragma once |
2 | |
3 | #include <Core/Names.h> |
4 | #include <Common/typeid_cast.h> |
5 | |
6 | #include <Parsers/ASTSubquery.h> |
7 | #include <Parsers/ASTSelectQuery.h> |
8 | #include <Parsers/ASTTablesInSelectQuery.h> |
9 | #include <Parsers/ASTIdentifier.h> |
10 | |
11 | #include <DataTypes/NestedUtils.h> |
12 | #include <Interpreters/InDepthNodeVisitor.h> |
13 | #include <Interpreters/IdentifierSemantic.h> |
14 | #include <Interpreters/Aliases.h> |
15 | |
16 | |
17 | namespace DB |
18 | { |
19 | |
20 | namespace ErrorCodes |
21 | { |
22 | extern const int ALIAS_REQUIRED; |
23 | extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; |
24 | extern const int LOGICAL_ERROR; |
25 | } |
26 | |
27 | /// Fills the array_join_result_to_source: on which columns-arrays to replicate, and how to call them after that. |
28 | class ArrayJoinedColumnsMatcher |
29 | { |
30 | public: |
31 | using Visitor = InDepthNodeVisitor<ArrayJoinedColumnsMatcher, true>; |
32 | |
33 | struct Data |
34 | { |
35 | const Aliases & aliases; |
36 | NameToNameMap & array_join_name_to_alias; |
37 | NameToNameMap & array_join_alias_to_name; |
38 | NameToNameMap & array_join_result_to_source; |
39 | }; |
40 | |
41 | static bool needChildVisit(ASTPtr & node, const ASTPtr & child) |
42 | { |
43 | if (node->as<ASTTablesInSelectQuery>()) |
44 | return false; |
45 | |
46 | if (child->as<ASTSubquery>() || child->as<ASTSelectQuery>()) |
47 | return false; |
48 | |
49 | return true; |
50 | } |
51 | |
52 | static void visit(ASTPtr & ast, Data & data) |
53 | { |
54 | if (const auto * t = ast->as<ASTIdentifier>()) |
55 | visit(*t, ast, data); |
56 | if (const auto * t = ast->as<ASTSelectQuery>()) |
57 | visit(*t, ast, data); |
58 | } |
59 | |
60 | private: |
61 | static void visit(const ASTSelectQuery & node, ASTPtr &, Data & data) |
62 | { |
63 | ASTPtr array_join_expression_list = node.array_join_expression_list(); |
64 | if (!array_join_expression_list) |
65 | throw Exception("Logical error: no ARRAY JOIN" , ErrorCodes::LOGICAL_ERROR); |
66 | |
67 | std::vector<ASTPtr *> out; |
68 | out.reserve(array_join_expression_list->children.size()); |
69 | |
70 | for (ASTPtr & ast : array_join_expression_list->children) |
71 | { |
72 | const String nested_table_name = ast->getColumnName(); |
73 | const String nested_table_alias = ast->getAliasOrColumnName(); |
74 | |
75 | if (nested_table_alias == nested_table_name && !ast->as<ASTIdentifier>()) |
76 | throw Exception("No alias for non-trivial value in ARRAY JOIN: " + nested_table_name, ErrorCodes::ALIAS_REQUIRED); |
77 | |
78 | if (data.array_join_alias_to_name.count(nested_table_alias) || data.aliases.count(nested_table_alias)) |
79 | throw Exception("Duplicate alias in ARRAY JOIN: " + nested_table_alias, ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS); |
80 | |
81 | data.array_join_alias_to_name[nested_table_alias] = nested_table_name; |
82 | data.array_join_name_to_alias[nested_table_name] = nested_table_alias; |
83 | |
84 | for (ASTPtr & child2 : ast->children) |
85 | out.emplace_back(&child2); |
86 | } |
87 | |
88 | for (ASTPtr * add_node : out) |
89 | Visitor(data).visit(*add_node); |
90 | } |
91 | |
92 | static void visit(const ASTIdentifier & node, ASTPtr &, Data & data) |
93 | { |
94 | NameToNameMap & array_join_name_to_alias = data.array_join_name_to_alias; |
95 | NameToNameMap & array_join_alias_to_name = data.array_join_alias_to_name; |
96 | NameToNameMap & array_join_result_to_source = data.array_join_result_to_source; |
97 | |
98 | if (!IdentifierSemantic::getColumnName(node)) |
99 | return; |
100 | |
101 | auto splitted = Nested::splitName(node.name); /// ParsedParams, Key1 |
102 | |
103 | if (array_join_alias_to_name.count(node.name)) |
104 | { |
105 | /// ARRAY JOIN was written with an array column. Example: SELECT K1 FROM ... ARRAY JOIN ParsedParams.Key1 AS K1 |
106 | array_join_result_to_source[node.name] = array_join_alias_to_name[node.name]; /// K1 -> ParsedParams.Key1 |
107 | } |
108 | else if (array_join_alias_to_name.count(splitted.first) && !splitted.second.empty()) |
109 | { |
110 | /// ARRAY JOIN was written with a nested table. Example: SELECT PP.KEY1 FROM ... ARRAY JOIN ParsedParams AS PP |
111 | array_join_result_to_source[node.name] /// PP.Key1 -> ParsedParams.Key1 |
112 | = Nested::concatenateName(array_join_alias_to_name[splitted.first], splitted.second); |
113 | } |
114 | else if (array_join_name_to_alias.count(node.name)) |
115 | { |
116 | /** Example: SELECT ParsedParams.Key1 FROM ... ARRAY JOIN ParsedParams.Key1 AS PP.Key1. |
117 | * That is, the query uses the original array, replicated by itself. |
118 | */ |
119 | array_join_result_to_source[ /// PP.Key1 -> ParsedParams.Key1 |
120 | array_join_name_to_alias[node.name]] = node.name; |
121 | } |
122 | else if (array_join_name_to_alias.count(splitted.first) && !splitted.second.empty()) |
123 | { |
124 | /** Example: SELECT ParsedParams.Key1 FROM ... ARRAY JOIN ParsedParams AS PP. |
125 | */ |
126 | array_join_result_to_source[ /// PP.Key1 -> ParsedParams.Key1 |
127 | Nested::concatenateName(array_join_name_to_alias[splitted.first], splitted.second)] = node.name; |
128 | } |
129 | } |
130 | }; |
131 | |
132 | using ArrayJoinedColumnsVisitor = ArrayJoinedColumnsMatcher::Visitor; |
133 | |
134 | } |
135 | |