diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 2df7970cdc67..4b2f66ff306e 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -3140,6 +3140,64 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLoo } } + auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) + { + /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and + * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. + * + * Identifiers can be resolved into functions in case of nested or subcolumns. + * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. + * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. + * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. + * + * Example: + * + * SELECT t.t FROM ( + * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t + * ) AS a FULL JOIN ( + * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t + * ) AS b USING t; + * + * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), + * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). + * + * It can be more complicated in case of Nested subcolumns, in that case in query: + * SELECT t FROM ... JOIN ... USING (t.t) + * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. + * + * Updating type accordingly is pretty complicated, so just forbid such cases. + * + * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: + * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; + * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. + * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. + */ + if (node->getNodeType() != QueryTreeNodeType::FUNCTION) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); + + const auto & function_argument_nodes = node->as().getArguments().getNodes(); + for (const auto & argument_node : function_argument_nodes) + { + if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) + { + const auto & column_name = argument_node->as().getColumnName(); + if (join_using_column_name_to_column_node.contains(column_name)) + throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, + "Cannot select subcolumn for identifier '{}' while joining using column '{}'", + identifier_lookup.identifier, column_name); + } + else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) + { + continue; + } + else + { + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", + argument_node->getNodeType(), node->formatASTForErrorMessage()); + } + } + }; + std::optional resolved_side; QueryTreeNodePtr resolved_identifier; @@ -3173,12 +3231,23 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLoo if (left_resolved_identifier && right_resolved_identifier) { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); + auto using_column_node_it = join_using_column_name_to_column_node.end(); + if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) + { + auto & left_resolved_column = left_resolved_identifier->as(); + auto & right_resolved_column = right_resolved_identifier->as(); + if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) + using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); + } + else + { + if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) + check_nested_column_not_in_using(left_resolved_identifier); + if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) + check_nested_column_not_in_using(right_resolved_identifier); + } - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() - && left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) + if (using_column_node_it != join_using_column_name_to_column_node.end()) { JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; auto & using_column_node = using_column_node_it->second->as(); @@ -3253,39 +3322,45 @@ QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLoo else if (left_resolved_identifier) { resolved_side = JoinTableSide::Left; - auto & left_resolved_column = left_resolved_identifier->as(); - resolved_identifier = left_resolved_identifier; - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) + if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); + check_nested_column_not_in_using(left_resolved_identifier); } else { - resolved_identifier = left_resolved_identifier; + auto & left_resolved_column = left_resolved_identifier->as(); + auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); + if (using_column_node_it != join_using_column_name_to_column_node.end() && + !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) + { + auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); + left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); + resolved_identifier = std::move(left_resolved_column_clone); + } } } else if (right_resolved_identifier) { resolved_side = JoinTableSide::Right; - auto & right_resolved_column = right_resolved_identifier->as(); + resolved_identifier = right_resolved_identifier; - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) + if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); + check_nested_column_not_in_using(right_resolved_identifier); } else { - resolved_identifier = right_resolved_identifier; + auto & right_resolved_column = right_resolved_identifier->as(); + auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); + if (using_column_node_it != join_using_column_name_to_column_node.end() && + !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) + { + auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); + right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); + resolved_identifier = std::move(right_resolved_column_clone); + } } } diff --git a/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.reference b/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.reference new file mode 100644 index 000000000000..5f1b7e8b1fe7 --- /dev/null +++ b/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.reference @@ -0,0 +1,314 @@ +[(1,'a')] +[1] +[(1,'a')] [(1,'a')] +[(1,'a')] +[1] +[(1,'a')] 1 +[(1,'a')] [1] +[1] +[1] +[1] +[1] 1 ['a'] 1 ['a'] +[(1,'a')] +[1] +[1] +[(1,'a')] +[1] +[('a',1)] +1 [1] ['a'] ['a'] [1] +[(1,'a')] +[1] +[1] +[(1,'a')] +[1] +[('a',1)] +1 [1] ['a'] 1 ['a'] [1] +(1,'s') +(1,'s') 1 +1 +((((1,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((2,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 1 (1,'a') 1 ('a',1) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 (1,'a') ('a',1) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 (1,'a') 1 ('a',1) +((((1,'s'),'s'),'s'),'s') +((((1,'s'),'s'),'s'),'s') +((((2,'s'),'s'),'s'),'s') +((((2,'s'),'s'),'s'),'s') +((1,'s'),'s') +((1,'s'),'s') +((2,'s'),'s') +((2,'s'),'s') +1 +1 +2 +2 +((((1,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((2,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((3,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 UInt32 +2 UInt32 +0 UInt32 +(((1,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +(((2,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +(((3,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +((1,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((2,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 UInt32 +2 UInt32 +0 UInt32 +(((1,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((2,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((0,''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +((1,'s'),'s') s Tuple(Tuple(Int64, String), String) String +((2,'s'),'s') s Tuple(Tuple(Int64, String), String) String +((3,'s'),'s') s Tuple(Tuple(Int64, String), String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(Tuple(Int64, String), String) +((2,'s'),'s') Tuple(Tuple(Int64, String), String) +((3,'s'),'s') Tuple(Tuple(Int64, String), String) +1 UInt32 +2 UInt32 +0 UInt32 +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 Int64 +2 Int64 +3 Int64 +(((1,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((2,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((0,''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +((1,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((2,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +[([([([(1,'d')],'d')],'s')],'s')] +[[[([(1,'d')],'d')]]] +[[[[1]]]] +[[([([(1,'d')],'d')],'s')]] Array(Array(Tuple(Array(Tuple(Array(Tuple(Int64, String)), String)), String))) +[[[([(1,'d')],'d')]]] Array(Array(Nested(t Nested(t Int32, s String), s String))) +[[[[1]]]] Array(Array(Array(Array(Int32)))) +[[[([(1,'d')],'d')]]] [['s']] Array(Array(Array(Tuple(Array(Tuple(Int64, String)), String)))) Array(Array(String)) +[[[[(1,'d')]]]] [[['d']]] Array(Array(Array(Array(Tuple(\n t Int32,\n s String))))) Array(Array(Array(String))) +[[[[1]]]] [[[['d']]]] Array(Array(Array(Array(Int32)))) Array(Array(Array(Array(String)))) +[([([([(1,'d')],'d')],'s')],'s')] Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String)),\n s String)) +[[([([(1,'d')],'d')],'s')]] Array(Nested(t Nested(t Nested(t Int32, s String), s String), s String)) +[[[([(1,'d')],'d')]]] Array(Array(Array(Tuple(Array(Tuple(Int64, String)), String)))) +[[[[1]]]] Array(Array(Array(Array(Int32)))) +[[([([(1,'d')],'d')],'s')]] ['s'] Array(Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String))) Array(String) +[[[([(1,'d')],'d')]]] [['s']] Array(Array(Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)))) Array(Array(String)) +[[[[(1,'d')]]]] [[['d']]] Array(Array(Array(Array(Tuple(Int64, String))))) Array(Array(Array(String))) +[[[[1]]]] [[[['d']]]] Array(Array(Array(Array(Int32)))) Array(Array(Array(Array(String)))) +[([([([(1,'d')],'d')],'s')],'s')] Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String)),\n s String)) +[[([([(1,'d')],'d')],'s')]] Array(Nested(t Nested(t Nested(t Int32, s String), s String), s String)) +[[[([(1,'d')],'d')]]] Array(Array(Nested(t Nested(t Int32, s String), s String))) +[[[[1]]]] Array(Array(Array(Array(Int64)))) +[[[[1]]]] [[[['d']]]] +[(1,'a')] +[1] +[(1,'a')] [(1,'a')] +[(1,'a')] +[1] +[(1,'a')] 1 +[(1,'a')] [1] +[1] +[1] +[1] +[1] 1 ['a'] 1 ['a'] +[(1,'a')] +[1] +[1] +[(1,'a')] +[1] +[('a',1)] +1 [1] ['a'] ['a'] [1] +[(1,'a')] +[1] +[1] +[(1,'a')] +[1] +[('a',1)] +1 [1] ['a'] 1 ['a'] [1] +(1,'s') +(1,'s') 1 +1 +((((1,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((2,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 1 (1,'a') 1 ('a',1) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 (1,'a') ('a',1) +(1,'a') +1 +1 +(1,'a') +1 +('a',1) +1 (1,'a') 1 ('a',1) +((((1,'s'),'s'),'s'),'s') +((((1,'s'),'s'),'s'),'s') +((((2,'s'),'s'),'s'),'s') +((((2,'s'),'s'),'s'),'s') +((1,'s'),'s') +((1,'s'),'s') +((2,'s'),'s') +((2,'s'),'s') +1 +1 +2 +2 +((((1,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((2,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((((3,'s'),'s'),'s'),'s') Tuple(Tuple(Tuple(Tuple(Int64, String), String), String), String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 Nullable(UInt32) +2 Nullable(UInt32) +\N Nullable(UInt32) +(((1,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +(((2,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +(((3,'s'),'s'),'s') s Tuple(Tuple(Tuple(Int64, String), String), String) String +((1,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((2,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 Nullable(UInt32) +2 Nullable(UInt32) +\N Nullable(UInt32) +(((1,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((2,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((0,''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +((1,'s'),'s') s Tuple(Tuple(Int64, String), String) String +((2,'s'),'s') s Tuple(Tuple(Int64, String), String) String +((3,'s'),'s') s Tuple(Tuple(Int64, String), String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(Tuple(Int64, String), String) +((2,'s'),'s') Tuple(Tuple(Int64, String), String) +((3,'s'),'s') Tuple(Tuple(Int64, String), String) +1 Nullable(UInt32) +2 Nullable(UInt32) +\N Nullable(UInt32) +((((1,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((2,'s'),'s'),'s'),'s') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((((0,''),''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String),\n s String) +((1,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((2,'s'),'s') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) +1 Nullable(Int64) +2 Nullable(Int64) +3 Nullable(Int64) +(((1,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((2,'s'),'s'),'s') s Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +(((0,''),''),'') Tuple(\n t Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String),\n s String) String +((1,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((2,'s'),'s') s Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +((0,''),'') Tuple(\n t Tuple(\n t UInt32,\n s String),\n s String) String +(1,'s') s Tuple(\n t UInt32,\n s String) String +(2,'s') s Tuple(\n t UInt32,\n s String) String +(0,'') Tuple(\n t UInt32,\n s String) String +1 s UInt32 String +2 s UInt32 String +0 UInt32 String +[([([([(1,'d')],'d')],'s')],'s')] +[[[([(1,'d')],'d')]]] +[[[[1]]]] +[[([([(1,'d')],'d')],'s')]] Array(Array(Tuple(Array(Tuple(Array(Tuple(Int64, String)), String)), String))) +[[[([(1,'d')],'d')]]] Array(Array(Nested(t Nested(t Int32, s String), s String))) +[[[[1]]]] Array(Array(Array(Array(Int32)))) +[[[([(1,'d')],'d')]]] [['s']] Array(Array(Array(Tuple(Array(Tuple(Int64, String)), String)))) Array(Array(String)) +[[[[(1,'d')]]]] [[['d']]] Array(Array(Array(Array(Tuple(\n t Int32,\n s String))))) Array(Array(Array(String))) +[[[[1]]]] [[[['d']]]] Array(Array(Array(Array(Int32)))) Array(Array(Array(Array(String)))) +[([([([(1,'d')],'d')],'s')],'s')] Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String)),\n s String)) +[[([([(1,'d')],'d')],'s')]] Array(Nested(t Nested(t Nested(t Int32, s String), s String), s String)) +[[[([(1,'d')],'d')]]] Array(Array(Array(Tuple(Array(Tuple(Int64, String)), String)))) +[[[[1]]]] Array(Array(Array(Array(Int32)))) +[[([([(1,'d')],'d')],'s')]] ['s'] Array(Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String))) Array(String) +[[[([(1,'d')],'d')]]] [['s']] Array(Array(Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)))) Array(Array(String)) +[[[[(1,'d')]]]] [[['d']]] Array(Array(Array(Array(Tuple(Int64, String))))) Array(Array(Array(String))) +[[[[1]]]] [[[['d']]]] Array(Array(Array(Array(Int32)))) Array(Array(Array(Array(String)))) +[([([([(1,'d')],'d')],'s')],'s')] Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Array(Tuple(\n t Int32,\n s String)),\n s String)),\n s String)),\n s String)) +[[([([(1,'d')],'d')],'s')]] Array(Nested(t Nested(t Nested(t Int32, s String), s String), s String)) +[[[([(1,'d')],'d')]]] Array(Array(Nested(t Nested(t Int32, s String), s String))) +[[[[1]]]] Array(Array(Array(Array(Int64)))) +[[[[1]]]] [[[['d']]]] diff --git a/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.sql.j2 b/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.sql.j2 new file mode 100644 index 000000000000..c2f3c51b17ab --- /dev/null +++ b/tests/queries/0_stateless/02731_analyzer_join_resolve_nested.sql.j2 @@ -0,0 +1,219 @@ +DROP TABLE IF EXISTS ta; +DROP TABLE IF EXISTS tb; +DROP TABLE IF EXISTS ttta; +DROP TABLE IF EXISTS tttb; +DROP TABLE IF EXISTS na; +DROP TABLE IF EXISTS nb; +DROP TABLE IF EXISTS nnna; +DROP TABLE IF EXISTS nnnb; + +CREATE table ta (x Int32, t Tuple(t UInt32, s String)) ENGINE = MergeTree ORDER BY x; +INSERT INTO ta VALUES (1, (1, 'a')); + +CREATE table tb (x Int32, t Tuple(s String, t Int32)) ENGINE = MergeTree ORDER BY x; +INSERT INTO tb VALUES (1, ('a', 1)); + +CREATE table ttta (x Int32, t Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String)) ENGINE = MergeTree ORDER BY x; +INSERT INTO ttta VALUES (1, ((((1, 's'), 's'), 's'), 's')), (2, ((((2, 's'), 's'), 's'), 's')); + +CREATE table tttb (x Int32, t Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String)) ENGINE = MergeTree ORDER BY x; +INSERT INTO tttb VALUES (2, ((((2, 's'), 's'), 's'), 's')), (3, ((((3, 's'), 's'), 's'), 's')); + +CREATE table na (x Int32, t Nested(t UInt32, s String)) ENGINE = MergeTree ORDER BY x; +INSERT INTO na VALUES (1, [1], ['a']); + +CREATE table nb (x Int32, t Nested(s String, t Int32)) ENGINE = MergeTree ORDER BY x; +INSERT INTO nb VALUES (1, ['a'], [1]); + +CREATE TABLE nnna ( x UInt64, t Nested(t Nested(t Nested(t Nested(t Int32, s String), s String), s String), s String) ) ENGINE = MergeTree ORDER BY x; +INSERT INTO nnna VALUES (1, [[([([(1,'d')],'d')], 's')]], ['s']); + +CREATE TABLE nnnb ( x UInt64, t Nested(t Nested(t Nested(t Nested(t UInt32, s String), s String), s String), s String) ) ENGINE = MergeTree ORDER BY x; +INSERT INTO nnnb VALUES (1, [[([([(1,'d')],'d')], 's')]], ['s']); + +SET allow_experimental_analyzer = 1; + +{% for join_use_nulls in [0, 1] -%} + +SET join_use_nulls = {{ join_use_nulls }}; + +SELECT t FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT [(1, 'a')] :: Nested(t Int32, s String) AS t) AS t; +SELECT na.t.t FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT [(1, 'a')] :: Nested(t Int32, s String) AS t) AS t; +SELECT * FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT [(1, 'a')] :: Nested(t Int32, s String) AS t) AS t; + +SELECT t FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT 1 AS t) AS t; +SELECT na.t.t FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT 1 AS t) AS t; +SELECT * FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na, (SELECT 1 AS t) AS t; + +SELECT * FROM (SELECT [(1, 'a')] :: Nested(t UInt32, s String) AS t) AS na FULL JOIN (SELECT [1] :: Array(Int32) AS t) AS nb ON nb.t = na.t.t; + +SELECT t FROM na FULL JOIN nb USING (t.t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT t.t FROM na FULL JOIN nb USING (t.t); +SELECT na.t.t FROM na FULL JOIN nb USING (t.t); +SELECT na.t FROM na FULL JOIN nb USING (t.t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT nb.t.t FROM na FULL JOIN nb USING (t.t); +SELECT nb.t FROM na FULL JOIN nb USING (t.t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT * FROM na FULL JOIN nb USING (t.t); + +SELECT t FROM na FULL JOIN nb USING (x); +SELECT t.t FROM na FULL JOIN nb USING (x); +SELECT na.t.t FROM na FULL JOIN nb USING (x); +SELECT na.t FROM na FULL JOIN nb USING (x); +SELECT nb.t.t FROM na FULL JOIN nb USING (x); +SELECT nb.t FROM na FULL JOIN nb USING (x); +SELECT * FROM na FULL JOIN nb USING (x); + +SELECT t FROM na, nb; +SELECT t.t FROM na, nb; +SELECT na.t.t FROM na, nb; +SELECT na.t FROM na, nb; +SELECT nb.t.t FROM na, nb; +SELECT nb.t FROM na, nb; +SELECT * FROM na, nb; + +--- + +SELECT * FROM (SELECT (1, 's') :: Tuple(t Int32, s String) as t ) as na FULL JOIN (SELECT (1, 's') :: Tuple(t UInt32, s String) as t ) as nb USING (t); +SELECT * FROM (SELECT (1, 's') :: Tuple(t Int32, s String) as t ) as na, (SELECT 1 as t ) as t; + +SELECT t.t FROM (SELECT (1, 's') :: Tuple(t Int32, s String) as t ) as na, (SELECT 1 as t ) as t; + +SELECT t.t FROM (SELECT (1, 's') :: Tuple(t Int32, s String) as t ) as na FULL JOIN (SELECT (1, 's') :: Tuple(t UInt32, s String) as t ) as nb USING (t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT * FROM (SELECT (1, 's') :: Tuple(t Int32, s String) as t ) as na FULL JOIN (SELECT (1, 's') :: Tuple(t UInt32, s String) as t ) as nb USING (t.t); -- { serverError UNSUPPORTED_METHOD } + +SELECT t as e, toTypeName(e) FROM ( + SELECT ((((1, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String) as t +) ttta FULL JOIN ( + SELECT ((((2, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String) as t +) tttb USING (t.t); -- { serverError UNSUPPORTED_METHOD } + +SELECT t.t as e, toTypeName(e) FROM ( + SELECT ((((1, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String) as t +) ttta FULL JOIN ( + SELECT ((((2, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String) as t +) tttb USING (t.t); -- { serverError UNSUPPORTED_METHOD } + +SELECT t.t.t as e, toTypeName(e) FROM ( + SELECT ((((1, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String) as t +) ttta FULL JOIN ( + SELECT ((((2, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String) as t +) tttb USING (t.t); -- { serverError UNSUPPORTED_METHOD } + +SELECT t as e, toTypeName(e) FROM ( + SELECT ((((1, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String) as t +) ttta FULL JOIN ( + SELECT ((((2, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String) as t +) tttb USING (t); + +SELECT t.t as e, toTypeName(e) FROM ( + SELECT ((((1, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t UInt32, s String), s String), s String), s String) as t +) ttta FULL JOIN ( + SELECT ((((2, 's'), 's'), 's'), 's') :: Tuple(t Tuple(t Tuple(t Tuple(t Int32, s String), s String), s String), s String) as t +) tttb USING (t); -- { serverError AMBIGUOUS_IDENTIFIER } + +SELECT t FROM ta FULL JOIN tb USING (t.t); +SELECT t.t FROM ta FULL JOIN tb USING (t.t); +SELECT ta.t.t FROM ta FULL JOIN tb USING (t.t); +SELECT ta.t FROM ta FULL JOIN tb USING (t.t); +SELECT tb.t.t FROM ta FULL JOIN tb USING (t.t); +SELECT tb.t FROM ta FULL JOIN tb USING (t.t); +SELECT * FROM ta FULL JOIN tb USING (t.t); + +SELECT t FROM ta FULL JOIN tb USING (x); +SELECT t.t FROM ta FULL JOIN tb USING (x); +SELECT ta.t.t FROM ta FULL JOIN tb USING (x); +SELECT ta.t FROM ta FULL JOIN tb USING (x); +SELECT tb.t.t FROM ta FULL JOIN tb USING (x); +SELECT tb.t FROM ta FULL JOIN tb USING (x); +SELECT * FROM ta FULL JOIN tb USING (x); + +SELECT t FROM ta, tb; +SELECT t.t FROM ta, tb; +SELECT ta.t.t FROM ta, tb; +SELECT ta.t FROM ta, tb; +SELECT tb.t.t FROM ta, tb; +SELECT tb.t FROM ta, tb; +SELECT * FROM ta, tb; + +SELECT t FROM ttta, tttb; +SELECT t.t.t FROM ttta, tttb; +SELECT t.t.t.t.t FROM ttta, tttb; + +SELECT t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t); +SELECT t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t); + +SELECT t.*, t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t); +SELECT t.t.*, t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t); +SELECT t.t.t.*, t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t); +SELECT t.t.t.t.*, t.t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t); + +SELECT t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t); +SELECT t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t); + +SELECT t.*, t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t); +SELECT t.t.*, t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t); +SELECT t.t.t.*, t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t); +SELECT t.t.t.t.*, t.t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t); + +SELECT t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t); +SELECT t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t); + +SELECT t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t.t.t); +SELECT t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t.t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM ttta FULL JOIN tttb USING (t.t.t.t.t); + +SELECT t.*, t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t.t.t.t); +SELECT t.t.*, t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t.t.t.t); +SELECT t.t.t.*, t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t.t.t.t); +SELECT t.t.t.t.*, t.t.t.t.* APPLY toTypeName FROM ttta FULL JOIN tttb USING (t.t.t.t.t); + +SELECT t FROM nnna, nnnb; +SELECT t.t.t FROM nnna, nnnb; +SELECT t.t.t.t.t FROM nnna, nnnb; + +SELECT t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t); -- { serverError UNSUPPORTED_METHOD } +SELECT t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t); -- { serverError UNSUPPORTED_METHOD } +SELECT t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t); -- { serverError UNSUPPORTED_METHOD } +SELECT t.t.t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t); -- { serverError UNSUPPORTED_METHOD } + +SELECT t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t); +SELECT t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t); + +SELECT t.*, t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t); -- { serverError AMBIGUOUS_IDENTIFIER } +SELECT t.t.*, t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t); +SELECT t.t.t.*, t.t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t); +SELECT t.t.t.t.*, t.t.t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t); + +SELECT t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t); + +SELECT t.*, t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t.*, t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t.t.*, t.t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t.t); +SELECT t.t.t.t.*, t.t.t.t.* APPLY toTypeName FROM nnna FULL JOIN nnnb USING (t.t.t); + +SELECT t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t.t.t); +SELECT t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t.t.t); +SELECT t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t.t.t); +SELECT t.t.t.t.t as e, toTypeName(e) FROM nnna FULL JOIN nnnb USING (t.t.t.t.t); +SELECT t.t.t.t.* FROM nnna FULL JOIN nnnb USING (t.t.t.t.t); + +SELECT 1 FROM na FULL JOIN nb USING (t); -- { serverError UNSUPPORTED_METHOD } + +{% endfor -%} + +DROP TABLE IF EXISTS ta; +DROP TABLE IF EXISTS tb; +DROP TABLE IF EXISTS ttta; +DROP TABLE IF EXISTS tttb; +DROP TABLE IF EXISTS na; +DROP TABLE IF EXISTS nb; +DROP TABLE IF EXISTS nnna; +DROP TABLE IF EXISTS nnnb;