[CALCITE-794] Detect cycles when computing statistics Make RelMetadataQuery methods non-static. Each active call is registered in the RelMetadataQuery instance; it throws CyclicMetadataException when it detects a cycle, and the caller can catch it to return a sensible default value for the particular kind of metadata.
Change signature of FlatLists.of(Object...) to FlatLists.copyOf(Comparable...). Temporarily disable all failing tests. Add metadata for EnumerableLimit. Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/cabdcf44 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/cabdcf44 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/cabdcf44 Branch: refs/heads/master Commit: cabdcf44e4aec4d4ceea7f97c8c6fd9e9dbd36b1 Parents: 2cef859 Author: Julian Hyde <[email protected]> Authored: Sat Jul 11 14:56:42 2015 -0700 Committer: Julian Hyde <[email protected]> Committed: Sun Jan 10 00:51:25 2016 -0800 ---------------------------------------------------------------------- .../adapter/enumerable/EnumerableCalc.java | 8 +- .../adapter/enumerable/EnumerableFilter.java | 6 +- .../enumerable/EnumerableInterpreter.java | 6 +- .../adapter/enumerable/EnumerableJoin.java | 9 +- .../adapter/enumerable/EnumerableLimit.java | 25 +- .../adapter/enumerable/EnumerableMergeJoin.java | 12 +- .../adapter/enumerable/EnumerableProject.java | 4 +- .../adapter/enumerable/EnumerableSemiJoin.java | 9 +- .../adapter/enumerable/EnumerableThetaJoin.java | 9 +- .../adapter/enumerable/EnumerableValues.java | 4 +- .../adapter/enumerable/EnumerableWindow.java | 5 +- .../adapter/enumerable/JavaRowFormat.java | 2 +- .../adapter/enumerable/PhysTypeImpl.java | 2 +- .../apache/calcite/adapter/jdbc/JdbcRules.java | 33 ++- .../adapter/jdbc/JdbcToEnumerableConverter.java | 6 +- .../apache/calcite/interpreter/Bindables.java | 14 +- .../calcite/plan/AbstractRelOptPlanner.java | 30 +-- .../apache/calcite/plan/ConventionTraitDef.java | 4 +- .../org/apache/calcite/plan/RelOptCost.java | 2 +- .../org/apache/calcite/plan/RelOptPlanner.java | 10 +- .../org/apache/calcite/plan/hep/HepPlanner.java | 57 +++-- .../plan/hep/HepRelMetadataProvider.java | 22 +- .../apache/calcite/plan/hep/HepRelVertex.java | 7 +- .../calcite/plan/volcano/AbstractConverter.java | 3 +- .../org/apache/calcite/plan/volcano/RelSet.java | 7 +- .../apache/calcite/plan/volcano/RelSubset.java | 46 ++-- .../apache/calcite/plan/volcano/RuleQueue.java | 14 +- .../calcite/plan/volcano/VolcanoPlanner.java | 23 +- .../volcano/VolcanoRelMetadataProvider.java | 31 +-- .../org/apache/calcite/prepare/PlannerImpl.java | 5 + .../org/apache/calcite/rel/AbstractRelNode.java | 28 +- .../java/org/apache/calcite/rel/RelNode.java | 24 +- .../java/org/apache/calcite/rel/SingleRel.java | 4 +- .../calcite/rel/convert/ConverterImpl.java | 6 +- .../org/apache/calcite/rel/core/Aggregate.java | 9 +- .../java/org/apache/calcite/rel/core/Calc.java | 18 +- .../org/apache/calcite/rel/core/Correlate.java | 13 +- .../org/apache/calcite/rel/core/Exchange.java | 5 +- .../org/apache/calcite/rel/core/Filter.java | 35 +-- .../org/apache/calcite/rel/core/Intersect.java | 5 +- .../java/org/apache/calcite/rel/core/Join.java | 14 +- .../java/org/apache/calcite/rel/core/Minus.java | 5 +- .../org/apache/calcite/rel/core/Project.java | 5 +- .../org/apache/calcite/rel/core/SemiJoin.java | 10 +- .../java/org/apache/calcite/rel/core/Sort.java | 5 +- .../calcite/rel/core/TableFunctionScan.java | 10 +- .../apache/calcite/rel/core/TableModify.java | 8 +- .../org/apache/calcite/rel/core/TableScan.java | 6 +- .../java/org/apache/calcite/rel/core/Union.java | 21 +- .../org/apache/calcite/rel/core/Values.java | 13 +- .../org/apache/calcite/rel/core/Window.java | 5 +- .../calcite/rel/externalize/RelWriterImpl.java | 15 +- .../apache/calcite/rel/logical/LogicalCalc.java | 6 +- .../calcite/rel/logical/LogicalFilter.java | 6 +- .../calcite/rel/logical/LogicalProject.java | 4 +- .../rel/logical/LogicalTableFunctionScan.java | 3 +- .../calcite/rel/logical/LogicalValues.java | 4 +- .../calcite/rel/metadata/BuiltInMetadata.java | 14 +- .../metadata/CachingRelMetadataProvider.java | 53 ++-- .../metadata/ChainedRelMetadataProvider.java | 44 ++-- .../rel/metadata/CyclicMetadataException.java | 37 +++ .../apache/calcite/rel/metadata/Metadata.java | 2 +- .../calcite/rel/metadata/MetadataFactory.java | 13 +- .../rel/metadata/MetadataFactoryImpl.java | 31 +-- .../metadata/ReflectiveRelMetadataProvider.java | 100 +++++--- .../calcite/rel/metadata/RelMdCollation.java | 102 ++++---- .../rel/metadata/RelMdColumnOrigins.java | 110 +++----- .../rel/metadata/RelMdColumnUniqueness.java | 255 +++++++++---------- .../rel/metadata/RelMdDistinctRowCount.java | 171 ++++++------- .../calcite/rel/metadata/RelMdDistribution.java | 47 ++-- .../rel/metadata/RelMdExplainVisibility.java | 10 +- .../calcite/rel/metadata/RelMdMaxRowCount.java | 69 +++-- .../calcite/rel/metadata/RelMdMemory.java | 24 +- .../calcite/rel/metadata/RelMdParallelism.java | 14 +- .../metadata/RelMdPercentageOriginalRows.java | 46 ++-- .../rel/metadata/RelMdPopulationSize.java | 73 +++--- .../calcite/rel/metadata/RelMdPredicates.java | 136 +++++----- .../calcite/rel/metadata/RelMdRowCount.java | 129 +++++++--- .../calcite/rel/metadata/RelMdSelectivity.java | 60 ++--- .../apache/calcite/rel/metadata/RelMdSize.java | 66 +++-- .../calcite/rel/metadata/RelMdUniqueKeys.java | 60 ++--- .../apache/calcite/rel/metadata/RelMdUtil.java | 255 +++++++++---------- .../rel/metadata/RelMetadataProvider.java | 8 +- .../calcite/rel/metadata/RelMetadataQuery.java | 159 ++++++------ .../calcite/rel/metadata/UnboundMetadata.java | 31 +++ .../rel/rules/AggregateFilterTransposeRule.java | 4 +- .../rel/rules/AggregateJoinTransposeRule.java | 12 +- .../AggregateProjectPullUpConstantsRule.java | 3 +- .../calcite/rel/rules/AggregateRemoveRule.java | 9 +- .../rel/rules/AggregateStarTableRule.java | 4 +- .../rel/rules/AggregateUnionTransposeRule.java | 5 +- .../rules/JoinPushTransitivePredicatesRule.java | 3 +- .../apache/calcite/rel/rules/LoptMultiJoin.java | 19 +- .../calcite/rel/rules/LoptOptimizeJoinRule.java | 63 ++--- .../rel/rules/LoptSemiJoinOptimizer.java | 39 ++- .../rel/rules/MultiJoinOptimizeBushyRule.java | 3 +- .../rel/rules/ReduceExpressionsRule.java | 13 +- .../rel/rules/SortJoinTransposeRule.java | 10 +- .../rel/rules/SortUnionTransposeRule.java | 6 +- .../calcite/rel/rules/SubQueryRemoveRule.java | 3 +- .../org/apache/calcite/runtime/FlatLists.java | 75 +++++- .../apache/calcite/schema/impl/StarTable.java | 4 +- .../apache/calcite/sql2rel/RelDecorrelator.java | 14 +- .../apache/calcite/sql2rel/RelFieldTrimmer.java | 10 +- .../main/java/org/apache/calcite/util/Bug.java | 6 +- .../org/apache/calcite/util/BuiltInMethod.java | 6 +- .../org/apache/calcite/util/NumberUtil.java | 11 + .../plan/volcano/TraitPropagationTest.java | 18 +- .../plan/volcano/VolcanoPlannerTest.java | 13 +- .../plan/volcano/VolcanoPlannerTraitTest.java | 22 +- .../apache/calcite/test/JdbcAdapterTest.java | 28 +- .../java/org/apache/calcite/test/JdbcTest.java | 8 +- .../apache/calcite/test/RelMetadataTest.java | 159 +++++++----- .../org/apache/calcite/tools/PlannerTest.java | 9 +- .../java/org/apache/calcite/util/UtilTest.java | 10 + core/src/test/resources/sql/agg.iq | 2 +- .../calcite/adapter/mongodb/MongoFilter.java | 6 +- .../calcite/adapter/mongodb/MongoProject.java | 6 +- .../calcite/adapter/mongodb/MongoSort.java | 6 +- .../calcite/adapter/mongodb/MongoTableScan.java | 6 +- .../mongodb/MongoToEnumerableConverter.java | 6 +- .../spark/EnumerableToSparkConverter.java | 6 +- .../adapter/spark/JdbcToSparkConverter.java | 6 +- .../calcite/adapter/spark/SparkRules.java | 16 +- .../spark/SparkToEnumerableConverter.java | 6 +- 125 files changed, 1912 insertions(+), 1564 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java index ce1f642..205bd05 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java @@ -37,6 +37,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.Calc; 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.rex.RexProgram; import org.apache.calcite.util.BuiltInMethod; import org.apache.calcite.util.Pair; @@ -86,18 +87,19 @@ public class EnumerableCalc extends Calc implements EnumerableRel { public static EnumerableCalc create(final RelNode input, final RexProgram program) { final RelOptCluster cluster = input.getCluster(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSet() .replace(EnumerableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.calc(input, program); + return RelMdCollation.calc(mq, input, program); } }) .replaceIf(RelDistributionTraitDef.INSTANCE, new Supplier<RelDistribution>() { public RelDistribution get() { - return RelMdDistribution.calc(input, program); + return RelMdDistribution.calc(mq, input, program); } }); return new EnumerableCalc(cluster, traitSet, input, program); @@ -207,7 +209,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel { Expressions.new_( enumeratorType, NO_EXPRS, - Expressions.<MemberDeclaration>list( + Expressions.list( Expressions.fieldDecl( Modifier.PUBLIC | Modifier.FINAL, http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java index 7dccf91..894ff16 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java @@ -26,6 +26,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.Filter; 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.rex.RexNode; import com.google.common.base.Supplier; @@ -53,19 +54,20 @@ public class EnumerableFilter public static EnumerableFilter create(final RelNode input, RexNode condition) { final RelOptCluster cluster = input.getCluster(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE) .replaceIfs( RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.filter(input); + return RelMdCollation.filter(mq, input); } }) .replaceIf(RelDistributionTraitDef.INSTANCE, new Supplier<RelDistribution>() { public RelDistribution get() { - return RelMdDistribution.filter(input); + return RelMdDistribution.filter(mq, input); } }); return new EnumerableFilter(cluster, traitSet, input, condition); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpreter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpreter.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpreter.java index cfa241f..1c53483 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpreter.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpreter.java @@ -27,6 +27,7 @@ import org.apache.calcite.plan.RelOptPlanner; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.SingleRel; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.util.BuiltInMethod; import java.util.List; @@ -72,8 +73,9 @@ public class EnumerableInterpreter extends SingleRel factor); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner).multiplyBy(factor); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(factor); } @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java index 0b86771..cfd00a4 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java @@ -125,8 +125,9 @@ public class EnumerableJoin extends EquiJoin implements EnumerableRel { } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - double rowCount = RelMetadataQuery.getRowCount(this); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + double rowCount = mq.getRowCount(this); // Joins can be flipped, and for many algorithms, both versions are viable // and have the same cost. To make the results stable between versions of @@ -143,8 +144,8 @@ public class EnumerableJoin extends EquiJoin implements EnumerableRel { // Cheaper if the smaller number of rows is coming from the LHS. // Model this by adding L log L to the cost. - final double rightRowCount = right.getRows(); - final double leftRowCount = left.getRows(); + final double rightRowCount = right.estimateRowCount(mq); + final double leftRowCount = left.estimateRowCount(mq); if (Double.isInfinite(leftRowCount)) { rowCount = leftRowCount; } else { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java index cea8755..827944f 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java @@ -30,6 +30,7 @@ import org.apache.calcite.rel.RelWriter; import org.apache.calcite.rel.SingleRel; 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.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.BuiltInMethod; @@ -40,8 +41,8 @@ import java.util.List; /** Relational expression that applies a limit and/or offset to its input. */ public class EnumerableLimit extends SingleRel implements EnumerableRel { - private final RexNode offset; - private final RexNode fetch; + public final RexNode offset; + public final RexNode fetch; /** Creates an EnumerableLimit. * @@ -63,19 +64,20 @@ public class EnumerableLimit extends SingleRel implements EnumerableRel { public static EnumerableLimit create(final RelNode input, RexNode offset, RexNode fetch) { final RelOptCluster cluster = input.getCluster(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE) .replaceIfs( RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.limit(input); + return RelMdCollation.limit(mq, input); } }) .replaceIf(RelDistributionTraitDef.INSTANCE, new Supplier<RelDistribution>() { public RelDistribution get() { - return RelMdDistribution.limit(input); + return RelMdDistribution.limit(mq, input); } }); return new EnumerableLimit(cluster, traitSet, input, offset, fetch); @@ -98,21 +100,6 @@ public class EnumerableLimit extends SingleRel implements EnumerableRel { .itemIf("fetch", fetch, fetch != null); } - @Override public double getRows() { - double rowCount = super.getRows(); - final int offset = - this.offset == null ? 0 : RexLiteral.intValue(this.offset); - rowCount = Math.max(rowCount - offset, 0D); - - if (this.fetch != null) { - final int limit = RexLiteral.intValue(this.fetch); - if (limit < rowCount) { - return (double) limit; - } - } - return rowCount; - } - public Result implement(EnumerableRelImplementor implementor, Prefer pref) { final BlockBuilder builder = new BlockBuilder(); final EnumerableRel child = (EnumerableRel) getInput(); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java index 18419e3..fd492cb 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java @@ -83,8 +83,9 @@ public class EnumerableMergeJoin extends EquiJoin implements EnumerableRel { final RelOptCluster cluster = right.getCluster(); RelTraitSet traitSet = cluster.traitSet(); if (traitSet.isEnabled(RelCollationTraitDef.INSTANCE)) { + final RelMetadataQuery mq = RelMetadataQuery.instance(); final List<RelCollation> collations = - RelMdCollation.mergeJoin(left, right, leftKeys, rightKeys); + RelMdCollation.mergeJoin(mq, left, right, leftKeys, rightKeys); traitSet = traitSet.replace(collations); } return new EnumerableMergeJoin(cluster, traitSet, left, right, condition, @@ -107,13 +108,14 @@ public class EnumerableMergeJoin extends EquiJoin implements EnumerableRel { } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { // We assume that the inputs are sorted. The price of sorting them has // already been paid. The cost of the join is therefore proportional to the // input and output size. - final double rightRowCount = right.getRows(); - final double leftRowCount = left.getRows(); - final double rowCount = RelMetadataQuery.getRowCount(this); + final double rightRowCount = right.estimateRowCount(mq); + final double leftRowCount = left.estimateRowCount(mq); + final double rowCount = mq.getRowCount(this); final double d = leftRowCount + rightRowCount + rowCount; return planner.getCostFactory().makeCost(d, 0, 0); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java index e6852f7..fa2b48b 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java @@ -23,6 +23,7 @@ import org.apache.calcite.rel.RelCollationTraitDef; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.Project; import org.apache.calcite.rel.metadata.RelMdCollation; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.Util; @@ -68,12 +69,13 @@ public class EnumerableProject extends Project implements EnumerableRel { public static EnumerableProject create(final RelNode input, final List<? extends RexNode> projects, RelDataType rowType) { final RelOptCluster cluster = input.getCluster(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSet().replace(EnumerableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.project(input, projects); + return RelMdCollation.project(mq, input, projects); } }); return new EnumerableProject(cluster, traitSet, input, projects, rowType); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java index 569e79e..0162c51 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java @@ -83,12 +83,13 @@ public class EnumerableSemiJoin extends SemiJoin implements EnumerableRel { } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - double rowCount = RelMetadataQuery.getRowCount(this); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + double rowCount = mq.getRowCount(this); // Right-hand input is the "build", and hopefully small, input. - final double rightRowCount = right.getRows(); - final double leftRowCount = left.getRows(); + final double rightRowCount = right.estimateRowCount(mq); + final double leftRowCount = left.estimateRowCount(mq); if (Double.isInfinite(leftRowCount)) { rowCount = leftRowCount; } else { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableThetaJoin.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableThetaJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableThetaJoin.java index e28ddfc..dc400ad 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableThetaJoin.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableThetaJoin.java @@ -73,8 +73,9 @@ public class EnumerableThetaJoin extends Join implements EnumerableRel { } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - double rowCount = RelMetadataQuery.getRowCount(this); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + double rowCount = mq.getRowCount(this); // Joins can be flipped, and for many algorithms, both versions are viable // and have the same cost. To make the results stable between versions of @@ -89,8 +90,8 @@ public class EnumerableThetaJoin extends Join implements EnumerableRel { } } - final double rightRowCount = right.getRows(); - final double leftRowCount = left.getRows(); + final double rightRowCount = right.estimateRowCount(mq); + final double leftRowCount = left.estimateRowCount(mq); if (Double.isInfinite(leftRowCount)) { rowCount = leftRowCount; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java ---------------------------------------------------------------------- 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 13dd24d..6023c02 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 @@ -31,6 +31,7 @@ import org.apache.calcite.rel.RelNode; 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.rel.type.RelDataTypeField; import org.apache.calcite.rex.RexLiteral; @@ -57,12 +58,13 @@ public class EnumerableValues extends Values implements EnumerableRel { public static EnumerableValues create(RelOptCluster cluster, final RelDataType rowType, final ImmutableList<ImmutableList<RexLiteral>> tuples) { + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.values(rowType, tuples); + return RelMdCollation.values(mq, rowType, tuples); } }) .replaceIf(RelDistributionTraitDef.INSTANCE, http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java index 433c6cd..f8bd84f 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java @@ -38,6 +38,7 @@ import org.apache.calcite.rel.RelFieldCollation; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.AggregateCall; import org.apache.calcite.rel.core.Window; +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.RexInputRef; @@ -74,8 +75,8 @@ public class EnumerableWindow extends Window implements EnumerableRel { constants, rowType, groups); } - public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner) + public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq) .multiplyBy(EnumerableConvention.COST_MULTIPLIER); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java index 9cb54ff..316af0d 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java @@ -148,7 +148,7 @@ public enum JavaRowFormat { null, BuiltInMethod.LIST_N.method, Expressions.newArrayInit( - Object.class, + Comparable.class, expressions)), List.class); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java index 2c0c491..0f83889 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java @@ -599,7 +599,7 @@ public class PhysTypeImpl implements PhysType { null, BuiltInMethod.LIST_N.method, Expressions.newArrayInit( - Object.class, + Comparable.class, list)), v1); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java index ca80d29..db8bc89 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java @@ -56,6 +56,7 @@ import org.apache.calcite.rel.logical.LogicalProject; import org.apache.calcite.rel.logical.LogicalTableModify; import org.apache.calcite.rel.logical.LogicalUnion; import org.apache.calcite.rel.logical.LogicalValues; +import org.apache.calcite.rel.metadata.RelMdUtil; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.rel2sql.SqlImplementor; import org.apache.calcite.rel.type.RelDataType; @@ -247,16 +248,17 @@ public class JdbcRules { } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { // We always "build" the - double rowCount = RelMetadataQuery.getRowCount(this); + double rowCount = mq.getRowCount(this); return planner.getCostFactory().makeCost(rowCount, 0, 0); } - @Override public double getRows() { - final double leftRowCount = left.getRows(); - final double rightRowCount = right.getRows(); + @Override public double estimateRowCount(RelMetadataQuery mq) { + final double leftRowCount = left.estimateRowCount(mq); + final double rightRowCount = right.estimateRowCount(mq); return Math.max(leftRowCount, rightRowCount); } @@ -316,13 +318,14 @@ public class JdbcRules { return program.explainCalc(super.explainTerms(pw)); } - public double getRows() { - return LogicalFilter.estimateFilteredRows(getInput(), program); + @Override public double estimateRowCount(RelMetadataQuery mq) { + return RelMdUtil.estimateFilteredRows(getInput(), program, mq); } - public RelOptCost computeSelfCost(RelOptPlanner planner) { - double dRows = RelMetadataQuery.getRowCount(this); - double dCpu = RelMetadataQuery.getRowCount(getInput()) + public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + double dRows = mq.getRowCount(this); + double dCpu = mq.getRowCount(getInput()) * program.getExprCount(); double dIo = 0; return planner.getCostFactory().makeCost(dRows, dCpu, dIo); @@ -387,8 +390,9 @@ public class JdbcRules { return new JdbcProject(getCluster(), traitSet, input, projects, rowType); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner) + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq) .multiplyBy(JdbcConvention.COST_MULTIPLIER); } @@ -604,8 +608,9 @@ public class JdbcRules { return new JdbcUnion(getCluster(), traitSet, inputs, all); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner).multiplyBy(.1); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(.1); } public JdbcImplementor.Result implement(JdbcImplementor implementor) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java index 125d61b..732772d 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java @@ -36,6 +36,7 @@ import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.prepare.CalcitePrepareImpl; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.convert.ConverterImpl; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.runtime.Hook; import org.apache.calcite.runtime.SqlFunctions; @@ -71,8 +72,9 @@ public class JdbcToEnumerableConverter getCluster(), traitSet, sole(inputs)); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner).multiplyBy(.1); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(.1); } public Result implement(EnumerableRelImplementor implementor, Prefer pref) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/interpreter/Bindables.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java index 9d4b250..aa44c6a 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java +++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java @@ -56,6 +56,7 @@ import org.apache.calcite.rel.logical.LogicalUnion; import org.apache.calcite.rel.logical.LogicalValues; import org.apache.calcite.rel.logical.LogicalWindow; import org.apache.calcite.rel.metadata.RelMdCollation; +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.rel.type.RelDataTypeField; @@ -217,8 +218,9 @@ public class Bindables { .itemIf("projects", projects, !projects.equals(identity())); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner).multiplyBy(0.01d); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(0.01d); } public static boolean canHandle(RelOptTable table) { @@ -267,12 +269,13 @@ public class Bindables { public static BindableFilter create(final RelNode input, RexNode condition) { final RelOptCluster cluster = input.getCluster(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelTraitSet traitSet = cluster.traitSetOf(BindableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, new Supplier<List<RelCollation>>() { public List<RelCollation> get() { - return RelMdCollation.filter(input); + return RelMdCollation.filter(mq, input); } }); return new BindableFilter(cluster, traitSet, input, condition); @@ -638,8 +641,9 @@ public class Bindables { constants, rowType, groups); } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner) + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq) .multiplyBy(BindableConvention.COST_MULTIPLIER); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java index b25c28c..38c0e7e 100644 --- a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java @@ -23,10 +23,10 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.util.CancelFlag; import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -53,8 +53,7 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { * Maps rule description to rule, just to ensure that rules' descriptions * are unique. */ - private final Map<String, RelOptRule> mapDescToRule = - new HashMap<String, RelOptRule>(); + private final Map<String, RelOptRule> mapDescToRule = new HashMap<>(); protected final RelOptCostFactory costFactory; @@ -64,11 +63,9 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { private CancelFlag cancelFlag; - @SuppressWarnings("unchecked") - private final Set<Class<? extends RelNode>> classes = - new HashSet<Class<? extends RelNode>>(); + private final Set<Class<? extends RelNode>> classes = new HashSet<>(); - private final Set<RelTrait> traits = new HashSet<RelTrait>(); + private final Set<RelTrait> traits = new HashSet<>(); /** External context. Never null. */ protected final Context context; @@ -111,7 +108,6 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { return costFactory; } - // implement RelOptPlanner public void setCancelFlag(CancelFlag cancelFlag) { this.cancelFlag = cancelFlag; } @@ -179,7 +175,6 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { return mapDescToRule.get(description); } - // implement RelOptPlanner public void setRuleDescExclusionFilter(Pattern exclusionFilter) { ruleDescExclusionFilter = exclusionFilter; } @@ -195,7 +190,6 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { && ruleDescExclusionFilter.matcher(rule.toString()).matches(); } - // implement RelOptPlanner public RelOptPlanner chooseDelegate() { return this; } @@ -213,11 +207,9 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { return null; } - // implement RelOptPlanner public void registerSchema(RelOptSchema schema) { } - // implement RelOptPlanner public long getRelMetadataTimestamp(RelNode rel) { return 0; } @@ -246,12 +238,15 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { return RelTraitSet.createEmpty(); } - // implement RelOptPlanner + public RelOptCost getCost(RelNode rel, RelMetadataQuery mq) { + return mq.getCumulativeCost(rel); + } + public RelOptCost getCost(RelNode rel) { - return RelMetadataQuery.getCumulativeCost(rel); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + return getCost(rel, mq); } - // implement RelOptPlanner public void addListener(RelOptListener newListener) { if (listener == null) { listener = new MulticastRelOptListener(); @@ -259,20 +254,17 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { listener.addListener(newListener); } - // implement RelOptPlanner public void registerMetadataProviders(List<RelMetadataProvider> list) { } - // implement RelOptPlanner public boolean addRelTraitDef(RelTraitDef relTraitDef) { return false; } - // implement RelOptPlanner public void clearRelTraitDefs() {} public List<RelTraitDef> getRelTraitDefs() { - return Collections.emptyList(); + return ImmutableList.of(); } public void setExecutor(Executor executor) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java b/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java index 9de4762..579e217 100644 --- a/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java +++ b/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java @@ -18,6 +18,7 @@ package org.apache.calcite.plan; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.convert.ConverterRule; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; import org.apache.calcite.util.graph.DefaultDirectedGraph; @@ -124,6 +125,7 @@ public class ConventionTraitDef extends RelTraitDef<Convention> { RelNode rel, Convention toConvention, boolean allowInfiniteCostConverters) { + final RelMetadataQuery mq = RelMetadataQuery.instance(); final ConversionData conversionData = getConversionData(planner); final Convention fromConvention = rel.getConvention(); @@ -139,7 +141,7 @@ public class ConventionTraitDef extends RelTraitDef<Convention> { RelNode converted = rel; Convention previous = null; for (Convention arc : conversionPath) { - if (planner.getCost(converted).isInfinite() + if (planner.getCost(converted, mq).isInfinite() && !allowInfiniteCostConverters) { continue loop; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/RelOptCost.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptCost.java b/core/src/main/java/org/apache/calcite/plan/RelOptCost.java index 1e19a72..bf9a55d 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptCost.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptCost.java @@ -32,7 +32,7 @@ public interface RelOptCost { /** * @return number of rows processed; this should not be confused with the * row count produced by a relational expression - * ({@link org.apache.calcite.rel.RelNode#getRows}) + * ({@link org.apache.calcite.rel.RelNode#estimateRowCount}) */ double getRows(); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java index 0e42cb7..9b5e22a 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java @@ -192,9 +192,17 @@ public interface RelOptPlanner { * Computes the cost of a RelNode. In most cases, this just dispatches to * {@link RelMetadataQuery#getCumulativeCost}. * - * @param rel expression of interest + * @param rel Relational expression of interest + * @param mq Metadata query * @return estimated cost */ + RelOptCost getCost(RelNode rel, RelMetadataQuery mq); + + /** + * @deprecated Use {@link #getCost(RelNode, RelMetadataQuery)} + * or, better, call {@link RelMetadataQuery#getCumulativeCost(RelNode)}. + */ + @Deprecated // to be removed before 2.0 RelOptCost getCost(RelNode rel); /** http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java index 30e28b0..5569431 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java @@ -134,12 +134,12 @@ public class HepPlanner extends AbstractRelOptPlanner { this.mainProgram = program; this.onCopyHook = Util.first(onCopyHook, Functions.<RelNode, RelNode, Void>ignore2()); - mapDigestToVertex = new HashMap<String, HepRelVertex>(); + mapDigestToVertex = new HashMap<>(); graph = DefaultDirectedGraph.create(); // NOTE jvs 24-Apr-2006: We use LinkedHashSet here and below // in order to provide deterministic behavior. - allRules = new LinkedHashSet<RelOptRule>(); + allRules = new LinkedHashSet<>(); this.noDAG = noDAG; } @@ -267,7 +267,7 @@ public class HepPlanner extends AbstractRelOptPlanner { LOGGER.finest("Applying rule class " + instruction.ruleClass); } if (instruction.ruleSet == null) { - instruction.ruleSet = new LinkedHashSet<RelOptRule>(); + instruction.ruleSet = new LinkedHashSet<>(); for (RelOptRule rule : allRules) { if (instruction.ruleClass.isInstance(rule)) { instruction.ruleSet.add(rule); @@ -299,7 +299,7 @@ public class HepPlanner extends AbstractRelOptPlanner { HepInstruction.ConverterRules instruction) { assert currentProgram.group == null; if (instruction.ruleSet == null) { - instruction.ruleSet = new LinkedHashSet<RelOptRule>(); + instruction.ruleSet = new LinkedHashSet<>(); for (RelOptRule rule : allRules) { if (!(rule instanceof ConverterRule)) { continue; @@ -323,7 +323,7 @@ public class HepPlanner extends AbstractRelOptPlanner { void executeInstruction(HepInstruction.CommonRelSubExprRules instruction) { assert currentProgram.group == null; if (instruction.ruleSet == null) { - instruction.ruleSet = new LinkedHashSet<RelOptRule>(); + instruction.ruleSet = new LinkedHashSet<>(); for (RelOptRule rule : allRules) { if (!(rule instanceof CommonRelSubExprRule)) { continue; @@ -447,7 +447,7 @@ public class HepPlanner extends AbstractRelOptPlanner { // TODO jvs 4-Apr-2006: enhance TopologicalOrderIterator // to support reverse walk. assert currentProgram.matchOrder == HepMatchOrder.BOTTOM_UP; - final List<HepRelVertex> list = new ArrayList<HepRelVertex>(); + final List<HepRelVertex> list = new ArrayList<>(); for (HepRelVertex vertex : iter) { list.add(vertex); } @@ -479,15 +479,14 @@ public class HepPlanner extends AbstractRelOptPlanner { if (parentVertices.size() < 2) { return null; } - parents = new ArrayList<RelNode>(); + parents = new ArrayList<>(); for (HepRelVertex pVertex : parentVertices) { parents.add(pVertex.getCurrentRel()); } } - List<RelNode> bindings = new ArrayList<RelNode>(); - Map<RelNode, List<RelNode>> nodeChildren = - new HashMap<RelNode, List<RelNode>>(); + final List<RelNode> bindings = new ArrayList<>(); + final Map<RelNode, List<RelNode>> nodeChildren = new HashMap<>(); boolean match = matchOperands( rule.getOperand(), @@ -554,8 +553,8 @@ public class HepPlanner extends AbstractRelOptPlanner { * @return the list of parents for the vertex */ private List<HepRelVertex> getVertexParents(HepRelVertex vertex) { - List<HepRelVertex> parents = new ArrayList<HepRelVertex>(); - List<HepRelVertex> parentVertices = + final List<HepRelVertex> parents = new ArrayList<>(); + final List<HepRelVertex> parentVertices = Graphs.predecessorListOf(graph, vertex); for (HepRelVertex pVertex : parentVertices) { @@ -604,7 +603,7 @@ public class HepPlanner extends AbstractRelOptPlanner { return false; } } - List<RelNode> children = new ArrayList<RelNode>(childRels.size()); + final List<RelNode> children = new ArrayList<>(childRels.size()); for (HepRelVertex childRel : childRels) { children.add(childRel.getCurrentRel()); } @@ -649,13 +648,13 @@ public class HepPlanner extends AbstractRelOptPlanner { bestRel = call.getResults().get(0); } else { RelOptCost bestCost = null; + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelNode rel : call.getResults()) { - RelOptCost thisCost = getCost(rel); + RelOptCost thisCost = getCost(rel, mq); if (LOGGER.isLoggable(Level.FINER)) { - LOGGER.finer( - "considering " + rel + " with cumulative cost=" - + thisCost + " and rowcount=" - + RelMetadataQuery.getRowCount(rel)); + LOGGER.finer("considering " + rel + + " with cumulative cost=" + thisCost + + " and rowcount=" + mq.getRowCount(rel)); } if ((bestRel == null) || thisCost.isLt(bestCost)) { bestRel = rel; @@ -675,8 +674,9 @@ public class HepPlanner extends AbstractRelOptPlanner { // we only update the existing parents, not the new parents // (otherwise loops can result). Also take care of filtering // out parents by traits in case we're dealing with a converter rule. - List<HepRelVertex> allParents = Graphs.predecessorListOf(graph, vertex); - List<HepRelVertex> parents = new ArrayList<HepRelVertex>(); + final List<HepRelVertex> allParents = + Graphs.predecessorListOf(graph, vertex); + final List<HepRelVertex> parents = new ArrayList<>(); for (HepRelVertex parent : allParents) { if (parentTrait != null) { RelNode parentRel = parent.getCurrentRel(); @@ -758,8 +758,8 @@ public class HepPlanner extends AbstractRelOptPlanner { // Recursively add children, replacing this rel's inputs // with corresponding child vertices. - List<RelNode> inputs = rel.getInputs(); - List<RelNode> newInputs = new ArrayList<RelNode>(); + final List<RelNode> inputs = rel.getInputs(); + final List<RelNode> newInputs = new ArrayList<>(); for (RelNode input1 : inputs) { HepRelVertex childVertex = addRelToGraph(input1); newInputs.add(childVertex); @@ -895,7 +895,7 @@ public class HepPlanner extends AbstractRelOptPlanner { LOGGER.finest("collecting garbage"); // Yer basic mark-and-sweep. - Set<HepRelVertex> rootSet = new HashSet<HepRelVertex>(); + final Set<HepRelVertex> rootSet = new HashSet<>(); if (graph.vertexSet().contains(root)) { BreadthFirstIterator.reachable(rootSet, graph, root); } @@ -904,7 +904,7 @@ public class HepPlanner extends AbstractRelOptPlanner { // Everything is reachable: no garbage to collect. return; } - Set<HepRelVertex> sweepSet = new HashSet<HepRelVertex>(); + final Set<HepRelVertex> sweepSet = new HashSet<>(); for (HepRelVertex vertex : graph.vertexSet()) { if (!rootSet.contains(vertex)) { sweepSet.add(vertex); @@ -929,8 +929,8 @@ public class HepPlanner extends AbstractRelOptPlanner { private void assertNoCycles() { // Verify that the graph is acyclic. - CycleDetector<HepRelVertex, DefaultEdge> cycleDetector = - new CycleDetector<HepRelVertex, DefaultEdge>(graph); + final CycleDetector<HepRelVertex, DefaultEdge> cycleDetector = + new CycleDetector<>(graph); Set<HepRelVertex> cyclicVertices = cycleDetector.findCycles(); if (cyclicVertices.isEmpty()) { return; @@ -948,6 +948,7 @@ public class HepPlanner extends AbstractRelOptPlanner { assertNoCycles(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final StringBuilder sb = new StringBuilder(); sb.append("\nBreadth-first from root: {\n"); for (HepRelVertex vertex : BreadthFirstIterator.of(graph, root)) { @@ -957,9 +958,9 @@ public class HepPlanner extends AbstractRelOptPlanner { RelNode rel = vertex.getCurrentRel(); sb.append(rel) .append(", rowcount=") - .append(RelMetadataQuery.getRowCount(rel)) + .append(mq.getRowCount(rel)) .append(", cumulative cost=") - .append(getCost(rel)) + .append(getCost(rel, mq)) .append('\n'); } sb.append("}"); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java index e944dbe..3f1170a 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java @@ -19,8 +19,8 @@ package org.apache.calcite.plan.hep; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.metadata.Metadata; import org.apache.calcite.rel.metadata.RelMetadataProvider; - -import com.google.common.base.Function; +import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rel.metadata.UnboundMetadata; /** * HepRelMetadataProvider implements the {@link RelMetadataProvider} interface @@ -29,20 +29,20 @@ import com.google.common.base.Function; class HepRelMetadataProvider implements RelMetadataProvider { //~ Methods ---------------------------------------------------------------- - public Function<RelNode, Metadata> apply(Class<? extends RelNode> relClass, - final Class<? extends Metadata> metadataClass) { - return new Function<RelNode, Metadata>() { - public Metadata apply(RelNode rel) { + public <M extends Metadata> UnboundMetadata<M> + apply(Class<? extends RelNode> relClass, + final Class<? extends M> metadataClass) { + return new UnboundMetadata<M>() { + public M bind(RelNode rel, RelMetadataQuery mq) { if (!(rel instanceof HepRelVertex)) { return null; } - HepRelVertex vertex = (HepRelVertex) rel; final RelNode rel2 = vertex.getCurrentRel(); - Function<RelNode, Metadata> function = - rel.getCluster().getMetadataProvider().apply( - rel2.getClass(), metadataClass); - return function.apply(rel2); + UnboundMetadata<M> function = + rel.getCluster().getMetadataProvider().apply(rel2.getClass(), + metadataClass); + return function.bind(rel2, mq); } }; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java index 15e8894..249d37d 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java @@ -60,14 +60,15 @@ public class HepRelVertex extends AbstractRelNode { return this; } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { // HepRelMetadataProvider is supposed to intercept this // and redirect to the real rels. But sometimes it doesn't. return planner.getCostFactory().makeTinyCost(); } - @Override public double getRows() { - return RelMetadataQuery.getRowCount(currentRel); + @Override public double estimateRowCount(RelMetadataQuery mq) { + return mq.getRowCount(currentRel); } @Override protected RelDataType deriveRowType() { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java index 96b7c19..42604c9 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java @@ -27,6 +27,7 @@ import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.RelWriter; import org.apache.calcite.rel.convert.ConverterImpl; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import java.util.List; @@ -66,7 +67,7 @@ public class AbstractConverter extends ConverterImpl { traitSet); } - public RelOptCost computeSelfCost(RelOptPlanner planner) { + public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { return planner.getCostFactory().makeInfiniteCost(); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/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 cf78dff..35cf026 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 @@ -23,6 +23,7 @@ import org.apache.calcite.plan.RelTrait; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.CorrelationId; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.util.trace.CalciteTrace; import com.google.common.collect.ImmutableList; @@ -275,12 +276,12 @@ class RelSet { } // Make sure the cost changes as a result of merging are propagated. - Set<RelSubset> activeSet = new HashSet<>(); + final Set<RelSubset> activeSet = new HashSet<>(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelNode parentRel : getParentRels()) { final RelSubset parentSubset = planner.getSubset(parentRel); parentSubset.propagateCostImprovements( - planner, - parentRel, + planner, mq, parentRel, activeSet); } assert activeSet.isEmpty(); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java index 3fede02..b71390b 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java @@ -128,8 +128,9 @@ public class RelSubset extends AbstractRelNode { */ private void computeBestCost(RelOptPlanner planner) { bestCost = planner.getCostFactory().makeInfiniteCost(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelNode rel : getRels()) { - final RelOptCost cost = planner.getCost(rel); + final RelOptCost cost = planner.getCost(rel, mq); if (cost.isLt(bestCost)) { bestCost = cost; best = rel; @@ -141,19 +142,23 @@ public class RelSubset extends AbstractRelNode { return best; } + public RelNode getOriginal() { + return set.rel; + } + public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { throw new UnsupportedOperationException(); } - public RelOptCost computeSelfCost(RelOptPlanner planner) { + public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { return planner.getCostFactory().makeZeroCost(); } - public double getRows() { + public double estimateRowCount(RelMetadataQuery mq) { if (best != null) { - return RelMetadataQuery.getRowCount(best); + return mq.getRowCount(best); } else { - return RelMetadataQuery.getRowCount(set.rel); + return mq.getRowCount(set.rel); } } @@ -189,7 +194,7 @@ public class RelSubset extends AbstractRelNode { * subset. */ Set<RelNode> getParents() { - final Set<RelNode> list = new LinkedHashSet<RelNode>(); + final Set<RelNode> list = new LinkedHashSet<>(); for (RelNode parent : set.getParentRels()) { for (RelSubset rel : inputSubsets(parent)) { if (rel.set == set && traitSet.satisfies(rel.getTraitSet())) { @@ -205,7 +210,7 @@ public class RelSubset extends AbstractRelNode { * of whose inputs is in this subset. */ Set<RelSubset> getParentSubsets(VolcanoPlanner planner) { - final Set<RelSubset> list = new LinkedHashSet<RelSubset>(); + final Set<RelSubset> list = new LinkedHashSet<>(); for (RelNode parent : set.getParentRels()) { for (RelSubset rel : inputSubsets(parent)) { if (rel.set == set && rel.getTraitSet().equals(traitSet)) { @@ -226,7 +231,7 @@ public class RelSubset extends AbstractRelNode { * subset. The elements of the list are distinct. */ public Collection<RelNode> getParentRels() { - final Set<RelNode> list = new LinkedHashSet<RelNode>(); + final Set<RelNode> list = new LinkedHashSet<>(); parentLoop: for (RelNode parent : set.getParentRels()) { for (RelSubset rel : inputSubsets(parent)) { @@ -303,24 +308,21 @@ public class RelSubset extends AbstractRelNode { * recursively checks whether that subset's parents have gotten cheaper. * * @param planner Planner + * @param mq Metadata query * @param rel Relational expression whose cost has improved * @param activeSet Set of active subsets, for cycle detection */ - void propagateCostImprovements( - VolcanoPlanner planner, - RelNode rel, - Set<RelSubset> activeSet) { + void propagateCostImprovements(VolcanoPlanner planner, RelMetadataQuery mq, + RelNode rel, Set<RelSubset> activeSet) { for (RelSubset subset : set.subsets) { if (rel.getTraitSet().satisfies(subset.traitSet)) { - subset.propagateCostImprovements0(planner, rel, activeSet); + subset.propagateCostImprovements0(planner, mq, rel, activeSet); } } } - void propagateCostImprovements0( - VolcanoPlanner planner, - RelNode rel, - Set<RelSubset> activeSet) { + void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, + RelNode rel, Set<RelSubset> activeSet) { ++timestamp; if (!activeSet.add(this)) { @@ -331,7 +333,7 @@ public class RelSubset extends AbstractRelNode { return; } try { - final RelOptCost cost = planner.getCost(rel); + final RelOptCost cost = planner.getCost(rel, mq); if (cost.isLt(bestCost)) { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("Subset cost improved: subset [" + this @@ -346,8 +348,8 @@ public class RelSubset extends AbstractRelNode { planner.ruleQueue.recompute(this); for (RelNode parent : getParents()) { final RelSubset parentSubset = planner.getSubset(parent); - parentSubset.propagateCostImprovements( - planner, parent, activeSet); + parentSubset.propagateCostImprovements(planner, mq, parent, + activeSet); } planner.checkForSatisfiedConverters(set, rel); } @@ -401,7 +403,7 @@ public class RelSubset extends AbstractRelNode { * As {@link #getRels()} but returns a list. */ public List<RelNode> getRelList() { - final List<RelNode> list = new ArrayList<RelNode>(); + final List<RelNode> list = new ArrayList<>(); for (RelNode rel : set.rels) { if (rel.getTraitSet().satisfies(traitSet)) { list.add(rel); @@ -460,7 +462,7 @@ public class RelSubset extends AbstractRelNode { } List<RelNode> oldInputs = p.getInputs(); - List<RelNode> inputs = new ArrayList<RelNode>(); + List<RelNode> inputs = new ArrayList<>(); for (int i = 0; i < oldInputs.size(); i++) { RelNode oldInput = oldInputs.get(i); RelNode input = visit(oldInput, i, p); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java index bce60ab..f14a681 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java @@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelOptCost; import org.apache.calcite.plan.RelOptRuleOperand; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.RelNodes; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.util.ChunkList; import org.apache.calcite.util.Stacks; import org.apache.calcite.util.Util; @@ -392,12 +393,14 @@ class RuleQueue { // The root always has importance = 1 importance = 1.0; } else { + final RelMetadataQuery mq = RelMetadataQuery.instance(); + // The importance of a subset is the max of its importance to its // parents importance = 0.0; for (RelSubset parent : subset.getParentSubsets(planner)) { final double childImportance = - computeImportanceOfChild(subset, parent); + computeImportanceOfChild(mq, subset, parent); importance = Math.max(importance, childImportance); } } @@ -582,12 +585,11 @@ class RuleQueue { * with cost 50 will have importance 0.4, and a child with cost 25 will have * importance 0.2. */ - private double computeImportanceOfChild( - RelSubset child, + private double computeImportanceOfChild(RelMetadataQuery mq, RelSubset child, RelSubset parent) { final double parentImportance = getImportance(parent); - final double childCost = toDouble(planner.getCost(child)); - final double parentCost = toDouble(planner.getCost(parent)); + final double childCost = toDouble(planner.getCost(child, mq)); + final double parentCost = toDouble(planner.getCost(parent, mq)); double alpha = childCost / parentCost; if (alpha >= 1.0) { // child is always less important than parent @@ -688,7 +690,7 @@ class RuleQueue { * <p>Use a hunkList because {@link java.util.ArrayList} does not implement * remove(0) efficiently.</p> */ - final List<VolcanoRuleMatch> list = new ChunkList<VolcanoRuleMatch>(); + final List<VolcanoRuleMatch> list = new ChunkList<>(); /** * A set of rule-match names contained in {@link #list}. Allows fast http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/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 425ebec..530148c 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 @@ -950,8 +950,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { RelVisitor visitor = new RelVisitor() { int depth = 0; - - final HashSet<RelSubset> visitedSubsets = new HashSet<>(); + final Set<RelSubset> visitedSubsets = new HashSet<>(); public void visit( RelNode p, @@ -991,7 +990,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { * {@link Convention#NONE} and boosts their importance by 25%. */ private void injectImportanceBoost() { - final HashSet<RelSubset> requireBoost = new HashSet<>(); + final Set<RelSubset> requireBoost = new HashSet<>(); SUBSET_LOOP: for (RelSubset subset : ruleQueue.subsetImportances.keySet()) { @@ -1060,6 +1059,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { * Checks internal consistency. */ protected void validate() { + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelSet set : allSets) { if (set.equivalentSet != null) { throw new AssertionError( @@ -1073,7 +1073,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { + "] is in wrong set [" + set + "]"); } for (RelNode rel : subset.getRels()) { - RelOptCost relCost = getCost(rel); + RelOptCost relCost = getCost(rel, mq); if (relCost.isLt(subset.bestCost)) { throw new AssertionError( "rel [" + rel.getDescription() @@ -1118,7 +1118,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { } } - public RelOptCost getCost(RelNode rel) { + public RelOptCost getCost(RelNode rel, RelMetadataQuery mq) { assert rel != null : "pre-condition: rel != null"; if (rel instanceof RelSubset) { return ((RelSubset) rel).bestCost; @@ -1127,13 +1127,13 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { == Convention.NONE) { return costFactory.makeInfiniteCost(); } - RelOptCost cost = RelMetadataQuery.getNonCumulativeCost(rel); + RelOptCost cost = mq.getNonCumulativeCost(rel); if (!zeroCost.isLt(cost)) { // cost must be positive, so nudge it cost = costFactory.makeTinyCost(); } for (RelNode input : rel.getInputs()) { - cost = cost.plus(getCost(input)); + cost = cost.plus(getCost(input, mq)); } return cost; } @@ -1341,6 +1341,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { * @see #normalizePlan(String) */ public void dump(PrintWriter pw) { + final RelMetadataQuery mq = RelMetadataQuery.instance(); pw.println("Root: " + root.getDescription()); pw.println("Original rel:"); pw.println(originalRootString); @@ -1395,8 +1396,8 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { if (importance != null) { pw.print(", importance=" + importance); } - pw.print(", rowcount=" + RelMetadataQuery.getRowCount(rel)); - pw.println(", cumulative cost=" + getCost(rel)); + pw.print(", rowcount=" + mq.getRowCount(rel)); + pw.println(", cumulative cost=" + getCost(rel, mq)); } } } @@ -1657,6 +1658,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { // implements the interface required by its calling convention. final RelTraitSet traits = rel.getTraitSet(); final Convention convention = traits.getTrait(ConventionTraitDef.INSTANCE); + assert convention != null; if (!convention.getInterface().isInstance(rel) && !(rel instanceof Converter)) { throw Util.newInternal( @@ -1842,7 +1844,8 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { // 100. We think this happens because the back-links to parents are // not established. So, give the subset another change to figure out // its cost. - subset.propagateCostImprovements(this, rel, new HashSet<RelSubset>()); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + subset.propagateCostImprovements(this, mq, rel, new HashSet<RelSubset>()); return subset; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java index e898a61..201670f 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java @@ -19,8 +19,8 @@ package org.apache.calcite.plan.volcano; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.metadata.Metadata; import org.apache.calcite.rel.metadata.RelMetadataProvider; - -import com.google.common.base.Function; +import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rel.metadata.UnboundMetadata; /** * VolcanoRelMetadataProvider implements the {@link RelMetadataProvider} @@ -29,16 +29,19 @@ import com.google.common.base.Function; public class VolcanoRelMetadataProvider implements RelMetadataProvider { //~ Methods ---------------------------------------------------------------- - public Function<RelNode, Metadata> apply(Class<? extends RelNode> relClass, - final Class<? extends Metadata> metadataClass) { + public <M extends Metadata> UnboundMetadata<M> + apply(Class<? extends RelNode> relClass, + final Class<? extends M> metadataClass) { if (relClass != RelSubset.class) { // let someone else further down the chain sort it out return null; } - return new Function<RelNode, Metadata>() { - public Metadata apply(RelNode rel) { - RelSubset subset = (RelSubset) rel; + return new UnboundMetadata<M>() { + public M bind(RelNode rel, RelMetadataQuery mq) { + final RelSubset subset = (RelSubset) rel; + final RelMetadataProvider provider = + rel.getCluster().getMetadataProvider(); // REVIEW jvs 29-Mar-2006: I'm not sure what the correct precedence // should be here. Letting the current best plan take the first shot is @@ -49,11 +52,10 @@ public class VolcanoRelMetadataProvider implements RelMetadataProvider { // First, try current best implementation. If it knows how to answer // this query, treat it as the most reliable. if (subset.best != null) { - final Function<RelNode, Metadata> function = - rel.getCluster().getMetadataProvider().apply( - subset.best.getClass(), metadataClass); + final UnboundMetadata<M> function = + provider.apply(subset.best.getClass(), metadataClass); if (function != null) { - Metadata metadata = function.apply(subset.best); + final M metadata = function.bind(subset.best, mq); if (metadata != null) { return metadata; } @@ -79,11 +81,10 @@ public class VolcanoRelMetadataProvider implements RelMetadataProvider { subset.set.inMetadataQuery = true; try { for (RelNode relCandidate : subset.set.rels) { - final Function<RelNode, Metadata> function = - rel.getCluster().getMetadataProvider().apply( - relCandidate.getClass(), metadataClass); + final UnboundMetadata<M> function = + provider.apply(relCandidate.getClass(), metadataClass); if (function != null) { - final Metadata result = function.apply(relCandidate); + final M result = function.bind(relCandidate, mq); if (result != null) { return result; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java index d58cfd8..d75d9c9 100644 --- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java @@ -26,6 +26,7 @@ import org.apache.calcite.plan.RelTraitDef; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.RelRoot; +import org.apache.calcite.rel.metadata.CachingRelMetadataProvider; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.schema.SchemaPlus; @@ -269,6 +270,10 @@ public class PlannerImpl implements Planner { public RelNode transform(int ruleSetIndex, RelTraitSet requiredOutputTraits, RelNode rel) throws RelConversionException { ensure(State.STATE_5_CONVERTED); + rel.getCluster().setMetadataProvider( + new CachingRelMetadataProvider( + rel.getCluster().getMetadataProvider(), + rel.getCluster().getPlanner())); Program program = programs.get(ruleSetIndex); return program.run(planner, rel, requiredOutputTraits); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java index 75a546c..164d34e 100644 --- a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java +++ b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java @@ -29,6 +29,7 @@ import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.core.CorrelationId; import org.apache.calcite.rel.externalize.RelWriterImpl; import org.apache.calcite.rel.metadata.Metadata; +import org.apache.calcite.rel.metadata.MetadataFactory; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; @@ -162,11 +163,13 @@ public abstract class AbstractRelNode implements RelNode { } public boolean isDistinct() { - return Boolean.TRUE.equals(RelMetadataQuery.areRowsUnique(this)); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + return Boolean.TRUE.equals(mq.areRowsUnique(this)); } public boolean isKey(ImmutableBitSet columns) { - return Boolean.TRUE.equals(RelMetadataQuery.areColumnsUnique(this, columns)); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + return Boolean.TRUE.equals(mq.areColumnsUnique(this, columns)); } public int getId() { @@ -235,7 +238,11 @@ public abstract class AbstractRelNode implements RelNode { return Collections.emptyList(); } - public double getRows() { + public final double getRows() { + return estimateRowCount(RelMetadataQuery.instance()); + } + + public double estimateRowCount(RelMetadataQuery mq) { return 1.0; } @@ -271,15 +278,22 @@ public abstract class AbstractRelNode implements RelNode { return this; } - public RelOptCost computeSelfCost(RelOptPlanner planner) { + public final RelOptCost computeSelfCost(RelOptPlanner planner) { + return computeSelfCost(planner, RelMetadataQuery.instance()); + } + + public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { // by default, assume cost is proportional to number of rows - double rowCount = RelMetadataQuery.getRowCount(this); + double rowCount = mq.getRowCount(this); double bytesPerRow = 1; return planner.getCostFactory().makeCost(rowCount, rowCount, 0); } - public final <M extends Metadata> M metadata(Class<M> metadataClass) { - final M metadata = cluster.getMetadataFactory().query(this, metadataClass); + public final <M extends Metadata> M metadata(Class<M> metadataClass, + RelMetadataQuery mq) { + final MetadataFactory factory = cluster.getMetadataFactory(); + final M metadata = factory.query(this, mq, metadataClass); assert metadata != null : "no provider found (rel=" + this + ", m=" + metadataClass + "); a backstop provider is recommended"; http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/RelNode.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/RelNode.java b/core/src/main/java/org/apache/calcite/rel/RelNode.java index 973bc98..0108e88 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelNode.java +++ b/core/src/main/java/org/apache/calcite/rel/RelNode.java @@ -170,9 +170,18 @@ public interface RelNode extends RelOptNode, Cloneable { * {@link RelMetadataQuery#getRowCount}, which gives plugins a chance to * override the rel's default ideas about row count. * + * @param mq Metadata query * @return Estimate of the number of rows this relational expression will * return */ + double estimateRowCount(RelMetadataQuery mq); + + /** + * @deprecated Call {@link RelMetadataQuery#getRowCount(RelNode)}; + * if you wish to override the default row count formula, override the + * {@link #estimateRowCount(RelMetadataQuery)} method. + */ + @Deprecated // to be removed before 2.0 double getRows(); /** @@ -246,20 +255,31 @@ public interface RelNode extends RelOptNode, Cloneable { * chance to override the rel's default ideas about cost. * * @param planner Planner for cost calculation + * @param mq Metadata query * @return Cost of this plan (not including children) */ + RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq); + + /** + * @deprecated Call {@link RelMetadataQuery#getNonCumulativeCost(RelNode)}; + * if you wish to override the default cost formula, override the + * {@link #computeSelfCost(RelOptPlanner, RelMetadataQuery)} method. + */ + @Deprecated // to be removed before 2.0 RelOptCost computeSelfCost(RelOptPlanner planner); /** * Returns a metadata interface. * - * @param metadataClass Metadata interface * @param <M> Type of metadata being requested + * @param metadataClass Metadata interface + * @param mq Metadata query + * * @return Metadata object that supplies the desired metadata (never null, * although if the information is not present the metadata object may * return null from all methods) */ - <M extends Metadata> M metadata(Class<M> metadataClass); + <M extends Metadata> M metadata(Class<M> metadataClass, RelMetadataQuery mq); /** * Describes the inputs and attributes of this relational expression. http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/SingleRel.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/SingleRel.java b/core/src/main/java/org/apache/calcite/rel/SingleRel.java index 5fbb2c6..186db36 100644 --- a/core/src/main/java/org/apache/calcite/rel/SingleRel.java +++ b/core/src/main/java/org/apache/calcite/rel/SingleRel.java @@ -63,9 +63,9 @@ public abstract class SingleRel extends AbstractRelNode { return ImmutableList.of(input); } - @Override public double getRows() { + @Override public double estimateRowCount(RelMetadataQuery mq) { // Not necessarily correct, but a better default than AbstractRelNode's 1.0 - return RelMetadataQuery.getRowCount(input); + return mq.getRowCount(input); } @Override public void childrenAccept(RelVisitor visitor) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java b/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java index 4bb84be..b0cb40b 100644 --- a/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java @@ -58,9 +58,9 @@ public abstract class ConverterImpl extends SingleRel //~ Methods ---------------------------------------------------------------- - // implement RelNode - public RelOptCost computeSelfCost(RelOptPlanner planner) { - double dRows = RelMetadataQuery.getRowCount(getInput()); + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { + double dRows = mq.getRowCount(getInput()); double dCpu = dRows; double dIo = 0; return planner.getCostFactory().makeCost(dRows, dCpu, dIo); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java index 1a07bed..7b46940 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java @@ -276,7 +276,7 @@ public abstract class Aggregate extends SingleRel { return pw; } - @Override public double getRows() { + @Override public double estimateRowCount(RelMetadataQuery mq) { // Assume that each sort column has 50% of the value count. // Therefore one sort column has .5 * rowCount, // 2 sort columns give .75 * rowCount. @@ -285,16 +285,17 @@ public abstract class Aggregate extends SingleRel { if (groupCount == 0) { return 1; } else { - double rowCount = super.getRows(); + double rowCount = super.estimateRowCount(mq); rowCount *= 1.0 - Math.pow(.5, groupCount); return rowCount; } } - @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { + @Override public RelOptCost computeSelfCost(RelOptPlanner planner, + RelMetadataQuery mq) { // REVIEW jvs 24-Aug-2008: This is bogus, but no more bogus // than what's currently in Join. - double rowCount = RelMetadataQuery.getRowCount(this); + double rowCount = mq.getRowCount(this); // Aggregates with more aggregate functions cost a bit more float multiplier = 1f + (float) aggCalls.size() * 0.125f; for (AggregateCall aggCall : aggCalls) {
