ClickHouse/src/Interpreters/ArrayJoinedColumnsVisitor.h

135 lines
5.0 KiB
C++
Raw Normal View History

#pragma once
2018-11-02 18:53:23 +00:00
#include <Core/Names.h>
#include <Common/typeid_cast.h>
#include <Parsers/ASTSubquery.h>
#include <Parsers/ASTSelectQuery.h>
2018-11-02 18:53:23 +00:00
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <DataTypes/NestedUtils.h>
#include <Interpreters/InDepthNodeVisitor.h>
#include <Interpreters/IdentifierSemantic.h>
2019-01-25 11:43:19 +00:00
#include <Interpreters/Aliases.h>
2018-11-02 18:53:23 +00:00
namespace DB
{
2019-01-22 17:36:08 +00:00
namespace ErrorCodes
{
extern const int ALIAS_REQUIRED;
extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS;
extern const int LOGICAL_ERROR;
}
/// Fills the array_join_result_to_source: on which columns-arrays to replicate, and how to call them after that.
class ArrayJoinedColumnsMatcher
{
public:
2019-02-22 13:33:56 +00:00
using Visitor = InDepthNodeVisitor<ArrayJoinedColumnsMatcher, true>;
struct Data
{
2019-01-22 17:36:08 +00:00
const Aliases & aliases;
NameToNameMap & array_join_name_to_alias;
NameToNameMap & array_join_alias_to_name;
NameToNameMap & array_join_result_to_source;
};
static bool needChildVisit(ASTPtr & node, const ASTPtr & child)
{
2019-03-11 13:22:51 +00:00
if (node->as<ASTTablesInSelectQuery>())
return false;
2019-03-11 13:22:51 +00:00
if (child->as<ASTSubquery>() || child->as<ASTSelectQuery>())
return false;
return true;
}
2019-02-22 13:33:56 +00:00
static void visit(ASTPtr & ast, Data & data)
{
2019-03-11 13:22:51 +00:00
if (const auto * t = ast->as<ASTIdentifier>())
visit(*t, ast, data);
2019-03-11 13:22:51 +00:00
if (const auto * t = ast->as<ASTSelectQuery>())
2019-02-22 13:33:56 +00:00
visit(*t, ast, data);
}
private:
2019-02-22 13:33:56 +00:00
static void visit(const ASTSelectQuery & node, ASTPtr &, Data & data)
2019-01-22 17:36:08 +00:00
{
ASTPtr array_join_expression_list = node.arrayJoinExpressionList();
2019-01-22 17:36:08 +00:00
if (!array_join_expression_list)
throw Exception("Logical error: no ARRAY JOIN", ErrorCodes::LOGICAL_ERROR);
std::vector<ASTPtr *> out;
out.reserve(array_join_expression_list->children.size());
for (ASTPtr & ast : array_join_expression_list->children)
{
const String nested_table_name = ast->getColumnName();
const String nested_table_alias = ast->getAliasOrColumnName();
2019-03-11 13:22:51 +00:00
if (nested_table_alias == nested_table_name && !ast->as<ASTIdentifier>())
2019-01-22 17:36:08 +00:00
throw Exception("No alias for non-trivial value in ARRAY JOIN: " + nested_table_name, ErrorCodes::ALIAS_REQUIRED);
if (data.array_join_alias_to_name.count(nested_table_alias) || data.aliases.count(nested_table_alias))
throw Exception("Duplicate alias in ARRAY JOIN: " + nested_table_alias, ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS);
data.array_join_alias_to_name[nested_table_alias] = nested_table_name;
data.array_join_name_to_alias[nested_table_name] = nested_table_alias;
2019-01-22 18:02:53 +00:00
for (ASTPtr & child2 : ast->children)
out.emplace_back(&child2);
2019-01-22 17:36:08 +00:00
}
2019-02-22 13:33:56 +00:00
for (ASTPtr * add_node : out)
Visitor(data).visit(*add_node);
2019-01-22 17:36:08 +00:00
}
static void visit(const ASTIdentifier & node, ASTPtr &, Data & data)
{
NameToNameMap & array_join_name_to_alias = data.array_join_name_to_alias;
NameToNameMap & array_join_alias_to_name = data.array_join_alias_to_name;
NameToNameMap & array_join_result_to_source = data.array_join_result_to_source;
if (!IdentifierSemantic::getColumnName(node))
return;
auto split = Nested::splitName(node.name()); /// ParsedParams, Key1
if (array_join_alias_to_name.count(node.name()))
{
/// ARRAY JOIN was written with an array column. Example: SELECT K1 FROM ... ARRAY JOIN ParsedParams.Key1 AS K1
array_join_result_to_source[node.name()] = array_join_alias_to_name[node.name()]; /// K1 -> ParsedParams.Key1
}
2020-08-08 01:01:47 +00:00
else if (array_join_alias_to_name.count(split.first) && !split.second.empty())
{
/// ARRAY JOIN was written with a nested table. Example: SELECT PP.KEY1 FROM ... ARRAY JOIN ParsedParams AS PP
array_join_result_to_source[node.name()] /// PP.Key1 -> ParsedParams.Key1
2020-08-08 01:01:47 +00:00
= Nested::concatenateName(array_join_alias_to_name[split.first], split.second);
}
else if (array_join_name_to_alias.count(node.name()))
{
/** Example: SELECT ParsedParams.Key1 FROM ... ARRAY JOIN ParsedParams.Key1 AS PP.Key1.
* That is, the query uses the original array, replicated by itself.
*/
array_join_result_to_source[ /// PP.Key1 -> ParsedParams.Key1
array_join_name_to_alias[node.name()]] = node.name();
}
2020-08-08 01:01:47 +00:00
else if (array_join_name_to_alias.count(split.first) && !split.second.empty())
{
/** Example: SELECT ParsedParams.Key1 FROM ... ARRAY JOIN ParsedParams AS PP.
*/
array_join_result_to_source[ /// PP.Key1 -> ParsedParams.Key1
Nested::concatenateName(array_join_name_to_alias[split.first], split.second)] = node.name();
}
}
};
2019-02-22 13:33:56 +00:00
using ArrayJoinedColumnsVisitor = ArrayJoinedColumnsMatcher::Visitor;
}