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

hyuan 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 55c5853  [CALCITE-3758] FilterTableScanRule generate wrong mapping for 
filter condition when underlying is BindableTableScan (Jin Xing)
55c5853 is described below

commit 55c58538256119abbac0a260b8ea63f107f2407c
Author: jinxing64 <[email protected]>
AuthorDate: Tue Jan 28 15:49:08 2020 +0800

    [CALCITE-3758] FilterTableScanRule generate wrong mapping for filter 
condition when underlying is BindableTableScan (Jin Xing)
---
 .../org/apache/calcite/interpreter/Bindables.java  | 12 +----
 .../calcite/rel/rules/FilterTableScanRule.java     |  2 +-
 .../apache/calcite/test/ScannableTableTest.java    | 51 +++++++++++++++++-----
 3 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java 
b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
index ba1ee86..c190d28 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
@@ -76,7 +76,6 @@ import org.apache.calcite.util.ImmutableIntList;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -261,16 +260,7 @@ public class Bindables {
     }
 
     public Enumerable<Object[]> bind(DataContext dataContext) {
-      final List<RexNode> mutableFilters = new ArrayList<>(filters);
-      if (table.unwrap(ProjectableFilterableTable.class) != null) {
-        return table.unwrap(ProjectableFilterableTable.class)
-            .scan(dataContext, mutableFilters, projects.toIntArray());
-      } else if (table.unwrap(FilterableTable.class) != null) {
-        return table.unwrap(FilterableTable.class)
-            .scan(dataContext, mutableFilters);
-      } else {
-        return table.unwrap(ScannableTable.class).scan(dataContext);
-      }
+      return help(dataContext, this);
     }
 
     public Node implement(InterpreterImplementor implementor) {
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
index f5bd14c..e39a81d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableScanRule.java
@@ -124,7 +124,7 @@ public abstract class FilterTableScanRule extends 
RelOptRule {
     final Mapping mapping = Mappings.target(projects,
         scan.getTable().getRowType().getFieldCount());
     filters.add(
-        RexUtil.apply(mapping, filter.getCondition()));
+        RexUtil.apply(mapping.inverse(), filter.getCondition()));
 
     call.transformTo(
         Bindables.BindableTableScan.create(scan.getCluster(), scan.getTable(),
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 02b1738..c3bbf8d 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -27,6 +27,7 @@ import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.FilterableTable;
 import org.apache.calcite.schema.ProjectableFilterableTable;
 import org.apache.calcite.schema.ScannableTable;
@@ -38,6 +39,7 @@ 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.test.CalciteAssert.ConnectionPostProcessor;
+import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableMap;
@@ -115,7 +117,7 @@ public class ScannableTableTest {
             "i=4; j=Paul; k=1942");
     // Only 2 rows came out of the table. If the value is 4, it means that the
     // planner did not pass the filter down.
-    assertThat(buf.toString(), is("returnCount=2, filter=4"));
+    assertThat(buf.toString(), is("returnCount=2, filter=<0, 4>"));
   }
 
   /** A filter on a {@link FilterableTable} with two columns (noncooperative). 
*/
@@ -150,7 +152,7 @@ public class ScannableTableTest {
             "j=Paul");
     // Only 2 rows came out of the table. If the value is 4, it means that the
     // planner did not pass the filter down.
-    assertThat(buf.toString(), is("returnCount=2, filter=4, projects=[1]"));
+    assertThat(buf.toString(), is("returnCount=2, filter=<0, 4>, 
projects=[1]"));
   }
 
   @Test void testProjectableFilterableNonCooperative() throws Exception {
@@ -183,7 +185,7 @@ public class ScannableTableTest {
         .returnsUnordered("k=1940; j=John",
             "k=1942; j=Paul");
     assertThat(buf.toString(),
-        is("returnCount=2, filter=4, projects=[2, 1]"));
+        is("returnCount=2, filter=<0, 4>, projects=[2, 1]"));
   }
 
   /** A filter on a {@link 
org.apache.calcite.schema.ProjectableFilterableTable}
@@ -279,7 +281,7 @@ public class ScannableTableTest {
         .returnsUnordered("k=1940; C=2");
   }
 
-  private static Integer getFilter(boolean cooperative, List<RexNode> filters) 
{
+  private static Pair<Integer, Object> getFilter(boolean cooperative, 
List<RexNode> filters) {
     final Iterator<RexNode> filterIter = filters.iterator();
     while (filterIter.hasNext()) {
       final RexNode node = filterIter.next();
@@ -287,12 +289,17 @@ public class ScannableTableTest {
           && node instanceof RexCall
           && ((RexCall) node).getOperator() == SqlStdOperatorTable.EQUALS
           && ((RexCall) node).getOperands().get(0) instanceof RexInputRef
-          && ((RexInputRef) ((RexCall) node).getOperands().get(0)).getIndex()
-          == 0
           && ((RexCall) node).getOperands().get(1) instanceof RexLiteral) {
-        final RexNode op1 = ((RexCall) node).getOperands().get(1);
         filterIter.remove();
-        return ((BigDecimal) ((RexLiteral) op1).getValue()).intValue();
+        final int pos = ((RexInputRef) ((RexCall) 
node).getOperands().get(0)).getIndex();
+        final RexLiteral op1 = (RexLiteral) ((RexCall) 
node).getOperands().get(1);
+        switch (pos) {
+        case 0:
+        case 2:
+          return Pair.of(pos, ((BigDecimal) op1.getValue()).intValue());
+        case 1:
+          return Pair.of(pos, ((NlsString) op1.getValue()).getValue());
+        }
       }
     }
     return null;
@@ -456,6 +463,26 @@ public class ScannableTableTest {
     }
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-3758";>[CALCITE-3758]
+   * FilterTableScanRule generate wrong mapping for filter condition
+   * when underlying is BindableTableScan</a>. */
+  @Test public void testPFTableInBindableConvention() {
+    final StringBuilder buf = new StringBuilder();
+    final Table table = new BeatlesProjectableFilterableTable(buf, true);
+    try (Hook.Closeable ignored = 
Hook.ENABLE_BINDABLE.addThread(Hook.propertyJ(true))) {
+      final String explain = "PLAN="
+          + "BindableTableScan(table=[[s, beatles]], filters=[[=($1, 
'John')]], projects=[[1]])";
+      CalciteAssert.that()
+          .with(newSchema("s", Pair.of("beatles", table)))
+          .query("select \"j\" from \"s\".\"beatles\" where \"j\" = 'John'")
+          .explainContains(explain)
+          .returnsUnordered("j=John");
+      assertThat(buf.toString(),
+          is("returnCount=1, filter=<1, John>, projects=[1]"));
+    }
+  }
+
   protected ConnectionPostProcessor newSchema(final String schemaName,
       Pair<String, Table>... tables) {
     return connection -> {
@@ -529,7 +556,7 @@ public class ScannableTableTest {
     }
 
     public Enumerable<Object[]> scan(DataContext root, List<RexNode> filters) {
-      final Integer filter = getFilter(cooperative, filters);
+      final Pair<Integer, Object> filter = getFilter(cooperative, filters);
       return new AbstractEnumerable<Object[]>() {
         public Enumerator<Object[]> enumerator() {
           return beatles(buf, filter, null);
@@ -561,7 +588,7 @@ public class ScannableTableTest {
 
     public Enumerable<Object[]> scan(DataContext root, List<RexNode> filters,
         final int[] projects) {
-      final Integer filter = getFilter(cooperative, filters);
+      final Pair<Integer, Object> filter = getFilter(cooperative, filters);
       return new AbstractEnumerable<Object[]>() {
         public Enumerator<Object[]> enumerator() {
           return beatles(buf, filter, projects);
@@ -606,7 +633,7 @@ public class ScannableTableTest {
   };
 
   private static Enumerator<Object[]> beatles(final StringBuilder buf,
-      final Integer filter, final int[] projects) {
+      final Pair<Integer, Object> filter, final int[] projects) {
     return new Enumerator<Object[]>() {
       int row = -1;
       int returnCount = 0;
@@ -619,7 +646,7 @@ public class ScannableTableTest {
       public boolean moveNext() {
         while (++row < 4) {
           Object[] current = BEATLES[row % 4];
-          if (filter == null || filter.equals(current[0])) {
+          if (filter == null || filter.right.equals(current[filter.left])) {
             if (projects == null) {
               this.current = current;
             } else {

Reply via email to