You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2014/11/30 14:46:22 UTC

incubator-calcite git commit: [CALCITE-488] - Enumerable where Holder is custom class with a single field does not work Calcite tries to treat it as SCALAR due to "premature" JavaRowFormat.optimize

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 55aa593b7 -> 28fd9c8b9


[CALCITE-488] - Enumerable<Holder> where Holder is custom class with a single field does not work
Calcite tries to treat it as SCALAR due to "premature" JavaRowFormat.optimize


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

Branch: refs/heads/master
Commit: 28fd9c8b991ff30d3657bc56a0f2c1b84261aac4
Parents: 55aa593
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Sun Nov 30 16:45:38 2014 +0300
Committer: Vladimir Sitnikov <si...@gmail.com>
Committed: Sun Nov 30 16:45:38 2014 +0300

----------------------------------------------------------------------
 .../adapter/enumerable/EnumerableTableScan.java | 52 ++++++++------------
 .../adapter/enumerable/JavaRowFormat.java       | 31 ++++++++++++
 .../org/apache/calcite/util/BuiltInMethod.java  |  1 +
 .../calcite/test/ReflectiveSchemaTest.java      | 52 ++++++++++++++++++++
 4 files changed, 105 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/28fd9c8b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
index 7eb30f1..641d9cf 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.interpreter.Row;
-import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.linq4j.function.Function1;
@@ -25,6 +24,7 @@ import org.apache.calcite.linq4j.tree.Blocks;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
+import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
@@ -82,38 +82,17 @@ public class EnumerableTableScan
   }
 
   private Expression toRows(PhysType physType, Expression expression) {
+    JavaRowFormat oldFormat = format();
+    if (physType.getFormat() == oldFormat) {
+      return expression;
+    }
     final ParameterExpression row_ =
         Expressions.parameter(elementType, "row");
-    List<Expression> expressionList = new ArrayList<Expression>();
     final int fieldCount = table.getRowType().getFieldCount();
-    if (elementType == Row.class) {
-      // Convert Enumerable<Row> to Enumerable<SyntheticRecord>
-      for (int i = 0; i < fieldCount; i++) {
-        expressionList.add(
-            RexToLixTranslator.convert(
-                Expressions.call(row_,
-                    BuiltInMethod.ROW_VALUE.method,
-                    Expressions.constant(i)),
-                physType.getJavaFieldType(i)));
-      }
-    } else if (elementType == Object[].class
-        && rowType.getFieldCount() == 1) {
-      // Convert Enumerable<Object[]> to Enumerable<SyntheticRecord>
-      for (int i = 0; i < fieldCount; i++) {
-        expressionList.add(
-            RexToLixTranslator.convert(
-                Expressions.arrayIndex(row_, Expressions.constant(i)),
-                physType.getJavaFieldType(i)));
-      }
-    } else if (elementType == Object.class) {
-      if (!(physType.getJavaRowType()
-          instanceof JavaTypeFactoryImpl.SyntheticRecordType)) {
-        return expression;
-      }
+    List<Expression> expressionList = new ArrayList<Expression>(fieldCount);
+    for (int i = 0; i < fieldCount; i++) {
       expressionList.add(
-          RexToLixTranslator.convert(row_, physType.getJavaFieldType(0)));
-    } else {
-      return expression;
+          oldFormat.field(row_, i, physType.getJavaFieldType(i)));
     }
     return Expressions.call(expression,
         BuiltInMethod.SELECT.method,
@@ -124,9 +103,20 @@ public class EnumerableTableScan
   private JavaRowFormat format() {
     if (Object[].class.isAssignableFrom(elementType)) {
       return JavaRowFormat.ARRAY;
-    } else {
-      return JavaRowFormat.CUSTOM;
     }
+    if (Row.class.isAssignableFrom(elementType)) {
+      return JavaRowFormat.ROW;
+    }
+    int fieldCount = getRowType().getFieldCount();
+    if (fieldCount == 0) {
+      return JavaRowFormat.LIST;
+    }
+    if (fieldCount == 1 && (Object.class == elementType
+          || Primitive.is(elementType)
+          || Number.class.isAssignableFrom(elementType))) {
+      return JavaRowFormat.SCALAR;
+    }
+    return JavaRowFormat.CUSTOM;
   }
 
   @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/28fd9c8b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
index 1144444..15dba2a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.interpreter.Row;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.ExpressionType;
 import org.apache.calcite.linq4j.tree.Expressions;
@@ -166,6 +167,36 @@ public enum JavaRowFormat {
     }
   },
 
+  /**
+   * See {@link org.apache.calcite.interpreter.Row}
+   */
+  ROW {
+    @Override
+    Type javaRowClass(JavaTypeFactory typeFactory, RelDataType type) {
+      return Row.class;
+    }
+
+    @Override
+    Type javaFieldClass(JavaTypeFactory typeFactory, RelDataType type,
+        int index) {
+      return Object.class;
+    }
+
+    @Override
+    public Expression record(Type javaRowClass, List<Expression> expressions) {
+      return Expressions.call(BuiltInMethod.ROW_AS_COPY.method, expressions);
+    }
+
+    @Override
+    public Expression field(Expression expression, int field, Type fieldType) {
+      return RexToLixTranslator.convert(
+          Expressions.call(expression,
+              BuiltInMethod.ROW_VALUE.method,
+              Expressions.constant(field)),
+          fieldType);
+    }
+  },
+
   ARRAY {
     Type javaRowClass(
         JavaTypeFactory typeFactory,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/28fd9c8b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index b60e980..98e0007 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -113,6 +113,7 @@ public enum BuiltInMethod {
   DATA_CONTEXT_GET_ROOT_SCHEMA(DataContext.class, "getRootSchema"),
   JDBC_SCHEMA_DATA_SOURCE(JdbcSchema.class, "getDataSource"),
   ROW_VALUE(Row.class, "getObject", int.class),
+  ROW_AS_COPY(Row.class, "asCopy", Object[].class),
   RESULT_SET_ENUMERABLE_OF(ResultSetEnumerable.class, "of", DataSource.class,
       String.class, Function1.class),
   JOIN(ExtendedEnumerable.class, "join", Enumerable.class, Function1.class,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/28fd9c8b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
index 0ff6ebc..30e2fb5 100644
--- a/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
@@ -495,6 +495,40 @@ public class ReflectiveSchemaTest {
             + "empid=4; deptno=10; name=Abd; salary=0.0; commission=null\n");
   }
 
+  /** Table with single field as Integer[] */
+  @Ignore(
+      "java.lang.AssertionError RelDataTypeImpl.getFieldList(RelDataTypeImpl.java:99)")
+  @Test public void testArrayOfBoxedPrimitives() {
+    CalciteAssert.that()
+        .with("s", new CatchallSchema())
+        .query("select * from \"s\".\"primesBoxed\"")
+        .returnsUnordered("value=1", "value=3", "value=7");
+  }
+
+  /** Table with single field as int[] */
+  @Ignore(
+      "java.lang.AssertionError RelDataTypeImpl.getFieldList(RelDataTypeImpl.java:99)")
+  @Test public void testArrayOfPrimitives() {
+    CalciteAssert.that()
+        .with("s", new CatchallSchema())
+        .query("select * from \"s\".\"primes\"")
+        .returnsUnordered("value=1", "value=3", "value=7");
+  }
+
+  @Test public void testCustomBoxedScalar() {
+    CalciteAssert.that()
+        .with("s", new ReflectiveSchemaTest.CatchallSchema())
+        .query("select \"value\" from \"s\".\"primesCustomBoxed\"")
+        .returnsUnordered("value=1", "value=3", "value=5");
+  }
+
+  @Test public void testCustomBoxedSalarCalc() {
+    CalciteAssert.that()
+        .with("s", new ReflectiveSchemaTest.CatchallSchema())
+        .query("select \"value\"*2 \"value\" from \"s\".\"primesCustomBoxed\"")
+        .returnsUnordered("value=2", "value=6", "value=10");
+  }
+
   /** Extension to {@link Employee} with a {@code hireDate} column. */
   public static class EmployeeWithHireDate extends Employee {
     public final java.sql.Date hireDate;
@@ -638,6 +672,24 @@ public class ReflectiveSchemaTest {
       new Employee(3, 10, "Abc", 0f, null),
       new Employee(4, 10, "Abd", 0f, null),
     };
+
+    public final Integer[] primesBoxed = new Integer[]{1, 3, 5};
+
+    public final int[] primes = new int[]{1, 3, 5};
+
+    public final IntHolder[] primesCustomBoxed =
+        new IntHolder[]{new IntHolder(1), new IntHolder(3), new IntHolder(5)};
+  }
+
+  /**
+   * Custom java class that holds just a single field.
+   */
+  public static class IntHolder {
+    public final int value;
+
+    public IntHolder(int value) {
+      this.value = value;
+    }
   }
 
   /** Schema that contains a table with a date column. */