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