Skip to content

Commit 4b92f09

Browse files
authored
Merge pull request ClickHouse#79399 from ClickHouse/improve-correlated-subqueries
Follow up to ClickHouse#76078
2 parents bbb5a88 + ec5e9bd commit 4b92f09

File tree

8 files changed

+24
-12
lines changed

8 files changed

+24
-12
lines changed

src/Analyzer/QueryNode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ ColumnNodePtrWithHashSet QueryNode::getCorrelatedColumnsSet() const
124124
return result;
125125
}
126126

127-
void QueryNode::addCorrelatedColumn(ColumnNodePtr correlated_column)
127+
void QueryNode::addCorrelatedColumn(const QueryTreeNodePtr & correlated_column)
128128
{
129129
auto & correlated_columns = getCorrelatedColumns().getNodes();
130130
for (const auto & column : correlated_columns)

src/Analyzer/QueryNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ class QueryNode final : public IQueryTreeNode
645645

646646
ColumnNodePtrWithHashSet getCorrelatedColumnsSet() const;
647647

648-
void addCorrelatedColumn(ColumnNodePtr correlated_column);
648+
void addCorrelatedColumn(const QueryTreeNodePtr & correlated_column);
649649

650650
QueryTreeNodeType getNodeType() const override
651651
{

src/Analyzer/Resolve/QueryAnalyzer.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,17 +1382,17 @@ IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const
13821382
{
13831383
auto current = nodes_to_process.back();
13841384
nodes_to_process.pop_back();
1385-
if (ColumnNodePtr current_column = std::dynamic_pointer_cast<ColumnNode>(current))
1385+
if (current->getNodeType() == QueryTreeNodeType::COLUMN)
13861386
{
1387-
auto is_correlated_column = checkCorrelatedColumn(&scope, current_column);
1387+
auto is_correlated_column = checkCorrelatedColumn(&scope, current);
13881388
if (is_correlated_column && !scope.context->getSettingsRef()[Setting::allow_experimental_correlated_subqueries])
13891389
{
13901390
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
13911391
"Resolved identifier '{}' in parent scope to expression '{}' with correlated column '{}'"
13921392
" (Enable 'allow_experimental_correlated_subqueries' setting to allow correlated subqueries execution). In scope {}",
13931393
identifier_lookup.identifier.getFullName(),
13941394
resolved_identifier->formatASTForErrorMessage(),
1395-
current_column->getColumnName(),
1395+
current->as<ColumnNode>()->getColumnName(),
13961396
scope.scope_node->formatASTForErrorMessage());
13971397
}
13981398
}
@@ -2932,13 +2932,13 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
29322932
if (is_special_function_exists)
29332933
{
29342934
checkFunctionNodeHasEmptyNullsAction(*function_node_ptr);
2935-
/// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1).
29362935
auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0);
29372936
bool correlated_exists_subquery = exists_subquery_argument->getNodeType() == QueryTreeNodeType::QUERY
29382937
? exists_subquery_argument->as<QueryNode>()->isCorrelated()
29392938
: exists_subquery_argument->as<UnionNode>()->isCorrelated();
29402939
if (!correlated_exists_subquery)
29412940
{
2941+
/// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1).
29422942
auto constant_data_type = std::make_shared<DataTypeUInt64>();
29432943

29442944
auto in_subquery = std::make_shared<QueryNode>(Context::createCopy(scope.context));

src/Analyzer/UnionNode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ void UnionNode::removeUnusedProjectionColumns(const std::unordered_set<size_t> &
132132
}
133133
}
134134

135-
void UnionNode::addCorrelatedColumn(ColumnNodePtr correlated_column)
135+
void UnionNode::addCorrelatedColumn(const QueryTreeNodePtr & correlated_column)
136136
{
137137
auto & correlated_columns = getCorrelatedColumns().getNodes();
138138
for (const auto & column : correlated_columns)

src/Analyzer/UnionNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class UnionNode final : public IQueryTreeNode
193193
return children[correlated_columns_list_index]->as<ListNode &>();
194194
}
195195

196-
void addCorrelatedColumn(ColumnNodePtr correlated_column);
196+
void addCorrelatedColumn(const QueryTreeNodePtr & correlated_column);
197197

198198
QueryTreeNodeType getNodeType() const override
199199
{

src/Analyzer/Utils.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,13 @@ bool isCorrelatedQueryOrUnionNode(const QueryTreeNodePtr & node)
252252

253253
bool checkCorrelatedColumn(
254254
IdentifierResolveScope * scope_to_check,
255-
const ColumnNodePtr & column
255+
const QueryTreeNodePtr & column
256256
)
257257
{
258-
auto column_source = column->getColumnSource();
258+
auto * current_scope = scope_to_check;
259+
chassert(column->getNodeType() == QueryTreeNodeType::COLUMN);
260+
auto * column_node = column->as<ColumnNode>();
261+
auto column_source = column_node->getColumnSource();
259262

260263
/// The case of lambda argument. Example:
261264
/// arrayMap(X -> X + Y, [0])
@@ -283,7 +286,11 @@ bool checkCorrelatedColumn(
283286
scope_to_check = scope_to_check->parent_scope;
284287
}
285288
if (!scope_to_check)
286-
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot find the original scope of the column");
289+
throw Exception(
290+
ErrorCodes::LOGICAL_ERROR,
291+
"Cannot find the original scope of the column '{}'. Current scope: {}",
292+
column_node->getColumnName(),
293+
current_scope->scope_node->formatASTForErrorMessage());
287294

288295
return is_correlated;
289296
}

src/Analyzer/Utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ bool isCorrelatedQueryOrUnionNode(const QueryTreeNodePtr & node);
7272
*/
7373
bool checkCorrelatedColumn(
7474
IdentifierResolveScope * scope_to_check,
75-
const ColumnNodePtr & column
75+
const QueryTreeNodePtr & column
7676
);
7777

7878
DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node);

src/Planner/CollectTableExpressionData.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ class CollectSourceColumnsVisitor : public InDepthQueryTreeVisitorWithContext<Co
4949

5050
if (isExistsFunction(node))
5151
{
52+
/// Add used in correlated subquery columns to the table expression data.
53+
/// These columns can be used only by correlated subquery, but still they
54+
/// must be read by query plan for current query.
55+
///
56+
/// Example: SELECT 1 FROM table as t WHERE EXISTS (SELECT * FROM numbers(10) WHERE t.id = number);
5257
auto * function_node = node->as<FunctionNode>();
5358
const auto & subquery_argument = function_node->getArguments().getNodes().front();
5459
auto * query_node = subquery_argument->as<QueryNode>();

0 commit comments

Comments
 (0)