mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-21 01:00:48 +00:00
MergeTreeWhereOptimizer::tryAnalyzeTuple, fix fuzz
This commit is contained in:
parent
e326b12a37
commit
64ffacd9e0
@ -119,6 +119,45 @@ static bool isConditionGood(const ASTPtr & condition)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergeTreeWhereOptimizer::tryAnalyzeTuple(Conditions & res, const ASTFunction * func, bool is_final) const
|
||||
{
|
||||
if (!func || func->name != "equals" || func->arguments->children.empty())
|
||||
return false;
|
||||
|
||||
const auto * func_tuple = func->arguments->children[0]->as<ASTFunction>();
|
||||
if (!func_tuple || func_tuple->name != "tuple")
|
||||
return false;
|
||||
|
||||
if (func->arguments->children.size() <= 1)
|
||||
return false;
|
||||
|
||||
Tuple tuple;
|
||||
{
|
||||
const auto * value_tuple = func->arguments->children[1]->as<ASTLiteral>();
|
||||
if (!value_tuple || !value_tuple->value.tryGet<Tuple>(tuple))
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (const auto & child : func_tuple->arguments->children)
|
||||
{
|
||||
std::shared_ptr<IAST> fetch_sign_column = nullptr;
|
||||
/// tuple in tuple like (a, (b, c)) = (1, (2, 3))
|
||||
if (const auto * child_func = child->as<ASTFunction>(); child_func && child_func->name == "tuple")
|
||||
fetch_sign_column = std::make_shared<ASTFunction>(*child_func);
|
||||
else if (const auto * child_ident = child->as<ASTIdentifier>())
|
||||
fetch_sign_column = std::make_shared<ASTIdentifier>(child_ident->name());
|
||||
else
|
||||
return false;
|
||||
|
||||
ASTPtr fetch_sign_value = std::make_shared<ASTLiteral>(tuple.at(index));
|
||||
ASTPtr func_node = makeASTFunction("equals", fetch_sign_column, fetch_sign_value);
|
||||
analyzeImpl(res, func_node, is_final);
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MergeTreeWhereOptimizer::analyzeImpl(Conditions & res, const ASTPtr & node, bool is_final) const
|
||||
{
|
||||
@ -129,63 +168,35 @@ void MergeTreeWhereOptimizer::analyzeImpl(Conditions & res, const ASTPtr & node,
|
||||
for (const auto & elem : func->arguments->children)
|
||||
analyzeImpl(res, elem, is_final);
|
||||
}
|
||||
else if (tryAnalyzeTuple(res, func, is_final))
|
||||
{
|
||||
/// analyzed
|
||||
}
|
||||
else
|
||||
{
|
||||
ASTFunction * func_tuple = nullptr;
|
||||
if (func && func->name == "equals")
|
||||
func_tuple = func->arguments->children[0]->as<ASTFunction>();
|
||||
Condition cond;
|
||||
cond.node = node;
|
||||
|
||||
if (func_tuple && func_tuple->name == "tuple")
|
||||
{
|
||||
const auto * value_tuple = func->arguments->children[1]->as<ASTLiteral>();
|
||||
auto & tuple = value_tuple->value.safeGet<Tuple>();
|
||||
collectIdentifiersNoSubqueries(node, cond.identifiers);
|
||||
|
||||
int index = 0;
|
||||
cond.columns_size = getIdentifiersColumnSize(cond.identifiers);
|
||||
|
||||
for (auto child : func_tuple->arguments->children)
|
||||
{
|
||||
const auto * child_func = child->as<ASTFunction>();
|
||||
const auto & fetch_sign_value = std::make_shared<ASTLiteral>(tuple.at(index));
|
||||
std::shared_ptr<IAST> fetch_sign_column = nullptr;
|
||||
cond.viable =
|
||||
/// Condition depend on some column. Constant expressions are not moved.
|
||||
!cond.identifiers.empty()
|
||||
&& !cannotBeMoved(node, is_final)
|
||||
/// Do not take into consideration the conditions consisting only of the first primary key column
|
||||
&& !hasPrimaryKeyAtoms(node)
|
||||
/// Only table columns are considered. Not array joined columns. NOTE We're assuming that aliases was expanded.
|
||||
&& isSubsetOfTableColumns(cond.identifiers)
|
||||
/// Do not move conditions involving all queried columns.
|
||||
&& cond.identifiers.size() < queried_columns.size();
|
||||
|
||||
// tuple in tuple like (a, (b,c)) = (1, (2,3))
|
||||
if (child_func && child_func->name == "tuple")
|
||||
fetch_sign_column = std::make_shared<ASTFunction>(*child_func);
|
||||
else
|
||||
fetch_sign_column = std::make_shared<ASTIdentifier>(child->as<ASTIdentifier>()->name());
|
||||
if (cond.viable)
|
||||
cond.good = isConditionGood(node);
|
||||
|
||||
auto func_node = makeASTFunction("equals", fetch_sign_column, fetch_sign_value);
|
||||
analyzeImpl(res, func_node, is_final);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Condition cond;
|
||||
cond.node = node;
|
||||
|
||||
collectIdentifiersNoSubqueries(node, cond.identifiers);
|
||||
|
||||
cond.columns_size = getIdentifiersColumnSize(cond.identifiers);
|
||||
|
||||
cond.viable =
|
||||
/// Condition depend on some column. Constant expressions are not moved.
|
||||
!cond.identifiers.empty()
|
||||
&& !cannotBeMoved(node, is_final)
|
||||
/// Do not take into consideration the conditions consisting only of the first primary key column
|
||||
&& !hasPrimaryKeyAtoms(node)
|
||||
/// Only table columns are considered. Not array joined columns. NOTE We're assuming that aliases was expanded.
|
||||
&& isSubsetOfTableColumns(cond.identifiers)
|
||||
/// Do not move conditions involving all queried columns.
|
||||
&& cond.identifiers.size() < queried_columns.size();
|
||||
|
||||
if (cond.viable)
|
||||
cond.good = isConditionGood(node);
|
||||
|
||||
res.emplace_back(std::move(cond));
|
||||
}
|
||||
res.emplace_back(std::move(cond));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Transform conjunctions chain in WHERE expression to Conditions list.
|
||||
|
@ -70,6 +70,7 @@ private:
|
||||
|
||||
using Conditions = std::list<Condition>;
|
||||
|
||||
bool tryAnalyzeTuple(Conditions & res, const ASTFunction * func, bool is_final) const;
|
||||
void analyzeImpl(Conditions & res, const ASTPtr & node, bool is_final) const;
|
||||
|
||||
/// Transform conjunctions chain in WHERE expression to Conditions list.
|
||||
|
@ -1,14 +1,24 @@
|
||||
DROP TABLE IF EXISTS test_tuple_filter;
|
||||
|
||||
CREATE TABLE test_tuple_filter (id UInt32, value String, log_date Date) Engine=MergeTree() ORDER BY id PARTITION BY log_date settings index_granularity=3;
|
||||
CREATE TABLE test_tuple_filter (id UInt32, value String, log_date Date) Engine=MergeTree() ORDER BY id PARTITION BY log_date SETTINGS index_granularity = 3;
|
||||
|
||||
insert into test_tuple_filter values (1, 'A','2021-01-01'),(2,'B','2021-01-01'),(3,'C','2021-01-01'),(4,'D','2021-01-02'),(5,'E','2021-01-02');
|
||||
INSERT INTO test_tuple_filter VALUES (1, 'A','2021-01-01'),(2,'B','2021-01-01'),(3,'C','2021-01-01'),(4,'D','2021-01-02'),(5,'E','2021-01-02');
|
||||
|
||||
set force_primary_key=1;
|
||||
SET force_primary_key = 1;
|
||||
SELECT * FROM test_tuple_filter WHERE (id, value) = (1, 'A');
|
||||
|
||||
set force_index_by_date=1;
|
||||
set force_primary_key=0;
|
||||
SET force_index_by_date = 1;
|
||||
SET force_primary_key = 0;
|
||||
SELECT * FROM test_tuple_filter WHERE (log_date, value) = ('2021-01-01', 'A');
|
||||
|
||||
|
||||
SET force_index_by_date = 0;
|
||||
SET force_primary_key = 0;
|
||||
|
||||
SELECT * FROM test_tuple_filter WHERE tuple(id) = tuple(1) FORMAT Null;
|
||||
SELECT * FROM test_tuple_filter WHERE (log_date, value) = tuple('2021-01-01'); -- { serverError 43 }
|
||||
SELECT * FROM test_tuple_filter WHERE (id, value) = tuple(1); -- { serverError 43 }
|
||||
SELECT * FROM test_tuple_filter WHERE tuple(id, value) = tuple(value, id); -- { serverError 386 }
|
||||
SELECT * FROM test_tuple_filter WHERE equals((id, value)); -- { serverError 42 }
|
||||
|
||||
DROP TABLE IF EXISTS test_tuple_filter;
|
||||
|
Loading…
Reference in New Issue
Block a user