diff --git a/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp b/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp index fad17d3d48f..d455e30477a 100644 --- a/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp +++ b/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -19,23 +20,112 @@ namespace ErrorCodes extern const int LOGICAL_ERROR; } -/// TODO: array join aliases? -struct CheckColumnsVisitorData +/// It checks if where expression could be moved to JOIN ON expression partially or entirely. +class CheckExpressionVisitorData { - using TypeToVisit = ASTIdentifier; +public: + using TypeToVisit = const ASTFunction; - const std::vector & tables; - size_t visited; - size_t found; + CheckExpressionVisitorData(const std::vector & tables_) + : tables(tables_) + , save_where(false) + , flat_ands(true) + {} - size_t allMatch() const { return visited == found; } - - void visit(ASTIdentifier & node, ASTPtr &) + void visit(const ASTFunction & node, ASTPtr & ast) { - ++visited; - for (const auto & t : tables) - if (IdentifierSemantic::canReferColumnToTable(node, t)) - ++found; + if (node.name == "and") + { + if (!node.arguments || node.arguments->children.empty()) + throw Exception("Logical error: function requires argiment", ErrorCodes::LOGICAL_ERROR); + + for (auto & child : node.arguments->children) + { + if (auto func = typeid_cast(child.get())) + { + if (func->name == "and") + flat_ands = false; + visit(*func, child); + } + else + save_where = true; + } + } + else if (node.name == "equals") + { + if (checkEquals(node)) + asts_to_join_on.push_back(ast); + else + save_where = true; + } + else + save_where = true; + } + + bool matchAny() const { return !asts_to_join_on.empty(); } + bool matchAll() const { return matchAny() && !save_where; } + bool canReuseWhere() const { return matchAll() && flat_ands; } + + ASTPtr makeOnExpression() + { + if (asts_to_join_on.size() == 1) + return asts_to_join_on[0]->clone(); + + std::vector arguments; + arguments.reserve(asts_to_join_on.size()); + for (auto & ast : asts_to_join_on) + arguments.emplace_back(ast->clone()); + + return makeASTFunction("and", std::move(arguments)); + } + +private: + const std::vector & tables; + std::vector asts_to_join_on; + bool save_where; + bool flat_ands; + + bool checkEquals(const ASTFunction & node) + { + if (!node.arguments) + throw Exception("Logical error: function requires argiment", ErrorCodes::LOGICAL_ERROR); + if (node.arguments->children.size() != 2) + return false; + + auto left = typeid_cast(node.arguments->children[0].get()); + auto right = typeid_cast(node.arguments->children[1].get()); + if (!left || !right) + return false; + + return checkIdentifiers(*left, *right); + } + + /// Check if the identifiers are from different joined tables. If it's a self joint, tables should have aliases. + /// select * from t1 a cross join t2 b where a.x = b.x + bool checkIdentifiers(const ASTIdentifier & left, const ASTIdentifier & right) + { + /// {best_match, berst_table_pos} + std::pair left_best{0, 0}; + std::pair right_best{0, 0}; + + for (size_t i = 0; i < tables.size(); ++i) + { + size_t match = IdentifierSemantic::canReferColumnToTable(left, tables[i]); + if (match > left_best.first) + { + left_best.first = match; + left_best.second = i; + } + + match = IdentifierSemantic::canReferColumnToTable(right, tables[i]); + if (match > right_best.first) + { + right_best.first = match; + right_best.second = i; + } + } + + return left_best.first && right_best.first && (left_best.second != right_best.second); } }; @@ -100,27 +190,33 @@ std::vector CrossToInnerJoinMatcher::visit(ASTPtr & ast, Data & data) void CrossToInnerJoinMatcher::visit(ASTSelectQuery & select, ASTPtr & ast, Data & data) { - using CheckColumnsMatcher = OneTypeMatcher; - using CheckColumnsVisitor = InDepthNodeVisitor; + using CheckExpressionMatcher = OneTypeMatcher; + using CheckExpressionVisitor = InDepthNodeVisitor; std::vector table_names; ASTPtr ast_join = getCrossJoin(select, table_names); if (!ast_join) return; - /// check Identifier names from where expression - CheckColumnsVisitor::Data columns_data{table_names, 0, 0}; - CheckColumnsVisitor(columns_data).visit(select.where_expression); + CheckExpressionVisitor::Data visitor_data{table_names}; + CheckExpressionVisitor(visitor_data).visit(select.where_expression); - if (!columns_data.allMatch()) - return; + if (visitor_data.matchAny()) + { + auto & join = typeid_cast(*ast_join); + join.kind = ASTTableJoin::Kind::Inner; + join.strictness = ASTTableJoin::Strictness::All; - auto & join = typeid_cast(*ast_join); - join.kind = ASTTableJoin::Kind::Inner; - join.strictness = ASTTableJoin::Strictness::All; /// TODO: do we need it? + if (visitor_data.canReuseWhere()) + join.on_expression.swap(select.where_expression); + else + join.on_expression = visitor_data.makeOnExpression(); - join.on_expression.swap(select.where_expression); - join.children.push_back(join.on_expression); + if (visitor_data.matchAll()) + select.where_expression.reset(); + + join.children.push_back(join.on_expression); + } ast = ast->clone(); /// rewrite AST in right manner data.done = true; diff --git a/dbms/src/Interpreters/InDepthNodeVisitor.h b/dbms/src/Interpreters/InDepthNodeVisitor.h index 5cb73a23776..be14580bbfe 100644 --- a/dbms/src/Interpreters/InDepthNodeVisitor.h +++ b/dbms/src/Interpreters/InDepthNodeVisitor.h @@ -53,7 +53,7 @@ private: }; /// Simple matcher for one node type without complex traversal logic. -template +template class OneTypeMatcher { public: @@ -62,7 +62,7 @@ public: static constexpr const char * label = ""; - static bool needChildVisit(ASTPtr &, const ASTPtr &) { return true; } + static bool needChildVisit(ASTPtr &, const ASTPtr &) { return _visit_children; } static std::vector visit(ASTPtr & ast, Data & data) { diff --git a/dbms/src/Interpreters/executeQuery.cpp b/dbms/src/Interpreters/executeQuery.cpp index 1666619d010..cd59a77d9fe 100644 --- a/dbms/src/Interpreters/executeQuery.cpp +++ b/dbms/src/Interpreters/executeQuery.cpp @@ -192,7 +192,7 @@ static std::tuple executeQueryImpl( if (!internal) logQuery(query.substr(0, settings.log_queries_cut_to_length), context); - if (settings.allow_experimental_multiple_joins_emulation) + if (!internal && settings.allow_experimental_multiple_joins_emulation) { JoinToSubqueryTransformVisitor::Data join_to_subs_data; JoinToSubqueryTransformVisitor(join_to_subs_data).visit(ast); @@ -200,7 +200,7 @@ static std::tuple executeQueryImpl( logQuery(queryToString(*ast), context); } - if (settings.allow_experimental_cross_to_join_conversion) + if (!internal && settings.allow_experimental_cross_to_join_conversion) { CrossToInnerJoinVisitor::Data cross_to_inner; CrossToInnerJoinVisitor(cross_to_inner).visit(ast); diff --git a/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.reference b/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.reference index c309901bd95..73c8a9f9ce4 100644 --- a/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.reference +++ b/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.reference @@ -1,23 +1,79 @@ cross 1 1 1 1 +1 1 1 2 +2 2 2 \N +1 1 1 1 +1 1 1 2 2 2 2 \N cross nullable 1 1 1 1 +2 2 1 2 +1 1 1 1 +2 2 1 2 cross nullable vs not nullable 1 1 1 1 -Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n -Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n -Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n -Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n -cross +2 2 1 2 1 1 1 1 +2 2 1 2 +cross self +1 1 1 1 +2 2 2 2 +1 1 1 1 +2 2 2 2 +cross one table expr +1 1 1 1 +1 1 1 2 +1 1 2 \N +1 1 3 \N +2 2 1 1 +2 2 1 2 2 2 2 \N -cross nullable +2 2 3 \N +1 1 1 1 +1 1 1 2 +1 1 2 \N +1 1 3 \N +2 2 1 1 +2 2 1 2 +2 2 2 \N +2 2 3 \N +cross multiple ands +1 1 1 1 +1 1 1 1 +cross and inside and +1 1 1 1 +1 1 1 1 +cross split conjunction 1 1 1 1 -cross nullable vs not nullable 1 1 1 1 comma 1 1 1 1 +1 1 1 2 2 2 2 \N comma nullable 1 1 1 1 +2 2 1 2 +cross +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n +cross nullable +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n TableExpression (children 1)\n Identifier t2\n +cross nullable vs not nullable +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.b\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.b\n TableExpression (children 1)\n Identifier t2\n +cross self +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1 (alias x)\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t1 (alias y)\n TableJoin\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier x.a\n Identifier y.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier x.b\n Identifier y.b\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1 (alias x)\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier x.a\n Identifier y.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier x.b\n Identifier y.b\n TableExpression (children 1)\n Identifier t1 (alias y)\n +cross one table expr +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t1.b\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin\n TableExpression (children 1)\n Identifier t2\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t1.b\n +cross multiple ands +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n TableExpression (children 1)\n Identifier t2\n +cross and inside and +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 2)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function and (children 1)\n ExpressionList (children 4)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n TableExpression (children 1)\n Identifier t2\n +cross split conjunction +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableExpression (children 1)\n Identifier t2\n TableJoin\n Function and (children 1)\n ExpressionList (children 4)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n Function greaterOrEquals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Literal UInt64_1\n Function greater (children 1)\n ExpressionList (children 2)\n Identifier t2.b\n Literal UInt64_0\n +Explain ParsedAST (children 1)\n SelectWithUnionQuery (children 1)\n ExpressionList (children 1)\n SelectQuery (children 3)\n ExpressionList (children 1)\n Asterisk\n TablesInSelectQuery (children 2)\n TablesInSelectQueryElement (children 1)\n TableExpression (children 1)\n Identifier t1\n TablesInSelectQueryElement (children 2)\n TableJoin (children 1)\n Function and (children 1)\n ExpressionList (children 2)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n TableExpression (children 1)\n Identifier t2\n Function and (children 1)\n ExpressionList (children 4)\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Identifier t2.a\n Function equals (children 1)\n ExpressionList (children 2)\n Identifier t1.b\n Identifier t2.b\n Function greaterOrEquals (children 1)\n ExpressionList (children 2)\n Identifier t1.a\n Literal UInt64_1\n Function greater (children 1)\n ExpressionList (children 2)\n Identifier t2.b\n Literal UInt64_0\n diff --git a/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.sql b/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.sql index dfb30bad753..26d8d5abd57 100644 --- a/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.sql +++ b/dbms/tests/queries/0_stateless/00826_cross_to_inner_join.sql @@ -1,3 +1,4 @@ +SET enable_debug_queries = 1; USE test; DROP TABLE IF EXISTS t1; @@ -7,36 +8,86 @@ CREATE TABLE t1 (a Int8, b Nullable(Int8)) ENGINE = Memory; CREATE TABLE t2 (a Int8, b Nullable(Int8)) ENGINE = Memory; INSERT INTO t1 values (1,1), (2,2); -INSERT INTO t2 values (1,1); +INSERT INTO t2 values (1,1), (1,2); INSERT INTO t2 (a) values (2), (3); SELECT 'cross'; +SET allow_experimental_cross_to_join_conversion = 0; +SELECT * FROM t1 cross join t2 where t1.a = t2.a; +SET allow_experimental_cross_to_join_conversion = 1; SELECT * FROM t1 cross join t2 where t1.a = t2.a; SELECT 'cross nullable'; +SET allow_experimental_cross_to_join_conversion = 0; +SELECT * FROM t1 cross join t2 where t1.b = t2.b; +SET allow_experimental_cross_to_join_conversion = 1; SELECT * FROM t1 cross join t2 where t1.b = t2.b; SELECT 'cross nullable vs not nullable'; +SET allow_experimental_cross_to_join_conversion = 0; SELECT * FROM t1 cross join t2 where t1.a = t2.b; - -SET enable_debug_queries = 1; -AST SELECT * FROM t1 cross join t2 where t1.a = t2.a; -AST SELECT * FROM t1, t2 where t1.a = t2.a; +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 cross join t2 where t1.a = t2.b; +SELECT 'cross self'; +SET allow_experimental_cross_to_join_conversion = 0; +SELECT * FROM t1 x cross join t1 y where x.a = y.a and x.b = y.b; +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 x cross join t1 y where x.a = y.a and x.b = y.b; +SELECT 'cross one table expr'; +SET allow_experimental_cross_to_join_conversion = 0; +SELECT * FROM t1 cross join t2 where t1.a = t1.b order by (t1.a, t2.a, t2.b); +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 cross join t2 where t1.a = t1.b order by (t1.a, t2.a, t2.b); +SELECT 'cross multiple ands'; +SET allow_experimental_cross_to_join_conversion = 0; +--SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.a = t2.a and t1.b = t2.b and t1.a = t2.a; +SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b; +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b; +SELECT 'cross and inside and'; +SET allow_experimental_cross_to_join_conversion = 0; +--SELECT * FROM t1 cross join t2 where t1.a = t2.a and (t1.a = t2.a and (t1.a = t2.a and t1.b = t2.b)); +--SELECT * FROM t1 x cross join t2 y where t1.a = t2.a and (t1.b = t2.b and (x.a = y.a and x.b = y.b)); +SELECT * FROM t1 cross join t2 where t1.a = t2.a and (t1.b = t2.b and 1); +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 cross join t2 where t1.a = t2.a and (t1.b = t2.b and 1); +SELECT 'cross split conjunction'; +SET allow_experimental_cross_to_join_conversion = 0; +SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b and t1.a >= 1 and t2.b = 1; +SET allow_experimental_cross_to_join_conversion = 1; +SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b and t1.a >= 1 and t2.b = 1; SET allow_experimental_cross_to_join_conversion = 1; -AST SELECT * FROM t1 cross join t2 where t1.a = t2.a; -AST SELECT * FROM t1, t2 where t1.a = t2.a; - -SELECT 'cross'; -SELECT * FROM t1 cross join t2 where t1.a = t2.a; -SELECT 'cross nullable'; -SELECT * FROM t1 cross join t2 where t1.b = t2.b; -SELECT 'cross nullable vs not nullable'; -SELECT * FROM t1 cross join t2 where t1.a = t2.b; - SELECT 'comma'; SELECT * FROM t1, t2 where t1.a = t2.a; SELECT 'comma nullable'; SELECT * FROM t1, t2 where t1.b = t2.b; + +SELECT 'cross'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a; +SELECT 'cross nullable'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1, t2 where t1.a = t2.a; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1, t2 where t1.a = t2.a; +SELECT 'cross nullable vs not nullable'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t2.b; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t2.b; +SELECT 'cross self'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 x cross join t1 y where x.a = y.a and x.b = y.b; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 x cross join t1 y where x.a = y.a and x.b = y.b; +SELECT 'cross one table expr'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t1.b; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t1.b; +SELECT 'cross multiple ands'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b; +SELECT 'cross and inside and'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and (t1.a = t2.a and (t1.a = t2.a and t1.b = t2.b)); +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and (t1.a = t2.a and (t1.a = t2.a and t1.b = t2.b)); + +SELECT 'cross split conjunction'; +SET allow_experimental_cross_to_join_conversion = 0; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b and t1.a >= 1 and t2.b > 0; +SET allow_experimental_cross_to_join_conversion = 1; AST SELECT * FROM t1 cross join t2 where t1.a = t2.a and t1.b = t2.b and t1.a >= 1 and t2.b > 0; + DROP TABLE t1; DROP TABLE t2;