You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by am...@apache.org on 2021/01/22 04:49:46 UTC
[calcite] branch master updated: [CALCITE-4466] Do not invoke
RelTraitDef.convert when the source trait satisfies the target trait
(Vladimir Ozerov)
This is an automated email from the ASF dual-hosted git repository.
amaliujia 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 2ee4d84 [CALCITE-4466] Do not invoke RelTraitDef.convert when the source trait satisfies the target trait (Vladimir Ozerov)
2ee4d84 is described below
commit 2ee4d841312049298840c22d36db6ab980ec5994
Author: devozerov <pp...@gmail.com>
AuthorDate: Wed Jan 13 19:48:12 2021 +0300
[CALCITE-4466] Do not invoke RelTraitDef.convert when the source trait satisfies the target trait (Vladimir Ozerov)
---
.../calcite/plan/volcano/VolcanoPlanner.java | 2 +-
.../plan/volcano/MultipleTraitConversionTest.java | 189 +++++++++++++++++++++
2 files changed, 190 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 68ca86d..8ee6c20 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -821,7 +821,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
}
assert traitDef == toTrait.getTraitDef();
- if (fromTrait.equals(toTrait)) {
+ if (fromTrait.satisfies(toTrait)) {
// No need to convert; it's already correct.
continue;
}
diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/MultipleTraitConversionTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/MultipleTraitConversionTest.java
new file mode 100644
index 0000000..5868664
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/plan/volcano/MultipleTraitConversionTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.plan.volcano;
+
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelTraitDef;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.SingleRel;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.util.ImmutableIntList;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.apache.calcite.plan.volcano.PlannerTests.newCluster;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests that ensures that we do not add enforcers for the already satisfied traits.
+ * See https://issues.apache.org/jira/browse/CALCITE-4466 for more information.
+ */
+public class MultipleTraitConversionTest {
+ @SuppressWarnings("ConstantConditions")
+ @Test public void testMultipleTraitConversion() {
+ VolcanoPlanner planner = new VolcanoPlanner();
+
+ planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
+ planner.addRelTraitDef(RelCollationTraitDef.INSTANCE);
+ planner.addRelTraitDef(CustomTraitDef.INSTANCE);
+ planner.setNoneConventionHasInfiniteCost(false);
+
+ RelOptCluster cluster = newCluster(planner);
+
+ RelTraitSet fromTraits = cluster.traitSetOf(RelCollations.of(ImmutableIntList.of(0, 1)));
+
+ RelTraitSet toTraits = fromTraits
+ .plus(RelCollations.of(0))
+ .plus(CustomTrait.TO);
+
+ CustomLeafRel rel = new CustomLeafRel(cluster, fromTraits);
+ planner.setRoot(rel);
+
+ RelNode convertedRel = planner.changeTraitsUsingConverters(rel, toTraits);
+ assertEquals(CustomTraitEnforcer.class, convertedRel.getClass());
+ assertTrue(convertedRel.getTraitSet().satisfies(toTraits));
+
+ // Make sure that the equivalence set contains only the original and converted rels.
+ // It should not contain the collation enforcer, because the "from" collation already
+ // satisfies the "to" collation.
+ List<RelNode> rels = planner.getSubset(rel).set.rels;
+ assertEquals(2, rels.size());
+ assertTrue(rels.stream().anyMatch(r -> r instanceof CustomLeafRel));
+ assertTrue(rels.stream().anyMatch(r -> r instanceof CustomTraitEnforcer));
+ }
+
+ /**
+ * Leaf rel.
+ */
+ private static class CustomLeafRel extends PlannerTests.TestLeafRel {
+ CustomLeafRel(RelOptCluster cluster, RelTraitSet traits) {
+ super(cluster, traits, CustomLeafRel.class.getSimpleName());
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ return new CustomLeafRel(getCluster(), traitSet);
+ }
+
+ @Override public @Nullable RelOptCost computeSelfCost(RelOptPlanner planner,
+ RelMetadataQuery mq) {
+ return planner.getCostFactory().makeTinyCost();
+ }
+ }
+
+ /**
+ * An enforcer used by the custom trait def.
+ */
+ private static class CustomTraitEnforcer extends SingleRel {
+ private CustomTraitEnforcer(RelOptCluster cluster, RelTraitSet traits, RelNode input) {
+ super(cluster, traits, input);
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ return new CustomTraitEnforcer(getCluster(), traitSet, inputs.get(0));
+ }
+ }
+
+ /**
+ * Custom trait.
+ */
+ private static class CustomTrait implements RelTrait {
+
+ private static final CustomTrait FROM = new CustomTrait("FROM");
+ private static final CustomTrait TO = new CustomTrait("TO");
+
+ private final String label;
+
+ private CustomTrait(String label) {
+ this.label = label;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override public RelTraitDef getTraitDef() {
+ return CustomTraitDef.INSTANCE;
+ }
+
+ @Override public boolean satisfies(RelTrait trait) {
+ return equals(trait);
+ }
+
+ @Override public void register(RelOptPlanner planner) {
+ // No-op
+ }
+
+ @Override public String toString() {
+ return label;
+ }
+
+ @Override public boolean equals(Object o) {
+ return (o instanceof CustomTrait) && label.equals(((CustomTrait) o).label);
+ }
+
+ @Override public int hashCode() {
+ return label.hashCode();
+ }
+ }
+
+ /**
+ * Custom trait definition.
+ */
+ private static class CustomTraitDef extends RelTraitDef<CustomTrait> {
+
+ private static final CustomTraitDef INSTANCE = new CustomTraitDef();
+
+ @Override public Class<CustomTrait> getTraitClass() {
+ return CustomTrait.class;
+ }
+
+ @Override public String getSimpleName() {
+ return "custom";
+ }
+
+ @Override public @Nullable RelNode convert(
+ RelOptPlanner planner,
+ RelNode rel,
+ CustomTrait toTrait,
+ boolean allowInfiniteCostConverters
+ ) {
+ return new CustomTraitEnforcer(
+ rel.getCluster(),
+ rel.getTraitSet().replace(toTrait),
+ rel
+ );
+ }
+
+ @Override public boolean canConvert(RelOptPlanner planner, CustomTrait fromTrait,
+ CustomTrait toTrait) {
+ return true;
+ }
+
+ @Override public CustomTrait getDefault() {
+ return CustomTrait.FROM;
+ }
+ }
+}