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 c63f0be38e [CALCITE-5381] Add `convertCorrelateToJoin` config property 
to RelBuilder
c63f0be38e is described below

commit c63f0be38e2de8d52b2ef09dc43588d0cfe48b1b
Author: Sergey Nuyanzin <[email protected]>
AuthorDate: Sun Mar 5 18:40:00 2023 +0100

    [CALCITE-5381] Add `convertCorrelateToJoin` config property to RelBuilder
---
 .../java/org/apache/calcite/tools/RelBuilder.java  |  13 ++-
 .../org/apache/calcite/test/RelBuilderTest.java    | 103 ++++++++++++++++++---
 2 files changed, 102 insertions(+), 14 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java 
b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 66814f9cb5..23ca4fdda8 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -3889,11 +3889,14 @@ public class RelBuilder {
    * @throws IllegalArgumentException if the {@link CorrelationId} is used by 
left side or if the a
    *   {@link CorrelationId} is present and the {@link JoinRelType} is FULL or 
RIGHT.
    */
-  private static boolean checkIfCorrelated(Set<CorrelationId> variablesSet,
+  private boolean checkIfCorrelated(Set<CorrelationId> variablesSet,
       JoinRelType joinType, RelNode leftNode, RelNode rightRel) {
     if (variablesSet.size() != 1) {
       return false;
     }
+    if (!config.convertCorrelateToJoin()) {
+      return true;
+    }
     CorrelationId id = Iterables.getOnlyElement(variablesSet);
     if (!RelOptUtil.notContainsCorrelation(leftNode, id, Litmus.IGNORE)) {
       throw new IllegalArgumentException("variable " + id
@@ -4688,6 +4691,14 @@ public class RelBuilder {
 
     /** Sets {@link #aggregateUnique()}. */
     Config withAggregateUnique(boolean aggregateUnique);
+
+    /** Whether to convert Correlate to Join if correlation variable is 
unused. */
+    @Value.Default default boolean convertCorrelateToJoin() {
+      return true;
+    }
+
+    /** Sets {@link #convertCorrelateToJoin()}. */
+    Config withConvertCorrelateToJoin(boolean convertCorrelateToJoin);
   }
 
 }
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java 
b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 796e008550..b47b101877 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -96,6 +96,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import org.hamcrest.Matcher;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.function.Executable;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import java.lang.reflect.Method;
 import java.sql.Connection;
@@ -4202,8 +4204,24 @@ public class RelBuilderTest {
         root, hasTree(expected));
   }
 
-  @Test void testSemiCorrelatedViaJoin() {
-    RelNode root = buildCorrelateWithJoin(JoinRelType.SEMI);
+  @Test void testSimpleSemiCorrelateViaJoinWithoutConvertCorrelateToJoin() {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildSimpleCorrelateWithJoin(JoinRelType.SEMI, b);
+    final String expected = ""
+        + "LogicalCorrelate(correlation=[$cor0], joinType=[semi], 
requiredColumns=[{7}])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[=($cor0.DEPTNO, $0)])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(
+        "Join with correlate id but the id never used should be simplified to 
a join.",
+        f.apply(createBuilder(c -> c.withConvertCorrelateToJoin(false))), 
hasTree(expected));
+  }
+
+  @ParameterizedTest
+  @ValueSource(booleans = {true, false})
+  void testSemiCorrelatedViaJoin(boolean convertCorrelateToJoin) {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildCorrelateWithJoin(JoinRelType.SEMI, b);
     final String expected = ""
         + "LogicalCorrelate(correlation=[$cor0], joinType=[semi], 
requiredColumns=[{0, 7}])\n"
         + "  LogicalTableScan(table=[[scott, EMP]])\n"
@@ -4212,7 +4230,8 @@ public class RelBuilderTest {
         + "      LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(
         "Correlated semi joins should emmit a correlate with a filter on the 
right side.",
-        root, hasTree(expected));
+        f.apply(createBuilder(c -> 
c.withConvertCorrelateToJoin(convertCorrelateToJoin))),
+            hasTree(expected));
   }
 
   @Test void testSimpleAntiCorrelateViaJoin() {
@@ -4226,8 +4245,24 @@ public class RelBuilderTest {
         root, hasTree(expected));
   }
 
-  @Test void testAntiCorrelateViaJoin() {
-    RelNode root = buildCorrelateWithJoin(JoinRelType.ANTI);
+  @Test void testSimpleAntiCorrelateViaJoinWithoutConvertCorrelateToJoin() {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildSimpleCorrelateWithJoin(JoinRelType.ANTI, b);
+    final String expected = ""
+        + "LogicalCorrelate(correlation=[$cor0], joinType=[anti], 
requiredColumns=[{7}])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[=($cor0.DEPTNO, $0)])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(
+        "Join with correlate id but the id never used should be simplified to 
a join.",
+        f.apply(createBuilder(c -> c.withConvertCorrelateToJoin(false))), 
hasTree(expected));
+  }
+
+  @ParameterizedTest
+  @ValueSource(booleans = {true, false})
+  void testAntiCorrelateViaJoin(boolean convertCorrelateToJoin) {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildCorrelateWithJoin(JoinRelType.ANTI, b);
     final String expected = ""
         + "LogicalCorrelate(correlation=[$cor0], joinType=[anti], 
requiredColumns=[{0, 7}])\n"
         + "  LogicalTableScan(table=[[scott, EMP]])\n"
@@ -4236,7 +4271,9 @@ public class RelBuilderTest {
         + "      LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(
         "Correlated anti joins should emmit a correlate with a filter on the 
right side.",
-        root, hasTree(expected));  }
+        f.apply(createBuilder(c -> 
c.withConvertCorrelateToJoin(convertCorrelateToJoin))),
+            hasTree(expected));
+  }
 
   @Test void testSimpleLeftCorrelateViaJoin() {
     RelNode root = buildSimpleCorrelateWithJoin(JoinRelType.LEFT);
@@ -4249,8 +4286,26 @@ public class RelBuilderTest {
         root, hasTree(expected));
   }
 
-  @Test void testLeftCorrelateViaJoin() {
-    RelNode root = buildCorrelateWithJoin(JoinRelType.LEFT);
+  @Test void testSimpleLeftCorrelateViaJoinWithoutConvertCorrelateToJoin() {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildSimpleCorrelateWithJoin(JoinRelType.LEFT, b);
+    final String expected = ""
+        + "LogicalCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{7}])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[=($cor0.DEPTNO, $0)])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(
+        "Join with correlate id but the id never used should be simplified to 
a join.",
+        f.apply(createBuilder(c -> c.withConvertCorrelateToJoin(false))), 
hasTree(expected));
+  }
+
+  @ParameterizedTest
+  @ValueSource(booleans = {true, false})
+  void testLeftCorrelateViaJoin(boolean convertCorrelateToJoin) {
+    RelNode root =
+        buildCorrelateWithJoin(
+            JoinRelType.LEFT,
+            createBuilder(c -> 
c.withConvertCorrelateToJoin(convertCorrelateToJoin)));
     final String expected = ""
         + "LogicalCorrelate(correlation=[$cor0], joinType=[left], 
requiredColumns=[{0, 7}])\n"
         + "  LogicalTableScan(table=[[scott, EMP]])\n"
@@ -4272,8 +4327,23 @@ public class RelBuilderTest {
         root, hasTree(expected));
   }
 
-  @Test void testInnerCorrelateViaJoin() {
-    RelNode root = buildCorrelateWithJoin(JoinRelType.INNER);
+  @Test void testSimpleInnerCorrelateViaJoinWithoutConvertCorrelateToJoin() {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildSimpleCorrelateWithJoin(JoinRelType.INNER, b);
+    final String expected = ""
+        + "LogicalFilter(condition=[=($7, $8)])\n"
+        + "  LogicalCorrelate(correlation=[$cor0], joinType=[inner], 
requiredColumns=[{}])\n"
+        + "    LogicalTableScan(table=[[scott, EMP]])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat("Join with correlate id but never used should be simplified to 
a join.",
+        f.apply(createBuilder(c -> c.withConvertCorrelateToJoin(false))), 
hasTree(expected));
+  }
+
+  @ParameterizedTest
+  @ValueSource(booleans = {true, false})
+  void testInnerCorrelateViaJoin(boolean convertCorrelateToJoin) {
+    final Function<RelBuilder, RelNode> f = b ->
+        buildCorrelateWithJoin(JoinRelType.INNER, b);
     final String expected = ""
         + "LogicalFilter(condition=[=($7, $8)])\n"
         + "  LogicalCorrelate(correlation=[$cor0], joinType=[inner], 
requiredColumns=[{0}])\n"
@@ -4282,7 +4352,8 @@ public class RelBuilderTest {
         + "      LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(
         "Correlated inner joins should emmit a correlate with a filter on 
top.",
-        root, hasTree(expected));
+        f.apply(createBuilder(c -> 
c.withConvertCorrelateToJoin(convertCorrelateToJoin))),
+            hasTree(expected));
   }
 
   @Test void testSimpleRightCorrelateViaJoinThrowsException() {
@@ -4310,7 +4381,10 @@ public class RelBuilderTest {
   }
 
   private static RelNode buildSimpleCorrelateWithJoin(JoinRelType type) {
-    final RelBuilder builder = RelBuilder.create(config().build());
+    return buildSimpleCorrelateWithJoin(type, 
RelBuilder.create(config().build()));
+  }
+
+  private static RelNode buildSimpleCorrelateWithJoin(JoinRelType type, 
RelBuilder builder) {
     final Holder<@Nullable RexCorrelVariable> v = Holder.empty();
     return builder
         .scan("EMP")
@@ -4324,7 +4398,10 @@ public class RelBuilderTest {
   }
 
   private static RelNode buildCorrelateWithJoin(JoinRelType type) {
-    final RelBuilder builder = RelBuilder.create(config().build());
+    return buildCorrelateWithJoin(type, RelBuilder.create(config().build()));
+  }
+
+  private static RelNode buildCorrelateWithJoin(JoinRelType type, RelBuilder 
builder) {
     final RexBuilder rexBuilder = builder.getRexBuilder();
     final Holder<@Nullable RexCorrelVariable> v = Holder.empty();
     return builder

Reply via email to