You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/04/01 22:05:15 UTC
[1/3] incubator-calcite git commit: Fix
TestTraitPropagation.withoutHack (withoutHack now succeeds,
withHack now fails).
Repository: incubator-calcite
Updated Branches:
refs/heads/master a13137dc9 -> 3b55c35a5
Fix TestTraitPropagation.withoutHack (withoutHack now succeeds, withHack now fails).
Deduce the collations of a RelSubset by looking at its traits. (For other kinds of RelNode that would cause a cycle.)
Remove AbstractConverters again (Jacques had restored them, but performance was terrible.)
When creating a RelSubset make sure that its traits are simple. (Occurs when creating a subset to convert an existing rel that has multiple collations to a different calling convention. The subset can only have one collation.)
Add a version of RelOptRule.convert that takes a single trait, to avoid simplifying other traits of that RelNode. Many current calls to convert(RelNode, RelTraitSet) should probably use this method.
Add a short-cut to RelTraitSet.replace for the case where the new trait is canonized and the same as the old.
In TestTraitPropagation, use SortRemoveRule; implement RelOptTable.unwrap and Table.getStatistic and use EnumerableTableScan.create, so that table scan is sorted; make PhysSortRule a ConvertRule, so that its input ends up in the same RelSet; fix a typo giving PhysTable the wrong convention.
Call simplify in RelOptRule.convert rather than VolcanoPlanner.
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/3b55c35a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/3b55c35a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/3b55c35a
Branch: refs/heads/master
Commit: 3b55c35a58b45d2a8538f9bc77f11e51a2d45e6b
Parents: b312031
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Mar 3 20:23:02 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Wed Apr 1 01:52:46 2015 -0400
----------------------------------------------------------------------
.../org/apache/calcite/plan/RelOptRule.java | 27 +-
.../org/apache/calcite/plan/RelTraitSet.java | 28 +-
.../org/apache/calcite/plan/volcano/RelSet.java | 44 +-
.../calcite/plan/volcano/VolcanoPlanner.java | 6 +-
.../calcite/rel/metadata/RelMdCollation.java | 7 +
.../plan/volcano/TestTraitPropagation.java | 418 ------------------
.../plan/volcano/TraitPropagationTest.java | 433 +++++++++++++++++++
.../org/apache/calcite/test/CalciteSuite.java | 2 +
8 files changed, 499 insertions(+), 466 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
index 058736d..464568a 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
@@ -480,9 +480,8 @@ public abstract class RelOptRule {
}
/**
- * Converts a relation expression to a give set of traits, if it does not
- * already have those traits. If the conversion is not possible, returns
- * null.
+ * Converts a relation expression to a given set of traits, if it does not
+ * already have those traits.
*
* @param rel Relational expression to convert
* @param toTraits desired traits
@@ -511,6 +510,28 @@ public abstract class RelOptRule {
}
/**
+ * Converts one trait of a relational expression, if it does not
+ * already have that trait.
+ *
+ * @param rel Relational expression to convert
+ * @param toTrait Desired trait
+ * @return a relational expression with the desired trait; never null
+ */
+ public static RelNode convert(RelNode rel, RelTrait toTrait) {
+ RelOptPlanner planner = rel.getCluster().getPlanner();
+ RelTraitSet outTraits = rel.getTraitSet();
+ if (toTrait != null) {
+ outTraits = outTraits.replace(toTrait);
+ }
+
+ if (rel.getTraitSet().matches(outTraits)) {
+ return rel;
+ }
+
+ return planner.changeTraits(rel, outTraits.simplify());
+ }
+
+ /**
* Converts a list of relational expressions.
*
* @param rels Relational expressions
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
index f4b0eac..5499bdb 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
@@ -180,6 +180,10 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
*/
public RelTraitSet replace(
RelTrait trait) {
+ // Quick check for common case
+ if (containsShallow(traits, trait)) {
+ return this;
+ }
final RelTraitDef traitDef = trait.getTraitDef();
int index = findIndex(traitDef);
if (index < 0) {
@@ -190,6 +194,18 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
return replace(index, trait);
}
+ /** Returns whether an element occurs within an array.
+ *
+ * <p>Uses {@code ==}, not {@link #equals}. Nulls are allowed. */
+ private static <T> boolean containsShallow(T[] ts, RelTrait seek) {
+ for (T t : ts) {
+ if (t == seek) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** Replaces the trait(s) of a given type with a list of traits of the same
* type.
*
@@ -259,7 +275,7 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
if (trait instanceof RelCompositeTrait) {
// Composite traits are canonized on creation
//noinspection unchecked
- return (T) trait;
+ return trait;
}
//noinspection unchecked
@@ -452,6 +468,7 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
// Then we can justify the cost of computing RelTraitSet.string in the
// constructor.
final RelTrait canonizedTrait = canonize(trait);
+ assert canonizedTrait != null;
List<RelTrait> newTraits;
switch (traits.length) {
case 0:
@@ -511,13 +528,10 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
for (int i = 0; i < traits.length; i++) {
final RelTrait trait = traits[i];
if (trait instanceof RelCompositeTrait) {
- //noinspection unchecked
- final RelCompositeTrait<RelMultipleTrait> compositeTrait =
- (RelCompositeTrait<RelMultipleTrait>) trait;
x = x.replace(i,
- compositeTrait.size() == 0
- ? trait.getTraitDef().getDefault()
- : compositeTrait.trait(0));
+ ((RelCompositeTrait) trait).size() == 1
+ ? ((RelCompositeTrait) trait).trait(0)
+ : trait.getTraitDef().getDefault());
}
}
return x;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index ed2c6b7..93d8509 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -16,14 +16,6 @@
*/
package org.apache.calcite.plan.volcano;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-
-import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.ConventionTraitDef;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptListener;
import org.apache.calcite.plan.RelOptUtil;
@@ -34,6 +26,12 @@ import org.apache.calcite.util.trace.CalciteTrace;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
/**
* A <code>RelSet</code> is an equivalence-set of expressions; that is, a set of
* expressions which have identical semantics. We are generally interested in
@@ -158,35 +156,11 @@ class RelSet {
final VolcanoPlanner planner =
(VolcanoPlanner) cluster.getPlanner();
-// if (planner.root != null
-// && planner.root.set == this) {
-// planner.ensureRootConverters();
-// }
-
- // Add converters to convert the new subset to each existing subset.
- for (RelSubset subset1 : subsets) {
- if (subset1.getConvention() == Convention.NONE) {
- continue;
- }
- final AbstractConverter converter =
- new AbstractConverter(
- cluster, subset, ConventionTraitDef.INSTANCE,
- subset1.getTraitSet());
- planner.register(converter, subset1);
- }
-
subsets.add(subset);
- // Add converters to convert each existing subset to this subset.
- for (RelSubset subset1 : subsets) {
- if (subset1 == subset) {
- continue;
- }
- final AbstractConverter converter =
- new AbstractConverter(
- cluster, subset1, ConventionTraitDef.INSTANCE,
- traits);
- planner.register(converter, subset);
+ if (planner.root != null
+ && planner.root.set == this) {
+ planner.ensureRootConverters();
}
if (planner.listener != null) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
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 d26ad6b..06bff19 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
@@ -684,15 +684,15 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
}
public RelNode changeTraits(final RelNode rel, RelTraitSet toTraits) {
- assert !rel.getTraitSet().equals(toTraits)
- : "pre: !rel.getTraits().equals(toTraits)";
+ assert !rel.getTraitSet().equals(toTraits);
+ assert toTraits.allSimple();
RelSubset rel2 = ensureRegistered(rel, null);
if (rel2.getTraitSet().equals(toTraits)) {
return rel2;
}
- return rel2.set.getOrCreateSubset(rel.getCluster(), toTraits);
+ return rel2.set.getOrCreateSubset(rel.getCluster(), toTraits.simplify());
}
public RelOptPlanner chooseDelegate() {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 98830e8..614c111 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -20,7 +20,9 @@ import org.apache.calcite.adapter.enumerable.EnumerableMergeJoin;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.hep.HepRelVertex;
+import org.apache.calcite.plan.volcano.RelSubset;
import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
@@ -134,6 +136,11 @@ public class RelMdCollation {
return RelMetadataQuery.collations(rel.getCurrentRel());
}
+ public ImmutableList<RelCollation> collations(RelSubset rel) {
+ return ImmutableList.copyOf(
+ rel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE));
+ }
+
// Helper methods
/** Helper method to determine a
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java b/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
deleted file mode 100644
index e2dc6fd..0000000
--- a/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * 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 static org.junit.Assert.assertEquals;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-
-import org.apache.calcite.adapter.enumerable.EnumerableConvention;
-import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.jdbc.CalcitePrepare;
-import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.ConventionTraitDef;
-import org.apache.calcite.plan.RelOptAbstractTable;
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptCost;
-import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelOptQuery;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.plan.RelOptSchema;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.plan.RelTrait;
-import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.plan.volcano.AbstractConverter.ExpandConversionRule;
-import org.apache.calcite.prepare.CalciteCatalogReader;
-import org.apache.calcite.rel.AbstractRelNode;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Aggregate;
-import org.apache.calcite.rel.core.AggregateCall;
-import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.logical.LogicalAggregate;
-import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Table;
-import org.apache.calcite.schema.impl.AbstractTable;
-import org.apache.calcite.server.CalciteServerStatement;
-import org.apache.calcite.sql.SqlExplainLevel;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.tools.FrameworkConfig;
-import org.apache.calcite.tools.Frameworks;
-import org.apache.calcite.tools.RuleSet;
-import org.apache.calcite.tools.RuleSets;
-import org.apache.calcite.util.ImmutableBitSet;
-
-/**
- * Tests that determine whether trait propagation work in Volcano Planner
- */
-public class TestTraitPropagation {
-
- static final Convention PHYSICAL =
- new Convention.Impl("PHYSICAL", Phys.class);
- static final RelCollation COLLATION =
- RelCollations.of(new RelFieldCollation(0,
- RelFieldCollation.Direction.ASCENDING,
- RelFieldCollation.NullDirection.FIRST));
-
- static final RuleSet RULES_NO_HACK = RuleSets.ofList(
- PhysAggRule.INSTANCE, //
- PhysProjRule.INSTANCE, //
- PhysTableRule.INSTANCE, //
- PhysSortRule.INSTANCE, //
- ExpandConversionRule.INSTANCE //
- );
-
- static final RuleSet RULES_HACK = RuleSets.ofList(
- PhysAggRule.INSTANCE, //
- PhysProjRule.INSTANCE_HACK, //
- PhysTableRule.INSTANCE, //
- PhysSortRule.INSTANCE, //
- ExpandConversionRule.INSTANCE //
- );
-
- @Test
- public void withoutHack() throws Exception {
- RelNode planned = run(new PropAction(), RULES_NO_HACK);
- System.out.println(RelOptUtil.dumpPlan("LOGICAL PLAN", planned, false,
- SqlExplainLevel.ALL_ATTRIBUTES));
- assertEquals("Sortedness was not propagated", 3,
- RelMetadataQuery.getCumulativeCost(planned).getRows(), 0);
- }
-
- @Test
- public void withHack() throws Exception {
- RelNode planned = run(new PropAction(), RULES_HACK);
- System.out.println(RelOptUtil.dumpPlan("LOGICAL PLAN", planned, false,
- SqlExplainLevel.ALL_ATTRIBUTES));
- assertEquals("Sortedness was not propagated", 3,
- RelMetadataQuery.getCumulativeCost(planned).getRows(), 0);
- }
-
- /**
- * Materialized anonymous class for simplicity
- */
- private class PropAction {
- public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema,
- SchemaPlus rootSchema) {
- final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
- final RexBuilder rexBuilder = cluster.getRexBuilder();
- final RelOptPlanner planner = cluster.getPlanner();
-
- final RelDataType stringType = typeFactory.createJavaType(String.class);
- final RelDataType integerType = typeFactory.createJavaType(Integer.class);
- final RelDataType sqlBigInt = typeFactory
- .createSqlType(SqlTypeName.BIGINT);
-
- // SELECT * from T;
- final Table table = new AbstractTable() {
- public RelDataType getRowType(RelDataTypeFactory typeFactory) {
- return typeFactory.builder().add("s", stringType)
- .add("i", integerType).build();
- }
- };
-
- final RelOptAbstractTable t1 = new RelOptAbstractTable(relOptSchema,
- "t1", table.getRowType(typeFactory)) {
- };
-
- final RelNode rt1 = new EnumerableTableScan(cluster,
- cluster.traitSetOf(EnumerableConvention.INSTANCE), t1,
- Object[].class);
-
- // project s column
- RelNode project = new LogicalProject(cluster,
- cluster.traitSetOf(Convention.NONE), rt1,
- ImmutableList.of(
- (RexNode) rexBuilder.makeInputRef(stringType, 0),
- rexBuilder.makeInputRef(integerType, 1)),
- typeFactory.builder().add("s", stringType).add("i", integerType)
- .build());
-
- // aggregate on s, count
- AggregateCall aggCall = new AggregateCall(SqlStdOperatorTable.COUNT,
- false, Collections.singletonList(1),
- sqlBigInt, "cnt");
- RelNode agg = new LogicalAggregate(cluster,
- cluster.traitSetOf(Convention.NONE), project, false,
- ImmutableBitSet.of(0), null, Collections.singletonList(aggCall));
-
- final RelNode rootRel = agg;
-
- RelOptUtil.dumpPlan("LOGICAL PLAN", rootRel, false,
- SqlExplainLevel.DIGEST_ATTRIBUTES);
-
- RelTraitSet desiredTraits = rootRel.getTraitSet().replace(PHYSICAL);
- final RelNode rootRel2 = planner.changeTraits(rootRel, desiredTraits);
- planner.setRoot(rootRel2);
- return planner.findBestExp();
- }
- }
-
-
- /* RULES */
- /** Rule for PhysAgg */
- private static class PhysAggRule extends RelOptRule {
- static final PhysAggRule INSTANCE = new PhysAggRule();
-
- private PhysAggRule() {
- super(anyChild(LogicalAggregate.class), "PhysAgg");
- }
-
- public void onMatch(RelOptRuleCall call) {
- RelTraitSet empty = call.getPlanner().emptyTraitSet();
- LogicalAggregate rel = (LogicalAggregate) call.rel(0);
- assert rel.getGroupSet().cardinality() == 1;
- int aggIndex = rel.getGroupSet().iterator().next();
- RelTrait collation = RelCollations.of(new RelFieldCollation(aggIndex,
- RelFieldCollation.Direction.ASCENDING,
- RelFieldCollation.NullDirection.FIRST));
- RelTraitSet desiredTraits = empty.replace(PHYSICAL).replace(collation);
- RelNode convertedInput = convert(rel.getInput(), desiredTraits);
- call.transformTo(new PhysAgg(rel.getCluster(), empty.replace(PHYSICAL),
- convertedInput, rel.indicator, rel
- .getGroupSet(), rel.getGroupSets(), rel.getAggCallList()));
- }
- }
-
- /** Rule for PhysProj */
- private static class PhysProjRule extends RelOptRule {
- static final PhysProjRule INSTANCE = new PhysProjRule(false);
- static final PhysProjRule INSTANCE_HACK = new PhysProjRule(true);
-
- final boolean subsetHack;
-
- private PhysProjRule(boolean subsetHack) {
- super(RelOptRule.operand(LogicalProject.class,
- anyChild(RelNode.class)), "PhysProj");
- this.subsetHack = subsetHack;
- }
-
- public void onMatch(RelOptRuleCall call) {
- RelTraitSet empty = call.getPlanner().emptyTraitSet();
- LogicalProject rel = (LogicalProject) call.rel(0);
- RelNode input = convert(rel.getInput(), empty.replace(PHYSICAL));
-
-
- if (subsetHack && input instanceof RelSubset) {
- RelSubset subset = (RelSubset) input;
- for (RelNode child : subset.getRels()) {
- // skip logical nodes
- if (child.getTraitSet().getTrait(ConventionTraitDef.INSTANCE)
- == Convention.NONE) {
- continue;
- } else {
- RelTraitSet outcome = child.getTraitSet().replace(PHYSICAL);
- call.transformTo(new PhysProj(rel.getCluster(), outcome,
- convert(child, outcome), rel.getChildExps(), rel.getRowType()));
- }
- }
- } else {
- call.transformTo(new PhysProj(rel.getCluster(), input.getTraitSet(),
- input, rel.getChildExps(), rel.getRowType()));
- }
-
- }
- }
-
- /** Rule for PhysSort */
- private static class PhysSortRule extends RelOptRule {
- static final PhysSortRule INSTANCE = new PhysSortRule();
-
- private PhysSortRule() {
- super(anyChild(Sort.class), "PhysSort");
- }
-
- public boolean matches(RelOptRuleCall call) {
- return !(call.rel(0) instanceof PhysSort);
- }
-
- public void onMatch(RelOptRuleCall call) {
- RelTraitSet empty = call.getPlanner().emptyTraitSet();
- Sort rel = (Sort) call.rel(0);
- RelNode input = convert(rel.getInput(), empty.plus(PHYSICAL));
- call.transformTo(
- new PhysSort(rel.getCluster(),
- input.getTraitSet().plus(rel.getCollation()),
- input, rel.getCollation(), rel.offset,
- rel.fetch));
- }
- }
-
- /** Rule for PhysTable */
- private static class PhysTableRule extends RelOptRule {
- static final PhysTableRule INSTANCE = new PhysTableRule();
-
- private PhysTableRule() {
- super(anyChild(EnumerableTableScan.class), "PhysScan");
- }
-
- public void onMatch(RelOptRuleCall call) {
- EnumerableTableScan rel = (EnumerableTableScan) call.rel(0);
- call.transformTo(new PhysTable(rel.getCluster()));
- }
- }
-
- /* RELS */
- /** Market interface for Phys nodes */
- private interface Phys extends RelNode { }
-
- /** Physical Aggregate RelNode */
- private static class PhysAgg extends Aggregate implements Phys {
- public PhysAgg(RelOptCluster cluster, RelTraitSet traits, RelNode child,
- boolean indicator, ImmutableBitSet groupSet,
- List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
- super(cluster, traits, child, indicator, groupSet, groupSets, aggCalls);
-
- }
-
- public Aggregate copy(RelTraitSet traitSet, RelNode input,
- boolean indicator, ImmutableBitSet groupSet,
- List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
- return new PhysAgg(getCluster(), traitSet, input, indicator, groupSet,
- groupSets, aggCalls);
- }
-
- public RelOptCost computeSelfCost(RelOptPlanner planner) {
- return planner.getCostFactory().makeCost(1, 1, 1);
- }
- }
-
- /** Physical Project RelNode */
- private static class PhysProj extends Project implements Phys {
- public PhysProj(RelOptCluster cluster, RelTraitSet traits, RelNode child,
- List<RexNode> exps, RelDataType rowType) {
- super(cluster, traits, child, exps, rowType);
- }
-
- public PhysProj copy(RelTraitSet traitSet, RelNode input,
- List<RexNode> exps, RelDataType rowType) {
- return new PhysProj(getCluster(), traitSet, input, exps, rowType);
- }
-
- public RelOptCost computeSelfCost(RelOptPlanner planner) {
- return planner.getCostFactory().makeCost(1, 1, 1);
- }
- }
-
- /** Physical Sort RelNode */
- private static class PhysSort extends Sort implements Phys {
- public PhysSort(RelOptCluster cluster, RelTraitSet traits, RelNode child,
- RelCollation collation, RexNode offset,
- RexNode fetch) {
- super(cluster, traits, child, collation, offset, fetch);
-
- }
-
- public PhysSort copy(RelTraitSet traitSet, RelNode newInput,
- RelCollation newCollation, RexNode offset,
- RexNode fetch) {
- return new PhysSort(getCluster(), traitSet, newInput, newCollation,
- offset, fetch);
- }
-
- public RelOptCost computeSelfCost(RelOptPlanner planner) {
- return planner.getCostFactory().makeCost(1, 1, 1);
- }
- }
-
- /** Physical Table RelNode */
- private static class PhysTable extends AbstractRelNode implements Phys {
- public PhysTable(RelOptCluster cluster) {
- super(cluster, cluster.traitSet().replace(PHYSICAL).replace(COLLATION));
- RelDataTypeFactory typeFactory = cluster.getTypeFactory();
- final RelDataType stringType = typeFactory.createJavaType(String.class);
- final RelDataType integerType = typeFactory.createJavaType(Integer.class);
- this.rowType = typeFactory.builder().add("s", stringType)
- .add("i", integerType).build();
- }
-
- public RelOptCost computeSelfCost(RelOptPlanner planner) {
- return planner.getCostFactory().makeCost(1, 1, 1);
- }
- }
-
- /* UTILS */
- public static RelOptRuleOperand anyChild(Class<? extends RelNode> first) {
- return RelOptRule.operand(first, RelOptRule.any());
- }
-
- // Created so that we can control when the TraitDefs are defined (e.g.
- // before the cluster is created).
- private static RelNode run(PropAction action, RuleSet rules)
- throws Exception {
-
- FrameworkConfig config = Frameworks.newConfigBuilder()
- .ruleSets(rules).build();
-
- final Properties info = new Properties();
- final Connection connection = DriverManager
- .getConnection("jdbc:calcite:", info);
- final CalciteServerStatement statement = connection
- .createStatement().unwrap(CalciteServerStatement.class);
- final CalcitePrepare.Context prepareContext =
- statement.createPrepareContext();
- final JavaTypeFactory typeFactory = prepareContext.getTypeFactory();
- CalciteCatalogReader catalogReader =
- new CalciteCatalogReader(prepareContext.getRootSchema(),
- prepareContext.config().caseSensitive(),
- prepareContext.getDefaultSchemaPath(),
- typeFactory);
- final RexBuilder rexBuilder = new RexBuilder(typeFactory);
- final RelOptPlanner planner = new VolcanoPlanner(config.getCostFactory(),
- config.getContext());
-
- // set up rules before we generate cluster
- planner.clearRelTraitDefs();
- planner.addRelTraitDef(RelCollationTraitDef.INSTANCE);
- planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
-
- planner.clear();
- for (RelOptRule r : rules) {
- planner.addRule(r);
- }
-
- final RelOptQuery query = new RelOptQuery(planner);
- final RelOptCluster cluster = query.createCluster(
- rexBuilder.getTypeFactory(), rexBuilder);
- return action.apply(cluster, catalogReader,
- prepareContext.getRootSchema().plus());
-
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/test/java/org/apache/calcite/plan/volcano/TraitPropagationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/TraitPropagationTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/TraitPropagationTest.java
new file mode 100644
index 0000000..dbd56b8
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/plan/volcano/TraitPropagationTest.java
@@ -0,0 +1,433 @@
+/*
+ * 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.adapter.enumerable.EnumerableTableScan;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptAbstractTable;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptQuery;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.plan.volcano.AbstractConverter.ExpandConversionRule;
+import org.apache.calcite.prepare.CalciteCatalogReader;
+import org.apache.calcite.prepare.CalcitePrepareImpl;
+import org.apache.calcite.rel.AbstractRelNode;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterRule;
+import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.metadata.RelMdCollation;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.rules.SortRemoveRule;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Statistic;
+import org.apache.calcite.schema.Statistics;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractTable;
+import org.apache.calcite.server.CalciteServerStatement;
+import org.apache.calcite.sql.SqlExplainLevel;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.tools.RuleSet;
+import org.apache.calcite.tools.RuleSets;
+import org.apache.calcite.util.ImmutableBitSet;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests that determine whether trait propagation work in Volcano Planner.
+ */
+public class TraitPropagationTest {
+ static final Convention PHYSICAL =
+ new Convention.Impl("PHYSICAL", Phys.class);
+ static final RelCollation COLLATION =
+ RelCollations.of(
+ new RelFieldCollation(0,
+ RelFieldCollation.Direction.ASCENDING,
+ RelFieldCollation.NullDirection.FIRST));
+
+ static final RuleSet RULES =
+ RuleSets.ofList(PhysAggRule.INSTANCE,
+ PhysProjRule.INSTANCE,
+ PhysTableRule.INSTANCE,
+ PhysSortRule.INSTANCE,
+ SortRemoveRule.INSTANCE,
+ ExpandConversionRule.INSTANCE);
+
+ @Test public void testOne() throws Exception {
+ RelNode planned = run(new PropAction(), RULES);
+ if (CalcitePrepareImpl.DEBUG) {
+ System.out.println(
+ RelOptUtil.dumpPlan("LOGICAL PLAN", planned, false,
+ SqlExplainLevel.ALL_ATTRIBUTES));
+ }
+ assertEquals("Sortedness was not propagated", 3,
+ RelMetadataQuery.getCumulativeCost(planned).getRows(), 0);
+ }
+
+ /**
+ * Materialized anonymous class for simplicity
+ */
+ private static class PropAction {
+ public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema,
+ SchemaPlus rootSchema) {
+ final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
+ final RexBuilder rexBuilder = cluster.getRexBuilder();
+ final RelOptPlanner planner = cluster.getPlanner();
+
+ final RelDataType stringType = typeFactory.createJavaType(String.class);
+ final RelDataType integerType = typeFactory.createJavaType(Integer.class);
+ final RelDataType sqlBigInt =
+ typeFactory.createSqlType(SqlTypeName.BIGINT);
+
+ // SELECT * from T;
+ final Table table = new AbstractTable() {
+ public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+ return typeFactory.builder()
+ .add("s", stringType)
+ .add("i", integerType).build();
+ }
+
+ @Override public Statistic getStatistic() {
+ return Statistics.of(100d, ImmutableList.<ImmutableBitSet>of(),
+ ImmutableList.of(COLLATION));
+ }
+ };
+
+ final RelOptAbstractTable t1 = new RelOptAbstractTable(relOptSchema,
+ "t1", table.getRowType(typeFactory)) {
+ @Override public <T> T unwrap(Class<T> clazz) {
+ return clazz.isInstance(table)
+ ? clazz.cast(table)
+ : super.unwrap(clazz);
+ }
+ };
+
+ final RelNode rt1 = EnumerableTableScan.create(cluster, t1);
+
+ // project s column
+ RelNode project = LogicalProject.create(rt1,
+ ImmutableList.of(
+ (RexNode) rexBuilder.makeInputRef(stringType, 0),
+ rexBuilder.makeInputRef(integerType, 1)),
+ typeFactory.builder().add("s", stringType).add("i", integerType)
+ .build());
+
+ // aggregate on s, count
+ AggregateCall aggCall = new AggregateCall(SqlStdOperatorTable.COUNT,
+ false, Collections.singletonList(1),
+ sqlBigInt, "cnt");
+ RelNode agg = new LogicalAggregate(cluster,
+ cluster.traitSetOf(Convention.NONE), project, false,
+ ImmutableBitSet.of(0), null, Collections.singletonList(aggCall));
+
+ final RelNode rootRel = agg;
+
+ RelOptUtil.dumpPlan("LOGICAL PLAN", rootRel, false,
+ SqlExplainLevel.DIGEST_ATTRIBUTES);
+
+ RelTraitSet desiredTraits = rootRel.getTraitSet().replace(PHYSICAL);
+ final RelNode rootRel2 = planner.changeTraits(rootRel, desiredTraits);
+ planner.setRoot(rootRel2);
+ return planner.findBestExp();
+ }
+ }
+
+ // RULES
+
+ /** Rule for PhysAgg */
+ private static class PhysAggRule extends RelOptRule {
+ static final PhysAggRule INSTANCE = new PhysAggRule();
+
+ private PhysAggRule() {
+ super(anyChild(LogicalAggregate.class), "PhysAgg");
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ RelTraitSet empty = call.getPlanner().emptyTraitSet();
+ LogicalAggregate rel = call.rel(0);
+ assert rel.getGroupSet().cardinality() == 1;
+ int aggIndex = rel.getGroupSet().iterator().next();
+ RelTrait collation = RelCollations.of(
+ new RelFieldCollation(aggIndex,
+ RelFieldCollation.Direction.ASCENDING,
+ RelFieldCollation.NullDirection.FIRST));
+ RelTraitSet desiredTraits = empty.replace(PHYSICAL).replace(collation);
+ RelNode convertedInput = convert(rel.getInput(), desiredTraits);
+ call.transformTo(
+ new PhysAgg(rel.getCluster(), empty.replace(PHYSICAL),
+ convertedInput, rel.indicator, rel.getGroupSet(),
+ rel.getGroupSets(), rel.getAggCallList()));
+ }
+ }
+
+ /** Rule for PhysProj */
+ private static class PhysProjRule extends RelOptRule {
+ static final PhysProjRule INSTANCE = new PhysProjRule(false);
+
+ final boolean subsetHack;
+
+ private PhysProjRule(boolean subsetHack) {
+ super(
+ RelOptRule.operand(LogicalProject.class,
+ anyChild(RelNode.class)),
+ "PhysProj");
+ this.subsetHack = subsetHack;
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ LogicalProject rel = call.rel(0);
+ RelNode rawInput = call.rel(1);
+ RelNode input = convert(rawInput, PHYSICAL);
+
+ if (subsetHack && input instanceof RelSubset) {
+ RelSubset subset = (RelSubset) input;
+ for (RelNode child : subset.getRels()) {
+ // skip logical nodes
+ if (child.getTraitSet().getTrait(ConventionTraitDef.INSTANCE)
+ == Convention.NONE) {
+ continue;
+ } else {
+ RelTraitSet outcome = child.getTraitSet().replace(PHYSICAL);
+ call.transformTo(
+ new PhysProj(rel.getCluster(), outcome, convert(child, outcome),
+ rel.getChildExps(), rel.getRowType()));
+ }
+ }
+ } else {
+ call.transformTo(
+ PhysProj.create(input, rel.getChildExps(), rel.getRowType()));
+ }
+
+ }
+ }
+
+ /** Rule for PhysSort */
+ private static class PhysSortRule extends ConverterRule {
+ static final PhysSortRule INSTANCE = new PhysSortRule();
+
+ PhysSortRule() {
+ super(Sort.class, Convention.NONE, PHYSICAL, "PhysSortRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final Sort sort = (Sort) rel;
+ final RelNode input = convert(sort.getInput(),
+ rel.getCluster().traitSetOf(PHYSICAL));
+ return new PhysSort(
+ rel.getCluster(),
+ input.getTraitSet().plus(sort.getCollation()),
+ convert(input, input.getTraitSet().replace(PHYSICAL)),
+ sort.getCollation(),
+ null,
+ null);
+ }
+ }
+
+ /** Rule for PhysTable */
+ private static class PhysTableRule extends RelOptRule {
+ static final PhysTableRule INSTANCE = new PhysTableRule();
+
+ private PhysTableRule() {
+ super(anyChild(EnumerableTableScan.class), "PhysScan");
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ EnumerableTableScan rel = call.rel(0);
+ call.transformTo(new PhysTable(rel.getCluster()));
+ }
+ }
+
+ /* RELS */
+ /** Market interface for Phys nodes */
+ private interface Phys extends RelNode { }
+
+ /** Physical Aggregate RelNode */
+ private static class PhysAgg extends Aggregate implements Phys {
+ public PhysAgg(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ boolean indicator, ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
+ super(cluster, traits, child, indicator, groupSet, groupSets, aggCalls);
+
+ }
+
+ public Aggregate copy(RelTraitSet traitSet, RelNode input,
+ boolean indicator, ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
+ return new PhysAgg(getCluster(), traitSet, input, indicator, groupSet,
+ groupSets, aggCalls);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Project RelNode */
+ private static class PhysProj extends Project implements Phys {
+ public PhysProj(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ List<RexNode> exps, RelDataType rowType) {
+ super(cluster, traits, child, exps, rowType);
+ }
+
+ public static PhysProj create(final RelNode input,
+ final List<RexNode> projects, RelDataType rowType) {
+ final RelOptCluster cluster = input.getCluster();
+ final RelTraitSet traitSet =
+ cluster.traitSet().replace(PHYSICAL)
+ .replaceIfs(
+ RelCollationTraitDef.INSTANCE,
+ new Supplier<List<RelCollation>>() {
+ public List<RelCollation> get() {
+ return RelMdCollation.project(input, projects);
+ }
+ });
+ return new PhysProj(cluster, traitSet, input, projects, rowType);
+ }
+
+ public PhysProj copy(RelTraitSet traitSet, RelNode input,
+ List<RexNode> exps, RelDataType rowType) {
+ return new PhysProj(getCluster(), traitSet, input, exps, rowType);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Sort RelNode */
+ private static class PhysSort extends Sort implements Phys {
+ public PhysSort(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ RelCollation collation, RexNode offset,
+ RexNode fetch) {
+ super(cluster, traits, child, collation, offset, fetch);
+
+ }
+
+ public PhysSort copy(RelTraitSet traitSet, RelNode newInput,
+ RelCollation newCollation, RexNode offset,
+ RexNode fetch) {
+ return new PhysSort(getCluster(), traitSet, newInput, newCollation,
+ offset, fetch);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Table RelNode */
+ private static class PhysTable extends AbstractRelNode implements Phys {
+ public PhysTable(RelOptCluster cluster) {
+ super(cluster, cluster.traitSet().replace(PHYSICAL).replace(COLLATION));
+ RelDataTypeFactory typeFactory = cluster.getTypeFactory();
+ final RelDataType stringType = typeFactory.createJavaType(String.class);
+ final RelDataType integerType = typeFactory.createJavaType(Integer.class);
+ this.rowType = typeFactory.builder().add("s", stringType)
+ .add("i", integerType).build();
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /* UTILS */
+ public static RelOptRuleOperand anyChild(Class<? extends RelNode> first) {
+ return RelOptRule.operand(first, RelOptRule.any());
+ }
+
+ // Created so that we can control when the TraitDefs are defined (e.g.
+ // before the cluster is created).
+ private static RelNode run(PropAction action, RuleSet rules)
+ throws Exception {
+
+ FrameworkConfig config = Frameworks.newConfigBuilder()
+ .ruleSets(rules).build();
+
+ final Properties info = new Properties();
+ final Connection connection = DriverManager
+ .getConnection("jdbc:calcite:", info);
+ final CalciteServerStatement statement = connection
+ .createStatement().unwrap(CalciteServerStatement.class);
+ final CalcitePrepare.Context prepareContext =
+ statement.createPrepareContext();
+ final JavaTypeFactory typeFactory = prepareContext.getTypeFactory();
+ CalciteCatalogReader catalogReader =
+ new CalciteCatalogReader(prepareContext.getRootSchema(),
+ prepareContext.config().caseSensitive(),
+ prepareContext.getDefaultSchemaPath(),
+ typeFactory);
+ final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+ final RelOptPlanner planner = new VolcanoPlanner(config.getCostFactory(),
+ config.getContext());
+
+ // set up rules before we generate cluster
+ planner.clearRelTraitDefs();
+ planner.addRelTraitDef(RelCollationTraitDef.INSTANCE);
+ planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
+
+ planner.clear();
+ for (RelOptRule r : rules) {
+ planner.addRule(r);
+ }
+
+ final RelOptQuery query = new RelOptQuery(planner);
+ final RelOptCluster cluster = query.createCluster(
+ rexBuilder.getTypeFactory(), rexBuilder);
+ return action.apply(cluster, catalogReader,
+ prepareContext.getRootSchema().plus());
+ }
+}
+
+// End TraitPropagationTest.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b55c35a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
index 24e642b..f50a8f1 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
@@ -20,6 +20,7 @@ import org.apache.calcite.adapter.clone.ArrayTableTest;
import org.apache.calcite.jdbc.CalciteRemoteDriverTest;
import org.apache.calcite.plan.RelOptUtilTest;
import org.apache.calcite.plan.RelWriterTest;
+import org.apache.calcite.plan.volcano.TraitPropagationTest;
import org.apache.calcite.plan.volcano.VolcanoPlannerTest;
import org.apache.calcite.plan.volcano.VolcanoPlannerTraitTest;
import org.apache.calcite.rel.RelCollationTest;
@@ -79,6 +80,7 @@ import org.junit.runners.Suite;
InterpreterTest.class,
VolcanoPlannerTest.class,
HepPlannerTest.class,
+ TraitPropagationTest.class,
RelWriterTest.class,
RexProgramTest.class,
RexTransformerTest.class,
[3/3] incubator-calcite git commit: Remove checkstyle Eclipse
properties from git tracking
Posted by jh...@apache.org.
Remove checkstyle Eclipse properties from git tracking
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/d3fc7cf2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/d3fc7cf2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/d3fc7cf2
Branch: refs/heads/master
Commit: d3fc7cf2595a3290c1f2de2ef9daf0dafb782be4
Parents: a13137d
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Mar 1 08:50:23 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Wed Apr 1 01:52:46 2015 -0400
----------------------------------------------------------------------
.gitignore | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d3fc7cf2/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 144930f..9c54233 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ settings.xml
.buildpath
.classpath
.settings
+.checkstyle
[2/3] incubator-calcite git commit: [CALCITE-606] Fix trait
propagation and add test case
Posted by jh...@apache.org.
[CALCITE-606] Fix trait propagation and add test case
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/b312031f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/b312031f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/b312031f
Branch: refs/heads/master
Commit: b312031f3ead3adb272b79d02d7fcfc095ec4deb
Parents: d3fc7cf
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Mar 1 07:57:39 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Wed Apr 1 01:52:46 2015 -0400
----------------------------------------------------------------------
.../org/apache/calcite/plan/volcano/RelSet.java | 44 +-
.../calcite/plan/volcano/VolcanoPlanner.java | 7 +-
.../plan/volcano/TestTraitPropagation.java | 418 +++++++++++++++++++
3 files changed, 457 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b312031f/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index 93d8509..ed2c6b7 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -16,6 +16,14 @@
*/
package org.apache.calcite.plan.volcano;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptListener;
import org.apache.calcite.plan.RelOptUtil;
@@ -26,12 +34,6 @@ import org.apache.calcite.util.trace.CalciteTrace;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-
/**
* A <code>RelSet</code> is an equivalence-set of expressions; that is, a set of
* expressions which have identical semantics. We are generally interested in
@@ -156,11 +158,35 @@ class RelSet {
final VolcanoPlanner planner =
(VolcanoPlanner) cluster.getPlanner();
+// if (planner.root != null
+// && planner.root.set == this) {
+// planner.ensureRootConverters();
+// }
+
+ // Add converters to convert the new subset to each existing subset.
+ for (RelSubset subset1 : subsets) {
+ if (subset1.getConvention() == Convention.NONE) {
+ continue;
+ }
+ final AbstractConverter converter =
+ new AbstractConverter(
+ cluster, subset, ConventionTraitDef.INSTANCE,
+ subset1.getTraitSet());
+ planner.register(converter, subset1);
+ }
+
subsets.add(subset);
- if (planner.root != null
- && planner.root.set == this) {
- planner.ensureRootConverters();
+ // Add converters to convert each existing subset to this subset.
+ for (RelSubset subset1 : subsets) {
+ if (subset1 == subset) {
+ continue;
+ }
+ final AbstractConverter converter =
+ new AbstractConverter(
+ cluster, subset1, ConventionTraitDef.INSTANCE,
+ traits);
+ planner.register(converter, subset);
}
if (planner.listener != null) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b312031f/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
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 e21cdbb..d26ad6b 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
@@ -22,6 +22,7 @@ import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.plan.AbstractRelOptPlanner;
import org.apache.calcite.plan.Context;
import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptCostFactory;
import org.apache.calcite.plan.RelOptLattice;
@@ -1090,7 +1091,8 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
if (rel instanceof RelSubset) {
return ((RelSubset) rel).bestCost;
}
- if (rel.getTraitSet().getTrait(0) == Convention.NONE) {
+ if (rel.getTraitSet().getTrait(ConventionTraitDef.INSTANCE)
+ == Convention.NONE) {
return costFactory.makeInfiniteCost();
}
RelOptCost cost = RelMetadataQuery.getNonCumulativeCost(rel);
@@ -1622,8 +1624,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
// Now is a good time to ensure that the relational expression
// implements the interface required by its calling convention.
final RelTraitSet traits = rel.getTraitSet();
- final Convention convention =
- (Convention) traits.getTrait(0);
+ final Convention convention = traits.getTrait(ConventionTraitDef.INSTANCE);
if (!convention.getInterface().isInstance(rel)
&& !(rel instanceof Converter)) {
throw Util.newInternal(
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b312031f/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java b/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
new file mode 100644
index 0000000..e2dc6fd
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/plan/volcano/TestTraitPropagation.java
@@ -0,0 +1,418 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+
+import org.apache.calcite.adapter.enumerable.EnumerableConvention;
+import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptAbstractTable;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptQuery;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.plan.volcano.AbstractConverter.ExpandConversionRule;
+import org.apache.calcite.prepare.CalciteCatalogReader;
+import org.apache.calcite.rel.AbstractRelNode;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractTable;
+import org.apache.calcite.server.CalciteServerStatement;
+import org.apache.calcite.sql.SqlExplainLevel;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.tools.RuleSet;
+import org.apache.calcite.tools.RuleSets;
+import org.apache.calcite.util.ImmutableBitSet;
+
+/**
+ * Tests that determine whether trait propagation work in Volcano Planner
+ */
+public class TestTraitPropagation {
+
+ static final Convention PHYSICAL =
+ new Convention.Impl("PHYSICAL", Phys.class);
+ static final RelCollation COLLATION =
+ RelCollations.of(new RelFieldCollation(0,
+ RelFieldCollation.Direction.ASCENDING,
+ RelFieldCollation.NullDirection.FIRST));
+
+ static final RuleSet RULES_NO_HACK = RuleSets.ofList(
+ PhysAggRule.INSTANCE, //
+ PhysProjRule.INSTANCE, //
+ PhysTableRule.INSTANCE, //
+ PhysSortRule.INSTANCE, //
+ ExpandConversionRule.INSTANCE //
+ );
+
+ static final RuleSet RULES_HACK = RuleSets.ofList(
+ PhysAggRule.INSTANCE, //
+ PhysProjRule.INSTANCE_HACK, //
+ PhysTableRule.INSTANCE, //
+ PhysSortRule.INSTANCE, //
+ ExpandConversionRule.INSTANCE //
+ );
+
+ @Test
+ public void withoutHack() throws Exception {
+ RelNode planned = run(new PropAction(), RULES_NO_HACK);
+ System.out.println(RelOptUtil.dumpPlan("LOGICAL PLAN", planned, false,
+ SqlExplainLevel.ALL_ATTRIBUTES));
+ assertEquals("Sortedness was not propagated", 3,
+ RelMetadataQuery.getCumulativeCost(planned).getRows(), 0);
+ }
+
+ @Test
+ public void withHack() throws Exception {
+ RelNode planned = run(new PropAction(), RULES_HACK);
+ System.out.println(RelOptUtil.dumpPlan("LOGICAL PLAN", planned, false,
+ SqlExplainLevel.ALL_ATTRIBUTES));
+ assertEquals("Sortedness was not propagated", 3,
+ RelMetadataQuery.getCumulativeCost(planned).getRows(), 0);
+ }
+
+ /**
+ * Materialized anonymous class for simplicity
+ */
+ private class PropAction {
+ public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema,
+ SchemaPlus rootSchema) {
+ final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
+ final RexBuilder rexBuilder = cluster.getRexBuilder();
+ final RelOptPlanner planner = cluster.getPlanner();
+
+ final RelDataType stringType = typeFactory.createJavaType(String.class);
+ final RelDataType integerType = typeFactory.createJavaType(Integer.class);
+ final RelDataType sqlBigInt = typeFactory
+ .createSqlType(SqlTypeName.BIGINT);
+
+ // SELECT * from T;
+ final Table table = new AbstractTable() {
+ public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+ return typeFactory.builder().add("s", stringType)
+ .add("i", integerType).build();
+ }
+ };
+
+ final RelOptAbstractTable t1 = new RelOptAbstractTable(relOptSchema,
+ "t1", table.getRowType(typeFactory)) {
+ };
+
+ final RelNode rt1 = new EnumerableTableScan(cluster,
+ cluster.traitSetOf(EnumerableConvention.INSTANCE), t1,
+ Object[].class);
+
+ // project s column
+ RelNode project = new LogicalProject(cluster,
+ cluster.traitSetOf(Convention.NONE), rt1,
+ ImmutableList.of(
+ (RexNode) rexBuilder.makeInputRef(stringType, 0),
+ rexBuilder.makeInputRef(integerType, 1)),
+ typeFactory.builder().add("s", stringType).add("i", integerType)
+ .build());
+
+ // aggregate on s, count
+ AggregateCall aggCall = new AggregateCall(SqlStdOperatorTable.COUNT,
+ false, Collections.singletonList(1),
+ sqlBigInt, "cnt");
+ RelNode agg = new LogicalAggregate(cluster,
+ cluster.traitSetOf(Convention.NONE), project, false,
+ ImmutableBitSet.of(0), null, Collections.singletonList(aggCall));
+
+ final RelNode rootRel = agg;
+
+ RelOptUtil.dumpPlan("LOGICAL PLAN", rootRel, false,
+ SqlExplainLevel.DIGEST_ATTRIBUTES);
+
+ RelTraitSet desiredTraits = rootRel.getTraitSet().replace(PHYSICAL);
+ final RelNode rootRel2 = planner.changeTraits(rootRel, desiredTraits);
+ planner.setRoot(rootRel2);
+ return planner.findBestExp();
+ }
+ }
+
+
+ /* RULES */
+ /** Rule for PhysAgg */
+ private static class PhysAggRule extends RelOptRule {
+ static final PhysAggRule INSTANCE = new PhysAggRule();
+
+ private PhysAggRule() {
+ super(anyChild(LogicalAggregate.class), "PhysAgg");
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ RelTraitSet empty = call.getPlanner().emptyTraitSet();
+ LogicalAggregate rel = (LogicalAggregate) call.rel(0);
+ assert rel.getGroupSet().cardinality() == 1;
+ int aggIndex = rel.getGroupSet().iterator().next();
+ RelTrait collation = RelCollations.of(new RelFieldCollation(aggIndex,
+ RelFieldCollation.Direction.ASCENDING,
+ RelFieldCollation.NullDirection.FIRST));
+ RelTraitSet desiredTraits = empty.replace(PHYSICAL).replace(collation);
+ RelNode convertedInput = convert(rel.getInput(), desiredTraits);
+ call.transformTo(new PhysAgg(rel.getCluster(), empty.replace(PHYSICAL),
+ convertedInput, rel.indicator, rel
+ .getGroupSet(), rel.getGroupSets(), rel.getAggCallList()));
+ }
+ }
+
+ /** Rule for PhysProj */
+ private static class PhysProjRule extends RelOptRule {
+ static final PhysProjRule INSTANCE = new PhysProjRule(false);
+ static final PhysProjRule INSTANCE_HACK = new PhysProjRule(true);
+
+ final boolean subsetHack;
+
+ private PhysProjRule(boolean subsetHack) {
+ super(RelOptRule.operand(LogicalProject.class,
+ anyChild(RelNode.class)), "PhysProj");
+ this.subsetHack = subsetHack;
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ RelTraitSet empty = call.getPlanner().emptyTraitSet();
+ LogicalProject rel = (LogicalProject) call.rel(0);
+ RelNode input = convert(rel.getInput(), empty.replace(PHYSICAL));
+
+
+ if (subsetHack && input instanceof RelSubset) {
+ RelSubset subset = (RelSubset) input;
+ for (RelNode child : subset.getRels()) {
+ // skip logical nodes
+ if (child.getTraitSet().getTrait(ConventionTraitDef.INSTANCE)
+ == Convention.NONE) {
+ continue;
+ } else {
+ RelTraitSet outcome = child.getTraitSet().replace(PHYSICAL);
+ call.transformTo(new PhysProj(rel.getCluster(), outcome,
+ convert(child, outcome), rel.getChildExps(), rel.getRowType()));
+ }
+ }
+ } else {
+ call.transformTo(new PhysProj(rel.getCluster(), input.getTraitSet(),
+ input, rel.getChildExps(), rel.getRowType()));
+ }
+
+ }
+ }
+
+ /** Rule for PhysSort */
+ private static class PhysSortRule extends RelOptRule {
+ static final PhysSortRule INSTANCE = new PhysSortRule();
+
+ private PhysSortRule() {
+ super(anyChild(Sort.class), "PhysSort");
+ }
+
+ public boolean matches(RelOptRuleCall call) {
+ return !(call.rel(0) instanceof PhysSort);
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ RelTraitSet empty = call.getPlanner().emptyTraitSet();
+ Sort rel = (Sort) call.rel(0);
+ RelNode input = convert(rel.getInput(), empty.plus(PHYSICAL));
+ call.transformTo(
+ new PhysSort(rel.getCluster(),
+ input.getTraitSet().plus(rel.getCollation()),
+ input, rel.getCollation(), rel.offset,
+ rel.fetch));
+ }
+ }
+
+ /** Rule for PhysTable */
+ private static class PhysTableRule extends RelOptRule {
+ static final PhysTableRule INSTANCE = new PhysTableRule();
+
+ private PhysTableRule() {
+ super(anyChild(EnumerableTableScan.class), "PhysScan");
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ EnumerableTableScan rel = (EnumerableTableScan) call.rel(0);
+ call.transformTo(new PhysTable(rel.getCluster()));
+ }
+ }
+
+ /* RELS */
+ /** Market interface for Phys nodes */
+ private interface Phys extends RelNode { }
+
+ /** Physical Aggregate RelNode */
+ private static class PhysAgg extends Aggregate implements Phys {
+ public PhysAgg(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ boolean indicator, ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
+ super(cluster, traits, child, indicator, groupSet, groupSets, aggCalls);
+
+ }
+
+ public Aggregate copy(RelTraitSet traitSet, RelNode input,
+ boolean indicator, ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
+ return new PhysAgg(getCluster(), traitSet, input, indicator, groupSet,
+ groupSets, aggCalls);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Project RelNode */
+ private static class PhysProj extends Project implements Phys {
+ public PhysProj(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ List<RexNode> exps, RelDataType rowType) {
+ super(cluster, traits, child, exps, rowType);
+ }
+
+ public PhysProj copy(RelTraitSet traitSet, RelNode input,
+ List<RexNode> exps, RelDataType rowType) {
+ return new PhysProj(getCluster(), traitSet, input, exps, rowType);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Sort RelNode */
+ private static class PhysSort extends Sort implements Phys {
+ public PhysSort(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ RelCollation collation, RexNode offset,
+ RexNode fetch) {
+ super(cluster, traits, child, collation, offset, fetch);
+
+ }
+
+ public PhysSort copy(RelTraitSet traitSet, RelNode newInput,
+ RelCollation newCollation, RexNode offset,
+ RexNode fetch) {
+ return new PhysSort(getCluster(), traitSet, newInput, newCollation,
+ offset, fetch);
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /** Physical Table RelNode */
+ private static class PhysTable extends AbstractRelNode implements Phys {
+ public PhysTable(RelOptCluster cluster) {
+ super(cluster, cluster.traitSet().replace(PHYSICAL).replace(COLLATION));
+ RelDataTypeFactory typeFactory = cluster.getTypeFactory();
+ final RelDataType stringType = typeFactory.createJavaType(String.class);
+ final RelDataType integerType = typeFactory.createJavaType(Integer.class);
+ this.rowType = typeFactory.builder().add("s", stringType)
+ .add("i", integerType).build();
+ }
+
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return planner.getCostFactory().makeCost(1, 1, 1);
+ }
+ }
+
+ /* UTILS */
+ public static RelOptRuleOperand anyChild(Class<? extends RelNode> first) {
+ return RelOptRule.operand(first, RelOptRule.any());
+ }
+
+ // Created so that we can control when the TraitDefs are defined (e.g.
+ // before the cluster is created).
+ private static RelNode run(PropAction action, RuleSet rules)
+ throws Exception {
+
+ FrameworkConfig config = Frameworks.newConfigBuilder()
+ .ruleSets(rules).build();
+
+ final Properties info = new Properties();
+ final Connection connection = DriverManager
+ .getConnection("jdbc:calcite:", info);
+ final CalciteServerStatement statement = connection
+ .createStatement().unwrap(CalciteServerStatement.class);
+ final CalcitePrepare.Context prepareContext =
+ statement.createPrepareContext();
+ final JavaTypeFactory typeFactory = prepareContext.getTypeFactory();
+ CalciteCatalogReader catalogReader =
+ new CalciteCatalogReader(prepareContext.getRootSchema(),
+ prepareContext.config().caseSensitive(),
+ prepareContext.getDefaultSchemaPath(),
+ typeFactory);
+ final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+ final RelOptPlanner planner = new VolcanoPlanner(config.getCostFactory(),
+ config.getContext());
+
+ // set up rules before we generate cluster
+ planner.clearRelTraitDefs();
+ planner.addRelTraitDef(RelCollationTraitDef.INSTANCE);
+ planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
+
+ planner.clear();
+ for (RelOptRule r : rules) {
+ planner.addRule(r);
+ }
+
+ final RelOptQuery query = new RelOptQuery(planner);
+ final RelOptCluster cluster = query.createCluster(
+ rexBuilder.getTypeFactory(), rexBuilder);
+ return action.apply(cluster, catalogReader,
+ prepareContext.getRootSchema().plus());
+
+ }
+}