diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/Passes/QueryAnalysisPass.cpp index 9c42c6621da..feca2980638 100644 --- a/src/Analyzer/Passes/QueryAnalysisPass.cpp +++ b/src/Analyzer/Passes/QueryAnalysisPass.cpp @@ -5730,6 +5730,8 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id subquery_node = resolved_identifier_node->as(); union_node = resolved_identifier_node->as(); + std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); + if (subquery_node) subquery_node->setIsCTE(false); else @@ -5738,10 +5740,21 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, Id IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); subquery_scope.subquery_depth = scope.subquery_depth + 1; + /// CTE is being resolved, it's required to forbid to resolve to it again + /// because recursive CTEs are not supported, e.g.: + /// + /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; + /// + /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, + /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. + cte_in_resolve_process.insert(cte_name); + if (subquery_node) resolveQuery(resolved_identifier_node, subquery_scope); else resolveUnion(resolved_identifier_node, subquery_scope); + + cte_in_resolve_process.erase(cte_name); } } }