Merge pull request #65755 from ClickHouse/backport/24.3/64517

Backport #64517 to 24.3: Fixing aliases for GLOBAL IN
This commit is contained in:
Nikolai Kochetov 2024-11-13 19:01:41 +03:00 committed by GitHub
commit cfa4e62b77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 39 additions and 10 deletions

View File

@ -6534,6 +6534,7 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id
scope.scope_node->formatASTForErrorMessage()); scope.scope_node->formatASTForErrorMessage());
auto & table_node = node->as<TableNode &>(); auto & table_node = node->as<TableNode &>();
if (result_projection_names.empty())
result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted());
break; break;
@ -8242,7 +8243,10 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
{ {
auto node = node_with_duplicated_alias; auto node = node_with_duplicated_alias;
auto node_alias = node->getAlias(); auto node_alias = node->getAlias();
resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/);
/// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache.
/// See 02896_cyclic_aliases_crash.
resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, true /*allow_table_expression*/);
bool has_node_in_alias_table = false; bool has_node_in_alias_table = false;
@ -8251,7 +8255,16 @@ void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, Identifier
{ {
has_node_in_alias_table = true; has_node_in_alias_table = true;
if (!it->second->isEqual(*node)) bool matched = it->second->isEqual(*node);
if (!matched)
/// Table expression could be resolved as scalar subquery,
/// but for duplicating alias we allow table expression to be returned.
/// So, check constant node source expression as well.
if (const auto * constant_node = it->second->as<ConstantNode>())
if (const auto & source_expression = constant_node->getSourceExpression())
matched = source_expression->isEqual(*node);
if (!matched)
throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS,
"Multiple expressions {} and {} for alias {}. In scope {}", "Multiple expressions {} and {} for alias {}. In scope {}",
node->formatASTForErrorMessage(), node->formatASTForErrorMessage(),

View File

@ -320,6 +320,8 @@ QueryTreeNodePtr buildQueryTreeForShard(const PlannerContextPtr & planner_contex
auto replacement_map = visitor.getReplacementMap(); auto replacement_map = visitor.getReplacementMap();
const auto & global_in_or_join_nodes = visitor.getGlobalInOrJoinNodes(); const auto & global_in_or_join_nodes = visitor.getGlobalInOrJoinNodes();
QueryTreeNodePtrWithHashMap<TableNodePtr> global_in_temporary_tables;
for (const auto & global_in_or_join_node : global_in_or_join_nodes) for (const auto & global_in_or_join_node : global_in_or_join_nodes)
{ {
if (auto * join_node = global_in_or_join_node.query_node->as<JoinNode>()) if (auto * join_node = global_in_or_join_node.query_node->as<JoinNode>())
@ -364,15 +366,19 @@ QueryTreeNodePtr buildQueryTreeForShard(const PlannerContextPtr & planner_contex
if (in_function_node_type != QueryTreeNodeType::QUERY && in_function_node_type != QueryTreeNodeType::UNION && in_function_node_type != QueryTreeNodeType::TABLE) if (in_function_node_type != QueryTreeNodeType::QUERY && in_function_node_type != QueryTreeNodeType::UNION && in_function_node_type != QueryTreeNodeType::TABLE)
continue; continue;
auto & temporary_table_expression_node = global_in_temporary_tables[in_function_subquery_node];
if (!temporary_table_expression_node)
{
auto subquery_to_execute = in_function_subquery_node; auto subquery_to_execute = in_function_subquery_node;
if (subquery_to_execute->as<TableNode>()) if (subquery_to_execute->as<TableNode>())
subquery_to_execute = buildSubqueryToReadColumnsFromTableExpression(std::move(subquery_to_execute), planner_context->getQueryContext()); subquery_to_execute = buildSubqueryToReadColumnsFromTableExpression(subquery_to_execute, planner_context->getQueryContext());
auto temporary_table_expression_node = executeSubqueryNode(subquery_to_execute, temporary_table_expression_node = executeSubqueryNode(subquery_to_execute,
planner_context->getMutableQueryContext(), planner_context->getMutableQueryContext(),
global_in_or_join_node.subquery_depth); global_in_or_join_node.subquery_depth);
}
in_function_subquery_node = std::move(temporary_table_expression_node); replacement_map.emplace(in_function_subquery_node.get(), temporary_table_expression_node);
} }
else else
{ {

View File

@ -0,0 +1,4 @@
1 1
1
1 1
1

View File

@ -0,0 +1,6 @@
SET allow_experimental_analyzer=1;
SELECT 1 GLOBAL IN (SELECT 1) AS s, s FROM remote('127.0.0.{2,3}', system.one) GROUP BY 1;
SELECT 1 GLOBAL IN (SELECT 1) AS s FROM remote('127.0.0.{2,3}', system.one) GROUP BY 1;
SELECT 1 GLOBAL IN (SELECT 1) AS s, s FROM remote('127.0.0.{1,3}', system.one) GROUP BY 1;
SELECT 1 GLOBAL IN (SELECT 1) AS s FROM remote('127.0.0.{1,3}', system.one) GROUP BY 1;