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

snuyanzin 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 25d62c555a [CALCITE-7753] `CorrelateProjectExtractor` corrupts plans 
with nested Correlates that reuse the same correlation id
25d62c555a is described below

commit 25d62c555af1814d0789f85ff5fc6b4489d52781
Author: Sergey Nuyanzin <[email protected]>
AuthorDate: Sat Aug 29 22:50:57 2026 +0200

    [CALCITE-7753] `CorrelateProjectExtractor` corrupts plans with nested 
Correlates that reuse the same correlation id
---
 .../calcite/sql2rel/CorrelateProjectExtractor.java |  6 ++++
 .../calcite/sql2rel/RelDecorrelatorTest.java       | 39 ++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/CorrelateProjectExtractor.java 
b/core/src/main/java/org/apache/calcite/sql2rel/CorrelateProjectExtractor.java
index 127f4e4879..a0c4747d2e 100644
--- 
a/core/src/main/java/org/apache/calcite/sql2rel/CorrelateProjectExtractor.java
+++ 
b/core/src/main/java/org/apache/calcite/sql2rel/CorrelateProjectExtractor.java
@@ -18,6 +18,7 @@
 
 import org.apache.calcite.rel.RelHomogeneousShuttle;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Correlate;
 import org.apache.calcite.rel.core.CorrelationId;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Project;
@@ -208,6 +209,11 @@ private static Set<RexNode> 
findCorrelationDependentCalls(CorrelationId corrId,
     SimpleCorrelationCollector finder = new SimpleCorrelationCollector(corrId);
     plan.accept(new RelHomogeneousShuttle() {
       @Override public RelNode visit(RelNode other) {
+        // Don't descend into a nested correlate that reuses this id: the refs 
below belong to it.
+        if (other instanceof Correlate
+            && ((Correlate) other).getCorrelationId().equals(corrId)) {
+          return other;
+        }
         if (other instanceof Project || other instanceof Filter) {
           other.accept(finder);
         }
diff --git 
a/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java 
b/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
index 80ef7f588a..2757a7a49b 100644
--- a/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
@@ -2548,4 +2548,43 @@ private RelNode decorrelateSql(String sql) {
         + "            LogicalTableScan(table=[[bookstore, authors]])\n";
     assertThat(after, hasTree(planAfter));
   }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7753";>[CALCITE-7753]
+   * CorrelateProjectExtractor corrupts plans with nested Correlates that reuse
+   * the same correlation id</a>. */
+  @Test void testNestedCorrelatesSharingCorrelationId() {
+    final RelBuilder builder = RelBuilder.create(config().build())
+        .transform(c -> c.withSimplify(false));
+    final Holder<@Nullable RexCorrelVariable> v = Holder.empty();
+    builder.scan("EMP").variable(v::set);
+    final RelNode emp = builder.build();
+
+    final RelNode inner = builder
+        .scan("EMP")
+        .scan("EMP")
+        .filter(builder.equals(builder.field(v.get(), "DEPTNO"), 
builder.field("DEPTNO")))
+        .correlate(JoinRelType.INNER, v.get().id, builder.field(2, 0, 
"DEPTNO"))
+        .filter(builder.isNull(builder.field(v.get(), "COMM")))
+        .build();
+
+    final RelNode before = builder
+        .push(emp)
+        .push(inner)
+        .correlate(JoinRelType.LEFT, v.get().id, builder.field(2, 0, "COMM"))
+        .build();
+    final String planBefore = ""
+        + "LogicalCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{6}])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[IS NULL($cor0.COMM)])\n"
+        + "    LogicalCorrelate(correlation=[$cor0], joinType=[inner], 
requiredColumns=[{7}])\n"
+        + "      LogicalTableScan(table=[[scott, EMP]])\n"
+        + "      LogicalFilter(condition=[=($cor0.DEPTNO, $7)])\n"
+        + "        LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(before, hasTree(planBefore));
+
+    RelDecorrelator.decorrelateQuery(before, builder,
+        RuleSets.ofList(Collections.emptyList()),
+        RuleSets.ofList(Collections.emptyList()));
+  }
 }

Reply via email to