You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by za...@apache.org on 2021/06/11 12:26:58 UTC

[calcite] branch master updated: [CALCITE-4619] `Full join` plan cannot be executed in MySQL (Jiasen Sheng)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new e5477e7  [CALCITE-4619] `Full join` plan cannot be executed in MySQL (Jiasen Sheng)
e5477e7 is described below

commit e5477e7cda4ed9747d970b830d1fe9c53c49f2f3
Author: shengjiasen <an...@gmail.com>
AuthorDate: Wed Jun 9 19:07:24 2021 +0800

    [CALCITE-4619] `Full join` plan cannot be executed in MySQL (Jiasen Sheng)
    
    Close apache/calcite#2430
---
 .../org/apache/calcite/adapter/jdbc/JdbcRules.java |  7 +++++++
 .../java/org/apache/calcite/sql/SqlDialect.java    |  8 ++++++++
 .../apache/calcite/sql/dialect/H2SqlDialect.java   |  5 +++++
 .../calcite/sql/dialect/MysqlSqlDialect.java       |  5 +++++
 .../org/apache/calcite/test/JdbcAdapterTest.java   | 23 ++++++++++++++++++++++
 5 files changed, 48 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index d173472..c6adeb6 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -24,6 +24,7 @@ import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelRule;
 import org.apache.calcite.plan.RelTraitSet;
@@ -361,6 +362,12 @@ public class JdbcRules {
         return false;
       }
     }
+
+    @Override public boolean matches(RelOptRuleCall call) {
+      Join join = call.rel(0);
+      JoinRelType joinType = join.getJoinType();
+      return ((JdbcConvention) getOutConvention()).dialect.supportsJoinType(joinType);
+    }
   }
 
   /** Join operator implemented in JDBC convention. */
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index 3bbdb90..fdb69fd 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -22,6 +22,7 @@ import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.config.NullCollation;
 import org.apache.calcite.linq4j.function.Experimental;
 import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
@@ -1004,6 +1005,13 @@ public class SqlDialect {
     return false;
   }
 
+  /**
+   * Returns whether this dialect support the specified type of join.
+   */
+  public boolean supportsJoinType(JoinRelType joinType) {
+    return true;
+  }
+
   /** Returns how NULL values are sorted if an ORDER BY item does not contain
    * NULLS ASCENDING or NULLS DESCENDING. */
   public NullCollation getNullCollation() {
diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/H2SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/H2SqlDialect.java
index 18c086d..1721971 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/H2SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/H2SqlDialect.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql.dialect;
 
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.sql.SqlDialect;
 
 /**
@@ -40,4 +41,8 @@ public class H2SqlDialect extends SqlDialect {
   @Override public boolean supportsWindowFunctions() {
     return false;
   }
+
+  @Override public boolean supportsJoinType(JoinRelType joinType) {
+    return joinType != JoinRelType.FULL;
+  }
 }
diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java
index 8667f1a..be1c8ef 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.Casing;
 import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.config.NullCollation;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
@@ -322,6 +323,10 @@ public class MysqlSqlDialect extends SqlDialect {
     }
   }
 
+  @Override public boolean supportsJoinType(JoinRelType joinType) {
+    return joinType != JoinRelType.FULL;
+  }
+
   private static TimeUnit validate(TimeUnit timeUnit) {
     switch (timeUnit) {
     case MICROSECOND:
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index ebc2ee0..4607667 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -1045,6 +1045,29 @@ class JdbcAdapterTest {
         .planHasSql("SELECT \"EMPNO\", \"ENAME\"\nFROM \"SCOTT\".\"EMP\"\nWHERE \"EMPNO\" = ?");
   }
 
+  /**
+   * Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-4619">[CALCITE-4619]
+   * "Full join" generates an incorrect execution plan under mysql</a>. */
+  @Test void testFullJoinNonSupportedDialect() {
+    CalciteAssert.model(JdbcTest.SCOTT_MODEL)
+        .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.H2
+            || CalciteAssert.DB == CalciteAssert.DatabaseInstance.MYSQL)
+        .query("select empno, ename, e.deptno, dname\n"
+            + "from scott.emp e full join scott.dept d\n"
+            + "on e.deptno = d.deptno")
+        .explainContains("PLAN=EnumerableCalc(expr#0..4=[{inputs}], proj#0..2=[{exprs}],"
+            + " DNAME=[$t4])\n"
+            + "  EnumerableHashJoin(condition=[=($2, $3)], joinType=[full])\n"
+            + "    JdbcToEnumerableConverter\n"
+            + "      JdbcProject(EMPNO=[$0], ENAME=[$1], DEPTNO=[$7])\n"
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "    JdbcToEnumerableConverter\n"
+            + "      JdbcProject(DEPTNO=[$0], DNAME=[$1])\n"
+            + "        JdbcTableScan(table=[[SCOTT, DEPT]])")
+        .runs();
+  }
+
   /** Acquires a lock, and releases it when closed. */
   static class LockWrapper implements AutoCloseable {
     private final Lock lock;