Handle not plain where tree in StorageMerge modifySelect

This commit is contained in:
vdimir 2021-04-06 12:29:29 +03:00
parent 1c5c1946df
commit 735154c81a
No known key found for this signature in database
GPG Key ID: F57B3E10A21DBB31
6 changed files with 39 additions and 72 deletions

View File

@ -81,56 +81,6 @@ private:
ASTTableJoin * join = nullptr;
};
/// Collect all identifiers from ast
class IdentifiersCollector
{
public:
using ASTIdentPtr = const ASTIdentifier *;
using ASTIdentifiers = std::vector<ASTIdentPtr>;
struct Data
{
ASTIdentifiers idents;
};
static void visit(const ASTPtr & node, Data & data)
{
if (const auto * ident = node->as<ASTIdentifier>())
data.idents.push_back(ident);
}
static bool needChildVisit(const ASTPtr &, const ASTPtr &)
{
return true;
}
static ASTIdentifiers collect(const ASTPtr & node)
{
IdentifiersCollector::Data ident_data;
ConstInDepthNodeVisitor<IdentifiersCollector, true> ident_visitor(ident_data);
ident_visitor.visit(node);
return ident_data.idents;
}
};
/// Split expression `expr_1 AND expr_2 AND ... AND expr_n` into vector `[expr_1, expr_2, ..., expr_n]`
void collectConjunctions(const ASTPtr & node, std::vector<ASTPtr> & members)
{
if (const auto * func = node->as<ASTFunction>(); func && func->name == NameAnd::name)
{
for (const auto & child : func->arguments->children)
collectConjunctions(child, members);
return;
}
members.push_back(node);
}
std::vector<ASTPtr> collectConjunctions(const ASTPtr & node)
{
std::vector<ASTPtr> members;
collectConjunctions(node, members);
return members;
}
bool isAllowedToRewriteCrossJoin(const ASTPtr & node, const Aliases & aliases)
{
if (node->as<ASTFunction>())

View File

@ -3,6 +3,8 @@
#include <Interpreters/IdentifierSemantic.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTFunction.h>
namespace DB
{
@ -313,4 +315,22 @@ std::optional<size_t> IdentifierMembershipCollector::getIdentsMembership(ASTPtr
return IdentifierSemantic::getIdentsMembership(ast, tables, aliases);
}
static void collectConjunctions(const ASTPtr & node, std::vector<ASTPtr> & members)
{
if (const auto * func = node->as<ASTFunction>(); func && func->name == "and")
{
for (const auto & child : func->arguments->children)
collectConjunctions(child, members);
return;
}
members.push_back(node);
}
std::vector<ASTPtr> collectConjunctions(const ASTPtr & node)
{
std::vector<ASTPtr> members;
collectConjunctions(node, members);
return members;
}
}

View File

@ -107,4 +107,7 @@ private:
Aliases aliases;
};
/// Split expression `expr_1 AND expr_2 AND ... AND expr_n` into vector `[expr_1, expr_2, ..., expr_n]`
std::vector<ASTPtr> collectConjunctions(const ASTPtr & node);
}

View File

@ -71,31 +71,23 @@ TreeRewriterResult modifySelect(ASTSelectQuery & select, const TreeRewriterResul
return;
const size_t left_table_pos = 0;
if (const auto * conjunctions = where->as<ASTFunction>(); conjunctions && conjunctions->name == "and")
/// Test each argument of `and` function and select ones related to only left table
std::shared_ptr<ASTFunction> new_conj = makeASTFunction("and");
for (const auto & node : collectConjunctions(where))
{
/// Test each argument of `and` function and select related to only left table
std::shared_ptr<ASTFunction> new_conj = makeASTFunction("and");
for (const auto & node : conjunctions->arguments->children)
{
if (membership_collector.getIdentsMembership(node) == left_table_pos)
new_conj->arguments->children.push_back(std::move(node));
}
if (new_conj->arguments->children.empty())
/// No identifiers from left table
query.setExpression(expr, {});
else if (new_conj->arguments->children.size() == 1)
/// Only one expression, lift from `and`
query.setExpression(expr, std::move(new_conj->arguments->children[0]));
else
/// Set new expression
query.setExpression(expr, std::move(new_conj));
if (membership_collector.getIdentsMembership(node) == left_table_pos)
new_conj->arguments->children.push_back(std::move(node));
}
if (new_conj->arguments->children.empty())
/// No identifiers from left table
query.setExpression(expr, {});
else if (new_conj->arguments->children.size() == 1)
/// Only one expression, lift from `and`
query.setExpression(expr, std::move(new_conj->arguments->children[0]));
else
{
/// Remove whole expression if not match to left table
if (membership_collector.getIdentsMembership(where) != left_table_pos)
query.setExpression(expr, {});
}
/// Set new expression
query.setExpression(expr, std::move(new_conj));
};
replace_where(select,ASTSelectQuery::Expression::WHERE);
replace_where(select,ASTSelectQuery::Expression::PREWHERE);

View File

@ -14,6 +14,7 @@ SET force_primary_key = 1;
SELECT * FROM foo_merge WHERE Val = 3 AND Id = 3;
SELECT count(), X FROM foo_merge JOIN t2 USING Val WHERE Val = 3 AND Id = 3 AND t2.X == 4 GROUP BY X;
SELECT count(), X FROM foo_merge JOIN t2 USING Val WHERE Val = 3 AND (Id = 3 AND t2.X == 4) GROUP BY X;
SELECT count(), X FROM foo_merge JOIN t2 USING Val WHERE Val = 3 AND Id = 3 GROUP BY X;
SELECT count(), X FROM (SELECT * FROM foo_merge) f JOIN t2 USING Val WHERE Val = 3 AND Id = 3 GROUP BY X;