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

mihaibudiu 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 d51ec640a8 [CALCITE-7543] RelBuilder.join should preserve variablesSet 
for RIGHT/FULL joins
d51ec640a8 is described below

commit d51ec640a81b6674945933af56d8a801e421834b
Author: Weihua Zhang <[email protected]>
AuthorDate: Mon May 25 10:31:45 2026 +0800

    [CALCITE-7543] RelBuilder.join should preserve variablesSet for RIGHT/FULL 
joins
---
 .../java/org/apache/calcite/tools/RelBuilder.java  |  20 ++--
 .../org/apache/calcite/test/RelBuilderTest.java    |  46 +++++---
 core/src/test/resources/sql/sub-query.iq           | 123 +++++++++++++++++++++
 3 files changed, 162 insertions(+), 27 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 9551c45395..cf9ccecdef 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -4465,21 +4465,17 @@ boolean isSimple() {
 
   /**
    * Checks for {@link CorrelationId}, then validates the id is not used on 
left,
-   * and finally checks if id is actually used on right.
+   * and finally checks whether the join should be converted to a {@link 
Correlate}.
    *
-   * @return true if a correlate id is present and used
+   * @return true if the join should be converted to a Correlate; false if it 
should remain a Join
    *
-   * @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.
+   * @throws IllegalArgumentException if the {@link CorrelationId} is used by 
left side
    */
   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
@@ -4490,12 +4486,14 @@ private boolean checkIfCorrelated(Set<CorrelationId> 
variablesSet,
     case ASOF:
     case RIGHT:
     case FULL:
-      throw new IllegalArgumentException("Correlated " + joinType + " join is 
not supported");
+      return false;
     default:
-      return !RelOptUtil.correlationColumns(
-          Iterables.getOnlyElement(variablesSet),
-          rightRel).isEmpty();
+      break;
+    }
+    if (!config.convertCorrelateToJoin()) {
+      return true;
     }
+    return !RelOptUtil.correlationColumns(id, rightRel).isEmpty();
   }
 
 
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 b54e08e26d..f1a4f1c271 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -5090,28 +5090,42 @@ void testInnerCorrelateViaJoin(boolean 
convertCorrelateToJoin) {
             hasTree(expected));
   }
 
-  @Test void testSimpleRightCorrelateViaJoinThrowsException() {
-    assertThrows(IllegalArgumentException.class,
-        () -> buildSimpleCorrelateWithJoin(JoinRelType.RIGHT),
-        "Right outer joins with correlated ids are invalid even if id is not 
used.");
+  @Test void testSimpleRightCorrelateViaJoin() {
+    RelNode root = buildSimpleCorrelateWithJoin(JoinRelType.RIGHT);
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $8)], joinType=[right], 
variablesSet=[[$cor0]])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(root, hasTree(expected));
   }
 
-  @Test void testSimpleFullCorrelateViaJoinThrowsException() {
-    assertThrows(IllegalArgumentException.class,
-        () -> buildSimpleCorrelateWithJoin(JoinRelType.FULL),
-        "Full outer joins with correlated ids are invalid even if id is not 
used.");
+  @Test void testSimpleFullCorrelateViaJoin() {
+    RelNode root = buildSimpleCorrelateWithJoin(JoinRelType.FULL);
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $8)], joinType=[full], 
variablesSet=[[$cor0]])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(root, hasTree(expected));
   }
 
-  @Test void testRightCorrelateViaJoinThrowsException() {
-    assertThrows(IllegalArgumentException.class,
-        () -> buildCorrelateWithJoin(JoinRelType.RIGHT),
-        "Right outer joins with correlated ids are invalid.");
+  @Test void testRightCorrelateViaJoin() {
+    RelNode root = buildCorrelateWithJoin(JoinRelType.RIGHT);
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $8)], joinType=[right], 
variablesSet=[[$cor0]])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[=($cor0.EMPNO, 'NaN')])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(root, hasTree(expected));
   }
 
-  @Test void testFullCorrelateViaJoinThrowsException() {
-    assertThrows(IllegalArgumentException.class,
-        () -> buildCorrelateWithJoin(JoinRelType.FULL),
-        "Full outer joins with correlated ids are invalid.");
+  @Test void testFullCorrelateViaJoin() {
+    RelNode root = buildCorrelateWithJoin(JoinRelType.FULL);
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $8)], joinType=[full], 
variablesSet=[[$cor0]])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalFilter(condition=[=($cor0.EMPNO, 'NaN')])\n"
+        + "    LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(root, hasTree(expected));
   }
 
   private static RelNode buildSimpleCorrelateWithJoin(JoinRelType type) {
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index a04c8634d2..2860493795 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -4975,6 +4975,129 @@ ORDER BY e1.empno, e1.deptno;
 
 !ok
 
+# [CALCITE-7543] RelBuilder.join should preserve variablesSet for RIGHT/FULL 
joins
+# this was validated using postgres
+SELECT empno
+FROM emp e
+RIGHT JOIN dept d
+  ON e.deptno = d.deptno
+ AND e.sal < (
+    SELECT MAX(e2.sal)
+    FROM emp e2
+    WHERE e2.deptno = d.deptno
+  )
+ORDER BY empno;
++-------+
+| EMPNO |
++-------+
+|  7369 |
+|  7499 |
+|  7521 |
+|  7566 |
+|  7654 |
+|  7782 |
+|  7844 |
+|  7876 |
+|  7900 |
+|  7934 |
+|       |
++-------+
+(11 rows)
+
+!ok
+
+SELECT empno
+FROM emp e
+FULL JOIN dept d
+  ON e.deptno = d.deptno
+ AND e.sal < (
+    SELECT MAX(e2.sal)
+    FROM emp e2
+    WHERE e2.deptno = d.deptno
+  )
+ORDER BY empno;
++-------+
+| EMPNO |
++-------+
+|  7369 |
+|  7499 |
+|  7521 |
+|  7566 |
+|  7654 |
+|  7698 |
+|  7782 |
+|  7788 |
+|  7839 |
+|  7844 |
+|  7876 |
+|  7900 |
+|  7902 |
+|  7934 |
+|       |
++-------+
+(15 rows)
+
+!ok
+
+SELECT empno
+FROM emp e
+RIGHT JOIN dept d
+  ON e.deptno = d.deptno
+ AND d.deptno <= ALL (
+    SELECT d2.deptno
+    FROM dept d2
+    WHERE d2.dname <> d.dname
+  )
+ORDER BY empno;
++-------+
+| EMPNO |
++-------+
+|  7782 |
+|  7839 |
+|  7934 |
+|       |
+|       |
+|       |
++-------+
+(6 rows)
+
+!ok
+
+SELECT empno
+FROM emp e
+FULL JOIN dept d
+  ON e.deptno = d.deptno
+ AND d.deptno <= ALL (
+    SELECT d2.deptno
+    FROM dept d2
+    WHERE d2.dname <> d.dname
+  )
+ORDER BY empno;
++-------+
+| EMPNO |
++-------+
+|  7369 |
+|  7499 |
+|  7521 |
+|  7566 |
+|  7654 |
+|  7698 |
+|  7782 |
+|  7788 |
+|  7839 |
+|  7844 |
+|  7876 |
+|  7900 |
+|  7902 |
+|  7934 |
+|       |
+|       |
+|       |
++-------+
+(17 rows)
+
+!ok
+
 # [CALCITE-6041] MAP sub-query gives NullPointerException
 # map size > 1
 SELECT map(SELECT empno, deptno from emp where deptno < 20);

Reply via email to