mirror of https://github.com/ByConity/ByConity
simplify InDepthNodeVisitor
This commit is contained in:
parent
89f4cab025
commit
9e2aa47478
|
@ -28,6 +28,8 @@ namespace ErrorCodes
|
|||
class ArrayJoinedColumnsMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<ArrayJoinedColumnsMatcher, true>;
|
||||
|
||||
struct Data
|
||||
{
|
||||
const Aliases & aliases;
|
||||
|
@ -36,8 +38,6 @@ public:
|
|||
NameToNameMap & array_join_result_to_source;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "ArrayJoinedColumns";
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr & child)
|
||||
{
|
||||
if (typeid_cast<ASTTablesInSelectQuery *>(node.get()))
|
||||
|
@ -50,17 +50,16 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
return {};
|
||||
visit(*t, ast, data);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<ASTPtr *> visit(const ASTSelectQuery & node, ASTPtr &, Data & data)
|
||||
static void visit(const ASTSelectQuery & node, ASTPtr &, Data & data)
|
||||
{
|
||||
ASTPtr array_join_expression_list = node.array_join_expression_list();
|
||||
if (!array_join_expression_list)
|
||||
|
@ -87,7 +86,8 @@ private:
|
|||
out.emplace_back(&child2);
|
||||
}
|
||||
|
||||
return out;
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
static void visit(const ASTIdentifier & node, ASTPtr &, Data & data)
|
||||
|
@ -130,6 +130,6 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
using ArrayJoinedColumnsVisitor = InDepthNodeVisitor<ArrayJoinedColumnsMatcher, true>;
|
||||
using ArrayJoinedColumnsVisitor = ArrayJoinedColumnsMatcher::Visitor;
|
||||
|
||||
}
|
||||
|
|
|
@ -181,11 +181,10 @@ static ASTPtr getCrossJoin(ASTSelectQuery & select, std::vector<DatabaseAndTable
|
|||
}
|
||||
|
||||
|
||||
std::vector<ASTPtr *> CrossToInnerJoinMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void CrossToInnerJoinMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
}
|
||||
|
||||
void CrossToInnerJoinMatcher::visit(ASTSelectQuery & select, ASTPtr & ast, Data & data)
|
||||
|
|
|
@ -16,10 +16,8 @@ public:
|
|||
bool done = false;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "JoinToSubqueryTransform";
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; }
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
|
||||
private:
|
||||
static void visit(ASTSelectQuery & select, ASTPtr & ast, Data & data);
|
||||
|
|
|
@ -60,13 +60,12 @@ bool ExecuteScalarSubqueriesMatcher::needChildVisit(ASTPtr & node, const ASTPtr
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> ExecuteScalarSubqueriesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void ExecuteScalarSubqueriesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTSubquery *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTFunction *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
return {};
|
||||
visit(*t, ast, data);
|
||||
}
|
||||
|
||||
void ExecuteScalarSubqueriesMatcher::visit(const ASTSubquery & subquery, ASTPtr & ast, Data & data)
|
||||
|
@ -134,7 +133,7 @@ void ExecuteScalarSubqueriesMatcher::visit(const ASTSubquery & subquery, ASTPtr
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> ExecuteScalarSubqueriesMatcher::visit(const ASTFunction & func, ASTPtr & ast, Data &)
|
||||
void ExecuteScalarSubqueriesMatcher::visit(const ASTFunction & func, ASTPtr & ast, Data & data)
|
||||
{
|
||||
/// Don't descend into subqueries in arguments of IN operator.
|
||||
/// But if an argument is not subquery, than deeper may be scalar subqueries and we need to descend in them.
|
||||
|
@ -156,7 +155,8 @@ std::vector<ASTPtr *> ExecuteScalarSubqueriesMatcher::visit(const ASTFunction &
|
|||
for (auto & child : ast->children)
|
||||
out.push_back(&child);
|
||||
|
||||
return out;
|
||||
for (ASTPtr * add_node : out)
|
||||
ExecuteScalarSubqueriesVisitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,14 +36,12 @@ public:
|
|||
size_t subquery_depth;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "ExecuteScalarSubqueries";
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr &);
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
|
||||
private:
|
||||
static void visit(const ASTSubquery & subquery, ASTPtr & ast, Data & data);
|
||||
static std::vector<ASTPtr *> visit(const ASTFunction & func, ASTPtr & ast, Data & data);
|
||||
static void visit(const ASTFunction & func, ASTPtr & ast, Data & data);
|
||||
};
|
||||
|
||||
using ExecuteScalarSubqueriesVisitor = InDepthNodeVisitor<ExecuteScalarSubqueriesMatcher, true>;
|
||||
|
|
|
@ -20,24 +20,20 @@ public:
|
|||
Tables & external_tables;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "ExternalTables";
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
return {};
|
||||
visit(*t, ast, data);
|
||||
}
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; }
|
||||
|
||||
private:
|
||||
static std::vector<ASTPtr *> visit(const ASTIdentifier & node, ASTPtr &, Data & data)
|
||||
static void visit(const ASTIdentifier & node, ASTPtr &, Data & data)
|
||||
{
|
||||
if (auto opt_name = IdentifierSemantic::getTableName(node))
|
||||
if (StoragePtr external_storage = data.context.tryGetExternalTable(*opt_name))
|
||||
data.external_tables[*opt_name] = external_storage;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -138,15 +138,12 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static constexpr const char * label = "GlobalSubqueries";
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTFunction *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTTablesInSelectQueryElement *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr & child)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Parsers/DumpASTNode.h>
|
||||
|
@ -8,7 +9,7 @@ namespace DB
|
|||
{
|
||||
|
||||
/// Visits AST tree in depth, call functions for nodes according to Matcher type data.
|
||||
/// You need to define Data, label, visit() and needChildVisit() in Matcher class.
|
||||
/// You need to define Data, visit() and needChildVisit() in Matcher class.
|
||||
template <typename Matcher, bool _top_to_bottom>
|
||||
class InDepthNodeVisitor
|
||||
{
|
||||
|
@ -23,17 +24,12 @@ public:
|
|||
|
||||
void visit(ASTPtr & ast)
|
||||
{
|
||||
DumpASTNode dump(*ast, ostr, visit_depth, Matcher::label);
|
||||
DumpASTNode dump(*ast, ostr, visit_depth, typeid(Matcher).name());
|
||||
|
||||
if constexpr (!_top_to_bottom)
|
||||
visitChildren(ast);
|
||||
|
||||
/// It operates with ASTPtr * cause we may want to rewrite ASTPtr in visit().
|
||||
std::vector<ASTPtr *> additional_nodes = Matcher::visit(ast, data);
|
||||
|
||||
/// visit additional nodes (ex. only part of children)
|
||||
for (ASTPtr * node : additional_nodes)
|
||||
visit(*node);
|
||||
Matcher::visit(ast, data);
|
||||
|
||||
if constexpr (_top_to_bottom)
|
||||
visitChildren(ast);
|
||||
|
@ -60,15 +56,12 @@ public:
|
|||
using Data = _Data;
|
||||
using TypeToVisit = typename Data::TypeToVisit;
|
||||
|
||||
static constexpr const char * label = "";
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return _visit_children; }
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<TypeToVisit *>(ast.get()))
|
||||
data.visit(*t, ast);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -79,15 +72,12 @@ class LinkedMatcher
|
|||
public:
|
||||
using Data = std::pair<typename First::Data, typename Second::Data>;
|
||||
|
||||
static constexpr const char * label = "";
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; }
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
First::visit(ast, data.first);
|
||||
Second::visit(ast, data.second);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -79,8 +79,6 @@ struct ColumnAliasesMatcher
|
|||
}
|
||||
};
|
||||
|
||||
static constexpr const char * label = "ColumnAliases";
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr &)
|
||||
{
|
||||
if (typeid_cast<const ASTQualifiedAsterisk *>(node.get()))
|
||||
|
@ -88,7 +86,7 @@ struct ColumnAliasesMatcher
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
|
||||
static void visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
|
||||
visit(*t, ast, data);
|
||||
|
@ -96,7 +94,6 @@ struct ColumnAliasesMatcher
|
|||
if (typeid_cast<ASTAsterisk *>(ast.get()) ||
|
||||
typeid_cast<ASTQualifiedAsterisk *>(ast.get()))
|
||||
throw Exception("Multiple JOIN do not support asterisks yet", ErrorCodes::NOT_IMPLEMENTED);
|
||||
return {};
|
||||
}
|
||||
|
||||
static void visit(ASTIdentifier & node, ASTPtr &, Data & data)
|
||||
|
@ -225,11 +222,10 @@ using AppendSemanticVisitor = InDepthNodeVisitor<AppendSemanticMatcher, true>;
|
|||
} /// namelesspace
|
||||
|
||||
|
||||
std::vector<ASTPtr *> JoinToSubqueryTransformMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void 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 &, Data & data)
|
||||
|
|
|
@ -18,10 +18,8 @@ public:
|
|||
bool done = false;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "JoinToSubqueryTransform";
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; }
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
|
||||
private:
|
||||
/// - combines two source TablesInSelectQueryElement into resulting one (Subquery)
|
||||
|
|
|
@ -33,26 +33,25 @@ bool QueryAliasesMatcher::needChildVisit(ASTPtr & node, const ASTPtr &)
|
|||
{
|
||||
/// Don't descent into table functions and subqueries and special case for ArrayJoin.
|
||||
if (typeid_cast<ASTTableExpression *>(node.get()) ||
|
||||
typeid_cast<ASTSelectWithUnionQuery *>(node.get()) ||
|
||||
typeid_cast<ASTSubquery *>(node.get()) ||
|
||||
typeid_cast<ASTArrayJoin *>(node.get()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> QueryAliasesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void QueryAliasesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTSubquery *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTArrayJoin *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
|
||||
visitOther(ast, data);
|
||||
return {};
|
||||
if (auto * s = typeid_cast<ASTSubquery *>(ast.get()))
|
||||
visit(*s, ast, data);
|
||||
else if (auto * aj = typeid_cast<ASTArrayJoin *>(ast.get()))
|
||||
visit(*aj, ast, data);
|
||||
else
|
||||
visitOther(ast, data);
|
||||
}
|
||||
|
||||
/// The top-level aliases in the ARRAY JOIN section have a special meaning, we will not add them
|
||||
/// (skip the expression list itself and its children).
|
||||
std::vector<ASTPtr *> QueryAliasesMatcher::visit(const ASTArrayJoin &, const ASTPtr & ast, Data & data)
|
||||
void QueryAliasesMatcher::visit(const ASTArrayJoin &, const ASTPtr & ast, Data & data)
|
||||
{
|
||||
visitOther(ast, data);
|
||||
|
||||
|
@ -64,15 +63,17 @@ std::vector<ASTPtr *> QueryAliasesMatcher::visit(const ASTArrayJoin &, const AST
|
|||
|
||||
/// create own visitor to run bottom to top
|
||||
for (auto & child : grand_children)
|
||||
QueryAliasesVisitor(data).visit(child);
|
||||
return {};
|
||||
Visitor(data).visit(child);
|
||||
}
|
||||
|
||||
/// set unique aliases for all subqueries. this is needed, because:
|
||||
/// 1) content of subqueries could change after recursive analysis, and auto-generated column names could become incorrect
|
||||
/// 2) result of different scalar subqueries can be cached inside expressions compilation cache and must have different names
|
||||
std::vector<ASTPtr *> QueryAliasesMatcher::visit(ASTSubquery & subquery, const ASTPtr & ast, Data & data)
|
||||
void QueryAliasesMatcher::visit(ASTSubquery & subquery, const ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (!data.subqueries)
|
||||
return;
|
||||
|
||||
Aliases & aliases = data.aliases;
|
||||
|
||||
static std::atomic_uint64_t subquery_index = 0;
|
||||
|
@ -92,7 +93,6 @@ std::vector<ASTPtr *> QueryAliasesMatcher::visit(ASTSubquery & subquery, const A
|
|||
}
|
||||
else
|
||||
visitOther(ast, data);
|
||||
return {};
|
||||
}
|
||||
|
||||
void QueryAliasesMatcher::visitOther(const ASTPtr & ast, Data & data)
|
||||
|
|
|
@ -15,23 +15,24 @@ struct ASTArrayJoin;
|
|||
class QueryAliasesMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<QueryAliasesMatcher, false>;
|
||||
|
||||
struct Data
|
||||
{
|
||||
Aliases & aliases;
|
||||
bool subqueries = true;
|
||||
};
|
||||
|
||||
static constexpr const char * label = "QueryAliases";
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr & child);
|
||||
|
||||
private:
|
||||
static std::vector<ASTPtr *> visit(ASTSubquery & subquery, const ASTPtr & ast, Data & data);
|
||||
static std::vector<ASTPtr *> visit(const ASTArrayJoin &, const ASTPtr & ast, Data & data);
|
||||
static void visit(ASTSubquery & subquery, const ASTPtr & ast, Data & data);
|
||||
static void visit(const ASTArrayJoin &, const ASTPtr & ast, Data & data);
|
||||
static void visitOther(const ASTPtr & ast, Data & data);
|
||||
};
|
||||
|
||||
/// Visits AST nodes and collect their aliases in one map (with links to source nodes).
|
||||
using QueryAliasesVisitor = InDepthNodeVisitor<QueryAliasesMatcher, false>;
|
||||
using QueryAliasesVisitor = QueryAliasesMatcher::Visitor;
|
||||
|
||||
}
|
||||
|
|
|
@ -62,20 +62,20 @@ bool RequiredSourceColumnsMatcher::needChildVisit(ASTPtr & node, const ASTPtr &
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void RequiredSourceColumnsMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
/// results are columns
|
||||
|
||||
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
|
||||
{
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
if (auto * t = typeid_cast<ASTFunction *>(ast.get()))
|
||||
{
|
||||
data.addColumnAliasIfAny(*ast);
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
/// results are tables
|
||||
|
@ -83,24 +83,25 @@ std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTPtr & ast, Data & d
|
|||
if (auto * t = typeid_cast<ASTTablesInSelectQueryElement *>(ast.get()))
|
||||
{
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto * t = typeid_cast<ASTTableExpression *>(ast.get()))
|
||||
{
|
||||
//data.addTableAliasIfAny(*ast); alias is attached to child
|
||||
visit(*t, ast, data);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
|
||||
{
|
||||
data.addTableAliasIfAny(*ast);
|
||||
return visit(*t, ast, data);
|
||||
visit(*t, ast, data);
|
||||
return;
|
||||
}
|
||||
if (typeid_cast<ASTSubquery *>(ast.get()))
|
||||
{
|
||||
data.addTableAliasIfAny(*ast);
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
/// other
|
||||
|
@ -108,13 +109,12 @@ std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTPtr & ast, Data & d
|
|||
if (auto * t = typeid_cast<ASTArrayJoin *>(ast.get()))
|
||||
{
|
||||
data.has_array_join = true;
|
||||
return visit(*t, ast, data);
|
||||
visit(*t, ast, data);
|
||||
return;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTSelectQuery & select, const ASTPtr &, Data & data)
|
||||
void RequiredSourceColumnsMatcher::visit(ASTSelectQuery & select, const ASTPtr &, Data & data)
|
||||
{
|
||||
/// special case for top-level SELECT items: they are publics
|
||||
for (auto & node : select.select_expression_list->children)
|
||||
|
@ -132,7 +132,9 @@ std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTSelectQuery & selec
|
|||
|
||||
/// revisit select_expression_list (with children) when all the aliases are set
|
||||
out.push_back(&select.select_expression_list);
|
||||
return out;
|
||||
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
void RequiredSourceColumnsMatcher::visit(const ASTIdentifier & node, const ASTPtr &, Data & data)
|
||||
|
@ -180,7 +182,7 @@ void RequiredSourceColumnsMatcher::visit(ASTTablesInSelectQueryElement & node, c
|
|||
data.tables.emplace_back(ColumnNamesContext::JoinedTable{expr, join});
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTTableExpression & node, const ASTPtr &, Data & data)
|
||||
void RequiredSourceColumnsMatcher::visit(ASTTableExpression & node, const ASTPtr &, Data & data)
|
||||
{
|
||||
/// ASTIdentifiers here are tables. Do not visit them as generic ones.
|
||||
if (node.database_and_table_name)
|
||||
|
@ -199,10 +201,11 @@ std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(ASTTableExpression & n
|
|||
out.push_back(&node.subquery);
|
||||
}
|
||||
|
||||
return out;
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(const ASTArrayJoin & node, const ASTPtr &, Data & data)
|
||||
void RequiredSourceColumnsMatcher::visit(const ASTArrayJoin & node, const ASTPtr &, Data & data)
|
||||
{
|
||||
ASTPtr expression_list = node.expression_list;
|
||||
if (!expression_list || expression_list->children.empty())
|
||||
|
@ -224,7 +227,8 @@ std::vector<ASTPtr *> RequiredSourceColumnsMatcher::visit(const ASTArrayJoin & n
|
|||
out.push_back(&expr);
|
||||
}
|
||||
|
||||
return out;
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,25 +21,24 @@ struct ASTTableExpression;
|
|||
class RequiredSourceColumnsMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<RequiredSourceColumnsMatcher, false>;
|
||||
using Data = ColumnNamesContext;
|
||||
|
||||
static constexpr const char * label = "RequiredSourceColumns";
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr & child);
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
|
||||
private:
|
||||
static void visit(const ASTIdentifier & node, const ASTPtr &, Data & data);
|
||||
static void visit(const ASTFunction & node, const ASTPtr &, Data & data);
|
||||
static void visit(ASTTablesInSelectQueryElement & node, const ASTPtr &, Data & data);
|
||||
static std::vector<ASTPtr *> visit(ASTTableExpression & node, const ASTPtr &, Data & data);
|
||||
static std::vector<ASTPtr *> visit(const ASTArrayJoin & node, const ASTPtr &, Data & data);
|
||||
static std::vector<ASTPtr *> visit(ASTSelectQuery & select, const ASTPtr &, Data & data);
|
||||
static void visit(ASTTableExpression & node, const ASTPtr &, Data & data);
|
||||
static void visit(const ASTArrayJoin & node, const ASTPtr &, Data & data);
|
||||
static void visit(ASTSelectQuery & select, const ASTPtr &, Data & data);
|
||||
};
|
||||
|
||||
/// Extracts all the information about columns and tables from ASTSelectQuery block into ColumnNamesContext object.
|
||||
/// It doesn't use anything but AST. It visits nodes from bottom to top except ASTFunction content to get aliases in right manner.
|
||||
/// @note There's some ambiguousness with nested columns names that can't be solved without schema.
|
||||
using RequiredSourceColumnsVisitor = InDepthNodeVisitor<RequiredSourceColumnsMatcher, false>;
|
||||
using RequiredSourceColumnsVisitor = RequiredSourceColumnsMatcher::Visitor;
|
||||
|
||||
}
|
||||
|
|
|
@ -44,22 +44,21 @@ bool TranslateQualifiedNamesMatcher::needChildVisit(ASTPtr & node, const ASTPtr
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
void TranslateQualifiedNamesMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTTableJoin *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
visit(*t, ast, data);
|
||||
if (auto * t = typeid_cast<ASTSelectQuery *>(ast.get()))
|
||||
return visit(*t, ast, data);
|
||||
visit(*t, ast, data);
|
||||
if (auto * node = typeid_cast<ASTExpressionList *>(ast.get()))
|
||||
visit(*node, ast, data);
|
||||
if (auto * node = typeid_cast<ASTFunction *>(ast.get()))
|
||||
visit(*node, ast, data);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTIdentifier & identifier, ASTPtr &, Data & data)
|
||||
void TranslateQualifiedNamesMatcher::visit(ASTIdentifier & identifier, ASTPtr &, Data & data)
|
||||
{
|
||||
if (IdentifierSemantic::getColumnName(identifier))
|
||||
{
|
||||
|
@ -82,8 +81,6 @@ std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTIdentifier & iden
|
|||
if (!data.tables.empty())
|
||||
IdentifierSemantic::setColumnNormalName(identifier, data.tables[best_table_pos].first);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/// As special case, treat count(*) as count(), not as count(list of all columns).
|
||||
|
@ -98,7 +95,7 @@ void TranslateQualifiedNamesMatcher::visit(ASTFunction & node, const ASTPtr &, D
|
|||
func_arguments->children.clear();
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(const ASTQualifiedAsterisk & , const ASTPtr & ast, Data & data)
|
||||
void TranslateQualifiedNamesMatcher::visit(const ASTQualifiedAsterisk & , const ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (ast->children.size() != 1)
|
||||
throw Exception("Logical error: qualified asterisk must have exactly one child", ErrorCodes::LOGICAL_ERROR);
|
||||
|
@ -110,22 +107,24 @@ std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(const ASTQualifiedAs
|
|||
|
||||
for (const auto & known_table : data.tables)
|
||||
if (db_and_table.satisfies(known_table.first, true))
|
||||
return {};
|
||||
return;
|
||||
|
||||
throw Exception("Unknown qualified identifier: " + ident->getAliasOrColumnName(), ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTTableJoin & join, const ASTPtr & , Data &)
|
||||
void TranslateQualifiedNamesMatcher::visit(ASTTableJoin & join, const ASTPtr & , Data & data)
|
||||
{
|
||||
std::vector<ASTPtr *> out;
|
||||
if (join.using_expression_list)
|
||||
out.push_back(&join.using_expression_list);
|
||||
else if (join.on_expression)
|
||||
out.push_back(&join.on_expression);
|
||||
return out;
|
||||
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTSelectQuery & select, const ASTPtr & , Data & data)
|
||||
void TranslateQualifiedNamesMatcher::visit(ASTSelectQuery & select, const ASTPtr & , Data & data)
|
||||
{
|
||||
if (auto join = select.join())
|
||||
extractJoinUsingColumns(join->table_join, data);
|
||||
|
@ -139,7 +138,9 @@ std::vector<ASTPtr *> TranslateQualifiedNamesMatcher::visit(ASTSelectQuery & sel
|
|||
out.push_back(&select.where_expression);
|
||||
if (select.having_expression)
|
||||
out.push_back(&select.having_expression);
|
||||
return out;
|
||||
|
||||
for (ASTPtr * add_node : out)
|
||||
Visitor(data).visit(*add_node);
|
||||
}
|
||||
|
||||
/// qualifed names for duplicates
|
||||
|
|
|
@ -20,6 +20,8 @@ class ASTFunction;
|
|||
class TranslateQualifiedNamesMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<TranslateQualifiedNamesMatcher, true>;
|
||||
|
||||
struct Data
|
||||
{
|
||||
const NameSet & source_columns;
|
||||
|
@ -46,16 +48,14 @@ public:
|
|||
bool processAsterisks() const { return !tables.empty() && has_columns; }
|
||||
};
|
||||
|
||||
static constexpr const char * label = "TranslateQualifiedNames";
|
||||
|
||||
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr & child);
|
||||
|
||||
private:
|
||||
static std::vector<ASTPtr *> visit(ASTIdentifier & node, ASTPtr & ast, Data &);
|
||||
static std::vector<ASTPtr *> visit(const ASTQualifiedAsterisk & node, const ASTPtr & ast, Data &);
|
||||
static std::vector<ASTPtr *> visit(ASTTableJoin & node, const ASTPtr & ast, Data &);
|
||||
static std::vector<ASTPtr *> visit(ASTSelectQuery & node, const ASTPtr & ast, Data &);
|
||||
static void visit(ASTIdentifier & node, ASTPtr & ast, Data &);
|
||||
static void visit(const ASTQualifiedAsterisk & node, const ASTPtr & ast, Data &);
|
||||
static void visit(ASTTableJoin & node, const ASTPtr & ast, Data &);
|
||||
static void visit(ASTSelectQuery & node, const ASTPtr & ast, Data &);
|
||||
static void visit(ASTExpressionList &, const ASTPtr &, Data &);
|
||||
static void visit(ASTFunction &, const ASTPtr &, Data &);
|
||||
|
||||
|
@ -64,6 +64,6 @@ private:
|
|||
|
||||
/// Visits AST for names qualification.
|
||||
/// It finds columns and translate their names to the normal form. Expand asterisks and qualified asterisks with column names.
|
||||
using TranslateQualifiedNamesVisitor = InDepthNodeVisitor<TranslateQualifiedNamesMatcher, true>;
|
||||
using TranslateQualifiedNamesVisitor = TranslateQualifiedNamesMatcher::Visitor;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue