diff --git a/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp b/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp index f73e10ae578..ede49b90538 100644 --- a/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp +++ b/dbms/src/Interpreters/CrossToInnerJoinVisitor.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -29,6 +31,8 @@ struct JoinedTable DatabaseAndTableWithAlias table; ASTTablesInSelectQueryElement * element = nullptr; ASTTableJoin * join = nullptr; + ASTPtr array_join = nullptr; + bool has_using = false; JoinedTable(ASTPtr table_element) { @@ -47,11 +51,16 @@ struct JoinedTable } if (join->using_expression_list) - throw Exception("Multiple CROSS/COMMA JOIN do not support USING", ErrorCodes::NOT_IMPLEMENTED); + has_using = true; } - auto & expr = typeid_cast(*element->table_expression); - table = DatabaseAndTableWithAlias(expr); + if (element->table_expression) + { + auto & expr = typeid_cast(*element->table_expression); + table = DatabaseAndTableWithAlias(expr); + } + + array_join = element->array_join; } void rewriteCommaToCross() @@ -63,6 +72,16 @@ struct JoinedTable bool canAttachOnExpression() const { return join && !join->on_expression; } }; +bool isComparison(const String & name) +{ + return name == NameEquals::name || + name == NameNotEquals::name || + name == NameLess::name || + name == NameGreater::name || + name == NameLessOrEquals::name || + name == NameGreaterOrEquals::name; +} + /// It checks if where expression could be moved to JOIN ON expression partially or entirely. class CheckExpressionVisitorData { @@ -79,7 +98,7 @@ public: if (!ands_only) return; - if (node.name == "and") + if (node.name == NameAnd::name) { if (!node.arguments || node.arguments->children.empty()) throw Exception("Logical error: function requires argiment", ErrorCodes::LOGICAL_ERROR); @@ -92,11 +111,15 @@ public: ands_only = false; } } - else if (node.name == "equals") + else if (node.name == NameEquals::name) { if (size_t min_table = canMoveEqualsToJoinOn(node)) asts_to_join_on[min_table].push_back(ast); } + else if (isComparison(node.name)) + { + /// leave other comparisons as is + } else { ands_only = false; @@ -122,7 +145,7 @@ public: for (auto & ast : expressions) arguments.emplace_back(ast->clone()); - return makeASTFunction("and", std::move(arguments)); + return makeASTFunction(NameAnd::name, std::move(arguments)); } private: @@ -202,8 +225,14 @@ bool getTables(ASTSelectQuery & select, std::vector & joined_tables for (auto & child : tables->children) { joined_tables.emplace_back(JoinedTable(child)); + JoinedTable & t = joined_tables.back(); + if (t.array_join) + return false; - if (ASTTableJoin * join = joined_tables.back().join) + if (num_tables > 2 && t.has_using) + throw Exception("Multiple CROSS/COMMA JOIN do not support USING", ErrorCodes::NOT_IMPLEMENTED); + + if (ASTTableJoin * join = t.join) if (join->kind == ASTTableJoin::Kind::Comma) ++num_comma; } 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 024026d2c8c..244ff8c9600 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 @@ -57,25 +57,25 @@ comma nullable 2 2 1 2 cross SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE a = t2.a -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON t1.a = t2.a +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON a = t2.a\nWHERE a = t2.a cross nullable SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \n, t2 \nWHERE a = t2.a -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON t1.a = t2.a +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON a = t2.a\nWHERE a = t2.a cross nullable vs not nullable SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE a = t2.b -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON t1.a = t2.b +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON a = t2.b\nWHERE a = t2.b cross self SELECT \n a, \n b, \n y.a, \n y.b\nFROM t1 AS x \nCROSS JOIN t1 AS y \nWHERE (a = y.a) AND (b = y.b) -SELECT *\nFROM t1 AS x \nALL INNER JOIN t1 AS y ON (x.a = y.a) AND (x.b = y.b) +SELECT \n a, \n b, \n y.a, \n y.b\nFROM t1 AS x \nALL INNER JOIN t1 AS y ON (a = y.a) AND (b = y.b)\nWHERE (a = y.a) AND (b = y.b) cross one table expr SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE a = b SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE a = b cross multiple ands SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE (a = t2.a) AND (b = t2.b) -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON (t1.a = t2.a) AND (t1.b = t2.b) +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON (a = t2.a) AND (b = t2.b)\nWHERE (a = t2.a) AND (b = t2.b) cross and inside and SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE (a = t2.a) AND ((a = t2.a) AND ((a = t2.a) AND (b = t2.b))) -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON (t1.a = t2.a) AND (t1.a = t2.a) AND (t1.a = t2.a) AND (t1.b = t2.b) +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON (a = t2.a) AND (a = t2.a) AND (a = t2.a) AND (b = t2.b)\nWHERE (a = t2.a) AND ((a = t2.a) AND ((a = t2.a) AND (b = t2.b))) cross split conjunction SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nCROSS JOIN t2 \nWHERE (a = t2.a) AND (b = t2.b) AND (a >= 1) AND (t2.b > 0) -SELECT *\nFROM t1 \nALL INNER JOIN t2 ON (t1.a = t2.a) AND (t1.b = t2.b)\nWHERE (t1.a = t2.a) AND (t1.b = t2.b) AND (t1.a >= 1) AND (t2.b > 0) +SELECT \n a, \n b, \n t2.a, \n t2.b\nFROM t1 \nALL INNER JOIN t2 ON (a = t2.a) AND (b = t2.b)\nWHERE (a = t2.a) AND (b = t2.b) AND (a >= 1) AND (t2.b > 0)