2018-12-17 16:20:15 +00:00
|
|
|
#include <Interpreters/JoinToSubqueryTransformVisitor.h>
|
2018-12-17 19:30:08 +00:00
|
|
|
#include <Interpreters/SemanticSelectQuery.h>
|
2018-12-17 16:20:15 +00:00
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTExpressionList.h>
|
|
|
|
#include <Parsers/ParserTablesInSelectQuery.h>
|
|
|
|
#include <Parsers/ExpressionListParsers.h>
|
|
|
|
#include <Parsers/parseQuery.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int LOGICAL_ERROR;
|
|
|
|
extern const int TOO_DEEP_AST;
|
|
|
|
}
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
/// Attach additional semantic info to generated select.
|
|
|
|
struct AppendSemanticVisitorData
|
2018-12-17 16:20:15 +00:00
|
|
|
{
|
|
|
|
using TypeToVisit = ASTSelectQuery;
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
const SemanticPtr & semantic;
|
2018-12-17 16:20:15 +00:00
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
void visit(ASTSelectQuery & select, ASTPtr &)
|
|
|
|
{
|
2018-12-17 19:30:08 +00:00
|
|
|
if (done || !semantic)
|
2018-12-17 16:20:15 +00:00
|
|
|
return;
|
2018-12-17 19:30:08 +00:00
|
|
|
select.semantic = semantic->clone();
|
2018-12-17 16:20:15 +00:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
/// Replaces one table element with pair.
|
2018-12-17 16:20:15 +00:00
|
|
|
struct RewriteTablesVisitorData
|
|
|
|
{
|
|
|
|
using TypeToVisit = ASTTablesInSelectQuery;
|
|
|
|
|
|
|
|
const ASTPtr & left;
|
|
|
|
const ASTPtr & right;
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
void visit(ASTTablesInSelectQuery &, ASTPtr & ast)
|
|
|
|
{
|
|
|
|
if (done)
|
|
|
|
return;
|
|
|
|
ast->children.clear();
|
|
|
|
ast->children.push_back(left);
|
|
|
|
ast->children.push_back(right);
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
static void appendTableNameAndAlias(std::vector<String> & hidden, const ASTPtr & table_element)
|
2018-12-17 16:20:15 +00:00
|
|
|
{
|
|
|
|
auto element = static_cast<const ASTTablesInSelectQueryElement *>(table_element.get());
|
|
|
|
if (!element || element->children.empty())
|
|
|
|
throw Exception("Expected TablesInSelectQueryElement with at least one child", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
auto table_expression = static_cast<const ASTTableExpression *>(element->children[0].get());
|
|
|
|
if (!table_expression || table_expression->children.empty())
|
|
|
|
throw Exception("Expected TableExpression with at least one child", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
String alias = table_expression->children[0]->tryGetAlias();
|
|
|
|
if (!alias.empty())
|
|
|
|
hidden.push_back(alias);
|
2018-12-17 16:20:15 +00:00
|
|
|
|
|
|
|
auto identifier = static_cast<const ASTIdentifier *>(table_expression->children[0].get());
|
2018-12-17 19:30:08 +00:00
|
|
|
if (!identifier && alias.empty())
|
2018-12-17 16:20:15 +00:00
|
|
|
throw Exception("Expected Identifier or subquery with alias", ErrorCodes::LOGICAL_ERROR);
|
2018-12-17 19:30:08 +00:00
|
|
|
hidden.push_back(identifier->name);
|
2018-12-17 16:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<ASTPtr *> JoinToSubqueryTransformMatcher::visit(ASTPtr & ast, Data & data)
|
|
|
|
{
|
|
|
|
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
|
|
|
|
visit(*t, ast, data);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
void JoinToSubqueryTransformMatcher::visit(ASTSelectQuery & select, ASTPtr & ast, Data & data)
|
|
|
|
{
|
|
|
|
static String alias_prefix = "__join"; /// FIXME
|
|
|
|
static const size_t max_joins = 64; /// TODO: settings.max_subquery_depth
|
|
|
|
|
|
|
|
auto tables = static_cast<const ASTTablesInSelectQuery *>(select.tables.get());
|
|
|
|
if (!tables)
|
|
|
|
throw Exception("TablesInSelectQuery expected", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
size_t num_tables = tables->children.size();
|
|
|
|
if (num_tables <= 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (num_tables > max_joins)
|
|
|
|
throw Exception("Too much joins", ErrorCodes::TOO_DEEP_AST);
|
|
|
|
|
|
|
|
ASTPtr left = tables->children[0];
|
|
|
|
|
|
|
|
for (size_t i = 1; i < num_tables - 1; ++i)
|
|
|
|
{
|
|
|
|
ASTPtr right = tables->children[i];
|
2018-12-17 19:30:08 +00:00
|
|
|
std::vector<String> hidden_names;
|
|
|
|
appendTableNameAndAlias(hidden_names, left);
|
|
|
|
appendTableNameAndAlias(hidden_names, right);
|
|
|
|
|
2018-12-17 16:20:15 +00:00
|
|
|
String subquery_name = alias_prefix + toString(i);
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
left = replaceJoin(select, left, right, subquery_name);
|
2018-12-17 16:20:15 +00:00
|
|
|
if (!left)
|
|
|
|
return;
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
SemanticSelectQuery::hideNames(select, hidden_names, subquery_name);
|
2018-12-17 16:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
select.tables = std::make_shared<ASTTablesInSelectQuery>();
|
|
|
|
select.tables->children.push_back(left);
|
|
|
|
select.tables->children.push_back(tables->children.back());
|
|
|
|
|
|
|
|
ast = ast->clone(); /// rewrite AST in right manner
|
|
|
|
data.done = true;
|
|
|
|
}
|
|
|
|
|
2018-12-17 19:30:08 +00:00
|
|
|
ASTPtr JoinToSubqueryTransformMatcher::replaceJoin(ASTSelectQuery & select, ASTPtr ast_left, ASTPtr ast_right, const String & subquery_alias)
|
2018-12-17 16:20:15 +00:00
|
|
|
{
|
|
|
|
using RewriteMatcher = LinkedMatcher<
|
|
|
|
OneTypeMatcher<RewriteTablesVisitorData>,
|
2018-12-17 19:30:08 +00:00
|
|
|
OneTypeMatcher<AppendSemanticVisitorData>>;
|
2018-12-17 16:20:15 +00:00
|
|
|
using RewriteVisitor = InDepthNodeVisitor<RewriteMatcher, true>;
|
|
|
|
|
|
|
|
auto left = static_cast<const ASTTablesInSelectQueryElement *>(ast_left.get());
|
|
|
|
auto right = static_cast<const ASTTablesInSelectQueryElement *>(ast_right.get());
|
|
|
|
if (!left || !right)
|
|
|
|
throw Exception("Two TablesInSelectQueryElements expected", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
if (!right->table_join || right->array_join)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto table_join = static_cast<const ASTTableJoin *>(right->table_join.get());
|
|
|
|
if (table_join->kind != ASTTableJoin::Kind::Inner)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
ParserTablesInSelectQueryElement parser(true);
|
|
|
|
String subquery = "(select * from _t) as " + subquery_alias;
|
|
|
|
ASTPtr res = parseQuery(parser, subquery, 0);
|
|
|
|
if (!res)
|
|
|
|
throw Exception("Cannot parse rewrite query", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
RewriteVisitor::Data visitor_data =
|
2018-12-17 19:30:08 +00:00
|
|
|
std::make_pair<RewriteTablesVisitorData, AppendSemanticVisitorData>({ast_left, ast_right}, {select.semantic});
|
2018-12-17 16:20:15 +00:00
|
|
|
RewriteVisitor(visitor_data).visit(res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|