[CALCITE-1688] Infinite loop during materialization substitution if query contains Union, Minus or Intersect
Close apache/calcite#398 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/785c2fbe Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/785c2fbe Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/785c2fbe Branch: refs/heads/master Commit: 785c2fbea745649903d98f0a9e7f43de9576e8c5 Parents: 6077714 Author: maryannxue <[email protected]> Authored: Thu Mar 9 16:22:08 2017 -0800 Committer: Julian Hyde <[email protected]> Committed: Fri Mar 10 12:02:12 2017 -0800 ---------------------------------------------------------------------- .../calcite/rel/mutable/MutableMultiRel.java | 8 ++- .../org/apache/calcite/test/CalciteAssert.java | 19 ++++++ .../calcite/test/MaterializationTest.java | 63 +++++--------------- 3 files changed, 42 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/785c2fbe/core/src/main/java/org/apache/calcite/rel/mutable/MutableMultiRel.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/mutable/MutableMultiRel.java b/core/src/main/java/org/apache/calcite/rel/mutable/MutableMultiRel.java index 6c026bd..531f3e5 100644 --- a/core/src/main/java/org/apache/calcite/rel/mutable/MutableMultiRel.java +++ b/core/src/main/java/org/apache/calcite/rel/mutable/MutableMultiRel.java @@ -16,10 +16,12 @@ */ package org.apache.calcite.rel.mutable; +import org.apache.calcite.linq4j.Ord; import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.rel.type.RelDataType; import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import java.util.List; @@ -31,7 +33,11 @@ abstract class MutableMultiRel extends MutableRel { protected MutableMultiRel(RelOptCluster cluster, RelDataType rowType, MutableRelType type, List<MutableRel> inputs) { super(cluster, rowType, type); - this.inputs = inputs; + this.inputs = ImmutableList.copyOf(inputs); + for (Ord<MutableRel> input : Ord.zip(inputs)) { + input.e.parent = this; + input.e.ordinalInParent = input.i; + } } @Override public void setInput(int ordinalInParent, MutableRel input) { http://git-wip-us.apache.org/repos/asf/calcite/blob/785c2fbe/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 dd7168c..1267546 100644 --- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java +++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java @@ -40,6 +40,8 @@ import org.apache.calcite.util.JsonBuilder; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; +import org.apache.commons.lang3.StringUtils; + import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Joiner; @@ -411,6 +413,23 @@ public class CalciteAssert { }; } + public static Function<ResultSet, Void> checkResultContains( + final String expected, final int count) { + return new Function<ResultSet, Void>() { + public Void apply(ResultSet s) { + try { + final String actual = Util.toLinux(CalciteAssert.toString(s)); + assertTrue( + actual + " should have " + count + " occurrence of " + expected, + StringUtils.countMatches(actual, expected) == count); + return null; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + }; + } + public static Function<ResultSet, Void> checkMaskedResultContains( final String expected) { return new Function<ResultSet, Void>() { http://git-wip-us.apache.org/repos/asf/calcite/blob/785c2fbe/core/src/test/java/org/apache/calcite/test/MaterializationTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java index f51e1ab..9a5d605 100644 --- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java +++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java @@ -40,9 +40,6 @@ import org.apache.calcite.tools.RuleSet; import org.apache.calcite.tools.RuleSets; import org.apache.calcite.util.JsonBuilder; import org.apache.calcite.util.TryThreadLocal; -import org.apache.calcite.util.Util; - -import org.apache.commons.lang3.StringUtils; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; @@ -53,7 +50,6 @@ import org.junit.Test; import java.math.BigDecimal; import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -916,33 +912,24 @@ public class MaterializationTest { checkMaterializeWithRules(m, q, rules); } + @Test public void testUnionAll() { + String q = "select * from \"emps\" where \"empid\" > 300\n" + + "union all select * from \"emps\" where \"empid\" < 200"; + String m = "select * from \"emps\" where \"empid\" < 500"; + checkMaterialize(m, q, JdbcTest.HR_MODEL, + CalciteAssert.checkResultContains( + "EnumerableTableScan(table=[[hr, m0]])", 1)); + } + @Test public void testSubQuery() { String q = "select \"empid\", \"deptno\", \"salary\" from \"emps\" e1\n" + "where \"empid\" = (\n" + " select max(\"empid\") from \"emps\"\n" + " where \"deptno\" = e1.\"deptno\")"; final String m = "select \"empid\", \"deptno\" from \"emps\"\n"; - try (final TryThreadLocal.Memo ignored = Prepare.THREAD_TRIM.push(true)) { - MaterializationService.setThreadLocal(); - CalciteAssert.that() - .withMaterializations(JdbcTest.HR_MODEL, "m0", m) - .query(q) - .enableMaterializations(true) - .explainMatches("", new Function<ResultSet, Void>() { - public Void apply(ResultSet s) { - try { - final String actual = Util.toLinux(CalciteAssert.toString(s)); - final String scan = "EnumerableTableScan(table=[[hr, m0]])"; - assertTrue(actual + " should have 1 occurrence of " + scan, - StringUtils.countMatches(actual, scan) == 1); - return null; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - }) - .sameResultWithMaterializationsDisabled(); - } + checkMaterialize(m, q, JdbcTest.HR_MODEL, + CalciteAssert.checkResultContains( + "EnumerableTableScan(table=[[hr, m0]])", 1)); } @Test public void testTableModify() { @@ -1046,28 +1033,10 @@ public class MaterializationTest { String q = "select *\n" + "from (select * from \"emps\" where \"empid\" < 300)\n" + "join (select * from \"emps\" where \"empid\" < 200) using (\"empid\")"; - try (final TryThreadLocal.Memo ignored = Prepare.THREAD_TRIM.push(true)) { - MaterializationService.setThreadLocal(); - CalciteAssert.that() - .withMaterializations(JdbcTest.HR_MODEL, - "m0", "select * from \"emps\" where \"empid\" < 500") - .query(q) - .enableMaterializations(true) - .explainMatches("", new Function<ResultSet, Void>() { - public Void apply(ResultSet s) { - try { - final String actual = Util.toLinux(CalciteAssert.toString(s)); - final String scan = "EnumerableTableScan(table=[[hr, m0]])"; - assertTrue(actual + " should have had two occurrences of " + scan, - StringUtils.countMatches(actual, scan) == 2); - return null; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - }) - .sameResultWithMaterializationsDisabled(); - } + String m = "select * from \"emps\" where \"empid\" < 500"; + checkMaterialize(m, q, JdbcTest.HR_MODEL, + CalciteAssert.checkResultContains( + "EnumerableTableScan(table=[[hr, m0]])", 2)); } @Test public void testMultiMaterializationMultiUsage() {
