Update CrossToInnerJoinVisitor, add tests to cross_to_inner_join

This commit is contained in:
vdimir 2021-02-19 17:06:57 +03:00
parent e052a5a05e
commit 946576017f
No known key found for this signature in database
GPG Key ID: F57B3E10A21DBB31
5 changed files with 168 additions and 70 deletions

View File

@ -124,6 +124,13 @@ void collectConjunctions(const ASTPtr & node, std::vector<ASTPtr> & members)
members.push_back(node);
}
std::vector<ASTPtr> collectConjunctions(const ASTPtr & node)
{
std::vector<ASTPtr> members;
collectConjunctions(node, members);
return members;
}
std::optional<size_t> getIdentMembership(const ASTIdentifier & ident, const std::vector<TableWithColumnNamesAndTypes> & tables)
{
std::optional<size_t> table_pos = IdentifierSemantic::getMembership(ident);
@ -169,20 +176,20 @@ bool isAllowedToRewriteCrossJoin(const ASTPtr & node, const Aliases & aliases)
return node->as<ASTIdentifier>() || node->as<ASTLiteral>();
}
bool canMoveExpressionToJoinOn(const ASTPtr & ast,
const std::vector<JoinedElement> & joined_tables,
const std::vector<TableWithColumnNamesAndTypes> & tables,
const Aliases & aliases,
std::map<size_t, std::vector<ASTPtr>> & asts_to_join_on)
/// Return mapping table_no -> expression with expression that can be moved into JOIN ON section
std::map<size_t, std::vector<ASTPtr>> moveExpressionToJoinOn(
const ASTPtr & ast,
const std::vector<JoinedElement> & joined_tables,
const std::vector<TableWithColumnNamesAndTypes> & tables,
const Aliases & aliases)
{
std::vector<ASTPtr> conjuncts;
collectConjunctions(ast, conjuncts);
for (const auto & node : conjuncts)
std::map<size_t, std::vector<ASTPtr>> asts_to_join_on;
for (const auto & node : collectConjunctions(ast))
{
if (const auto * func = node->as<ASTFunction>(); func && func->name == NameEquals::name)
{
if (!func->arguments || func->arguments->children.size() != 2)
return false;
return {};
/// Check if the identifiers are from different joined tables.
/// If it's a self joint, tables should have aliases.
@ -196,14 +203,14 @@ bool canMoveExpressionToJoinOn(const ASTPtr & ast,
if (joined_tables[table_pos].canAttachOnExpression())
asts_to_join_on[table_pos].push_back(node);
else
return false;
return {};
}
}
if (!isAllowedToRewriteCrossJoin(node, aliases))
return false;
return {};
}
return true;
return asts_to_join_on;
}
ASTPtr makeOnExpression(const std::vector<ASTPtr> & expressions)
@ -317,7 +324,6 @@ void CrossToInnerJoinMatcher::visit(ASTSelectQuery & select, ASTPtr &, Data & da
}
/// COMMA to CROSS
if (num_comma)
{
for (auto & table : joined_tables)
@ -325,22 +331,16 @@ void CrossToInnerJoinMatcher::visit(ASTSelectQuery & select, ASTPtr &, Data & da
}
/// CROSS to INNER
if (select.where() && data.cross_to_inner_join_rewrite)
if (data.cross_to_inner_join_rewrite && select.where())
{
std::map<size_t, std::vector<ASTPtr>> asts_to_join_on;
bool can_move_where
= canMoveExpressionToJoinOn(select.where(), joined_tables, data.tables_with_columns, data.aliases, asts_to_join_on);
if (can_move_where)
auto asts_to_join_on = moveExpressionToJoinOn(select.where(), joined_tables, data.tables_with_columns, data.aliases);
for (size_t i = 1; i < joined_tables.size(); ++i)
{
for (size_t i = 1; i < joined_tables.size(); ++i)
const auto & expr_it = asts_to_join_on.find(i);
if (expr_it != asts_to_join_on.end())
{
const auto & expr_it = asts_to_join_on.find(i);
if (expr_it != asts_to_join_on.end())
{
if (joined_tables[i].rewriteCrossToInner(makeOnExpression(expr_it->second)))
data.done = true;
}
if (joined_tables[i].rewriteCrossToInner(makeOnExpression(expr_it->second)))
data.done = true;
}
}
}

View File

@ -1,18 +1,18 @@
0 0
cross
--- cross ---
1 1 1 1
1 1 1 2
2 2 2 \N
cross nullable
--- cross nullable ---
1 1 1 1
2 2 1 2
cross nullable vs not nullable
--- cross nullable vs not nullable ---
1 1 1 1
2 2 1 2
cross self
--- cross self ---
1 1 1 1
2 2 2 2
cross one table expr
--- cross one table expr ---
1 1 1 1
1 1 1 2
1 1 2 \N
@ -21,20 +21,34 @@ cross one table expr
2 2 1 2
2 2 2 \N
2 2 3 \N
cross multiple ands
--- cross multiple ands ---
1 1 1 1
cross and inside and
--- cross and inside and ---
1 1 1 1
cross split conjunction
--- cross split conjunction ---
1 1 1 1
comma
--- and or ---
1 1 1 1
--- arithmetic expr ---
2 2 1 2
--- is null or ---
1 1 1 2
2 2 2 \N
--- do not rewrite alias ---
1
1
2
--- comma ---
1 1 1 1
1 1 1 2
2 2 2 \N
comma nullable
--- comma nullable ---
1 1 1 1
2 2 1 2
cross
--- comma and or ---
1 1 1 1
2 2 2 \N
--- cross ---
SELECT
a,
b,
@ -43,7 +57,7 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE a = t2_00826.a
cross nullable
--- cross nullable ---
SELECT
a,
b,
@ -52,7 +66,7 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE a = t2_00826.a
cross nullable vs not nullable
--- cross nullable vs not nullable ---
SELECT
a,
b,
@ -61,7 +75,7 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.b
WHERE a = t2_00826.b
cross self
--- cross self ---
SELECT
a,
b,
@ -70,7 +84,7 @@ SELECT
FROM t1_00826 AS x
ALL INNER JOIN t1_00826 AS y ON (a = y.a) AND (b = y.b)
WHERE (a = y.a) AND (b = y.b)
cross one table expr
--- cross one table expr ---
SELECT
a,
b,
@ -79,7 +93,7 @@ SELECT
FROM t1_00826
CROSS JOIN t2_00826
WHERE a = b
cross multiple ands
--- cross multiple ands ---
SELECT
a,
b,
@ -88,7 +102,7 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND (b = t2_00826.b)
cross and inside and
--- cross and inside and ---
SELECT
a,
b,
@ -97,7 +111,7 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (a = t2_00826.a) AND (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND ((a = t2_00826.a) AND ((a = t2_00826.a) AND (b = t2_00826.b)))
cross split conjunction
--- cross split conjunction ---
SELECT
a,
b,
@ -106,3 +120,62 @@ SELECT
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND (b = t2_00826.b) AND (a >= 1) AND (t2_00826.b > 0)
--- and or ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a = t2_00826.a) AND (b = t2_00826.b)
WHERE (a = t2_00826.a) AND (b = t2_00826.b) AND ((a >= 1) OR (t2_00826.b = 1))
--- arithmetic expr ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON (a + 1) = (t2_00826.a + t2_00826.b)
WHERE ((a + 1) = (t2_00826.a + t2_00826.b)) AND ((((a + b) + t2_00826.a) + t2_00826.b) > 5)
--- is null or ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON b = t2_00826.a
WHERE (b = t2_00826.a) AND (isNull(t2_00826.b) OR (t2_00826.b > t2_00826.a))
--- do not rewrite alias ---
SELECT a AS b
FROM t1_00826
CROSS JOIN t2_00826
WHERE (b = t2_00826.a) AND (b > 0)
--- comma ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE a = t2_00826.a
--- comma nullable ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON b = t2_00826.b
WHERE b = t2_00826.b
--- comma and or ---
SELECT
a,
b,
t2_00826.a,
t2_00826.b
FROM t1_00826
ALL INNER JOIN t2_00826 ON a = t2_00826.a
WHERE (a = t2_00826.a) AND (isNull(t2_00826.b) OR (t2_00826.b < 2))

View File

@ -12,46 +12,79 @@ INSERT INTO t1_00826 values (1,1), (2,2);
INSERT INTO t2_00826 values (1,1), (1,2);
INSERT INTO t2_00826 (a) values (2), (3);
SELECT 'cross';
SELECT '--- cross ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a;
SELECT 'cross nullable';
SELECT '--- cross nullable ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.b = t2_00826.b;
SELECT 'cross nullable vs not nullable';
SELECT '--- cross nullable vs not nullable ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.b;
SELECT 'cross self';
SELECT '--- cross self ---';
SELECT * FROM t1_00826 x cross join t1_00826 y where x.a = y.a and x.b = y.b;
SELECT 'cross one table expr';
SELECT '--- cross one table expr ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t1_00826.b order by (t1_00826.a, t2_00826.a, t2_00826.b);
SELECT 'cross multiple ands';
SELECT '--- cross multiple ands ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b;
SELECT 'cross and inside and';
SELECT '--- cross and inside and ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and (t1_00826.b = t2_00826.b and 1);
SELECT 'cross split conjunction';
SELECT '--- cross split conjunction ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b and t1_00826.a >= 1 and t2_00826.b = 1;
SELECT 'comma';
SELECT '--- and or ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b and (t1_00826.a >= 1 OR t2_00826.b = 1);
SELECT '--- arithmetic expr ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a + 1 = t2_00826.a + t2_00826.b AND (t1_00826.a + t1_00826.b + t2_00826.a + t2_00826.b > 5);
SELECT '--- is null or ---';
SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.b = t2_00826.a AND (t2_00826.b IS NULL OR t2_00826.b > t2_00826.a);
SELECT '--- do not rewrite alias ---';
SELECT a as b FROM t1_00826 cross join t2_00826 where t1_00826.b = t2_00826.a AND b > 0;
SELECT '--- comma ---';
SELECT * FROM t1_00826, t2_00826 where t1_00826.a = t2_00826.a;
SELECT 'comma nullable';
SELECT '--- comma nullable ---';
SELECT * FROM t1_00826, t2_00826 where t1_00826.b = t2_00826.b;
SELECT '--- comma and or ---';
SELECT * FROM t1_00826, t2_00826 where t1_00826.a = t2_00826.a AND (t2_00826.b IS NULL OR t2_00826.b < 2);
SELECT 'cross';
SELECT '--- cross ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a;
SELECT 'cross nullable';
SELECT '--- cross nullable ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826, t2_00826 where t1_00826.a = t2_00826.a;
SELECT 'cross nullable vs not nullable';
SELECT '--- cross nullable vs not nullable ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.b;
SELECT 'cross self';
SELECT '--- cross self ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 x cross join t1_00826 y where x.a = y.a and x.b = y.b;
SELECT 'cross one table expr';
SELECT '--- cross one table expr ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t1_00826.b;
SELECT 'cross multiple ands';
SELECT '--- cross multiple ands ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b;
SELECT 'cross and inside and';
SELECT '--- cross and inside and ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and (t1_00826.a = t2_00826.a and (t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b));
SELECT 'cross split conjunction';
SELECT '--- cross split conjunction ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b and t1_00826.a >= 1 and t2_00826.b > 0;
SELECT '--- and or ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a = t2_00826.a and t1_00826.b = t2_00826.b and (t1_00826.a >= 1 OR t2_00826.b = 1);
SELECT '--- arithmetic expr ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.a + 1 = t2_00826.a + t2_00826.b AND (t1_00826.a + t1_00826.b + t2_00826.a + t2_00826.b > 5);
SELECT '--- is null or ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826 cross join t2_00826 where t1_00826.b = t2_00826.a AND (t2_00826.b IS NULL OR t2_00826.b > t2_00826.a);
SELECT '--- do not rewrite alias ---';
EXPLAIN SYNTAX SELECT a as b FROM t1_00826 cross join t2_00826 where t1_00826.b = t2_00826.a AND b > 0;
SELECT '--- comma ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826, t2_00826 where t1_00826.a = t2_00826.a;
SELECT '--- comma nullable ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826, t2_00826 where t1_00826.b = t2_00826.b;
SELECT '--- comma and or ---';
EXPLAIN SYNTAX SELECT * FROM t1_00826, t2_00826 where t1_00826.a = t2_00826.a AND (t2_00826.b IS NULL OR t2_00826.b < 2);
DROP TABLE t1_00826;
DROP TABLE t2_00826;

View File

@ -19,10 +19,3 @@ SELECT
FROM n
ALL INNER JOIN r ON k = r.k
WHERE (k = r.k) AND (name NOT LIKE \'A%\')
SELECT
k,
r.k,
name
FROM n
ALL INNER JOIN r ON (k + 1) = (r.k + 1)
WHERE ((k + 1) = (r.k + 1)) AND ((name = \'A\') OR (name = \'AA\'))

View File

@ -9,7 +9,6 @@ SET enable_optimize_predicate_expression = 0;
EXPLAIN SYNTAX SELECT * FROM n, r WHERE n.k = r.k AND r.name = 'A';
EXPLAIN SYNTAX SELECT * FROM n, r WHERE n.k = r.k AND r.name LIKE 'A%';
EXPLAIN SYNTAX SELECT * FROM n, r WHERE n.k = r.k AND r.name NOT LIKE 'A%';
EXPLAIN SYNTAX SELECT * FROM n, r WHERE n.k + 1 = r.k + 1 AND (r.name = 'A' OR r.name = 'AA');
DROP TABLE n;
DROP TABLE r;