diff --git a/src/Interpreters/JoinToSubqueryTransformVisitor.cpp b/src/Interpreters/JoinToSubqueryTransformVisitor.cpp index 3cb8004a29f..65848e4fbb9 100644 --- a/src/Interpreters/JoinToSubqueryTransformVisitor.cpp +++ b/src/Interpreters/JoinToSubqueryTransformVisitor.cpp @@ -91,7 +91,20 @@ public: { if (should_add_column_predicate(column.name)) { - auto identifier = std::make_shared(std::vector{it->first, column.name}); + ASTPtr identifier; + if (it->first.empty()) + /// We want tables from JOIN to have aliases. + /// But it is possible to set joined_subquery_requires_alias = 0, + /// and write a query like `select * FROM (SELECT 1), (SELECT 1), (SELECT 1)`. + /// If so, table name will be empty here. + /// + /// We cannot create compound identifier with empty part (there is an assert). + /// So, try our luck and use only column name. + /// (Rewriting AST for JOIN is not an efficient design). + identifier = std::make_shared(column.name); + else + identifier = std::make_shared(std::vector{it->first, column.name}); + new_select_expression_list->children.emplace_back(std::move(identifier)); } } diff --git a/src/Parsers/ASTIdentifier.cpp b/src/Parsers/ASTIdentifier.cpp index 54ccc155dbf..02430cb40f7 100644 --- a/src/Parsers/ASTIdentifier.cpp +++ b/src/Parsers/ASTIdentifier.cpp @@ -80,7 +80,7 @@ void ASTIdentifier::setShortName(const String & new_name) name_parts = {new_name}; bool special = semantic->special; - //how about keep the semantic info here, such as table + /// How about keep the semantic info here, such as table auto table = semantic->table; *semantic = IdentifierSemanticImpl(); @@ -116,8 +116,14 @@ void ASTIdentifier::formatImplWithoutAlias(const FormatSettings & settings, Form if (i != 0) settings.ostr << '.'; - if (name_parts[i].empty()) - children[j++]->formatImpl(settings, state, frame); + /// Some AST rewriting code, like IdentifierSemantic::setColumnLongName, + /// does not respect children of identifier. + /// Here we also ignore children if they are empty. + if (name_parts[i].empty() && j < children.size()) + { + children[j]->formatImpl(settings, state, frame); + ++j; + } else format_element(name_parts[i]); } @@ -125,7 +131,7 @@ void ASTIdentifier::formatImplWithoutAlias(const FormatSettings & settings, Form else { const auto & name = shortName(); - if (name.empty()) + if (name.empty() && !children.empty()) children.front()->formatImpl(settings, state, frame); else format_element(name); diff --git a/tests/queries/0_stateless/01890_cross_join_explain_crash.reference b/tests/queries/0_stateless/01890_cross_join_explain_crash.reference new file mode 100644 index 00000000000..76315843adb --- /dev/null +++ b/tests/queries/0_stateless/01890_cross_join_explain_crash.reference @@ -0,0 +1,3 @@ +2 1 1 +1 2 1 +1 1 2 diff --git a/tests/queries/0_stateless/01890_cross_join_explain_crash.sql b/tests/queries/0_stateless/01890_cross_join_explain_crash.sql new file mode 100644 index 00000000000..20a1956ea6b --- /dev/null +++ b/tests/queries/0_stateless/01890_cross_join_explain_crash.sql @@ -0,0 +1,8 @@ +SET joined_subquery_requires_alias = 0; +select * FROM (SELECT 1), (SELECT 1), (SELECT 1); -- { serverError 352 } + +-- This queries work by luck. +-- Feel free to remove then if it is the only failed test. +select * from (select 2), (select 1) as a, (select 1) as b; +select * from (select 1) as a, (select 2), (select 1) as b; +select * from (select 1) as a, (select 1) as b, (select 2);