This is an automated email from the ASF dual-hosted git repository. rubenql 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 3c70ca4 [CALCITE-3820] EnumerableDefaults#orderBy should be lazily computed + support enumerator re-initialization 3c70ca4 is described below commit 3c70ca47272053a7c1f1f41079b88713da06f29c Author: rubenada <rube...@gmail.com> AuthorDate: Tue Feb 25 16:54:40 2020 +0100 [CALCITE-3820] EnumerableDefaults#orderBy should be lazily computed + support enumerator re-initialization --- .../test/enumerable/EnumerableJoinTest.java | 80 ++++++++++++++++++++++ .../apache/calcite/linq4j/EnumerableDefaults.java | 18 +++-- 2 files changed, 91 insertions(+), 7 deletions(-) diff --git a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableJoinTest.java b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableJoinTest.java index 18d0215..aa500ab 100644 --- a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableJoinTest.java +++ b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableJoinTest.java @@ -21,11 +21,13 @@ import org.apache.calcite.adapter.enumerable.EnumerableRules; import org.apache.calcite.adapter.java.ReflectiveSchema; import org.apache.calcite.config.CalciteConnectionProperty; import org.apache.calcite.config.Lex; +import org.apache.calcite.interpreter.Bindables; import org.apache.calcite.plan.RelOptPlanner; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.runtime.Hook; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.test.CalciteAssert; +import org.apache.calcite.test.HierarchySchema; import org.apache.calcite.test.JdbcTest; import org.junit.jupiter.api.Test; @@ -218,6 +220,84 @@ public class EnumerableJoinTest { + "empid=150; name=Sebastian; dept_name=Sales; e_deptno=10; d_deptno=10"); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-3820">[CALCITE-3820] + * EnumerableDefaults#orderBy should be lazily computed + support enumerator + * re-initialization</a>. */ + @Test public void testRepeatUnionWithMergeJoin() { + tester(false, new HierarchySchema()) + .query("?") + .withHook(Hook.PLANNER, (Consumer<RelOptPlanner>) planner -> { + planner.addRule(Bindables.BINDABLE_TABLE_SCAN_RULE); + planner.addRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE); + planner.removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE); + }) + // Note: explicit sort is used so EnumerableMergeJoin can actually work + .withRel(builder -> builder + // WITH RECURSIVE delta(empid, name) as ( + // SELECT empid, name FROM emps WHERE empid = 2 + // UNION ALL + // SELECT e.empid, e.name FROM delta d + // JOIN hierarchies h ON d.empid = h.managerid + // JOIN emps e ON h.subordinateid = e.empid + // ) + // SELECT empid, name FROM delta + .scan("s", "emps") + .filter( + builder.equals( + builder.field("empid"), + builder.literal(2))) + .project( + builder.field("emps", "empid"), + builder.field("emps", "name")) + + .transientScan("#DELTA#") + .sort(builder.field("empid")) + .scan("s", "hierarchies") + .sort(builder.field("managerid")) + .join( + JoinRelType.INNER, + builder.equals( + builder.field(2, "#DELTA#", "empid"), + builder.field(2, "hierarchies", "managerid"))) + .sort(builder.field("subordinateid")) + + .scan("s", "emps") + .sort(builder.field("empid")) + .join( + JoinRelType.INNER, + builder.equals( + builder.field(2, "hierarchies", "subordinateid"), + builder.field(2, "emps", "empid"))) + .project( + builder.field("emps", "empid"), + builder.field("emps", "name")) + .repeatUnion("#DELTA#", true) + .build() + ) + .explainHookMatches("" // It is important to have MergeJoin + EnumerableSort in the plan + + "EnumerableRepeatUnion(all=[true])\n" + + " EnumerableTableSpool(readType=[LAZY], writeType=[LAZY], table=[[#DELTA#]])\n" + + " EnumerableCalc(expr#0..4=[{inputs}], expr#5=[2], expr#6=[=($t0, $t5)], empid=[$t0], name=[$t2], $condition=[$t6])\n" + + " EnumerableTableScan(table=[[s, emps]])\n" + + " EnumerableTableSpool(readType=[LAZY], writeType=[LAZY], table=[[#DELTA#]])\n" + + " EnumerableCalc(expr#0..8=[{inputs}], empid=[$t0], name=[$t2])\n" + + " EnumerableMergeJoin(condition=[=($0, $8)], joinType=[inner])\n" + + " EnumerableSort(sort0=[$0], dir0=[ASC])\n" + + " EnumerableTableScan(table=[[s, emps]])\n" + + " EnumerableSort(sort0=[$3], dir0=[ASC])\n" + + " EnumerableMergeJoin(condition=[=($0, $2)], joinType=[inner])\n" + + " EnumerableSort(sort0=[$0], dir0=[ASC])\n" + + " EnumerableInterpreter\n" + + " BindableTableScan(table=[[#DELTA#]])\n" + + " EnumerableSort(sort0=[$0], dir0=[ASC])\n" + + " EnumerableTableScan(table=[[s, hierarchies]])\n") + .returnsUnordered("" + + "empid=2; name=Emp2\n" + + "empid=3; name=Emp3\n" + + "empid=5; name=Emp5"); + } + private CalciteAssert.AssertThat tester(boolean forceDecorrelate, Object schema) { return CalciteAssert.that() diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java index 57531d1..a20f5fa 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java @@ -2407,13 +2407,17 @@ public abstract class EnumerableDefaults { public static <TSource, TKey> Enumerable<TSource> orderBy( Enumerable<TSource> source, Function1<TSource, TKey> keySelector, Comparator<TKey> comparator) { - // NOTE: TreeMap allows null comparator. But the caller of this method - // must supply a comparator if the key does not extend Comparable. - // Otherwise there will be a ClassCastException while retrieving. - final Map<TKey, List<TSource>> map = new TreeMap<>(comparator); - LookupImpl<TKey, TSource> lookup = toLookup_(map, source, keySelector, - Functions.identitySelector()); - return lookup.valuesEnumerable(); + return new AbstractEnumerable<TSource>() { + @Override public Enumerator<TSource> enumerator() { + // NOTE: TreeMap allows null comparator. But the caller of this method + // must supply a comparator if the key does not extend Comparable. + // Otherwise there will be a ClassCastException while retrieving. + final Map<TKey, List<TSource>> map = new TreeMap<>(comparator); + final LookupImpl<TKey, TSource> lookup = toLookup_(map, source, keySelector, + Functions.identitySelector()); + return lookup.valuesEnumerable().enumerator(); + } + }; } /**