calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [1/2] incubator-calcite git commit: [CALCITE-445] Pull up filters rejected by a ProjectableFilterableTable
Date Sun, 22 Feb 2015 18:56:47 GMT
Repository: incubator-calcite
Updated Branches:
  refs/heads/master 1ae40b005 -> bd0b60617


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/rel/rules/FilterTableRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableRule.java
deleted file mode 100644
index f135dca..0000000
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableRule.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.rel.rules;
-
-import org.apache.calcite.DataContext;
-import org.apache.calcite.adapter.enumerable.EnumerableInterpreter;
-import org.apache.calcite.adapter.enumerable.EnumerableRel;
-import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.schema.FilterableTable;
-import org.apache.calcite.schema.ProjectableFilterableTable;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-import static org.apache.calcite.util.Static.RESOURCE;
-
-/**
- * Planner rule that pushes a filter into a scan of a {@link FilterableTable}
- * or {@link org.apache.calcite.schema.ProjectableFilterableTable}.
- */
-public class FilterTableRule extends RelOptRule {
-  private static final Predicate<TableScan> PREDICATE =
-      new Predicate<TableScan>() {
-        public boolean apply(TableScan scan) {
-          // We can only push filters into a FilterableTable or
-          // ProjectableFilterableTable.
-          final RelOptTable table = scan.getTable();
-          return table.unwrap(FilterableTable.class) != null
-              || table.unwrap(ProjectableFilterableTable.class) != null;
-        }
-      };
-
-  public static final FilterTableRule INSTANCE = new FilterTableRule();
-
-  //~ Constructors -----------------------------------------------------------
-
-  /** Creates a FilterTableRule. */
-  private FilterTableRule() {
-    super(
-        operand(Filter.class,
-            operand(EnumerableInterpreter.class,
-                operand(TableScan.class, null, PREDICATE, none()))));
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  // implement RelOptRule
-  public void onMatch(RelOptRuleCall call) {
-    final Filter filter = call.rel(0);
-    final EnumerableInterpreter interpreter = call.rel(1);
-    final TableScan scan = call.rel(2);
-    final FilterableTable filterableTable =
-        scan.getTable().unwrap(FilterableTable.class);
-    final ProjectableFilterableTable projectableFilterableTable =
-        scan.getTable().unwrap(ProjectableFilterableTable.class);
-
-    final FilterSplit filterSplit;
-    if (filterableTable != null) {
-      filterSplit = FilterSplit.of(filterableTable, filter.getCondition(),
-          null);
-    } else if (projectableFilterableTable != null) {
-      filterSplit = FilterSplit.of(projectableFilterableTable,
-          filter.getCondition(), null);
-    } else {
-      throw new AssertionError(scan.getTable());
-    }
-
-    // It's worth using the ProjectableFilterableTable interface even if it
-    // refused all filters.
-    final RelNode newFilter =
-        RelOptUtil.createFilter(interpreter.getInput(),
-            filterSplit.acceptedFilters, EnumerableRel.FILTER_FACTORY);
-    final RelNode newInterpreter =
-        new EnumerableInterpreter(interpreter.getCluster(),
-            interpreter.getTraitSet(), newFilter, 0.15d);
-    final RelNode residue =
-        RelOptUtil.createFilter(newInterpreter, filterSplit.rejectedFilters);
-    call.transformTo(residue);
-  }
-
-  /** Splits a filter condition into parts that can and cannot be
-   * handled by a {@link FilterableTable} or
-   * {@link ProjectableFilterableTable}. */
-  public static class FilterSplit {
-    public final ImmutableList<RexNode> acceptedFilters;
-    public final ImmutableList<RexNode> rejectedFilters;
-
-    public FilterSplit(ImmutableList<RexNode> acceptedFilters,
-        ImmutableList<RexNode> rejectedFilters) {
-      this.acceptedFilters = acceptedFilters;
-      this.rejectedFilters = rejectedFilters;
-    }
-
-    public static FilterSplit of(FilterableTable table,
-        RexNode condition, DataContext dataContext) {
-      final List<RexNode> filters = Lists.newArrayList();
-      RelOptUtil.decomposeConjunction(condition, filters);
-      final List<RexNode> originalFilters = ImmutableList.copyOf(filters);
-
-      final Enumerable<Object[]> enumerable =
-          table.scan(dataContext, filters);
-      return rest(originalFilters, filters, enumerable);
-    }
-
-    public static FilterSplit of(ProjectableFilterableTable table,
-        RexNode condition, DataContext dataContext) {
-      final List<RexNode> filters = Lists.newArrayList();
-      RelOptUtil.decomposeConjunction(condition, filters);
-      final List<RexNode> originalFilters = ImmutableList.copyOf(filters);
-
-      final Enumerable<Object[]> enumerable =
-          table.scan(dataContext, filters, null);
-      return rest(originalFilters, filters, enumerable);
-    }
-
-    private static FilterSplit rest(List<RexNode> originalFilters,
-        List<RexNode> filters,
-        Enumerable<Object[]> enumerable) {
-      if (enumerable == null) {
-        throw RESOURCE.filterableTableScanReturnedNull().ex();
-      }
-      final ImmutableList.Builder<RexNode> accepted = ImmutableList.builder();
-      final ImmutableList.Builder<RexNode> rejected = ImmutableList.builder();
-      for (RexNode originalFilter : originalFilters) {
-        if (filters.contains(originalFilter)) {
-          rejected.add(originalFilter);
-        } else {
-          accepted.add(originalFilter);
-        }
-      }
-      for (RexNode node : filters) {
-        if (!originalFilters.contains(node)) {
-          throw RESOURCE.filterableTableInventedFilter(node.toString()).ex();
-        }
-      }
-      return new FilterSplit(accepted.build(), rejected.build());
-    }
-  }
-}
-
-// End FilterTableRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java
new file mode 100644
index 0000000..b16d6b7
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.rel.rules;
+
+import org.apache.calcite.adapter.enumerable.EnumerableInterpreter;
+import org.apache.calcite.interpreter.Bindables;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.schema.FilterableTable;
+import org.apache.calcite.schema.ProjectableFilterableTable;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.Mappings;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Planner rule that converts
+ * a {@link org.apache.calcite.rel.core.Filter}
+ * on a {@link org.apache.calcite.rel.core.TableScan}
+ * of a {@link org.apache.calcite.schema.FilterableTable}
+ * or a {@link org.apache.calcite.schema.ProjectableFilterableTable}
+ * to a {@link org.apache.calcite.interpreter.Bindables.BindableTableScan}.
+ *
+ * <p>The {@link #INTERPRETER} variant allows an intervening
+ * {@link org.apache.calcite.adapter.enumerable.EnumerableInterpreter}.
+ *
+ * @see org.apache.calcite.rel.rules.ProjectTableScanRule
+ */
+public abstract class FilterTableScanRule extends RelOptRule {
+  public static final Predicate<TableScan> PREDICATE =
+      new Predicate<TableScan>() {
+        public boolean apply(TableScan scan) {
+          // We can only push filters into a FilterableTable or
+          // ProjectableFilterableTable.
+          final RelOptTable table = scan.getTable();
+          return table.unwrap(FilterableTable.class) != null
+              || table.unwrap(ProjectableFilterableTable.class) != null;
+        }
+      };
+
+  /** Rule that matches Filter on TableScan. */
+  public static final FilterTableScanRule INSTANCE =
+      new FilterTableScanRule(
+          operand(Filter.class,
+              operand(TableScan.class, null, PREDICATE, none())),
+          "FilterTableRule") {
+        public void onMatch(RelOptRuleCall call) {
+          final Filter filter = call.rel(0);
+          final TableScan scan = call.rel(1);
+          apply(call, filter, scan);
+        }
+      };
+
+  /** Rule that matches Filter on EnumerableInterpreter on TableScan. */
+  public static final FilterTableScanRule INTERPRETER =
+      new FilterTableScanRule(
+          operand(Filter.class,
+              operand(EnumerableInterpreter.class,
+                  operand(TableScan.class, null, PREDICATE, none()))),
+          "FilterTableRule:interpreter") {
+        public void onMatch(RelOptRuleCall call) {
+          final Filter filter = call.rel(0);
+          final TableScan scan = call.rel(2);
+          apply(call, filter, scan);
+        }
+      };
+
+  //~ Constructors -----------------------------------------------------------
+
+  /** Creates a FilterTableRule. */
+  protected FilterTableScanRule(RelOptRuleOperand operand, String description) {
+    super(operand, description);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  protected void apply(RelOptRuleCall call, Filter filter, TableScan scan) {
+    final ImmutableIntList projects;
+    final ImmutableList.Builder<RexNode> filters = ImmutableList.builder();
+    if (scan instanceof Bindables.BindableTableScan) {
+      final Bindables.BindableTableScan bindableScan =
+          (Bindables.BindableTableScan) scan;
+      filters.addAll(bindableScan.filters);
+      projects = bindableScan.projects;
+    } else {
+      projects = scan.identity();
+    }
+
+    final Mapping mapping = Mappings.target(projects,
+        scan.getTable().getRowType().getFieldCount());
+    filters.add(
+        RexUtil.apply(mapping, filter.getCondition()));
+
+    call.transformTo(
+        Bindables.BindableTableScan.create(scan.getCluster(), scan.getTable(),
+            filters.build(), projects));
+  }
+}
+
+// End FilterTableScanRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableRule.java
deleted file mode 100644
index 785cc26..0000000
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableRule.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.rel.rules;
-
-import org.apache.calcite.adapter.enumerable.EnumerableInterpreter;
-import org.apache.calcite.adapter.enumerable.EnumerableRel;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexInputRef;
-import org.apache.calcite.rex.RexLocalRef;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.rex.RexShuttle;
-import org.apache.calcite.schema.ProjectableFilterableTable;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-/**
- * Planner rule that pushes a project into a scan of a
- * {@link org.apache.calcite.schema.ProjectableFilterableTable}.
- *
- * @see org.apache.calcite.rel.rules.FilterTableRule
- */
-public abstract class ProjectTableRule extends RelOptRule {
-  private static final Predicate<TableScan> PREDICATE =
-      new Predicate<TableScan>() {
-        public boolean apply(TableScan scan) {
-          // We can only push projects into a ProjectableFilterableTable.
-          final RelOptTable table = scan.getTable();
-          return table.unwrap(ProjectableFilterableTable.class) != null;
-        }
-      };
-
-  public static final ProjectTableRule INSTANCE =
-      new ProjectTableRule(
-          operand(Project.class,
-              operand(EnumerableInterpreter.class,
-                  operand(TableScan.class, null, PREDICATE, none()))),
-          "ProjectTableRule:basic") {
-        @Override public void onMatch(RelOptRuleCall call) {
-          final Project project = call.rel(0);
-          final EnumerableInterpreter interpreter = call.rel(1);
-          final TableScan scan = call.rel(2);
-          final RelOptTable table = scan.getTable();
-          assert table.unwrap(ProjectableFilterableTable.class) != null;
-          apply(call, project, null, interpreter);
-        }
-      };
-
-  public static final ProjectTableRule INSTANCE2 =
-      new ProjectTableRule(
-          operand(Project.class,
-              operand(Filter.class,
-                  operand(EnumerableInterpreter.class,
-                      operand(TableScan.class, null, PREDICATE,
-                          none())))),
-          "ProjectTableRule:filter") {
-        @Override public void onMatch(RelOptRuleCall call) {
-          final Project project = call.rel(0);
-          final Filter filter = call.rel(1);
-          final EnumerableInterpreter interpreter = call.rel(2);
-          final TableScan scan = call.rel(3);
-          final RelOptTable table = scan.getTable();
-          assert table.unwrap(ProjectableFilterableTable.class) != null;
-          apply(call, project, filter, interpreter);
-        }
-      };
-
-  //~ Constructors -----------------------------------------------------------
-
-  /** Creates a FilterTableRule. */
-  private ProjectTableRule(RelOptRuleOperand operand, String description) {
-    super(operand, description);
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  protected void apply(RelOptRuleCall call, Project project,
-      Filter filter, EnumerableInterpreter interpreter) {
-    // Split the projects into column references and expressions on top of them.
-    // Creating a RexProgram is a convenient way to do this.
-    final RexBuilder rexBuilder = project.getCluster().getRexBuilder();
-    final RexProgram program = RexProgram.create(interpreter.getRowType(),
-        project.getProjects(), null, project.getRowType(), rexBuilder);
-    final List<Integer> projectOrdinals = Lists.newArrayList();
-    final List<RexNode> extraProjects;
-    if (program.getExprList().size()
-        == program.getInputRowType().getFieldCount()) {
-      // There are only field references, no non-trivial expressions.
-      for (RexLocalRef ref : program.getProjectList()) {
-        projectOrdinals.add(ref.getIndex());
-      }
-      extraProjects = null;
-    } else {
-      extraProjects = Lists.newArrayList();
-      RexShuttle shuttle = new RexShuttle() {
-        final List<RexInputRef> inputRefs = Lists.newArrayList();
-
-        @Override public RexNode visitInputRef(RexInputRef inputRef) {
-          final int source = inputRef.getIndex();
-          int target = projectOrdinals.indexOf(source);
-          final RexInputRef ref;
-          if (target < 0) {
-            target = projectOrdinals.size();
-            projectOrdinals.add(source);
-            ref = rexBuilder.makeInputRef(inputRef.getType(), target);
-            inputRefs.add(ref);
-          } else {
-            ref = inputRefs.get(target);
-          }
-          return ref;
-        }
-      };
-      for (RexNode node : project.getProjects()) {
-        extraProjects.add(node.accept(shuttle));
-      }
-    }
-
-    RelNode input = interpreter.getInput();
-    if (filter != null) {
-      input = RelOptUtil.createFilter(input, filter.getCondition(),
-          EnumerableRel.FILTER_FACTORY);
-    }
-    final RelNode newProject =
-        RelOptUtil.createProject(EnumerableRel.PROJECT_FACTORY, input,
-            projectOrdinals);
-    final RelNode newInterpreter =
-        new EnumerableInterpreter(interpreter.getCluster(),
-            interpreter.getTraitSet(), newProject, 0.15d);
-    final RelNode residue;
-    if (extraProjects != null) {
-      residue = RelOptUtil.createProject(newInterpreter, extraProjects,
-          project.getRowType().getFieldNames());
-    } else {
-      residue = newInterpreter;
-    }
-    call.transformTo(residue);
-  }
-}
-
-// End ProjectTableRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableScanRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableScanRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableScanRule.java
new file mode 100644
index 0000000..25cbe83
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectTableScanRule.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.rel.rules;
+
+import org.apache.calcite.adapter.enumerable.EnumerableInterpreter;
+import org.apache.calcite.interpreter.Bindables;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ProjectableFilterableTable;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.Mappings;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * Planner rule that converts a {@link Project}
+ * on a {@link org.apache.calcite.rel.core.TableScan}
+ * of a {@link org.apache.calcite.schema.ProjectableFilterableTable}
+ * to a {@link org.apache.calcite.interpreter.Bindables.BindableTableScan}.
+ *
+ * <p>The {@link #INTERPRETER} variant allows an intervening
+ * {@link org.apache.calcite.adapter.enumerable.EnumerableInterpreter}.
+ *
+ * @see FilterTableScanRule
+ */
+public abstract class ProjectTableScanRule extends RelOptRule {
+  public static final Predicate<TableScan> PREDICATE =
+      new Predicate<TableScan>() {
+        public boolean apply(TableScan scan) {
+          // We can only push projects into a ProjectableFilterableTable.
+          final RelOptTable table = scan.getTable();
+          return table.unwrap(ProjectableFilterableTable.class) != null;
+        }
+      };
+
+  /** Rule that matches Project on TableScan. */
+  public static final ProjectTableScanRule INSTANCE =
+      new ProjectTableScanRule(
+          operand(Project.class,
+              operand(TableScan.class, null, PREDICATE, none())),
+          "ProjectScanRule") {
+        @Override public void onMatch(RelOptRuleCall call) {
+          final Project project = call.rel(0);
+          final TableScan scan = call.rel(1);
+          apply(call, project, scan);
+        }
+      };
+
+  /** Rule that matches Project on EnumerableInterpreter on TableScan. */
+  public static final ProjectTableScanRule INTERPRETER =
+      new ProjectTableScanRule(
+          operand(Project.class,
+              operand(EnumerableInterpreter.class,
+                  operand(TableScan.class, null, PREDICATE, none()))),
+          "ProjectScanRule:interpreter") {
+        @Override public void onMatch(RelOptRuleCall call) {
+          final Project project = call.rel(0);
+          final TableScan scan = call.rel(2);
+          apply(call, project, scan);
+        }
+      };
+
+  //~ Constructors -----------------------------------------------------------
+
+  /** Creates a ProjectScanRule. */
+  private ProjectTableScanRule(RelOptRuleOperand operand, String description) {
+    super(operand, description);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  protected void apply(RelOptRuleCall call, Project project, TableScan scan) {
+    final RelOptTable table = scan.getTable();
+    assert table.unwrap(ProjectableFilterableTable.class) != null;
+
+    final Mappings.TargetMapping mapping = project.getMapping();
+    if (mapping == null
+        || Mappings.isIdentity(mapping)) {
+      return;
+    }
+
+    final ImmutableIntList projects;
+    final ImmutableList<RexNode> filters;
+    if (scan instanceof Bindables.BindableTableScan) {
+      final Bindables.BindableTableScan bindableScan =
+          (Bindables.BindableTableScan) scan;
+      filters = bindableScan.filters;
+      projects = bindableScan.projects;
+    } else {
+      filters = ImmutableList.of();
+      projects = scan.identity();
+    }
+
+    final List<Integer> projects2 =
+        Mappings.apply((Mapping) mapping, projects);
+    call.transformTo(
+        Bindables.BindableTableScan.create(scan.getCluster(), scan.getTable(),
+            filters, projects2));
+  }
+}
+
+// End ProjectTableScanRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/schema/Schemas.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index 4172aab..63d0e4e 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -173,16 +173,22 @@ public final class Schemas {
           Expressions.constant(tableName));
       if (ScannableTable.class.isAssignableFrom(clazz)) {
         return Expressions.call(
-            BuiltInMethod.SCHEMAS_ENUMERABLE.method,
+            BuiltInMethod.SCHEMAS_ENUMERABLE_SCANNABLE.method,
             Expressions.convert_(expression, ScannableTable.class),
             DataContext.ROOT);
       }
       if (FilterableTable.class.isAssignableFrom(clazz)) {
         return Expressions.call(
-            BuiltInMethod.SCHEMAS_ENUMERABLE2.method,
+            BuiltInMethod.SCHEMAS_ENUMERABLE_FILTERABLE.method,
             Expressions.convert_(expression, FilterableTable.class),
             DataContext.ROOT);
       }
+      if (ProjectableFilterableTable.class.isAssignableFrom(clazz)) {
+        return Expressions.call(
+            BuiltInMethod.SCHEMAS_ENUMERABLE_PROJECTABLE_FILTERABLE.method,
+            Expressions.convert_(expression, ProjectableFilterableTable.class),
+            DataContext.ROOT);
+      }
     } else {
       expression = Expressions.call(
           BuiltInMethod.SCHEMAS_QUERYABLE.method,
@@ -241,6 +247,23 @@ public final class Schemas {
     return table.scan(root, ImmutableList.<RexNode>of());
   }
 
+  /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over the rows of
+   * a given table, not applying any filters and projecting all columns,
+   * representing each row as an object array. */
+  public static Enumerable<Object[]> enumerable(
+      final ProjectableFilterableTable table, final DataContext root) {
+    return table.scan(root, ImmutableList.<RexNode>of(),
+        identity(table.getRowType(root.getTypeFactory()).getFieldCount()));
+  }
+
+  private static int[] identity(int count) {
+    final int[] integers = new int[count];
+    for (int i = 0; i < integers.length; i++) {
+      integers[i] = i;
+    }
+    return integers;
+  }
+
   /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over object
    * arrays, given a fully-qualified table name which leads to a
    * {@link ScannableTable}. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java
index 154766f..3f6c05f 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -40,7 +40,7 @@ import org.apache.calcite.rel.rules.FilterAggregateTransposeRule;
 import org.apache.calcite.rel.rules.FilterCalcMergeRule;
 import org.apache.calcite.rel.rules.FilterJoinRule;
 import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
-import org.apache.calcite.rel.rules.FilterTableRule;
+import org.apache.calcite.rel.rules.FilterTableScanRule;
 import org.apache.calcite.rel.rules.FilterToCalcRule;
 import org.apache.calcite.rel.rules.JoinAssociateRule;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
@@ -122,7 +122,7 @@ public class Programs {
               : ProjectMergeRule.INSTANCE,
           AggregateStarTableRule.INSTANCE,
           AggregateStarTableRule.INSTANCE2,
-          FilterTableRule.INSTANCE,
+          FilterTableScanRule.INSTANCE,
           FilterProjectTransposeRule.INSTANCE,
           FilterJoinRule.FILTER_ON_JOIN,
           AggregateExpandDistinctAggregatesRule.INSTANCE,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/util/Bug.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Bug.java b/core/src/main/java/org/apache/calcite/util/Bug.java
index 46189c2..f2a2450 100644
--- a/core/src/main/java/org/apache/calcite/util/Bug.java
+++ b/core/src/main/java/org/apache/calcite/util/Bug.java
@@ -157,11 +157,6 @@ public abstract class Bug {
   public static final boolean CALCITE_319_FIXED = false;
 
   /** Whether
-   * <a href="https://issues.apache.org/jira/browse/CALCITE-445">[CALCITE-445]
-   * Pull up filters rejected by a ProjectableFilterableTable</a> is fixed. */
-  public static final boolean CALCITE_445_FIXED = false;
-
-  /** Whether
    * <a href="https://issues.apache.org/jira/browse/CALCITE-461">[CALCITE-461]
    * Convert more planner rules to handle grouping sets</a> is fixed. */
   public static final boolean CALCITE_461_FIXED = false;
@@ -173,10 +168,21 @@ public abstract class Bug {
 
   /**
    * Use this method to flag temporary code.
-   */
-  public static boolean remark(String remark) {
-    Util.discard(remark);
-    return false;
+   *
+   * <p>Example #1:
+   * <blockquote><pre>
+   * if (Bug.remark("baz fixed") == null) {
+   *   baz();
+   * }</pre></blockquote>
+   *
+   * <p>Example #2:
+   * <blockquote><pre>
+   * /&#42;&#42; &#64;see Bug#remark Remove before checking in &#42;/
+   * void uselessMethod() {}
+   * </pre></blockquote>
+   */
+  public static <T> T remark(T remark) {
+    return remark;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/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 2db00dd..6d21b11 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -55,6 +55,7 @@ import org.apache.calcite.runtime.SortedMultiMap;
 import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.schema.FilterableTable;
 import org.apache.calcite.schema.ModifiableTable;
+import org.apache.calcite.schema.ProjectableFilterableTable;
 import org.apache.calcite.schema.QueryableTable;
 import org.apache.calcite.schema.ScannableTable;
 import org.apache.calcite.schema.Schema;
@@ -110,10 +111,12 @@ public enum BuiltInMethod {
   SCHEMA_GET_SUB_SCHEMA(Schema.class, "getSubSchema", String.class),
   SCHEMA_GET_TABLE(Schema.class, "getTable", String.class),
   SCHEMA_PLUS_UNWRAP(SchemaPlus.class, "unwrap", Class.class),
-  SCHEMAS_ENUMERABLE(Schemas.class, "enumerable", ScannableTable.class,
-      DataContext.class),
-  SCHEMAS_ENUMERABLE2(Schemas.class, "enumerable", FilterableTable.class,
-      DataContext.class),
+  SCHEMAS_ENUMERABLE_SCANNABLE(Schemas.class, "enumerable",
+      ScannableTable.class, DataContext.class),
+  SCHEMAS_ENUMERABLE_FILTERABLE(Schemas.class, "enumerable",
+      FilterableTable.class, DataContext.class),
+  SCHEMAS_ENUMERABLE_PROJECTABLE_FILTERABLE(Schemas.class, "enumerable",
+      ProjectableFilterableTable.class, DataContext.class),
   SCHEMAS_QUERYABLE(Schemas.class, "queryable", DataContext.class,
       SchemaPlus.class, Class.class, String.class),
   REFLECTIVE_SCHEMA_GET_TARGET(ReflectiveSchema.class, "getTarget"),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
index 2568bc8..867c8f3 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
@@ -112,9 +112,9 @@ public class ImmutableIntList extends FlatLists.AbstractFlatList<Integer> {
   @Override public boolean equals(Object obj) {
     return this == obj
         || obj instanceof ImmutableIntList
-        && Arrays.equals(ints, ((ImmutableIntList) obj).ints)
-        || obj instanceof List
-        && obj.equals(this);
+        ? Arrays.equals(ints, ((ImmutableIntList) obj).ints)
+        : obj instanceof List
+            && obj.equals(this);
   }
 
   @Override public String toString() {
@@ -236,6 +236,15 @@ public class ImmutableIntList extends FlatLists.AbstractFlatList<Integer> {
     };
   }
 
+  /** Returns the identity list [0, ..., count - 1]. */
+  public static ImmutableIntList identity(int count) {
+    final int[] integers = new int[count];
+    for (int i = 0; i < integers.length; i++) {
+      integers[i] = i;
+    }
+    return new ImmutableIntList(integers);
+  }
+
   /** Special sub-class of {@link ImmutableIntList} that is always
    * empty and has only one instance. */
   private static class EmptyImmutableIntList extends ImmutableIntList {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 2f40d9c..dd6b62c 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -535,21 +535,27 @@ public class CalciteAssert {
     final StringBuilder buf = new StringBuilder();
     final ResultSetMetaData metaData = resultSet.getMetaData();
     while (resultSet.next()) {
-      int n = metaData.getColumnCount();
-      if (n > 0) {
-        for (int i = 1;; i++) {
-          buf.append(metaData.getColumnLabel(i))
-              .append("=")
-              .append(resultSet.getString(i));
-          if (i == n) {
-            break;
-          }
-          buf.append("; ");
+      rowToString(resultSet, buf, metaData).append("\n");
+    }
+    return buf.toString();
+  }
+
+  /** Converts one row to a string. */
+  static StringBuilder rowToString(ResultSet resultSet, StringBuilder buf,
+      ResultSetMetaData metaData) throws SQLException {
+    int n = metaData.getColumnCount();
+    if (n > 0) {
+      for (int i = 1;; i++) {
+        buf.append(metaData.getColumnLabel(i))
+            .append("=")
+            .append(resultSet.getString(i));
+        if (i == n) {
+          break;
         }
+        buf.append("; ");
       }
-      buf.append("\n");
     }
-    return buf.toString();
+    return buf;
   }
 
   static int countRows(ResultSet resultSet) throws SQLException {
@@ -564,18 +570,7 @@ public class CalciteAssert {
       Collection<String> list) throws SQLException {
     final StringBuilder buf = new StringBuilder();
     while (resultSet.next()) {
-      int n = resultSet.getMetaData().getColumnCount();
-      if (n > 0) {
-        for (int i = 1;; i++) {
-          buf.append(resultSet.getMetaData().getColumnLabel(i))
-              .append("=")
-              .append(resultSet.getString(i));
-          if (i == n) {
-            break;
-          }
-          buf.append("; ");
-        }
-      }
+      rowToString(resultSet, buf, resultSet.getMetaData());
       list.add(buf.toString());
       buf.setLength(0);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
index 042e37e..9f5200c 100644
--- a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
@@ -47,6 +47,7 @@ import static org.junit.Assert.assertThat;
 public class InterpreterTest {
   private SchemaPlus rootSchema;
   private Planner planner;
+  private MyDataContext dataContext;
 
   /** Implementation of {@link DataContext} for executing queries without a
    * connection. */
@@ -82,11 +83,13 @@ public class InterpreterTest {
             CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.HR))
         .build();
     planner = Frameworks.getPlanner(config);
+    dataContext = new MyDataContext(planner);
   }
 
   @After public void tearDown() {
     rootSchema = null;
     planner = null;
+    dataContext = null;
   }
 
   /** Tests executing a simple plan using an interpreter. */
@@ -99,7 +102,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter = new Interpreter(null, convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter, "[b, 2]", "[c, 3]");
   }
 
@@ -134,8 +137,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter,
         "[100, 10, Bill, 10000.0, 1000]",
         "[110, 10, Theodore, 11500.0, 250]",
@@ -153,8 +155,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter,
         "[4, John]",
         "[4, Paul]",
@@ -170,8 +171,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter,
         "[4]");
   }
@@ -184,8 +184,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRowsUnordered(interpreter,
         "[George, 1]",
         "[Paul, 1]",
@@ -203,8 +202,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter, "[0]", "[10]");
   }
 
@@ -219,8 +217,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter,
         "[0]", "[10]", "[20]", "[30]", "[0]", "[10]", "[20]", "[30]");
   }
@@ -236,8 +233,7 @@ public class InterpreterTest {
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
 
-    final Interpreter interpreter =
-        new Interpreter(new MyDataContext(planner), convert);
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
     assertRows(interpreter, "[0]", "[10]", "[20]", "[30]");
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 8caf12f..890fd08 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -253,8 +253,8 @@ public class JdbcTest {
   @Test public void testTableFunctionDynamicStructure()
       throws SQLException, ClassNotFoundException {
     Connection connection = getConnectionWithMultiplyFunction();
-    final PreparedStatement ps = connection.prepareStatement(
-        "select *\n" + "from table(\"s\".\"multiplication\"(4, 3, ?))\n");
+    final PreparedStatement ps = connection.prepareStatement("select *\n"
+        + "from table(\"s\".\"multiplication\"(4, 3, ?))\n");
     ps.setInt(1, 100);
     ResultSet resultSet = ps.executeQuery();
     assertThat(CalciteAssert.toString(resultSet),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/test/ModelTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/ModelTest.java b/core/src/test/java/org/apache/calcite/test/ModelTest.java
index a6e875c..989ddf4 100644
--- a/core/src/test/java/org/apache/calcite/test/ModelTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ModelTest.java
@@ -18,6 +18,7 @@ package org.apache.calcite.test;
 
 import org.apache.calcite.model.JsonColumn;
 import org.apache.calcite.model.JsonCustomSchema;
+import org.apache.calcite.model.JsonCustomTable;
 import org.apache.calcite.model.JsonJdbcSchema;
 import org.apache.calcite.model.JsonLattice;
 import org.apache.calcite.model.JsonMapSchema;
@@ -131,13 +132,22 @@ public class ModelTest {
             + "       type: 'custom',\n"
             + "       name: 'My Custom Schema',\n"
             + "       factory: 'com.acme.MySchemaFactory',\n"
-            + "       operand: {a: 'foo', b: [1, 3.5] }\n"
+            + "       operand: {a: 'foo', b: [1, 3.5] },\n"
+            + "       tables: [\n"
+            + "         { type: 'custom', name: 'T1' },\n"
+            + "         { type: 'custom', name: 'T2', operand: {} },\n"
+            + "         { type: 'custom', name: 'T3', operand: {a: 'foo'} }\n"
+            + "       ]\n"
+            + "     },\n"
+            + "     {\n"
+            + "       type: 'custom',\n"
+            + "       name: 'has-no-operand'\n"
             + "     }\n"
             + "   ]\n"
             + "}",
         JsonRoot.class);
     assertEquals("1.0", root.version);
-    assertEquals(1, root.schemas.size());
+    assertEquals(2, root.schemas.size());
     final JsonCustomSchema schema = (JsonCustomSchema) root.schemas.get(0);
     assertEquals("My Custom Schema", schema.name);
     assertEquals("com.acme.MySchemaFactory", schema.factory);
@@ -148,6 +158,10 @@ public class ModelTest {
     assertEquals(2, list.size());
     assertEquals(1, list.get(0));
     assertEquals(3.5, list.get(1));
+
+    assertEquals(3, schema.tables.size());
+    assertNull(((JsonCustomTable) schema.tables.get(0)).operand);
+    assertTrue(((JsonCustomTable) schema.tables.get(1)).operand.isEmpty());
   }
 
   /** Tests that an immutable schema in a model cannot contain a

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/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 4b51753..377fe67 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -39,7 +39,6 @@ import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.AbstractTable;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.util.Bug;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -207,7 +206,7 @@ public class ScannableTableTest {
         equalTo("i=4; k=1942\n"
             + "i=6; k=1943\n"));
     assertThat(buf.toString(),
-        equalTo("returnCount=4"));
+        equalTo("returnCount=4, projects=[0, 2]"));
     buf.setLength(0);
   }
 
@@ -233,9 +232,7 @@ public class ScannableTableTest {
     assertThat(CalciteAssert.toString(resultSet), equalTo("k=1940\nk=1942\n"));
     resultSet.close();
     assertThat(buf.toString(),
-        equalTo(Bug.CALCITE_445_FIXED
-                ? "returnCount=4, projects=[0, 2]"
-                : "returnCount=4"));
+        equalTo("returnCount=4, projects=[2, 0]"));
     buf.setLength(0);
   }
 
@@ -278,9 +275,7 @@ public class ScannableTableTest {
     ResultSet resultSet = statement.executeQuery(
         "select \"k\" from \"s\".\"beatles2\" where \"k\" > 1941");
     assertThat(buf.toString(),
-        equalTo(Bug.CALCITE_445_FIXED
-                ? "returnCount=4, projects=[2]"
-                : "returnCount=4"));
+        equalTo("returnCount=4, projects=[2]"));
     assertThat(CalciteAssert.toString(resultSet), equalTo("k=1942\nk=1943\n"));
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/test/TableInRootSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/TableInRootSchemaTest.java b/core/src/test/java/org/apache/calcite/test/TableInRootSchemaTest.java
index c7ce994..c85641e 100644
--- a/core/src/test/java/org/apache/calcite/test/TableInRootSchemaTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TableInRootSchemaTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.test;
 
-import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
 import org.apache.calcite.adapter.java.AbstractQueryableTable;
 import org.apache.calcite.jdbc.CalciteConnection;
@@ -109,7 +108,7 @@ public class TableInRootSchemaTest {
     public RelDataType getRowType(RelDataTypeFactory typeFactory) {
       int columnCount = columnNames.length;
       final List<Pair<String, RelDataType>> columnDesc =
-          new ArrayList<Pair<String, RelDataType>>(columnCount);
+          new ArrayList<>(columnCount);
       for (int i = 0; i < columnCount; i++) {
         final RelDataType colType = typeFactory
             .createJavaType(columnTypes[i]);
@@ -176,12 +175,9 @@ public class TableInRootSchemaTest {
       };
     }
 
-    // keep
     public RelNode toRel(RelOptTable.ToRelContext context,
         RelOptTable relOptTable) {
-      return new EnumerableTableScan(context.getCluster(),
-          context.getCluster().traitSetOf(EnumerableConvention.INSTANCE),
-          relOptTable, (Class) getElementType());
+      return EnumerableTableScan.create(context.getCluster(), relOptTable);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/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 48759a6..13cc03b 100644
--- a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
@@ -84,9 +84,7 @@ public class FrameworksTest {
                 table.getRowType(typeFactory)) {
             };
             final EnumerableTableScan tableRel =
-                new EnumerableTableScan(
-                    cluster, cluster.traitSetOf(EnumerableConvention.INSTANCE),
-                    relOptTable, Object[].class);
+                EnumerableTableScan.create(cluster, relOptTable);
 
             // "WHERE i > 1"
             final RexBuilder rexBuilder = cluster.getRexBuilder();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/core/src/test/java/org/apache/calcite/util/UtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/UtilTest.java b/core/src/test/java/org/apache/calcite/util/UtilTest.java
index 980a5eb..4fcdd20 100644
--- a/core/src/test/java/org/apache/calcite/util/UtilTest.java
+++ b/core/src/test/java/org/apache/calcite/util/UtilTest.java
@@ -874,21 +874,28 @@ public class UtilTest {
   }
 
   @Test public void testImmutableIntList() {
-    ImmutableIntList list = ImmutableIntList.of();
+    final ImmutableIntList list = ImmutableIntList.of();
     assertEquals(0, list.size());
     assertEquals(list, Collections.<Integer>emptyList());
     assertThat(list.toString(), equalTo("[]"));
     assertThat(BitSets.of(list), equalTo(new BitSet()));
 
-    list = ImmutableIntList.of(1, 3, 5);
-    assertEquals(3, list.size());
-    assertEquals("[1, 3, 5]", list.toString());
-    assertEquals(list.hashCode(), Arrays.asList(1, 3, 5).hashCode());
+    final ImmutableIntList list2 = ImmutableIntList.of(1, 3, 5);
+    assertEquals(3, list2.size());
+    assertEquals("[1, 3, 5]", list2.toString());
+    assertEquals(list2.hashCode(), Arrays.asList(1, 3, 5).hashCode());
 
-    Integer[] integers = list.toArray(new Integer[3]);
+    Integer[] integers = list2.toArray(new Integer[3]);
     assertEquals(1, (int) integers[0]);
     assertEquals(3, (int) integers[1]);
     assertEquals(5, (int) integers[2]);
+
+    //noinspection EqualsWithItself
+    assertThat(list.equals(list), is(true));
+    assertThat(list.equals(list2), is(false));
+    assertThat(list2.equals(list), is(false));
+    //noinspection EqualsWithItself
+    assertThat(list2.equals(list2), is(true));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bd0b6061/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
----------------------------------------------------------------------
diff --git a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
index 773e77f..ba7c276 100644
--- a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
+++ b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
@@ -133,7 +133,8 @@ public class CsvTest {
   @Test public void testPushDownProjectDumb() throws SQLException {
     // rule does not fire, because we're using 'dumb' tables in simple model
     checkSql("model", "explain plan for select * from EMPS",
-        "PLAN=EnumerableTableScan(table=[[SALES, EMPS]])\n");
+        "PLAN=EnumerableInterpreter\n"
+            + "  BindableTableScan(table=[[SALES, EMPS]])\n");
   }
 
   @Test public void testPushDownProject() throws SQLException {


Mime
View raw message