http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java index d77ca13..cb1de64 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java @@ -54,20 +54,23 @@ public class RelMdUniqueKeys { //~ Methods ---------------------------------------------------------------- - public Set<ImmutableBitSet> getUniqueKeys(Filter rel, boolean ignoreNulls) { - return RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls); + public Set<ImmutableBitSet> getUniqueKeys(Filter rel, RelMetadataQuery mq, + boolean ignoreNulls) { + return mq.getUniqueKeys(rel.getInput(), ignoreNulls); } - public Set<ImmutableBitSet> getUniqueKeys(Sort rel, boolean ignoreNulls) { - return RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls); + public Set<ImmutableBitSet> getUniqueKeys(Sort rel, RelMetadataQuery mq, + boolean ignoreNulls) { + return mq.getUniqueKeys(rel.getInput(), ignoreNulls); } - public Set<ImmutableBitSet> getUniqueKeys(Correlate rel, + public Set<ImmutableBitSet> getUniqueKeys(Correlate rel, RelMetadataQuery mq, boolean ignoreNulls) { - return RelMetadataQuery.getUniqueKeys(rel.getLeft(), ignoreNulls); + return mq.getUniqueKeys(rel.getLeft(), ignoreNulls); } - public Set<ImmutableBitSet> getUniqueKeys(Project rel, boolean ignoreNulls) { + public Set<ImmutableBitSet> getUniqueKeys(Project rel, RelMetadataQuery mq, + boolean ignoreNulls) { // LogicalProject maps a set of rows to a different set; // Without knowledge of the mapping function(whether it // preserves uniqueness), it is only safe to derive uniqueness @@ -75,11 +78,9 @@ public class RelMdUniqueKeys { // // Further more, the unique bitset coming from the child needs // to be mapped to match the output of the project. - Map<Integer, Integer> mapInToOutPos = new HashMap<>(); - - List<RexNode> projExprs = rel.getProjects(); - - Set<ImmutableBitSet> projUniqueKeySet = new HashSet<>(); + final Map<Integer, Integer> mapInToOutPos = new HashMap<>(); + final List<RexNode> projExprs = rel.getProjects(); + final Set<ImmutableBitSet> projUniqueKeySet = new HashSet<>(); // Build an input to output position map. for (int i = 0; i < projExprs.size(); i++) { @@ -96,7 +97,7 @@ public class RelMdUniqueKeys { } Set<ImmutableBitSet> childUniqueKeySet = - RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls); + mq.getUniqueKeys(rel.getInput(), ignoreNulls); if (childUniqueKeySet != null) { // Now add to the projUniqueKeySet the child keys that are fully @@ -123,7 +124,8 @@ public class RelMdUniqueKeys { return projUniqueKeySet; } - public Set<ImmutableBitSet> getUniqueKeys(Join rel, boolean ignoreNulls) { + public Set<ImmutableBitSet> getUniqueKeys(Join rel, RelMetadataQuery mq, + boolean ignoreNulls) { final RelNode left = rel.getLeft(); final RelNode right = rel.getRight(); @@ -136,13 +138,11 @@ public class RelMdUniqueKeys { // that is undesirable, use RelMetadataQuery.areColumnsUnique() as // an alternative way of getting unique key information. - Set<ImmutableBitSet> retSet = new HashSet<>(); - Set<ImmutableBitSet> leftSet = - RelMetadataQuery.getUniqueKeys(left, ignoreNulls); + final Set<ImmutableBitSet> retSet = new HashSet<>(); + final Set<ImmutableBitSet> leftSet = mq.getUniqueKeys(left, ignoreNulls); Set<ImmutableBitSet> rightSet = null; - Set<ImmutableBitSet> tmpRightSet = - RelMetadataQuery.getUniqueKeys(right, ignoreNulls); + final Set<ImmutableBitSet> tmpRightSet = mq.getUniqueKeys(right, ignoreNulls); int nFieldsOnLeft = left.getRowType().getFieldCount(); if (tmpRightSet != null) { @@ -169,12 +169,10 @@ public class RelMdUniqueKeys { // determine if either or both the LHS and RHS are unique on the // equijoin columns - Boolean leftUnique = - RelMetadataQuery.areColumnsUnique(left, joinInfo.leftSet(), - ignoreNulls); - Boolean rightUnique = - RelMetadataQuery.areColumnsUnique(right, joinInfo.rightSet(), - ignoreNulls); + final Boolean leftUnique = + mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls); + final Boolean rightUnique = + mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls); // if the right hand side is unique on its equijoin columns, then we can // add the unique keys from left if the left hand side is not null @@ -197,19 +195,20 @@ public class RelMdUniqueKeys { return retSet; } - public Set<ImmutableBitSet> getUniqueKeys(SemiJoin rel, boolean ignoreNulls) { + public Set<ImmutableBitSet> getUniqueKeys(SemiJoin rel, RelMetadataQuery mq, + boolean ignoreNulls) { // only return the unique keys from the LHS since a semijoin only // returns the LHS - return RelMetadataQuery.getUniqueKeys(rel.getLeft(), ignoreNulls); + return mq.getUniqueKeys(rel.getLeft(), ignoreNulls); } - public Set<ImmutableBitSet> getUniqueKeys(Aggregate rel, + public Set<ImmutableBitSet> getUniqueKeys(Aggregate rel, RelMetadataQuery mq, boolean ignoreNulls) { // group by keys form a unique key return ImmutableSet.of(rel.getGroupSet()); } - public Set<ImmutableBitSet> getUniqueKeys(SetOp rel, + public Set<ImmutableBitSet> getUniqueKeys(SetOp rel, RelMetadataQuery mq, boolean ignoreNulls) { if (!rel.all) { return ImmutableSet.of( @@ -219,7 +218,8 @@ public class RelMdUniqueKeys { } // Catch-all rule when none of the others apply. - public Set<ImmutableBitSet> getUniqueKeys(RelNode rel, boolean ignoreNulls) { + public Set<ImmutableBitSet> getUniqueKeys(RelNode rel, RelMetadataQuery mq, + boolean ignoreNulls) { // no information available return null; }
http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java index dc1ea3e..5435979 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java @@ -26,11 +26,14 @@ import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.core.Minus; import org.apache.calcite.rel.core.Project; import org.apache.calcite.rel.core.SemiJoin; +import org.apache.calcite.rel.core.Union; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; +import org.apache.calcite.rex.RexLocalRef; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexProgram; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.rex.RexVisitorImpl; import org.apache.calcite.sql.SqlFunction; @@ -77,13 +80,11 @@ public class RelMdUtil { * @param rel the semijoin of interest * @return constructed rexnode */ - public static RexNode makeSemiJoinSelectivityRexNode(SemiJoin rel) { + public static RexNode makeSemiJoinSelectivityRexNode(RelMetadataQuery mq, + SemiJoin rel) { RexBuilder rexBuilder = rel.getCluster().getRexBuilder(); double selectivity = - computeSemiJoinSelectivity( - rel.getLeft(), - rel.getRight(), - rel); + computeSemiJoinSelectivity(mq, rel.getLeft(), rel.getRight(), rel); RexNode selec = rexBuilder.makeApproxLiteral(new BigDecimal(selectivity)); return rexBuilder.makeCall(ARTIFICIAL_SELECTIVITY_FUNC, selec); @@ -113,12 +114,10 @@ public class RelMdUtil { * @param rel semijoin rel * @return calculated selectivity */ - public static double computeSemiJoinSelectivity(SemiJoin rel) { - return computeSemiJoinSelectivity( - rel.getLeft(), - rel.getRight(), - rel.getLeftKeys(), - rel.getRightKeys()); + public static double computeSemiJoinSelectivity(RelMetadataQuery mq, + SemiJoin rel) { + return computeSemiJoinSelectivity(mq, rel.getLeft(), rel.getRight(), + rel.getLeftKeys(), rel.getRightKeys()); } /** @@ -132,14 +131,9 @@ public class RelMdUtil { * @param rel semijoin rel * @return calculated selectivity */ - public static double computeSemiJoinSelectivity( - RelNode factRel, - RelNode dimRel, - SemiJoin rel) { - return computeSemiJoinSelectivity( - factRel, - dimRel, - rel.getLeftKeys(), + public static double computeSemiJoinSelectivity(RelMetadataQuery mq, + RelNode factRel, RelNode dimRel, SemiJoin rel) { + return computeSemiJoinSelectivity(mq, factRel, dimRel, rel.getLeftKeys(), rel.getRightKeys()); } @@ -155,10 +149,8 @@ public class RelMdUtil { * @param dimKeyList RHS keys used in the filter * @return calculated selectivity */ - public static double computeSemiJoinSelectivity( - RelNode factRel, - RelNode dimRel, - List<Integer> factKeyList, + public static double computeSemiJoinSelectivity(RelMetadataQuery mq, + RelNode factRel, RelNode dimRel, List<Integer> factKeyList, List<Integer> dimKeyList) { ImmutableBitSet.Builder factKeys = ImmutableBitSet.builder(); for (int factCol : factKeyList) { @@ -170,20 +162,19 @@ public class RelMdUtil { } final ImmutableBitSet dimKeys = dimKeyBuilder.build(); - Double factPop = - RelMetadataQuery.getPopulationSize(factRel, factKeys.build()); + Double factPop = mq.getPopulationSize(factRel, factKeys.build()); if (factPop == null) { // use the dimension population if the fact population is // unavailable; since we're filtering the fact table, that's // the population we ideally want to use - factPop = RelMetadataQuery.getPopulationSize(dimRel, dimKeys); + factPop = mq.getPopulationSize(dimRel, dimKeys); } // if cardinality and population are available, use them; otherwise // use percentage original rows Double selectivity; Double dimCard = - RelMetadataQuery.getDistinctRowCount( + mq.getDistinctRowCount( dimRel, dimKeys, null); @@ -194,7 +185,7 @@ public class RelMdUtil { } selectivity = dimCard / factPop; } else { - selectivity = RelMetadataQuery.getPercentageOriginalRows(dimRel); + selectivity = mq.getPercentageOriginalRows(dimRel); } if (selectivity == null) { @@ -220,26 +211,24 @@ public class RelMdUtil { * @return true if bit mask represents a unique column set; false if not (or * if no metadata is available) */ - public static boolean areColumnsDefinitelyUnique( - RelNode rel, - ImmutableBitSet colMask) { - Boolean b = RelMetadataQuery.areColumnsUnique(rel, colMask, false); + public static boolean areColumnsDefinitelyUnique(RelMetadataQuery mq, + RelNode rel, ImmutableBitSet colMask) { + Boolean b = mq.areColumnsUnique(rel, colMask, false); return b != null && b; } - public static Boolean areColumnsUnique( - RelNode rel, + public static Boolean areColumnsUnique(RelMetadataQuery mq, RelNode rel, List<RexInputRef> columnRefs) { ImmutableBitSet.Builder colMask = ImmutableBitSet.builder(); for (RexInputRef columnRef : columnRefs) { colMask.set(columnRef.getIndex()); } - return RelMetadataQuery.areColumnsUnique(rel, colMask.build()); + return mq.areColumnsUnique(rel, colMask.build()); } - public static boolean areColumnsDefinitelyUnique(RelNode rel, - List<RexInputRef> columnRefs) { - Boolean b = areColumnsUnique(rel, columnRefs); + public static boolean areColumnsDefinitelyUnique(RelMetadataQuery mq, + RelNode rel, List<RexInputRef> columnRefs) { + Boolean b = areColumnsUnique(mq, rel, columnRefs); return b != null && b; } @@ -255,31 +244,29 @@ public class RelMdUtil { * @return true if bit mask represents a unique column set; false if not (or * if no metadata is available) */ - public static boolean areColumnsDefinitelyUniqueWhenNullsFiltered(RelNode rel, - ImmutableBitSet colMask) { - Boolean b = RelMetadataQuery.areColumnsUnique(rel, colMask, true); + public static boolean areColumnsDefinitelyUniqueWhenNullsFiltered( + RelMetadataQuery mq, RelNode rel, ImmutableBitSet colMask) { + Boolean b = mq.areColumnsUnique(rel, colMask, true); if (b == null) { return false; } return b; } - public static Boolean areColumnsUniqueWhenNullsFiltered( - RelNode rel, - List<RexInputRef> columnRefs) { + public static Boolean areColumnsUniqueWhenNullsFiltered(RelMetadataQuery mq, + RelNode rel, List<RexInputRef> columnRefs) { ImmutableBitSet.Builder colMask = ImmutableBitSet.builder(); for (RexInputRef columnRef : columnRefs) { colMask.set(columnRef.getIndex()); } - return RelMetadataQuery.areColumnsUnique(rel, colMask.build(), true); + return mq.areColumnsUnique(rel, colMask.build(), true); } public static boolean areColumnsDefinitelyUniqueWhenNullsFiltered( - RelNode rel, - List<RexInputRef> columnRefs) { - Boolean b = areColumnsUniqueWhenNullsFiltered(rel, columnRefs); + RelMetadataQuery mq, RelNode rel, List<RexInputRef> columnRefs) { + Boolean b = areColumnsUniqueWhenNullsFiltered(mq, rel, columnRefs); if (b == null) { return false; } @@ -476,9 +463,9 @@ public class RelMdUtil { RexBuilder rexBuilder, RexNode pred1, RexNode pred2) { - List<RexNode> list1 = RelOptUtil.conjunctions(pred1); - List<RexNode> list2 = RelOptUtil.conjunctions(pred2); - List<RexNode> minusList = new ArrayList<>(); + final List<RexNode> list1 = RelOptUtil.conjunctions(pred1); + final List<RexNode> list2 = RelOptUtil.conjunctions(pred2); + final List<RexNode> minusList = new ArrayList<>(); for (RexNode rex1 : list1) { boolean add = true; @@ -550,14 +537,15 @@ public class RelMdUtil { /** * Computes the cardinality of a particular expression from the projection - * list + * list. * * @param rel RelNode corresponding to the project * @param expr projection expression * @return cardinality */ - public static Double cardOfProjExpr(Project rel, RexNode expr) { - return expr.accept(new CardOfProjExpr(rel)); + public static Double cardOfProjExpr(RelMetadataQuery mq, Project rel, + RexNode expr) { + return expr.accept(new CardOfProjExpr(mq, rel)); } /** @@ -567,9 +555,8 @@ public class RelMdUtil { * @param groupKey keys to compute the population for * @return computed population size */ - public static Double getJoinPopulationSize( - RelNode joinRel, - ImmutableBitSet groupKey) { + public static Double getJoinPopulationSize(RelMetadataQuery mq, + RelNode joinRel, ImmutableBitSet groupKey) { ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder(); ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder(); RelNode left = joinRel.getInputs().get(0); @@ -577,23 +564,14 @@ public class RelMdUtil { // separate the mask into masks for the left and right RelMdUtil.setLeftRightBitmaps( - groupKey, - leftMask, - rightMask, - left.getRowType().getFieldCount()); + groupKey, leftMask, rightMask, left.getRowType().getFieldCount()); Double population = NumberUtil.multiply( - RelMetadataQuery.getPopulationSize( - left, - leftMask.build()), - RelMetadataQuery.getPopulationSize( - right, - rightMask.build())); + mq.getPopulationSize(left, leftMask.build()), + mq.getPopulationSize(right, rightMask.build())); - return RelMdUtil.numDistinctVals( - population, - RelMetadataQuery.getRowCount(joinRel)); + return numDistinctVals(population, mq.getRowCount(joinRel)); } /** @@ -608,12 +586,9 @@ public class RelMdUtil { * otherwise use <code>left NDV * right NDV</code>. * @return number of distinct rows */ - public static Double getJoinDistinctRowCount( - RelNode joinRel, - JoinRelType joinType, - ImmutableBitSet groupKey, - RexNode predicate, - boolean useMaxNdv) { + public static Double getJoinDistinctRowCount(RelMetadataQuery mq, + RelNode joinRel, JoinRelType joinType, ImmutableBitSet groupKey, + RexNode predicate, boolean useMaxNdv) { Double distRowCount; ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder(); ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder(); @@ -630,10 +605,10 @@ public class RelMdUtil { RexNode leftPred = null; RexNode rightPred = null; if (predicate != null) { - List<RexNode> leftFilters = new ArrayList<>(); - List<RexNode> rightFilters = new ArrayList<>(); - List<RexNode> joinFilters = new ArrayList<>(); - List<RexNode> predList = RelOptUtil.conjunctions(predicate); + final List<RexNode> leftFilters = new ArrayList<>(); + final List<RexNode> rightFilters = new ArrayList<>(); + final List<RexNode> joinFilters = new ArrayList<>(); + final List<RexNode> predList = RelOptUtil.conjunctions(predicate); RelOptUtil.classifyFilters( joinRel, @@ -655,35 +630,35 @@ public class RelMdUtil { if (useMaxNdv) { distRowCount = Math.max( - RelMetadataQuery.getDistinctRowCount(left, leftMask.build(), - leftPred), - RelMetadataQuery.getDistinctRowCount(right, rightMask.build(), - rightPred)); + mq.getDistinctRowCount(left, leftMask.build(), leftPred), + mq.getDistinctRowCount(right, rightMask.build(), rightPred)); } else { distRowCount = NumberUtil.multiply( - RelMetadataQuery.getDistinctRowCount( - left, - leftMask.build(), - leftPred), - RelMetadataQuery.getDistinctRowCount( - right, - rightMask.build(), - rightPred)); + mq.getDistinctRowCount(left, leftMask.build(), leftPred), + mq.getDistinctRowCount(right, rightMask.build(), rightPred)); } - return RelMdUtil.numDistinctVals( - distRowCount, - RelMetadataQuery.getRowCount(joinRel)); + return RelMdUtil.numDistinctVals(distRowCount, mq.getRowCount(joinRel)); + } + + /** Returns an estimate of the number of rows returned by a {@link Union} + * (before duplicates are eliminated). */ + public static double getUnionAllRowCount(RelMetadataQuery mq, Union rel) { + double rowCount = 0; + for (RelNode input : rel.getInputs()) { + rowCount += mq.getRowCount(input); + } + return rowCount; } /** Returns an estimate of the number of rows returned by a {@link Minus}. */ - public static double getMinusRowCount(Minus minus) { + public static double getMinusRowCount(RelMetadataQuery mq, Minus minus) { // REVIEW jvs 30-May-2005: I just pulled this out of a hat. final List<RelNode> inputs = minus.getInputs(); - double dRows = RelMetadataQuery.getRowCount(inputs.get(0)); + double dRows = mq.getRowCount(inputs.get(0)); for (int i = 1; i < inputs.size(); i++) { - dRows -= 0.5 * RelMetadataQuery.getRowCount(inputs.get(i)); + dRows -= 0.5 * mq.getRowCount(inputs.get(i)); } if (dRows < 0) { dRows = 0; @@ -692,16 +667,17 @@ public class RelMdUtil { } /** Returns an estimate of the number of rows returned by a {@link Join}. */ - public static Double getJoinRowCount(Join join, RexNode condition) { + public static Double getJoinRowCount(RelMetadataQuery mq, Join join, + RexNode condition) { // Row count estimates of 0 will be rounded up to 1. // So, use maxRowCount where the product is very small. - final Double left = RelMetadataQuery.getRowCount(join.getLeft()); - final Double right = RelMetadataQuery.getRowCount(join.getRight()); + final Double left = mq.getRowCount(join.getLeft()); + final Double right = mq.getRowCount(join.getRight()); if (left == null || right == null) { return null; } if (left <= 1D || right <= 1D) { - Double max = RelMetadataQuery.getMaxRowCount(join); + Double max = mq.getMaxRowCount(join); if (max != null && max <= 1D) { return max; } @@ -709,30 +685,51 @@ public class RelMdUtil { double product = left * right; // TODO: correlation factor - return product * RelMetadataQuery.getSelectivity(join, condition); + return product * mq.getSelectivity(join, condition); } /** Returns an estimate of the number of rows returned by a * {@link SemiJoin}. */ - public static Double getSemiJoinRowCount(RelNode left, RelNode right, - JoinRelType joinType, RexNode condition) { + public static Double getSemiJoinRowCount(RelMetadataQuery mq, RelNode left, + RelNode right, JoinRelType joinType, RexNode condition) { // TODO: correlation factor - final Double leftCount = RelMetadataQuery.getRowCount(left); + final Double leftCount = mq.getRowCount(left); if (leftCount == null) { return null; } return leftCount * RexUtil.getSelectivity(condition); } + public static double estimateFilteredRows(RelNode child, RexProgram program, + RelMetadataQuery mq) { + // convert the program's RexLocalRef condition to an expanded RexNode + RexLocalRef programCondition = program.getCondition(); + RexNode condition; + if (programCondition == null) { + condition = null; + } else { + condition = program.expandLocalRef(programCondition); + } + return estimateFilteredRows(child, condition, mq); + } + + public static double estimateFilteredRows(RelNode child, RexNode condition, + RelMetadataQuery mq) { + return mq.getRowCount(child) + * mq.getSelectivity(child, condition); + } + //~ Inner Classes ---------------------------------------------------------- /** Visitor that walks over a scalar expression and computes the * cardinality of its result. */ private static class CardOfProjExpr extends RexVisitorImpl<Double> { + private final RelMetadataQuery mq; private Project rel; - public CardOfProjExpr(Project rel) { + public CardOfProjExpr(RelMetadataQuery mq, Project rel) { super(true); + this.mq = mq; this.rel = rel; } @@ -740,57 +737,45 @@ public class RelMdUtil { int index = var.getIndex(); ImmutableBitSet col = ImmutableBitSet.of(index); Double distinctRowCount = - RelMetadataQuery.getDistinctRowCount( - rel.getInput(), - col, - null); + mq.getDistinctRowCount(rel.getInput(), col, null); if (distinctRowCount == null) { return null; } else { - return RelMdUtil.numDistinctVals( - distinctRowCount, - RelMetadataQuery.getRowCount(rel)); + return numDistinctVals(distinctRowCount, mq.getRowCount(rel)); } } public Double visitLiteral(RexLiteral literal) { - return RelMdUtil.numDistinctVals( - 1.0, - RelMetadataQuery.getRowCount(rel)); + return numDistinctVals(1.0, mq.getRowCount(rel)); } public Double visitCall(RexCall call) { Double distinctRowCount; - Double rowCount = RelMetadataQuery.getRowCount(rel); + Double rowCount = mq.getRowCount(rel); if (call.isA(SqlKind.MINUS_PREFIX)) { - distinctRowCount = - cardOfProjExpr(rel, call.getOperands().get(0)); + distinctRowCount = cardOfProjExpr(mq, rel, call.getOperands().get(0)); } else if (call.isA(ImmutableList.of(SqlKind.PLUS, SqlKind.MINUS))) { - Double card0 = cardOfProjExpr(rel, call.getOperands().get(0)); + Double card0 = cardOfProjExpr(mq, rel, call.getOperands().get(0)); if (card0 == null) { return null; } - Double card1 = cardOfProjExpr(rel, call.getOperands().get(1)); + Double card1 = cardOfProjExpr(mq, rel, call.getOperands().get(1)); if (card1 == null) { return null; } distinctRowCount = Math.max(card0, card1); - } else if (call.isA( - ImmutableList.of(SqlKind.TIMES, SqlKind.DIVIDE))) { + } else if (call.isA(ImmutableList.of(SqlKind.TIMES, SqlKind.DIVIDE))) { distinctRowCount = NumberUtil.multiply( - cardOfProjExpr(rel, call.getOperands().get(0)), - cardOfProjExpr(rel, call.getOperands().get(1))); + cardOfProjExpr(mq, rel, call.getOperands().get(0)), + cardOfProjExpr(mq, rel, call.getOperands().get(1))); // TODO zfong 6/21/06 - Broadbase has code to handle date // functions like year, month, day; E.g., cardinality of Month() // is 12 } else { if (call.getOperands().size() == 1) { - distinctRowCount = - cardOfProjExpr( - rel, - call.getOperands().get(0)); + distinctRowCount = cardOfProjExpr(mq, rel, call.getOperands().get(0)); } else { distinctRowCount = rowCount / 10; } @@ -805,13 +790,11 @@ public class RelMdUtil { * * <p>If this is the case, it is safe to push down a * {@link org.apache.calcite.rel.core.Sort} with limit and optional offset. */ - public static boolean checkInputForCollationAndLimit(RelNode input, - RelCollation collation, RexNode offset, RexNode fetch) { + public static boolean checkInputForCollationAndLimit(RelMetadataQuery mq, + RelNode input, RelCollation collation, RexNode offset, RexNode fetch) { // Check if the input is already sorted - ImmutableList<RelCollation> inputCollations = - RelMetadataQuery.collations(input); boolean alreadySorted = false; - for (RelCollation inputCollation : inputCollations) { + for (RelCollation inputCollation : mq.collations(input)) { if (inputCollation.satisfies(collation)) { alreadySorted = true; break; @@ -819,7 +802,7 @@ public class RelMdUtil { } // Check if we are not reducing the number of tuples boolean alreadySmaller = true; - final Double rowCount = RelMetadataQuery.getMaxRowCount(input); + final Double rowCount = mq.getMaxRowCount(input); if (rowCount != null && fetch != null) { final int offsetVal = offset == null ? 0 : RexLiteral.intValue(offset); final int limit = RexLiteral.intValue(fetch); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java index 0e1bf4f..a2fd272 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java @@ -18,8 +18,6 @@ package org.apache.calcite.rel.metadata; import org.apache.calcite.rel.RelNode; -import com.google.common.base.Function; - /** * RelMetadataProvider defines an interface for obtaining metadata about * relational expressions. This interface is weakly-typed and is not intended to @@ -56,9 +54,9 @@ public interface RelMetadataProvider { * @return Function that will field a metadata instance; or null if this * provider cannot supply metadata of this type */ - Function<RelNode, Metadata> apply( - Class<? extends RelNode> relClass, - Class<? extends Metadata> metadataClass); + <M extends Metadata> UnboundMetadata<M> + apply(Class<? extends RelNode> relClass, + Class<? extends M> metadataClass); } // End RelMetadataProvider.java http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java index 44d0724..f4eb748 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java @@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -64,14 +65,26 @@ import java.util.Set; * custom providers for the standard queries in order to handle additional * relational expressions (either logical or physical). In either case, the * process is the same: write a reflective provider and chain it on to an - * instance of {@link DefaultRelMetadataProvider}, prepending it to the default + * instance of {@link DefaultRelMetadataProvider}, pre-pending it to the default * providers. Then supply that instance to the planner via the appropriate * plugin mechanism. */ public abstract class RelMetadataQuery { + /** Set of active metadata queries. */ + public final Set<List> set = new HashSet<>(); + //~ Methods ---------------------------------------------------------------- /** + * Returns an instance of RelMetadataQuery. It ensures that cycles do not + * occur while computing metadata. + */ + public static RelMetadataQuery instance() { + return new RelMetadataQuery() { + }; + } + + /** * Returns the * {@link BuiltInMetadata.RowCount#getRowCount()} * statistic. @@ -80,9 +93,9 @@ public abstract class RelMetadataQuery { * @return estimated row count, or null if no reliable estimate can be * determined */ - public static Double getRowCount(RelNode rel) { + public Double getRowCount(RelNode rel) { final BuiltInMetadata.RowCount metadata = - rel.metadata(BuiltInMetadata.RowCount.class); + rel.metadata(BuiltInMetadata.RowCount.class, this); Double result = metadata.getRowCount(); return validateResult(result); } @@ -95,9 +108,9 @@ public abstract class RelMetadataQuery { * @param rel the relational expression * @return max row count */ - public static Double getMaxRowCount(RelNode rel) { + public Double getMaxRowCount(RelNode rel) { final BuiltInMetadata.MaxRowCount metadata = - rel.metadata(BuiltInMetadata.MaxRowCount.class); + rel.metadata(BuiltInMetadata.MaxRowCount.class, this); return metadata.getMaxRowCount(); } @@ -109,9 +122,9 @@ public abstract class RelMetadataQuery { * @param rel the relational expression * @return estimated cost, or null if no reliable estimate can be determined */ - public static RelOptCost getCumulativeCost(RelNode rel) { + public RelOptCost getCumulativeCost(RelNode rel) { final BuiltInMetadata.CumulativeCost metadata = - rel.metadata(BuiltInMetadata.CumulativeCost.class); + rel.metadata(BuiltInMetadata.CumulativeCost.class, this); return metadata.getCumulativeCost(); } @@ -123,9 +136,9 @@ public abstract class RelMetadataQuery { * @param rel the relational expression * @return estimated cost, or null if no reliable estimate can be determined */ - public static RelOptCost getNonCumulativeCost(RelNode rel) { + public RelOptCost getNonCumulativeCost(RelNode rel) { final BuiltInMetadata.NonCumulativeCost metadata = - rel.metadata(BuiltInMetadata.NonCumulativeCost.class); + rel.metadata(BuiltInMetadata.NonCumulativeCost.class, this); return metadata.getNonCumulativeCost(); } @@ -138,9 +151,9 @@ public abstract class RelMetadataQuery { * @return estimated percentage (between 0.0 and 1.0), or null if no * reliable estimate can be determined */ - public static Double getPercentageOriginalRows(RelNode rel) { + public Double getPercentageOriginalRows(RelNode rel) { final BuiltInMetadata.PercentageOriginalRows metadata = - rel.metadata(BuiltInMetadata.PercentageOriginalRows.class); + rel.metadata(BuiltInMetadata.PercentageOriginalRows.class, this); Double result = metadata.getPercentageOriginalRows(); assert isPercentage(result, true); return result; @@ -157,9 +170,9 @@ public abstract class RelMetadataQuery { * determined (whereas empty set indicates definitely no origin columns at * all) */ - public static Set<RelColumnOrigin> getColumnOrigins(RelNode rel, int column) { + public Set<RelColumnOrigin> getColumnOrigins(RelNode rel, int column) { final BuiltInMetadata.ColumnOrigin metadata = - rel.metadata(BuiltInMetadata.ColumnOrigin.class); + rel.metadata(BuiltInMetadata.ColumnOrigin.class, this); return metadata.getColumnOrigins(column); } @@ -176,7 +189,7 @@ public abstract class RelMetadataQuery { * @return the origin of a column provided it's a simple column; otherwise, * returns null */ - public static RelColumnOrigin getColumnOrigin(RelNode rel, int column) { + public RelColumnOrigin getColumnOrigin(RelNode rel, int column) { final Set<RelColumnOrigin> origins = getColumnOrigins(rel, column); if (origins == null || origins.size() != 1) { return null; @@ -193,12 +206,11 @@ public abstract class RelMetadataQuery { * * @return the table, if the RelNode is a simple table; otherwise null */ - public static RelOptTable getTableOrigin(RelNode rel) { + public RelOptTable getTableOrigin(RelNode rel) { // Determine the simple origin of the first column in the // RelNode. If it's simple, then that means that the underlying // table is also simple, even if the column itself is derived. - final Set<RelColumnOrigin> colOrigins = - getColumnOrigins(rel, 0); + final Set<RelColumnOrigin> colOrigins = getColumnOrigins(rel, 0); if (colOrigins == null || colOrigins.size() == 0) { return null; } @@ -212,13 +224,13 @@ public abstract class RelMetadataQuery { * * @param rel the relational expression * @param predicate predicate whose selectivity is to be estimated against - * rel's output + * {@code rel}'s output * @return estimated selectivity (between 0.0 and 1.0), or null if no * reliable estimate can be determined */ - public static Double getSelectivity(RelNode rel, RexNode predicate) { + public Double getSelectivity(RelNode rel, RexNode predicate) { final BuiltInMetadata.Selectivity metadata = - rel.metadata(BuiltInMetadata.Selectivity.class); + rel.metadata(BuiltInMetadata.Selectivity.class, this); Double result = metadata.getSelectivity(predicate); assert isPercentage(result, true); return result; @@ -233,9 +245,9 @@ public abstract class RelMetadataQuery { * @return set of keys, or null if this information cannot be determined * (whereas empty set indicates definitely no keys at all) */ - public static Set<ImmutableBitSet> getUniqueKeys(RelNode rel) { + public Set<ImmutableBitSet> getUniqueKeys(RelNode rel) { final BuiltInMetadata.UniqueKeys metadata = - rel.metadata(BuiltInMetadata.UniqueKeys.class); + rel.metadata(BuiltInMetadata.UniqueKeys.class, this); return metadata.getUniqueKeys(false); } @@ -247,13 +259,14 @@ public abstract class RelMetadataQuery { * @param rel the relational expression * @param ignoreNulls if true, ignore null values when determining * whether the keys are unique + * * @return set of keys, or null if this information cannot be determined * (whereas empty set indicates definitely no keys at all) */ - public static Set<ImmutableBitSet> getUniqueKeys(RelNode rel, + public Set<ImmutableBitSet> getUniqueKeys(RelNode rel, boolean ignoreNulls) { final BuiltInMetadata.UniqueKeys metadata = - rel.metadata(BuiltInMetadata.UniqueKeys.class); + rel.metadata(BuiltInMetadata.UniqueKeys.class, this); return metadata.getUniqueKeys(ignoreNulls); } @@ -264,12 +277,13 @@ public abstract class RelMetadataQuery { * statistic over all columns. * * @param rel the relational expression + * * @return true or false depending on whether the rows are unique, or * null if not enough information is available to make that determination */ - public static Boolean areRowsUnique(RelNode rel) { + public Boolean areRowsUnique(RelNode rel) { final BuiltInMetadata.ColumnUniqueness metadata = - rel.metadata(BuiltInMetadata.ColumnUniqueness.class); + rel.metadata(BuiltInMetadata.ColumnUniqueness.class, this); final ImmutableBitSet columns = ImmutableBitSet.range(rel.getRowType().getFieldCount()); return metadata.areColumnsUnique(columns, false); @@ -277,24 +291,25 @@ public abstract class RelMetadataQuery { /** * Returns the - * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(org.apache.calcite.util.ImmutableBitSet, boolean)} + * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(ImmutableBitSet, boolean)} * statistic. * * @param rel the relational expression * @param columns column mask representing the subset of columns for which * uniqueness will be determined + * * @return true or false depending on whether the columns are unique, or * null if not enough information is available to make that determination */ - public static Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns) { + public Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns) { final BuiltInMetadata.ColumnUniqueness metadata = - rel.metadata(BuiltInMetadata.ColumnUniqueness.class); + rel.metadata(BuiltInMetadata.ColumnUniqueness.class, this); return metadata.areColumnsUnique(columns, false); } /** * Returns the - * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(org.apache.calcite.util.ImmutableBitSet, boolean)} + * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(ImmutableBitSet, boolean)} * statistic. * * @param rel the relational expression @@ -305,46 +320,46 @@ public abstract class RelMetadataQuery { * @return true or false depending on whether the columns are unique, or * null if not enough information is available to make that determination */ - public static Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns, + public Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns, boolean ignoreNulls) { final BuiltInMetadata.ColumnUniqueness metadata = - rel.metadata(BuiltInMetadata.ColumnUniqueness.class); + rel.metadata(BuiltInMetadata.ColumnUniqueness.class, this); return metadata.areColumnsUnique(columns, ignoreNulls); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Collation#collations()} + * {@link BuiltInMetadata.Collation#collations()} * statistic. * * @param rel the relational expression * @return List of sorted column combinations, or * null if not enough information is available to make that determination */ - public static ImmutableList<RelCollation> collations(RelNode rel) { + public ImmutableList<RelCollation> collations(RelNode rel) { final BuiltInMetadata.Collation metadata = - rel.metadata(BuiltInMetadata.Collation.class); + rel.metadata(BuiltInMetadata.Collation.class, this); return metadata.collations(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Distribution#distribution()} + * {@link BuiltInMetadata.Distribution#distribution()} * statistic. * * @param rel the relational expression * @return List of sorted column combinations, or * null if not enough information is available to make that determination */ - public static RelDistribution distribution(RelNode rel) { + public RelDistribution distribution(RelNode rel) { final BuiltInMetadata.Distribution metadata = - rel.metadata(BuiltInMetadata.Distribution.class); + rel.metadata(BuiltInMetadata.Distribution.class, this); return metadata.distribution(); } /** * Returns the - * {@link BuiltInMetadata.PopulationSize#getPopulationSize(org.apache.calcite.util.ImmutableBitSet)} + * {@link BuiltInMetadata.PopulationSize#getPopulationSize(ImmutableBitSet)} * statistic. * * @param rel the relational expression @@ -354,31 +369,31 @@ public abstract class RelMetadataQuery { * estimate can be determined * */ - public static Double getPopulationSize(RelNode rel, + public Double getPopulationSize(RelNode rel, ImmutableBitSet groupKey) { final BuiltInMetadata.PopulationSize metadata = - rel.metadata(BuiltInMetadata.PopulationSize.class); + rel.metadata(BuiltInMetadata.PopulationSize.class, this); Double result = metadata.getPopulationSize(groupKey); return validateResult(result); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Size#averageRowSize()} + * {@link BuiltInMetadata.Size#averageRowSize()} * statistic. * * @param rel the relational expression * @return average size of a row, in bytes, or null if not known */ - public static Double getAverageRowSize(RelNode rel) { + public Double getAverageRowSize(RelNode rel) { final BuiltInMetadata.Size metadata = - rel.metadata(BuiltInMetadata.Size.class); + rel.metadata(BuiltInMetadata.Size.class, this); return metadata.averageRowSize(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Size#averageColumnSizes()} + * {@link BuiltInMetadata.Size#averageColumnSizes()} * statistic. * * @param rel the relational expression @@ -386,17 +401,17 @@ public abstract class RelMetadataQuery { * value, in bytes. Each value or the entire list may be null if the * metadata is not available */ - public static List<Double> getAverageColumnSizes(RelNode rel) { + public List<Double> getAverageColumnSizes(RelNode rel) { final BuiltInMetadata.Size metadata = - rel.metadata(BuiltInMetadata.Size.class); + rel.metadata(BuiltInMetadata.Size.class, this); return metadata.averageColumnSizes(); } /** As {@link #getAverageColumnSizes(org.apache.calcite.rel.RelNode)} but * never returns a null list, only ever a list of nulls. */ - public static List<Double> getAverageColumnSizesNotNull(RelNode rel) { + public List<Double> getAverageColumnSizesNotNull(RelNode rel) { final BuiltInMetadata.Size metadata = - rel.metadata(BuiltInMetadata.Size.class); + rel.metadata(BuiltInMetadata.Size.class, this); final List<Double> averageColumnSizes = metadata.averageColumnSizes(); return averageColumnSizes == null ? Collections.<Double>nCopies(rel.getRowType().getFieldCount(), null) @@ -405,7 +420,7 @@ public abstract class RelMetadataQuery { /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Parallelism#isPhaseTransition()} + * {@link BuiltInMetadata.Parallelism#isPhaseTransition()} * statistic. * * @param rel the relational expression @@ -413,29 +428,29 @@ public abstract class RelMetadataQuery { * expression belongs to a different process than its inputs, or null if not * known */ - public static Boolean isPhaseTransition(RelNode rel) { + public Boolean isPhaseTransition(RelNode rel) { final BuiltInMetadata.Parallelism metadata = - rel.metadata(BuiltInMetadata.Parallelism.class); + rel.metadata(BuiltInMetadata.Parallelism.class, this); return metadata.isPhaseTransition(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Parallelism#splitCount()} + * {@link BuiltInMetadata.Parallelism#splitCount()} * statistic. * * @param rel the relational expression * @return the number of distinct splits of the data, or null if not known */ - public static Integer splitCount(RelNode rel) { + public Integer splitCount(RelNode rel) { final BuiltInMetadata.Parallelism metadata = - rel.metadata(BuiltInMetadata.Parallelism.class); + rel.metadata(BuiltInMetadata.Parallelism.class, this); return metadata.splitCount(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Memory#memory()} + * {@link BuiltInMetadata.Memory#memory()} * statistic. * * @param rel the relational expression @@ -443,15 +458,15 @@ public abstract class RelMetadataQuery { * operator implementing this relational expression, across all splits, * or null if not known */ - public static Double memory(RelNode rel) { + public Double memory(RelNode rel) { final BuiltInMetadata.Memory metadata = - rel.metadata(BuiltInMetadata.Memory.class); + rel.metadata(BuiltInMetadata.Memory.class, this); return metadata.memory(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Memory#cumulativeMemoryWithinPhase()} + * {@link BuiltInMetadata.Memory#cumulativeMemoryWithinPhase()} * statistic. * * @param rel the relational expression @@ -459,15 +474,15 @@ public abstract class RelMetadataQuery { * physical operator implementing this relational expression, and all other * operators within the same phase, across all splits, or null if not known */ - public static Double cumulativeMemoryWithinPhase(RelNode rel) { + public Double cumulativeMemoryWithinPhase(RelNode rel) { final BuiltInMetadata.Memory metadata = - rel.metadata(BuiltInMetadata.Memory.class); + rel.metadata(BuiltInMetadata.Memory.class, this); return metadata.cumulativeMemoryWithinPhase(); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Memory#cumulativeMemoryWithinPhaseSplit()} + * {@link BuiltInMetadata.Memory#cumulativeMemoryWithinPhaseSplit()} * statistic. * * @param rel the relational expression @@ -475,15 +490,15 @@ public abstract class RelMetadataQuery { * the physical operator implementing this relational expression, and all * operators within the same phase, within each split, or null if not known */ - public static Double cumulativeMemoryWithinPhaseSplit(RelNode rel) { + public Double cumulativeMemoryWithinPhaseSplit(RelNode rel) { final BuiltInMetadata.Memory metadata = - rel.metadata(BuiltInMetadata.Memory.class); + rel.metadata(BuiltInMetadata.Memory.class, this); return metadata.cumulativeMemoryWithinPhaseSplit(); } /** * Returns the - * {@link BuiltInMetadata.DistinctRowCount#getDistinctRowCount(org.apache.calcite.util.ImmutableBitSet, org.apache.calcite.rex.RexNode)} + * {@link BuiltInMetadata.DistinctRowCount#getDistinctRowCount(ImmutableBitSet, RexNode)} * statistic. * * @param rel the relational expression @@ -492,27 +507,27 @@ public abstract class RelMetadataQuery { * @return distinct row count for groupKey, filtered by predicate, or null * if no reliable estimate can be determined */ - public static Double getDistinctRowCount( + public Double getDistinctRowCount( RelNode rel, ImmutableBitSet groupKey, RexNode predicate) { final BuiltInMetadata.DistinctRowCount metadata = - rel.metadata(BuiltInMetadata.DistinctRowCount.class); + rel.metadata(BuiltInMetadata.DistinctRowCount.class, this); Double result = metadata.getDistinctRowCount(groupKey, predicate); return validateResult(result); } /** * Returns the - * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Predicates#getPredicates()} + * {@link BuiltInMetadata.Predicates#getPredicates()} * statistic. * * @param rel the relational expression * @return Predicates that can be pulled above this RelNode */ - public static RelOptPredicateList getPulledUpPredicates(RelNode rel) { + public RelOptPredicateList getPulledUpPredicates(RelNode rel) { final BuiltInMetadata.Predicates metadata = - rel.metadata(BuiltInMetadata.Predicates.class); + rel.metadata(BuiltInMetadata.Predicates.class, this); return metadata.getPredicates(); } @@ -526,10 +541,10 @@ public abstract class RelMetadataQuery { * @return true for visible, false for invisible; if no metadata is available, * defaults to true */ - public static boolean isVisibleInExplain(RelNode rel, + public boolean isVisibleInExplain(RelNode rel, SqlExplainLevel explainLevel) { final BuiltInMetadata.ExplainVisibility metadata = - rel.metadata(BuiltInMetadata.ExplainVisibility.class); + rel.metadata(BuiltInMetadata.ExplainVisibility.class, this); Boolean b = metadata.isVisibleInExplain(explainLevel); return b == null || b; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/metadata/UnboundMetadata.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/UnboundMetadata.java b/core/src/main/java/org/apache/calcite/rel/metadata/UnboundMetadata.java new file mode 100644 index 0000000..ef8dc4a --- /dev/null +++ b/core/src/main/java/org/apache/calcite/rel/metadata/UnboundMetadata.java @@ -0,0 +1,31 @@ +/* + * 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.rel.metadata; + +import org.apache.calcite.rel.RelNode; + +/** + * Metadata that needs to be bound to a {@link RelNode} and + * {@link RelMetadataQuery} before it can be used. + * + * @param <M> Metadata type + */ +public interface UnboundMetadata<M extends Metadata> { + M bind(RelNode rel, RelMetadataQuery mq); +} + +// End UnboundMetadata.java http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java index 52b5497..b2ebf84 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java @@ -72,8 +72,8 @@ public class AggregateFilterTransposeRule extends RelOptRule { final ImmutableBitSet newGroupSet = aggregate.getGroupSet().union(filterColumns); final RelNode input = filter.getInput(); - final Boolean unique = - RelMetadataQuery.areColumnsUnique(input, newGroupSet); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final Boolean unique = mq.areColumnsUnique(input, newGroupSet); if (unique != null && unique) { // The input is already unique on the grouping columns, so there's little // advantage of aggregating again. More important, without this check, http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java index 016e45a..6978e04 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java @@ -38,7 +38,9 @@ import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlSplittableAggFunction; import org.apache.calcite.tools.RelBuilder; import org.apache.calcite.tools.RelBuilderFactory; +import org.apache.calcite.util.Bug; import org.apache.calcite.util.ImmutableBitSet; +import org.apache.calcite.util.Util; import org.apache.calcite.util.mapping.Mapping; import org.apache.calcite.util.mapping.Mappings; @@ -153,8 +155,9 @@ public class AggregateJoinTransposeRule extends RelOptRule { // Do the columns used by the join appear in the output of the aggregate? final ImmutableBitSet aggregateColumns = aggregate.getGroupSet(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final ImmutableBitSet keyColumns = keyColumns(aggregateColumns, - RelMetadataQuery.getPulledUpPredicates(join).pulledUpPredicates); + mq.getPulledUpPredicates(join).pulledUpPredicates); final ImmutableBitSet joinColumns = RelOptUtil.InputFinder.bits(join.getCondition()); final boolean allColumnsInAggregate = @@ -202,17 +205,18 @@ public class AggregateJoinTransposeRule extends RelOptRule { // any functions experiencing a cartesian product effect. // // But finding out whether the input is already unique requires a call - // to areColumnsUnique that currently (until [CALCITE-794] "Detect - // cycles when computing statistics" is fixed) places a heavy load on + // to areColumnsUnique that currently (until [CALCITE-1048] "Make + // metadata more robust" is fixed) places a heavy load on // the metadata system. // // So we choose to imagine the the input is already unique, which is // untrue but harmless. // + Util.discard(Bug.CALCITE_1048_FIXED); unique = true; } else { final Boolean unique0 = - RelMetadataQuery.areColumnsUnique(joinInput, belowAggregateKey); + mq.areColumnsUnique(joinInput, belowAggregateKey); unique = unique0 != null && unique0; } if (unique) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java index a0ff130..bb7797e 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java @@ -109,8 +109,9 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule { } final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelOptPredicateList predicates = - RelMetadataQuery.getPulledUpPredicates(aggregate.getInput()); + mq.getPulledUpPredicates(aggregate.getInput()); if (predicates == null) { return; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java index aa74448..b98ba64 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java @@ -57,10 +57,11 @@ public class AggregateRemoveRule extends RelOptRule { public void onMatch(RelOptRuleCall call) { final LogicalAggregate aggregate = call.rel(0); final RelNode input = call.rel(1); - if (!aggregate.getAggCallList().isEmpty() - || aggregate.indicator - || !SqlFunctions.isTrue( - RelMetadataQuery.areColumnsUnique(input, aggregate.getGroupSet()))) { + if (!aggregate.getAggCallList().isEmpty() || aggregate.indicator) { + return; + } + final RelMetadataQuery mq = RelMetadataQuery.instance(); + if (!SqlFunctions.isTrue(mq.areColumnsUnique(input, aggregate.getGroupSet()))) { return; } // Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java index 7464a0f..3945924 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java @@ -33,6 +33,7 @@ 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.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.schema.Table; import org.apache.calcite.schema.impl.StarTable; @@ -115,7 +116,8 @@ public class AggregateStarTableRule extends RelOptRule { final RelBuilder relBuilder = call.builder(); final CalciteSchema.TableEntry tableEntry = pair.left; final TileKey tileKey = pair.right; - final double rowCount = aggregate.getRows(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final double rowCount = aggregate.estimateRowCount(mq); final Table aggregateTable = tableEntry.getTable(); final RelDataType aggregateTableRowType = aggregateTable.getRowType(cluster.getTypeFactory()); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java index 2a2ef98..12300d9 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java @@ -27,6 +27,7 @@ import org.apache.calcite.rel.core.Union; import org.apache.calcite.rel.logical.LogicalAggregate; import org.apache.calcite.rel.logical.LogicalUnion; import org.apache.calcite.rel.metadata.RelMdUtil; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.fun.SqlCountAggFunction; @@ -115,10 +116,10 @@ public class AggregateUnionTransposeRule extends RelOptRule { // create corresponding aggregates on top of each union child final RelBuilder relBuilder = call.builder(); int transformCount = 0; + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelNode input : union.getInputs()) { boolean alreadyUnique = - RelMdUtil.areColumnsDefinitelyUnique( - input, + RelMdUtil.areColumnsDefinitelyUnique(mq, input, aggRel.getGroupSet()); relBuilder.push(input); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java index 1d375c6..0b020c7 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java @@ -59,7 +59,8 @@ public class JoinPushTransitivePredicatesRule extends RelOptRule { @Override public void onMatch(RelOptRuleCall call) { Join join = call.rel(0); - RelOptPredicateList preds = RelMetadataQuery.getPulledUpPredicates(join); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + RelOptPredicateList preds = mq.getPulledUpPredicates(join); if (preds.leftInferredPredicates.isEmpty() && preds.rightInferredPredicates.isEmpty()) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java index a41e1aa..ee4eeaa 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java @@ -192,7 +192,7 @@ public class LoptMultiJoin { joinFilters = Lists.newArrayList(RelOptUtil.conjunctions(multiJoin.getJoinFilter())); - allJoinFilters = new ArrayList<RexNode>(joinFilters); + allJoinFilters = new ArrayList<>(joinFilters); List<RexNode> outerJoinFilters = multiJoin.getOuterJoinConditions(); for (int i = 0; i < nJoinFactors; i++) { allJoinFilters.addAll(RelOptUtil.conjunctions(outerJoinFilters.get(i))); @@ -235,8 +235,8 @@ public class LoptMultiJoin { joinRemovalFactors = new Integer[nJoinFactors]; joinRemovalSemiJoins = new SemiJoin[nJoinFactors]; - removableOuterJoinFactors = new HashSet<Integer>(); - removableSelfJoinPairs = new HashMap<Integer, RemovableSelfJoin>(); + removableOuterJoinFactors = new HashSet<>(); + removableSelfJoinPairs = new HashMap<>(); } //~ Methods ---------------------------------------------------------------- @@ -695,15 +695,15 @@ public class LoptMultiJoin { // Compute a column mapping such that if a column from the right // factor is also referenced in the left factor, we will map the // right reference to the left to avoid redundant references. - Map<Integer, Integer> columnMapping = new HashMap<Integer, Integer>(); + final Map<Integer, Integer> columnMapping = new HashMap<>(); // First, locate the originating column for all simple column // references in the left factor. - RelNode left = getJoinFactor(leftFactor); - Map<Integer, Integer> leftFactorColMapping = - new HashMap<Integer, Integer>(); + final RelNode left = getJoinFactor(leftFactor); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final Map<Integer, Integer> leftFactorColMapping = new HashMap<>(); for (int i = 0; i < left.getRowType().getFieldCount(); i++) { - RelColumnOrigin colOrigin = RelMetadataQuery.getColumnOrigin(left, i); + final RelColumnOrigin colOrigin = mq.getColumnOrigin(left, i); if (colOrigin != null) { leftFactorColMapping.put( colOrigin.getOriginColumnOrdinal(), @@ -717,8 +717,7 @@ public class LoptMultiJoin { // factor. RelNode right = getJoinFactor(rightFactor); for (int i = 0; i < right.getRowType().getFieldCount(); i++) { - final RelColumnOrigin colOrigin = - RelMetadataQuery.getColumnOrigin(right, i); + final RelColumnOrigin colOrigin = mq.getColumnOrigin(right, i); if (colOrigin == null) { continue; } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java index 66ae671..e522ade 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java @@ -209,9 +209,9 @@ public class LoptOptimizeJoinRule extends RelOptRule { // part of an equality join condition, nulls are filtered out // by the join. So, it's ok if there are nulls in the join // keys. - if (RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered( - multiJoin.getJoinFactor(factIdx), - joinKeys)) { + final RelMetadataQuery mq = RelMetadataQuery.instance(); + if (RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, + multiJoin.getJoinFactor(factIdx), joinKeys)) { multiJoin.addRemovableOuterJoinFactor(factIdx); // Since we are no longer joining this factor, @@ -319,7 +319,7 @@ public class LoptOptimizeJoinRule extends RelOptRule { // the appropriate join condition between the two factors that will // allow the join to be removed. for (Integer factor1 : selfJoinPairs.keySet()) { - int factor2 = selfJoinPairs.get(factor1); + final int factor2 = selfJoinPairs.get(factor1); final List<RexNode> selfJoinFilters = new ArrayList<>(); for (RexNode filter : multiJoin.getJoinFilters()) { ImmutableBitSet joinFactors = @@ -361,13 +361,14 @@ public class LoptOptimizeJoinRule extends RelOptRule { if (multiJoin.getMultiJoinRel().isFullOuterJoin()) { return returnList; } + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (int factIdx = 0; factIdx < multiJoin.getNumJoinFactors(); factIdx++) { if (multiJoin.isNullGenerating(factIdx) || (multiJoin.getJoinRemovalFactor(factIdx) != null)) { continue; } final RelNode rel = multiJoin.getJoinFactor(factIdx); - final RelOptTable table = RelMetadataQuery.getTableOrigin(rel); + final RelOptTable table = mq.getTableOrigin(rel); if (table != null) { returnList.put(factIdx, table); } @@ -421,7 +422,8 @@ public class LoptOptimizeJoinRule extends RelOptRule { rightRel.getRowType().getFieldList(), adjustments)); - return areSelfJoinKeysUnique(leftRel, rightRel, joinFilters); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + return areSelfJoinKeysUnique(mq, leftRel, rightRel, joinFilters); } /** @@ -439,7 +441,7 @@ public class LoptOptimizeJoinRule extends RelOptRule { RelOptRuleCall call) { final List<RelNode> plans = new ArrayList<>(); - List<String> fieldNames = + final List<String> fieldNames = multiJoin.getMultiJoinRel().getRowType().getFieldNames(); // generate the N join orderings @@ -603,10 +605,9 @@ public class LoptOptimizeJoinRule extends RelOptRule { if (joinKeys.isEmpty()) { return null; } else { - return RelMetadataQuery.getDistinctRowCount( - semiJoinOpt.getChosenSemiJoin(factor), - joinKeys.build(), - null); + final RelMetadataQuery mq = semiJoinOpt.mq; + return mq.getDistinctRowCount(semiJoinOpt.getChosenSemiJoin(factor), + joinKeys.build(), null); } } @@ -671,9 +672,9 @@ public class LoptOptimizeJoinRule extends RelOptRule { LoptSemiJoinOptimizer semiJoinOpt, int firstFactor) { LoptJoinTree joinTree = null; - int nJoinFactors = multiJoin.getNumJoinFactors(); - BitSet factorsToAdd = BitSets.range(0, nJoinFactors); - BitSet factorsAdded = new BitSet(nJoinFactors); + final int nJoinFactors = multiJoin.getNumJoinFactors(); + final BitSet factorsToAdd = BitSets.range(0, nJoinFactors); + final BitSet factorsAdded = new BitSet(nJoinFactors); final List<RexNode> filtersToAdd = new ArrayList<>(multiJoin.getJoinFilters()); @@ -867,6 +868,8 @@ public class LoptOptimizeJoinRule extends RelOptRule { BitSet factorsNeeded, List<RexNode> filtersToAdd, boolean selfJoin) { + final RelMetadataQuery mq = semiJoinOpt.mq; + // if the factor corresponds to the null generating factor in an outer // join that can be removed, then create a replacement join if (multiJoin.isRemovableOuterJoinFactor(factorToAdd)) { @@ -935,11 +938,10 @@ public class LoptOptimizeJoinRule extends RelOptRule { RelOptCost costPushDown = null; RelOptCost costTop = null; if (pushDownTree != null) { - costPushDown = - RelMetadataQuery.getCumulativeCost(pushDownTree.getJoinTree()); + costPushDown = mq.getCumulativeCost(pushDownTree.getJoinTree()); } if (topTree != null) { - costTop = RelMetadataQuery.getCumulativeCost(topTree.getJoinTree()); + costTop = mq.getCumulativeCost(topTree.getJoinTree()); } if (pushDownTree == null) { @@ -1337,7 +1339,7 @@ public class LoptOptimizeJoinRule extends RelOptRule { int factorAdded, List<Integer> origJoinOrder, List<RelDataTypeField> origFields) { - List<Integer> newJoinOrder = new ArrayList<>(); + final List<Integer> newJoinOrder = new ArrayList<>(); left.getTreeOrder(newJoinOrder); right.getTreeOrder(newJoinOrder); @@ -1858,8 +1860,9 @@ public class LoptOptimizeJoinRule extends RelOptRule { ((LoptJoinTree.Leaf) left.getFactorTree()).getId()); } - Double leftRowCount = RelMetadataQuery.getRowCount(left.getJoinTree()); - Double rightRowCount = RelMetadataQuery.getRowCount(right.getJoinTree()); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final Double leftRowCount = mq.getRowCount(left.getJoinTree()); + final Double rightRowCount = mq.getRowCount(right.getJoinTree()); // The left side is smaller than the right if it has fewer rows, // or if it has the same number of rows as the right (excluding @@ -1990,11 +1993,12 @@ public class LoptOptimizeJoinRule extends RelOptRule { } // Make sure the join is between the same simple factor - final RelOptTable leftTable = RelMetadataQuery.getTableOrigin(left); + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final RelOptTable leftTable = mq.getTableOrigin(left); if (leftTable == null) { return false; } - final RelOptTable rightTable = RelMetadataQuery.getTableOrigin(right); + final RelOptTable rightTable = mq.getTableOrigin(right); if (rightTable == null) { return false; } @@ -2003,35 +2007,34 @@ public class LoptOptimizeJoinRule extends RelOptRule { } // Determine if the join keys are identical and unique - return areSelfJoinKeysUnique(left, right, joinRel.getCondition()); + return areSelfJoinKeysUnique(mq, left, right, joinRel.getCondition()); } /** * Determines if the equality portion of a self-join condition is between * identical keys that are unique. * + * @param mq Metadata query * @param leftRel left side of the join * @param rightRel right side of the join * @param joinFilters the join condition * * @return true if the equality join keys are the same and unique */ - private static boolean areSelfJoinKeysUnique( - RelNode leftRel, - RelNode rightRel, - RexNode joinFilters) { + private static boolean areSelfJoinKeysUnique(RelMetadataQuery mq, + RelNode leftRel, RelNode rightRel, RexNode joinFilters) { final JoinInfo joinInfo = JoinInfo.of(leftRel, rightRel, joinFilters); // Make sure each key on the left maps to the same simple column as the // corresponding key on the right for (IntPair pair : joinInfo.pairs()) { final RelColumnOrigin leftOrigin = - RelMetadataQuery.getColumnOrigin(leftRel, pair.source); + mq.getColumnOrigin(leftRel, pair.source); if (leftOrigin == null) { return false; } final RelColumnOrigin rightOrigin = - RelMetadataQuery.getColumnOrigin(rightRel, pair.target); + mq.getColumnOrigin(rightRel, pair.target); if (rightOrigin == null) { return false; } @@ -2045,7 +2048,7 @@ public class LoptOptimizeJoinRule extends RelOptRule { // are unique. When removing self-joins, if needed, we'll later add an // IS NOT NULL filter on the join keys that are nullable. Therefore, // it's ok if there are nulls in the unique key. - return RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(leftRel, + return RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, leftRel, joinInfo.leftSet()); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java index 080cb9c..308091e 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java @@ -58,10 +58,11 @@ public class LoptSemiJoinOptimizer { //~ Instance fields -------------------------------------------------------- - /** - * RexBuilder for constructing new RexNodes - */ - private RexBuilder rexBuilder; + private final RexBuilder rexBuilder; + + /** Not thread-safe. But should be OK, because an optimizer is only used + * from within one thread.*/ + final RelMetadataQuery mq = RelMetadataQuery.instance(); /** * Semijoins corresponding to each join factor, if they are going to be @@ -406,7 +407,7 @@ public class LoptSemiJoinOptimizer { while (keyIter.hasNext()) { boolean removeKey = false; final RelColumnOrigin colOrigin = - RelMetadataQuery.getColumnOrigin(factRel, keyIter.next()); + mq.getColumnOrigin(factRel, keyIter.next()); // can't use the rid column as a semijoin key if ((colOrigin == null) @@ -635,13 +636,13 @@ public class LoptSemiJoinOptimizer { // a middle ground based on testing that was done with a large // data set. final ImmutableBitSet dimCols = ImmutableBitSet.of(semiJoin.getRightKeys()); - double selectivity = - RelMdUtil.computeSemiJoinSelectivity(factRel, dimRel, semiJoin); + final double selectivity = + RelMdUtil.computeSemiJoinSelectivity(mq, factRel, dimRel, semiJoin); if (selectivity > .5) { return 0; } - RelOptCost factCost = RelMetadataQuery.getCumulativeCost(factRel); + final RelOptCost factCost = mq.getCumulativeCost(factRel); // if not enough information, return a low score if (factCost == null) { @@ -654,9 +655,8 @@ public class LoptSemiJoinOptimizer { // Additional savings if the dimension columns are unique. We can // ignore nulls since they will be filtered out by the semijoin. boolean uniq = - RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered( - dimRel, - dimCols); + RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, + dimRel, dimCols); if (uniq) { savings *= 2.0; } @@ -664,9 +664,9 @@ public class LoptSemiJoinOptimizer { // compute the cost of doing an extra scan on the dimension table, // including the distinct sort on top of the scan; if the dimension // columns are already unique, no need to add on the dup removal cost - Double dimSortCost = RelMetadataQuery.getRowCount(dimRel); - Double dupRemCost = uniq ? 0 : dimSortCost; - RelOptCost dimCost = RelMetadataQuery.getCumulativeCost(dimRel); + final Double dimSortCost = mq.getRowCount(dimRel); + final Double dupRemCost = uniq ? 0 : dimSortCost; + final RelOptCost dimCost = mq.getCumulativeCost(dimRel); if ((dimSortCost == null) || (dupRemCost == null) || (dimCost == null)) { @@ -708,9 +708,8 @@ public class LoptSemiJoinOptimizer { // Check if the semijoin keys corresponding to the dimension table // are unique. The semijoin will filter out the nulls. final ImmutableBitSet dimKeys = ImmutableBitSet.of(semiJoin.getRightKeys()); - RelNode dimRel = multiJoin.getJoinFactor(dimIdx); - if (!RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered( - dimRel, + final RelNode dimRel = multiJoin.getJoinFactor(dimIdx); + if (!RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, dimRel, dimKeys)) { return; } @@ -800,14 +799,14 @@ public class LoptSemiJoinOptimizer { //~ Inner Classes ---------------------------------------------------------- - /** . */ + /** Compares factors. */ private class FactorCostComparator implements Comparator<Integer> { public int compare(Integer rel1Idx, Integer rel2Idx) { RelOptCost c1 = - RelMetadataQuery.getCumulativeCost(chosenSemiJoins[rel1Idx]); + mq.getCumulativeCost(chosenSemiJoins[rel1Idx]); RelOptCost c2 = - RelMetadataQuery.getCumulativeCost(chosenSemiJoins[rel2Idx]); + mq.getCumulativeCost(chosenSemiJoins[rel2Idx]); // nulls are arbitrarily sorted if ((c1 == null) || (c2 == null)) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java index 477b74a..b0b372d 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java @@ -87,6 +87,7 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule { final MultiJoin multiJoinRel = call.rel(0); final RexBuilder rexBuilder = multiJoinRel.getCluster().getRexBuilder(); final RelBuilder relBuilder = call.builder(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final LoptMultiJoin multiJoin = new LoptMultiJoin(multiJoinRel); @@ -94,7 +95,7 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule { int x = 0; for (int i = 0; i < multiJoin.getNumJoinFactors(); i++) { final RelNode rel = multiJoin.getJoinFactor(i); - double cost = RelMetadataQuery.getRowCount(rel); + double cost = mq.getRowCount(rel); vertexes.add(new LeafVertex(i, rel, cost, x)); x += rel.getRowType().getFieldCount(); } http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java index 759748c..3fce8a6 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java @@ -140,8 +140,9 @@ public abstract class ReduceExpressionsRule extends RelOptRule { Lists.newArrayList(filter.getCondition()); RexNode newConditionExp; boolean reduced; + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelOptPredicateList predicates = - RelMetadataQuery.getPulledUpPredicates(filter.getInput()); + mq.getPulledUpPredicates(filter.getInput()); if (reduceExpressions(filter, expList, predicates)) { assert expList.size() == 1; newConditionExp = expList.get(0); @@ -229,9 +230,10 @@ public abstract class ReduceExpressionsRule extends RelOptRule { } @Override public void onMatch(RelOptRuleCall call) { - Project project = call.rel(0); + final Project project = call.rel(0); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelOptPredicateList predicates = - RelMetadataQuery.getPulledUpPredicates(project.getInput()); + mq.getPulledUpPredicates(project.getInput()); final List<RexNode> expList = Lists.newArrayList(project.getProjects()); if (reduceExpressions(project, expList, predicates)) { @@ -261,10 +263,11 @@ public abstract class ReduceExpressionsRule extends RelOptRule { final Join join = call.rel(0); final List<RexNode> expList = Lists.newArrayList(join.getCondition()); final int fieldCount = join.getLeft().getRowType().getFieldCount(); + final RelMetadataQuery mq = RelMetadataQuery.instance(); final RelOptPredicateList leftPredicates = - RelMetadataQuery.getPulledUpPredicates(join.getLeft()); + mq.getPulledUpPredicates(join.getLeft()); final RelOptPredicateList rightPredicates = - RelMetadataQuery.getPulledUpPredicates(join.getRight()); + mq.getPulledUpPredicates(join.getRight()); final RelOptPredicateList predicates = leftPredicates.union(rightPredicates.shift(fieldCount)); if (!reduceExpressions(join, expList, predicates)) { http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java index 66b0afb..2da9a35 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java @@ -29,6 +29,7 @@ import org.apache.calcite.rel.core.Sort; import org.apache.calcite.rel.logical.LogicalJoin; import org.apache.calcite.rel.logical.LogicalSort; import org.apache.calcite.rel.metadata.RelMdUtil; +import org.apache.calcite.rel.metadata.RelMetadataQuery; /** @@ -99,11 +100,12 @@ public class SortJoinTransposeRule extends RelOptRule { // We create a new sort operator on the corresponding input final RelNode newLeftInput; final RelNode newRightInput; + final RelMetadataQuery mq = RelMetadataQuery.instance(); if (join.getJoinType() == JoinRelType.LEFT) { // If the input is already sorted and we are not reducing the number of tuples, // we bail out - if (RelMdUtil.checkInputForCollationAndLimit(join.getLeft(), sort.getCollation(), - sort.offset, sort.fetch)) { + if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getLeft(), + sort.getCollation(), sort.offset, sort.fetch)) { return; } newLeftInput = sort.copy(sort.getTraitSet(), join.getLeft(), sort.getCollation(), @@ -116,8 +118,8 @@ public class SortJoinTransposeRule extends RelOptRule { -join.getLeft().getRowType().getFieldCount())); // If the input is already sorted and we are not reducing the number of tuples, // we bail out - if (RelMdUtil.checkInputForCollationAndLimit(join.getRight(), rightCollation, - sort.offset, sort.fetch)) { + if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getRight(), + rightCollation, sort.offset, sort.fetch)) { return; } newLeftInput = join.getLeft(); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/SortUnionTransposeRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortUnionTransposeRule.java index b195e3f..26d2106 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/SortUnionTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/SortUnionTransposeRule.java @@ -23,6 +23,7 @@ import org.apache.calcite.rel.core.RelFactories; import org.apache.calcite.rel.core.Sort; import org.apache.calcite.rel.core.Union; import org.apache.calcite.rel.metadata.RelMdUtil; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.tools.RelBuilderFactory; import java.util.ArrayList; @@ -93,9 +94,10 @@ public class SortUnionTransposeRule extends RelOptRule { // Thus we use 'ret' as a flag to identify if we have finished pushing the // sort past a union. boolean ret = true; + final RelMetadataQuery mq = RelMetadataQuery.instance(); for (RelNode input : union.getInputs()) { - if (!RelMdUtil.checkInputForCollationAndLimit(input, sort.getCollation(), - sort.offset, sort.fetch)) { + if (!RelMdUtil.checkInputForCollationAndLimit(mq, input, + sort.getCollation(), sort.offset, sort.fetch)) { ret = false; Sort branchSort = sort.copy(sort.getTraitSet(), input, sort.getCollation(), sort.offset, sort.fetch); http://git-wip-us.apache.org/repos/asf/calcite/blob/cabdcf44/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java index c3daf49..56b362d 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java @@ -148,7 +148,8 @@ public abstract class SubQueryRemoveRule extends RelOptRule { switch (e.getKind()) { case SCALAR_QUERY: builder.push(e.rel); - final Boolean unique = RelMetadataQuery.areColumnsUnique(builder.peek(), + final RelMetadataQuery mq = RelMetadataQuery.instance(); + final Boolean unique = mq.areColumnsUnique(builder.peek(), ImmutableBitSet.of()); if (unique == null || !unique) { builder.aggregate(builder.groupKey(),
