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

zhenchen 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 04eececf8d [CALCITE-7087] SQLite does not support RIGHT/FULL JOIN 
until version 3.39.0
04eececf8d is described below

commit 04eececf8d9547de355667899056c07f35e1205e
Author: Zhen Chen <[email protected]>
AuthorDate: Mon Dec 1 06:49:40 2025 +0800

    [CALCITE-7087] SQLite does not support RIGHT/FULL JOIN until version 3.39.0
---
 .../apache/calcite/rel/rel2sql/SqlImplementor.java |  4 +
 .../calcite/sql/dialect/SqliteSqlDialect.java      | 19 +++++
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 85 +++++++++++++++++++++-
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java 
b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index 8952736563..ece87d0b5c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -194,6 +194,10 @@ public final Result visitRoot(RelNode r) {
       rules.add(FullToLeftAndRightJoinRule.Config.DEFAULT.toRule());
     }
 
+    if (!this.dialect.supportsJoinType(JoinRelType.RIGHT)) {
+      rules.add(CoreRules.JOIN_COMMUTE_RIGHT_TO_LEFT);
+    }
+
     if (!this.dialect.supportsOrderByLiteral()) {
       rules.add(CoreRules.SORT_REMOVE_CONSTANT_KEYS);
     }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java
index cd809efa8b..18e865f7e9 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/SqliteSqlDialect.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.sql.dialect;
 
 import org.apache.calcite.config.NullCollation;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlDialect;
 import org.apache.calcite.sql.SqlNode;
@@ -40,9 +41,27 @@ public class SqliteSqlDialect extends SqlDialect {
 
   public static final SqlDialect DEFAULT = new 
SqliteSqlDialect(DEFAULT_CONTEXT);
 
+  private final int majorVersion;
+  private final int minorVersion;
+
   /** Creates a SqliteSqlDialect. */
   public SqliteSqlDialect(SqlDialect.Context context) {
     super(context);
+    this.majorVersion = context.databaseMajorVersion();
+    this.minorVersion = context.databaseMinorVersion();
+  }
+
+  @Override public boolean supportsJoinType(JoinRelType joinType) {
+    // Unknown version means we conservatively assume support for no join types
+    if (majorVersion < 0) {
+      return false;
+    }
+
+    // For non-RIGHT/FULL join types, SQLite supports them in any version
+    // For RIGHT/FULL joins, SQLite added support in 3.39.0
+    // See: https://www.sqlite.org/releaselog/3_39_0.html
+    return (joinType != JoinRelType.RIGHT && joinType != JoinRelType.FULL)
+        || (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 39));
   }
 
   @Override public boolean supportsAliasedValues() {
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index fd13824c87..b96530fc2a 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -3164,10 +3164,86 @@ private SqlDialect nonOrdinalDialect() {
         .withHsqldb().ok(expectedHsqldb);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7087";>[CALCITE-7087]
+   * SQLite does not support RIGHT/FULL JOIN until version 3.39.0</a>. */
+  @Test void testSqliteRightJoinRewrittenToLeftOnOldVersion() {
+    final String query = "SELECT \"EMP\".\"ENAME\", \"DEPT\".\"DNAME\"\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "RIGHT JOIN \"scott\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = 
\"DEPT\".\"DEPTNO\"";
+    final String expected = "SELECT \"EMP\".\"ENAME\", \"DEPT\".\"DNAME\"\n"
+        + "FROM \"scott\".\"DEPT\"\n"
+        + "LEFT JOIN \"scott\".\"EMP\" ON \"DEPT\".\"DEPTNO\" = 
\"EMP\".\"DEPTNO\"";
+    sql(query)
+        .schema(CalciteAssert.SchemaSpec.SCOTT)
+        .withSQLite(3, 38)
+        .ok(expected);
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7087";>[CALCITE-7087]
+   * SQLite does not support RIGHT/FULL JOIN until version 3.39.0</a>. */
+  @Test void testSqliteRightJoinKeptOnNewerVersion() {
+    final String query = "SELECT \"EMP\".\"ENAME\", \"DEPT\".\"DNAME\"\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "RIGHT JOIN \"scott\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = 
\"DEPT\".\"DEPTNO\"";
+    sql(query)
+        .schema(CalciteAssert.SchemaSpec.SCOTT)
+        .withSQLite(3, 39)
+        .ok(query);
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7087";>[CALCITE-7087]
+   * SQLite does not support RIGHT/FULL JOIN until version 3.39.0</a>. */
+  @Test void testSqliteFullJoinThrowsOnOldVersion() {
+    final String query = "SELECT \"EMP\".\"ENAME\", \"DEPT\".\"DNAME\"\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "FULL JOIN \"scott\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = 
\"DEPT\".\"DEPTNO\"";
+    final String expected = "SELECT \"ENAME\", \"DNAME\"\n"
+        + "FROM (SELECT *\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "LEFT JOIN \"scott\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = 
\"DEPT\".\"DEPTNO\"\n"
+        + "UNION ALL\n"
+        + "SELECT *\n"
+        + "FROM (SELECT \"EMP0\".\"EMPNO\","
+        + " \"EMP0\".\"ENAME\","
+        + " \"EMP0\".\"JOB\","
+        + " \"EMP0\".\"MGR\","
+        + " \"EMP0\".\"HIREDATE\","
+        + " \"EMP0\".\"SAL\","
+        + " \"EMP0\".\"COMM\","
+        + " \"EMP0\".\"DEPTNO\","
+        + " \"DEPT0\".\"DEPTNO\" AS \"DEPTNO0\","
+        + " \"DEPT0\".\"DNAME\","
+        + " \"DEPT0\".\"LOC\"\n"
+        + "FROM \"scott\".\"DEPT\" AS \"DEPT0\"\n"
+        + "LEFT JOIN \"scott\".\"EMP\" AS \"EMP0\""
+        + " ON \"DEPT0\".\"DEPTNO\" = \"EMP0\".\"DEPTNO\") AS \"t\"\n"
+        + "WHERE \"t\".\"DEPTNO\" = \"t\".\"DEPTNO0\" IS NOT TRUE) AS \"t1\"";
+    sql(query)
+        .schema(CalciteAssert.SchemaSpec.SCOTT)
+        .withSQLite(3, 38)
+        .ok(expected);
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7087";>[CALCITE-7087]
+   * SQLite does not support RIGHT/FULL JOIN until version 3.39.0</a>. */
+  @Test void testSqliteFullJoinKeptOnNewerVersion() {
+    final String query = "SELECT *\n"
+        + "FROM \"scott\".\"EMP\"\n"
+        + "FULL JOIN \"scott\".\"DEPT\""
+        + " ON \"EMP\".\"DEPTNO\" = \"DEPT\".\"DEPTNO\"";
+    sql(query)
+        .schema(CalciteAssert.SchemaSpec.SCOTT)
+        .withSQLite(3, 39)
+        .ok(query);
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-3771";>[CALCITE-3771]
    * Support of TRIM function for SPARK dialect and improvement in HIVE 
Dialect</a>. */
-
   @Test void testHiveAndSparkTrimWithLeadingChar() {
     final String query = "SELECT TRIM(LEADING 'a' from 'abcd')\n"
         + "from \"foodmart\".\"reserve_employee\"";
@@ -11027,6 +11103,13 @@ Sql withSQLite() {
       return dialect(DatabaseProduct.SQLITE.getDialect());
     }
 
+    Sql withSQLite(int majorVersion, int minorVersion) {
+      return dialect(
+          new SqliteSqlDialect(SqliteSqlDialect.DEFAULT_CONTEXT
+              .withDatabaseMajorVersion(majorVersion)
+              .withDatabaseMinorVersion(minorVersion)));
+    }
+
     Sql withSybase() {
       return dialect(DatabaseProduct.SYBASE.getDialect());
     }

Reply via email to