You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by ru...@apache.org on 2020/05/07 09:45:28 UTC
[calcite] branch master updated: [CALCITE-3926] CannotPlanException
when an empty LogicalValues requires a certain collation
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 e3fe745 [CALCITE-3926] CannotPlanException when an empty LogicalValues requires a certain collation
e3fe745 is described below
commit e3fe745a4e8e5e15ae5e04345975c98ab737b31b
Author: rubenada <ru...@gmail.com>
AuthorDate: Wed Apr 15 19:20:05 2020 +0200
[CALCITE-3926] CannotPlanException when an empty LogicalValues requires a certain collation
---
.../adapter/enumerable/EnumerableValues.java | 2 +-
.../adapter/enumerable/EnumerableValuesRule.java | 9 +++++---
.../apache/calcite/rel/logical/LogicalValues.java | 6 ++++-
.../apache/calcite/rel/rules/PruneEmptyRules.java | 26 +++++++++++++++++-----
.../org/apache/calcite/test/RelBuilderTest.java | 19 ++++++++++++++++
.../org/apache/calcite/test/RelOptRulesTest.java | 25 +++++++++++++++++++++
.../org/apache/calcite/test/RelOptRulesTest.xml | 17 +++++++++++---
7 files changed, 91 insertions(+), 13 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
index 497e820..97b6554 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
@@ -67,7 +67,7 @@ public class EnumerableValues extends Values implements EnumerableRel {
@Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
assert inputs.isEmpty();
- return create(getCluster(), rowType, tuples);
+ return new EnumerableValues(getCluster(), rowType, tuples, traitSet);
}
public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
index 6a71ac0..c981a8b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
@@ -41,8 +41,11 @@ public class EnumerableValuesRule extends ConverterRule {
}
@Override public RelNode convert(RelNode rel) {
- LogicalValues values = (LogicalValues) rel;
- return EnumerableValues.create(values.getCluster(), values.getRowType(),
- values.getTuples());
+ final LogicalValues logicalValues = (LogicalValues) rel;
+ final EnumerableValues enumerableValues = EnumerableValues.create(
+ logicalValues.getCluster(), logicalValues.getRowType(), logicalValues.getTuples());
+ return enumerableValues.copy(
+ logicalValues.getTraitSet().replace(EnumerableConvention.INSTANCE),
+ enumerableValues.getInputs());
}
}
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
index edbea5d..32b9850 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
@@ -20,11 +20,13 @@ import org.apache.calcite.plan.Convention;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelDistributionTraitDef;
import org.apache.calcite.rel.RelInput;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rel.metadata.RelMdCollation;
+import org.apache.calcite.rel.metadata.RelMdDistribution;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexLiteral;
@@ -83,7 +85,9 @@ public class LogicalValues extends Values {
final RelMetadataQuery mq = cluster.getMetadataQuery();
final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE)
.replaceIfs(RelCollationTraitDef.INSTANCE,
- () -> RelMdCollation.values(mq, rowType, tuples));
+ () -> RelMdCollation.values(mq, rowType, tuples))
+ .replaceIf(RelDistributionTraitDef.INSTANCE,
+ () -> RelMdDistribution.values(rowType, tuples));
return new LogicalValues(cluster, traitSet, rowType, tuples);
}
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
index 1fb6b26..88d408d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptRuleOperand;
import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.plan.SubstitutionRule;
import org.apache.calcite.plan.hep.HepRelVertex;
import org.apache.calcite.plan.volcano.RelSubset;
@@ -42,6 +43,7 @@ import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
+import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
@@ -266,7 +268,7 @@ public abstract class PruneEmptyRules {
* <p>Examples:
*
* <ul>
- * <li>Sort(Empty) becomes Empty
+ * <li>Sort[fetch=0] becomes Empty
* </ul>
*/
public static final RelOptRule SORT_FETCH_ZERO_INSTANCE =
@@ -277,7 +279,14 @@ public abstract class PruneEmptyRules {
if (sort.fetch != null
&& !(sort.fetch instanceof RexDynamicParam)
&& RexLiteral.intValue(sort.fetch) == 0) {
- call.transformTo(call.builder().push(sort).empty().build());
+ RelNode emptyValues = call.builder().push(sort).empty().build();
+ RelTraitSet traits = sort.getTraitSet();
+ // propagate all traits (except convention) from the original sort into the empty values
+ if (emptyValues.getConvention() != null) {
+ traits = traits.replace(emptyValues.getConvention());
+ }
+ emptyValues = emptyValues.copy(traits, Collections.emptyList());
+ call.transformTo(emptyValues);
}
}
};
@@ -375,7 +384,7 @@ public abstract class PruneEmptyRules {
/** Creates a simple RemoveEmptySingleRule. */
public <R extends SingleRel> RemoveEmptySingleRule(Class<R> clazz,
String description) {
- this(clazz, (Predicate<R>) project -> true, RelFactories.LOGICAL_BUILDER,
+ this(clazz, (Predicate<R>) singleRel -> true, RelFactories.LOGICAL_BUILDER,
description);
}
@@ -399,8 +408,15 @@ public abstract class PruneEmptyRules {
}
public void onMatch(RelOptRuleCall call) {
- SingleRel single = call.rel(0);
- call.transformTo(call.builder().push(single).empty().build());
+ SingleRel singleRel = call.rel(0);
+ RelNode emptyValues = call.builder().push(singleRel).empty().build();
+ RelTraitSet traits = singleRel.getTraitSet();
+ // propagate all traits (except convention) from the original singleRel into the empty values
+ if (emptyValues.getConvention() != null) {
+ traits = traits.replace(emptyValues.getConvention());
+ }
+ emptyValues = emptyValues.copy(traits, Collections.emptyList());
+ call.transformTo(emptyValues);
}
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index cee5808..f096e39 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -3463,4 +3463,23 @@ public class RelBuilderTest {
builder.literal(5));
assertThat(call.toStringRaw(), is("BETWEEN ASYMMETRIC($0, 1, 5)"));
}
+
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-3926">[CALCITE-3926]
+ * CannotPlanException when an empty LogicalValues requires a certain collation</a>. */
+ @Test void testEmptyValuesWithCollation() throws Exception {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder
+ .scan("DEPT").empty()
+ .sort(
+ builder.field("DNAME"),
+ builder.field("DEPTNO"))
+ .build();
+ try (PreparedStatement preparedStatement = RelRunners.run(root)) {
+ final String result = CalciteAssert.toString(preparedStatement.executeQuery());
+ final String expectedResult = "";
+ assertThat(result, is(expectedResult));
+ }
+ }
}
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 468f509..4ff8902 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -3430,6 +3430,7 @@ class RelOptRulesTest extends RelOptTestBase {
@Test void testEmptySort() {
HepProgram program = new HepProgramBuilder()
.addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+ .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
.addRuleInstance(PruneEmptyRules.SORT_INSTANCE)
.build();
@@ -3437,6 +3438,30 @@ class RelOptRulesTest extends RelOptTestBase {
sql(sql).with(program).check();
}
+ @Test void testEmptySort2() {
+ final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
+ final RelNode relNode = relBuilder
+ .scan("DEPT").empty()
+ .sort(
+ relBuilder.field("DNAME"),
+ relBuilder.field("DEPTNO"))
+ .build();
+
+ final HepProgram program = new HepProgramBuilder()
+ .addRuleInstance(PruneEmptyRules.SORT_INSTANCE)
+ .build();
+
+ final HepPlanner hepPlanner = new HepPlanner(program);
+ hepPlanner.setRoot(relNode);
+ final RelNode output = hepPlanner.findBestExp();
+
+ final String planBefore = NL + RelOptUtil.toString(relNode);
+ final String planAfter = NL + RelOptUtil.toString(output);
+ final DiffRepository diffRepos = getDiffRepos();
+ diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
+ diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ }
+
@Test void testEmptySortLimitZero() {
final String sql = "select * from emp order by deptno limit 0";
sql(sql).withRule(PruneEmptyRules.SORT_FETCH_ZERO_INSTANCE).check();
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 4b6d286..2685ee7 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3168,9 +3168,20 @@ LogicalSort(sort0=[$7], dir0=[ASC])
</Resource>
<Resource name="planAfter">
<![CDATA[
-LogicalSort(sort0=[$7], dir0=[ASC])
- LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
- LogicalValues(tuples=[[]])
+LogicalValues(tuples=[[]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testEmptySort2">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[ASC])
+ LogicalValues(tuples=[[]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>