This is an automated email from the ASF dual-hosted git repository.

silun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git

The following commit(s) were added to refs/heads/main by this push:
     new 2029412cdc [CALCITE-7401] Multi-level correlated subqueries cause an 
out-of-range error in the TopDownGeneralDecorrelator
2029412cdc is described below

commit 2029412cdcc0518e3dee3891c468501344e103e0
Author: Silun Dong <[email protected]>
AuthorDate: Wed Jan 28 23:07:48 2026 +0800

    [CALCITE-7401] Multi-level correlated subqueries cause an out-of-range 
error in the TopDownGeneralDecorrelator
---
 .../sql2rel/TopDownGeneralDecorrelator.java        | 23 +++++++++++++++-------
 core/src/test/resources/sql/new-decorr.iq          | 17 ++++++++++++++++
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/TopDownGeneralDecorrelator.java 
b/core/src/main/java/org/apache/calcite/sql2rel/TopDownGeneralDecorrelator.java
index 72401e3426..068ec441e5 100644
--- 
a/core/src/main/java/org/apache/calcite/sql2rel/TopDownGeneralDecorrelator.java
+++ 
b/core/src/main/java/org/apache/calcite/sql2rel/TopDownGeneralDecorrelator.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.sql2rel;
 
 import org.apache.calcite.linq4j.function.Experimental;
+import org.apache.calcite.plan.RelOptCostImpl;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.Strong;
 import org.apache.calcite.plan.hep.HepPlanner;
@@ -66,6 +67,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableMap;
@@ -122,10 +124,10 @@ public class TopDownGeneralDecorrelator implements 
ReflectiveVisitor {
   private final NavigableSet<CorDef> corDefs;
 
   // a map from RelNode to whether existing correlated expressions (according 
to corDefs).
-  private final Map<RelNode, Boolean> hasCorrelatedExpressions;
+  private final IdentityHashMap<RelNode, Boolean> hasCorrelatedExpressions;
 
   // a map from RelNode to its UnnestedQuery.
-  private final Map<RelNode, UnnestedQuery> mapRelToUnnestedQuery;
+  private final IdentityHashMap<RelNode, UnnestedQuery> mapRelToUnnestedQuery;
 
   private final boolean hasParent;
 
@@ -155,8 +157,8 @@ private TopDownGeneralDecorrelator(
       RelBuilder builder,
       boolean hasParent,
       @Nullable Set<CorDef> parentCorDefs,
-      @Nullable Map<RelNode, Boolean> parentHasCorrelatedExpressions,
-      @Nullable Map<RelNode, UnnestedQuery> parentMapRelToUnnestedQuery) {
+      @Nullable IdentityHashMap<RelNode, Boolean> 
parentHasCorrelatedExpressions,
+      @Nullable IdentityHashMap<RelNode, UnnestedQuery> 
parentMapRelToUnnestedQuery) {
     this.builder = builder;
     this.hasParent = hasParent;
     this.corDefs = new TreeSet<>();
@@ -164,10 +166,10 @@ private TopDownGeneralDecorrelator(
       this.corDefs.addAll(parentCorDefs);
     }
     this.hasCorrelatedExpressions = parentHasCorrelatedExpressions == null
-        ? new HashMap<>()
+        ? new IdentityHashMap<>()
         : parentHasCorrelatedExpressions;
     this.mapRelToUnnestedQuery = parentMapRelToUnnestedQuery == null
-        ? new HashMap<>()
+        ? new IdentityHashMap<>()
         : parentMapRelToUnnestedQuery;
   }
 
@@ -202,7 +204,14 @@ public static RelNode decorrelateQuery(RelNode rel, 
RelBuilder builder) {
                 CoreRules.FILTER_INTO_JOIN,
                 CoreRules.FILTER_CORRELATE))
         .build();
-    HepPlanner prePlanner = new HepPlanner(preProgram);
+    // In scenarios with nested correlations, equivalent nodes at different 
nesting levels bind
+    // to different outer variables and therefore have different decorrelation 
information. We
+    // need to avoid equivalent nodes in the plan sharing the same object (in 
the form of a DAG)
+    // to prevent corruption of entries in mapRelToUnnestedQuery and 
hasCorrelatedExpressions.
+    // So we set noDag config of HepPlanner to TRUE.
+    HepPlanner prePlanner =
+        new HepPlanner(preProgram, null, true,
+            null, RelOptCostImpl.FACTORY);
     prePlanner.setRoot(rel);
     RelNode preparedRel = prePlanner.findBestExp();
 
diff --git a/core/src/test/resources/sql/new-decorr.iq 
b/core/src/test/resources/sql/new-decorr.iq
index 529bca6d1b..9677fae713 100644
--- a/core/src/test/resources/sql/new-decorr.iq
+++ b/core/src/test/resources/sql/new-decorr.iq
@@ -235,4 +235,21 @@ select 1 in (values(null), (null));
 
 !ok
 
+# [CALCITE-7401] Multi-level correlated subqueries cause an out-of-range error 
in the TopDownGeneralDecorrelator
+# This case comes from sub-query.iq [CALCITE-5789]
+select deptno from dept d1 where exists (
+ select 1 from dept d2 where d2.deptno = d1.deptno and exists (
+  select 1 from dept d3 where d3.deptno = d2.deptno and d3.dname = d1.dname));
++--------+
+| DEPTNO |
++--------+
+|     10 |
+|     20 |
+|     30 |
+|     40 |
++--------+
+(4 rows)
+
+!ok
+
 # End new-decorr.iq

Reply via email to