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 2017/11/16 06:47:51 UTC

calcite git commit: [CALCITE-2039] AssertionError when pushing project to ProjectableFilterableTable

Repository: calcite
Updated Branches:
  refs/heads/master f7933c7cb -> 051809b4d


[CALCITE-2039] AssertionError when pushing project to ProjectableFilterableTable

Test case from Enrico Olivelli.


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

Branch: refs/heads/master
Commit: 051809b4dc580bda04c401e861a62b52553c2418
Parents: f7933c7
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Nov 15 17:17:17 2017 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Nov 15 17:17:17 2017 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/rel/core/Project.java    |   3 +
 .../apache/calcite/test/ScannableTableTest.java |  24 ++++
 .../apache/calcite/tools/FrameworksTest.java    | 143 +++++++++++++++++++
 3 files changed, 170 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/051809b4/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index 953eb8e..c3a2c2b 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -273,6 +273,9 @@ public abstract class Project extends SingleRel {
    */
   public static Mappings.TargetMapping getMapping(int inputFieldCount,
       List<? extends RexNode> projects) {
+    if (inputFieldCount < projects.size()) {
+      return null; // surjection is not possible
+    }
     Mappings.TargetMapping mapping =
         Mappings.create(MappingType.INVERSE_SURJECTION,
             inputFieldCount, projects.size());

http://git-wip-us.apache.org/repos/asf/calcite/blob/051809b4/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
index 7065f1f..ae18bc6 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -319,6 +319,30 @@ public class ScannableTableTest {
   }
 
   /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-2039">[CALCITE-2039]
+   * AssertionError when pushing project to ProjectableFilterableTable</a>.
+   * Cannot push down a project if it is not a permutation of columns; in this
+   * case, it contains a literal. */
+  @Test public void testCannotPushProject() throws Exception {
+    final StringBuilder buf = new StringBuilder();
+    final Table table = new BeatlesProjectableFilterableTable(buf, true);
+    final String explain = "PLAN="
+        + "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[3], k=[$t2], j=[$t1], "
+        + "i=[$t0], EXPR$3=[$t3])\n"
+        + "  EnumerableInterpreter\n"
+        + "    BindableTableScan(table=[[s, beatles]])";
+    CalciteAssert.that()
+        .with(newSchema("s", "beatles", table))
+        .query("select \"k\",\"j\",\"i\",3 from \"s\".\"beatles\"")
+        .explainContains(explain)
+        .returnsUnordered("k=1940; j=John; i=4; EXPR$3=3",
+            "k=1940; j=Ringo; i=5; EXPR$3=3",
+            "k=1942; j=Paul; i=4; EXPR$3=3",
+            "k=1943; j=George; i=6; EXPR$3=3");
+    assertThat(buf.toString(), is("returnCount=4"));
+  }
+
+  /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-1031">[CALCITE-1031]
    * In prepared statement, CsvScannableTable.scan is called twice</a>. */
   @Test public void testPrepared2() throws SQLException {

http://git-wip-us.apache.org/repos/asf/calcite/blob/051809b4/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
index 6a89266..684cfe7 100644
--- a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
@@ -16,17 +16,32 @@
  */
 package org.apache.calcite.tools;
 
+import org.apache.calcite.DataContext;
 import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
 import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.plan.ConventionTraitDef;
 import org.apache.calcite.plan.RelOptAbstractTable;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.plan.volcano.AbstractConverter;
+import org.apache.calcite.prepare.CalcitePrepareImpl;
+import org.apache.calcite.prepare.Prepare;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelDistributionTraitDef;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.TableModify;
 import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
@@ -34,10 +49,15 @@ import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ModifiableTable;
 import org.apache.calcite.schema.Path;
+import org.apache.calcite.schema.ProjectableFilterableTable;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.schema.Statistic;
+import org.apache.calcite.schema.Statistics;
 import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.AbstractTable;
 import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SqlExplainFormat;
@@ -45,15 +65,23 @@ import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.dialect.AnsiSqlDialect;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
 
 import org.junit.Test;
 
+import java.lang.reflect.Type;
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
@@ -279,6 +307,121 @@ public class FrameworksTest {
         });
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-2039">[CALCITE-2039]
+   * AssertionError when pushing project to ProjectableFilterableTable</a>
+   * using UPDATE via {@link Frameworks}. */
+  @Test public void testUpdate() throws Exception {
+    Table table = new TableImpl();
+    final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
+    SchemaPlus schema = rootSchema.add("x", new AbstractSchema());
+    schema.add("MYTABLE", table);
+    List<RelTraitDef> traitDefs = new ArrayList<>();
+    traitDefs.add(ConventionTraitDef.INSTANCE);
+    traitDefs.add(RelDistributionTraitDef.INSTANCE);
+    SqlParser.Config parserConfig =
+        SqlParser.configBuilder(SqlParser.Config.DEFAULT)
+            .setCaseSensitive(false)
+            .build();
+
+    final FrameworkConfig config = Frameworks.newConfigBuilder()
+        .parserConfig(parserConfig)
+        .defaultSchema(schema)
+        .traitDefs(traitDefs)
+        // define the rules you want to apply
+        .ruleSets(
+            RuleSets.ofList(AbstractConverter.ExpandConversionRule.INSTANCE))
+        .programs(Programs.ofRules(Programs.RULE_SET))
+        .build();
+    executeQuery(config, " UPDATE MYTABLE set id=7 where id=1",
+        CalcitePrepareImpl.DEBUG);
+  }
+
+  private void executeQuery(FrameworkConfig config,
+      @SuppressWarnings("SameParameterValue") String query, boolean debug)
+      throws RelConversionException, SqlParseException, ValidationException {
+    Planner planner = Frameworks.getPlanner(config);
+    if (debug) {
+      System.out.println("Query:" + query);
+    }
+    SqlNode n = planner.parse(query);
+    n = planner.validate(n);
+    RelNode root = planner.rel(n).project();
+    if (debug) {
+      System.out.println(
+          RelOptUtil.dumpPlan("-- Logical Plan", root, SqlExplainFormat.TEXT,
+              SqlExplainLevel.DIGEST_ATTRIBUTES));
+    }
+    RelOptCluster cluster = root.getCluster();
+    final RelOptPlanner optPlanner = cluster.getPlanner();
+
+    RelTraitSet desiredTraits  =
+        cluster.traitSet().replace(EnumerableConvention.INSTANCE);
+    final RelNode newRoot = optPlanner.changeTraits(root, desiredTraits);
+    if (debug) {
+      System.out.println(
+          RelOptUtil.dumpPlan("-- Mid Plan", newRoot, SqlExplainFormat.TEXT,
+              SqlExplainLevel.DIGEST_ATTRIBUTES));
+    }
+    optPlanner.setRoot(newRoot);
+    RelNode bestExp = optPlanner.findBestExp();
+    if (debug) {
+      System.out.println(
+          RelOptUtil.dumpPlan("-- Best Plan", bestExp, SqlExplainFormat.TEXT,
+              SqlExplainLevel.DIGEST_ATTRIBUTES));
+    }
+  }
+
+  /** Modifiable, filterable table. */
+  private static class TableImpl extends AbstractTable
+      implements ModifiableTable, ProjectableFilterableTable {
+    TableImpl() {}
+
+    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+      return typeFactory.builder()
+          .add("id", typeFactory.createSqlType(SqlTypeName.INTEGER))
+          .add("name", typeFactory.createSqlType(SqlTypeName.INTEGER))
+          .build();
+    }
+
+    public Statistic getStatistic() {
+      return Statistics.of(15D,
+          ImmutableList.of(ImmutableBitSet.of(0)),
+          ImmutableList.<RelCollation>of());
+    }
+
+    public Enumerable<Object[]> scan(DataContext root, List<RexNode> filters,
+        int[] projects) {
+      throw new UnsupportedOperationException();
+    }
+
+    public Collection getModifiableCollection() {
+      throw new UnsupportedOperationException();
+    }
+
+    public TableModify toModificationRel(RelOptCluster cluster,
+        RelOptTable table, Prepare.CatalogReader catalogReader, RelNode child,
+        TableModify.Operation operation, List<String> updateColumnList,
+        List<RexNode> sourceExpressionList, boolean flattened) {
+      return LogicalTableModify.create(table, catalogReader, child, operation,
+          updateColumnList, sourceExpressionList, flattened);
+    }
+
+    public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
+        SchemaPlus schema, String tableName) {
+      throw new UnsupportedOperationException();
+    }
+
+    public Type getElementType() {
+      return Object.class;
+    }
+
+    public Expression getExpression(SchemaPlus schema, String tableName,
+        Class clazz) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
   /** Dummy type system, similar to Hive's, accessed via an INSTANCE member. */
   public static class HiveLikeTypeSystem extends RelDataTypeSystemImpl {
     public static final RelDataTypeSystem INSTANCE = new HiveLikeTypeSystem();