Skip to content

Commit

Permalink
[CALCITE-5019] Avoid multiple scans when table is ProjectableFilterab…
Browse files Browse the repository at this point in the history
…leTable and projections and filters act on different columns
  • Loading branch information
IceMimosa authored and liyafan82 committed Mar 4, 2022
1 parent b125ab9 commit c3dbf52
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,6 @@ private static TableScanNode createProjectableFilterable(Compiler compiler,
} else {
projectInts = projects.toIntArray();
}
final Enumerable<@Nullable Object[]> enumerable1 =
pfTable.scan(root, mutableFilters, projectInts);
for (RexNode filter : mutableFilters) {
if (!filters.contains(filter)) {
throw RESOURCE.filterableTableInventedFilter(filter.toString())
Expand All @@ -227,6 +225,8 @@ private static TableScanNode createProjectableFilterable(Compiler compiler,
continue;
}
}
final Enumerable<@Nullable Object[]> enumerable1 =
pfTable.scan(root, mutableFilters, projectInts);
final Enumerable<Row> rowEnumerable = Enumerables.toRow(enumerable1);
final ImmutableIntList rejectedProjects;
if (originalProjects == null || originalProjects.equals(projects)) {
Expand Down
29 changes: 27 additions & 2 deletions core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,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=<0, 4>, projects=[1]"));
assertThat(buf.toString(), is("returnCount=2, filter=<0, 4>, projects=[1, 0]"));
}

@Test void testProjectableFilterableNonCooperative() throws Exception {
Expand Down Expand Up @@ -188,7 +188,7 @@ public class ScannableTableTest {
.returnsUnordered("k=1940; j=John",
"k=1942; j=Paul");
assertThat(buf.toString(),
is("returnCount=2, filter=<0, 4>, projects=[2, 1]"));
is("returnCount=2, filter=<0, 4>, projects=[2, 1, 0]"));
}

/** A filter on a {@link org.apache.calcite.schema.ProjectableFilterableTable}
Expand Down Expand Up @@ -396,6 +396,25 @@ private static Pair<Integer, Object> getFilter(boolean cooperative, List<RexNode
.explainContains(explain);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5019">[CALCITE-5019]
* Avoid multiple scans when table is ProjectableFilterableTable</a>.*/
@Test void testProjectableFilterableWithScanCounter() throws Exception {
final StringBuilder buf = new StringBuilder();
final BeatlesProjectableFilterableTable table =
new BeatlesProjectableFilterableTable(buf, false);
final String explain = "PLAN="
+ "EnumerableInterpreter\n"
+ " BindableTableScan(table=[[s, beatles]], filters=[[=($0, 4)]], projects=[[1]]";
CalciteAssert.that()
.with(newSchema("s", Pair.of("beatles", table)))
.query("select \"j\" from \"s\".\"beatles\" where \"i\" = 4")
.explainContains(explain)
.returnsUnordered("j=John", "j=Paul");
assertThat(table.getScanCount(), is(1));
assertThat(buf.toString(), is("returnCount=4, projects=[1, 0]"));
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-1031">[CALCITE-1031]
* In prepared statement, CsvScannableTable.scan is called twice</a>. */
Expand Down Expand Up @@ -558,6 +577,7 @@ public Enumerator<Object[]> enumerator() {
* interface. */
public static class BeatlesProjectableFilterableTable
extends AbstractTable implements ProjectableFilterableTable {
private final AtomicInteger scanCounter = new AtomicInteger();
private final StringBuilder buf;
private final boolean cooperative;

Expand All @@ -577,13 +597,18 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) {

public Enumerable<@Nullable Object[]> scan(DataContext root, List<RexNode> filters,
final int @Nullable [] projects) {
scanCounter.incrementAndGet();
final Pair<Integer, Object> filter = getFilter(cooperative, filters);
return new AbstractEnumerable<Object[]>() {
public Enumerator<Object[]> enumerator() {
return beatles(buf, filter, projects);
}
};
}

public int getScanCount() {
return this.scanCounter.get();
}
}

private static Enumerator<Object[]> tens() {
Expand Down

0 comments on commit c3dbf52

Please sign in to comment.