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
17namespace DB
18{
19
20namespace 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.
28class ArrayJoinedColumnsMatcher
29{
30public:
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
60private:
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
132using ArrayJoinedColumnsVisitor = ArrayJoinedColumnsMatcher::Visitor;
133
134}
135