You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/09/29 22:21:56 UTC

[3/3] incubator-calcite git commit: [CALCITE-893] Theta join in JdbcAdapter

 [CALCITE-893] Theta join in JdbcAdapter


Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/c2950eba
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/c2950eba
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/c2950eba

Branch: refs/heads/master
Commit: c2950ebaf83176e56d3cb4bf44ca74078dc45a83
Parents: 0f8b866
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 29 12:53:07 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 29 12:53:07 2015 -0700

----------------------------------------------------------------------
 .../calcite/adapter/jdbc/JdbcImplementor.java   | 54 ++++++++++++++++----
 .../apache/calcite/adapter/jdbc/JdbcRules.java  | 10 ++--
 .../apache/calcite/test/JdbcAdapterTest.java    | 16 ++++++
 3 files changed, 67 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c2950eba/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
index aa6c041..02f9e07 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcImplementor.java
@@ -29,7 +29,6 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlBinaryOperator;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlDataTypeSpec;
@@ -82,7 +81,7 @@ public class JdbcImplementor {
           SqlFunctionCategory.STRING);
 
   final SqlDialect dialect;
-  private final Set<String> aliasSet = new LinkedHashSet<String>();
+  private final Set<String> aliasSet = new LinkedHashSet<>();
 
   public JdbcImplementor(SqlDialect dialect, JavaTypeFactory typeFactory) {
     this.dialect = dialect;
@@ -105,8 +104,7 @@ public class JdbcImplementor {
   /** Creates a result based on a join. (Each join could contain one or more
    * relational expressions.) */
   public Result result(SqlNode join, Result leftResult, Result rightResult) {
-    final List<Pair<String, RelDataType>> list =
-        new ArrayList<Pair<String, RelDataType>>();
+    final List<Pair<String, RelDataType>> list = new ArrayList<>();
     list.addAll(leftResult.aliases);
     list.addAll(rightResult.aliases);
     return new Result(join, Expressions.list(Clause.FROM), null, list);
@@ -133,7 +131,7 @@ public class JdbcImplementor {
    * {@link RelNode}) into a {@link SqlNode} expression (within a SQL parse
    * tree). */
   public abstract class Context {
-    private final int fieldCount;
+    final int fieldCount;
 
     protected Context(int fieldCount) {
       this.fieldCount = fieldCount;
@@ -280,7 +278,7 @@ public class JdbcImplementor {
     }
 
     private List<SqlNode> toSql(RexProgram program, List<RexNode> operandList) {
-      final List<SqlNode> list = new ArrayList<SqlNode>();
+      final List<SqlNode> list = new ArrayList<>();
       for (RexNode rex : operandList) {
         list.add(toSql(program, rex));
       }
@@ -301,7 +299,7 @@ public class JdbcImplementor {
 
     /** Converts a call to an aggregate function to an expression. */
     public SqlNode toSql(AggregateCall aggCall) {
-      SqlOperator op = (SqlAggFunction) aggCall.getAggregation();
+      SqlOperator op = aggCall.getAggregation();
       if (op instanceof SqlSumEmptyIsZeroAggFunction) {
         op = SqlStdOperatorTable.SUM;
       }
@@ -332,6 +330,10 @@ public class JdbcImplementor {
       }
       return node;
     }
+
+    public JdbcImplementor implementor() {
+      return JdbcImplementor.this;
+    }
   }
 
   private static int computeFieldCount(
@@ -343,13 +345,23 @@ public class JdbcImplementor {
     return x;
   }
 
+  Context aliasContext(List<Pair<String, RelDataType>> aliases,
+      boolean qualified) {
+    return new AliasContext(aliases, qualified);
+  }
+
+  Context joinContext(Context leftContext, Context rightContext) {
+    return new JoinContext(leftContext, rightContext);
+  }
+
   /** Implementation of Context that precedes field references with their
    * "table alias" based on the current sub-query's FROM clause. */
   public class AliasContext extends Context {
     private final boolean qualified;
     private final List<Pair<String, RelDataType>> aliases;
 
-    public AliasContext(List<Pair<String, RelDataType>> aliases,
+    /** Creates an AliasContext; use {@link #aliasContext(List, boolean)}. */
+    private AliasContext(List<Pair<String, RelDataType>> aliases,
         boolean qualified) {
       super(computeFieldCount(aliases));
       this.aliases = aliases;
@@ -373,6 +385,28 @@ public class JdbcImplementor {
     }
   }
 
+  /** Context for translating ON clause of a JOIN from {@link RexNode} to
+   * {@link SqlNode}. */
+  class JoinContext extends Context {
+    private final JdbcImplementor.Context leftContext;
+    private final JdbcImplementor.Context rightContext;
+
+    /** Creates a JoinContext; use {@link #joinContext(Context, Context)}. */
+    private JoinContext(Context leftContext, Context rightContext) {
+      super(leftContext.fieldCount + rightContext.fieldCount);
+      this.leftContext = leftContext;
+      this.rightContext = rightContext;
+    }
+
+    public SqlNode field(int ordinal) {
+      if (ordinal < leftContext.fieldCount) {
+        return leftContext.field(ordinal);
+      } else {
+        return rightContext.field(ordinal - leftContext.fieldCount);
+      }
+    }
+  }
+
   /** Result of implementing a node. */
   public class Result {
     final SqlNode node;
@@ -439,7 +473,7 @@ public class JdbcImplementor {
           }
         };
       } else {
-        newContext = new AliasContext(aliases, aliases.size() > 1);
+        newContext = aliasContext(aliases, aliases.size() > 1);
       }
       return new Builder(rel, clauseList, select, newContext);
     }
@@ -495,7 +529,7 @@ public class JdbcImplementor {
      * Context deals with just one arm of a join, yet we wish to generate
      * a join condition that qualifies column names to disambiguate them. */
     public Context qualifiedContext() {
-      return new AliasContext(aliases, true);
+      return aliasContext(aliases, true);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c2950eba/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
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 c52d7f3..cd91515 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
@@ -392,7 +392,8 @@ public class JdbcRules {
       case LESS_THAN_OR_EQUAL:
         operands = ((RexCall) node).getOperands();
         op = ((RexCall) node).getOperator();
-        if (operands.get(0) instanceof RexInputRef
+        if (operands.size() == 2
+            && operands.get(0) instanceof RexInputRef
             && operands.get(1) instanceof RexInputRef) {
           final RexInputRef op0 = (RexInputRef) operands.get(0);
           final RexInputRef op1 = (RexInputRef) operands.get(1);
@@ -412,6 +413,9 @@ public class JdbcRules {
                 rightContext.field(op0.getIndex() - leftFieldCount));
           }
         }
+        final JdbcImplementor.Context joinContext =
+            leftContext.implementor().joinContext(leftContext, rightContext);
+        return joinContext.toSql(null, node);
       }
       throw new AssertionError(node);
     }
@@ -1155,9 +1159,9 @@ public class JdbcRules {
       final List<String> fields = getRowType().getFieldNames();
       final List<JdbcImplementor.Clause> clauses = Collections.singletonList(
           JdbcImplementor.Clause.SELECT);
+      final List<Pair<String, RelDataType>> pairs = ImmutableList.of();
       final JdbcImplementor.Context context =
-          implementor.new AliasContext(
-              Collections.<Pair<String, RelDataType>>emptyList(), false);
+          implementor.aliasContext(pairs, false);
       final List<SqlSelect> selects = new ArrayList<>();
       for (List<RexLiteral> tuple : tuples) {
         final List<SqlNode> selectList = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c2950eba/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
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 265990e..1bc8b0a 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -294,6 +294,22 @@ public class JdbcAdapterTest {
   }
 
   /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-893">[CALCITE-893]
+   * Theta join in JdbcAdapter</a>. */
+  @Test public void testJoinPlan() {
+    final String sql = "SELECT T1.\"brand_name\"\n"
+        + "FROM \"foodmart\".\"product\" AS T1\n"
+        + " INNER JOIN \"foodmart\".\"product_class\" AS T2\n"
+        + " ON T1.\"product_class_id\" = T2.\"product_class_id\"\n"
+        + "WHERE T2.\"product_department\" = 'Frozen Foods'\n"
+        + " OR T2.\"product_department\" = 'Baking Goods'\n"
+        + " AND T1.\"brand_name\" <> 'King'";
+    CalciteAssert.model(JdbcTest.FOODMART_MODEL)
+        .query(sql).runs()
+        .returnsCount(275);
+  }
+
+  /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-657">[CALCITE-657]
    * NullPointerException when executing JdbcAggregate implement method</a>. */
   @Test public void testJdbcAggregate() throws Exception {