Java Code Examples for org.apache.calcite.util.ImmutableBitSet#isEmpty()

The following examples show how to use org.apache.calcite.util.ImmutableBitSet#isEmpty() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: RelMdDistinctRowCount.java    From Bats with Apache License 2.0 6 votes vote down vote up
public Double getDistinctRowCount(Filter rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  // REVIEW zfong 4/18/06 - In the Broadbase code, duplicates are not
  // removed from the two filter lists.  However, the code below is
  // doing so.
  RexNode unionPreds =
      RelMdUtil.unionPreds(
          rel.getCluster().getRexBuilder(),
          predicate,
          rel.getCondition());

  return mq.getDistinctRowCount(rel.getInput(), groupKey, unionPreds);
}
 
Example 2
Source File: RelMdExpressionLineage.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Given an expression, it will create all equivalent expressions resulting
 * from replacing all possible combinations of references in the mapping by
 * the corresponding expressions.
 *
 * @param rexBuilder rexBuilder
 * @param expr expression
 * @param mapping mapping
 * @return set of resulting expressions equivalent to the input expression
 */
protected static Set<RexNode> createAllPossibleExpressions(RexBuilder rexBuilder,
    RexNode expr, Map<RexInputRef, Set<RexNode>> mapping) {
  // Extract input fields referenced by expression
  final ImmutableBitSet predFieldsUsed = extractInputRefs(expr);

  if (predFieldsUsed.isEmpty()) {
    // The unique expression is the input expression
    return ImmutableSet.of(expr);
  }

  try {
    return createAllPossibleExpressions(rexBuilder, expr, predFieldsUsed, mapping,
        new HashMap<>());
  } catch (UnsupportedOperationException e) {
    // There may be a RexNode unsupported by RexCopier, just return null
    return null;
  }
}
 
Example 3
Source File: RelMdExpressionLineage.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Given an expression, it will create all equivalent expressions resulting
 * from replacing all possible combinations of references in the mapping by
 * the corresponding expressions.
 *
 * @param rexBuilder rexBuilder
 * @param expr expression
 * @param mapping mapping
 * @return set of resulting expressions equivalent to the input expression
 */
@Nullable protected static Set<RexNode> createAllPossibleExpressions(RexBuilder rexBuilder,
    RexNode expr, Map<RexInputRef, Set<RexNode>> mapping) {
  // Extract input fields referenced by expression
  final ImmutableBitSet predFieldsUsed = extractInputRefs(expr);

  if (predFieldsUsed.isEmpty()) {
    // The unique expression is the input expression
    return ImmutableSet.of(expr);
  }

  try {
    return createAllPossibleExpressions(rexBuilder, expr, predFieldsUsed, mapping,
        new HashMap<>());
  } catch (UnsupportedOperationException e) {
    // There may be a RexNode unsupported by RexCopier, just return null
    return null;
  }
}
 
Example 4
Source File: RelMdUtil.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Computes the number of distinct rows for a set of keys returned from a
 * semi-join
 *
 * @param semiJoinRel RelNode representing the semi-join
 * @param mq          metadata query
 * @param groupKey    keys that the distinct row count will be computed for
 * @param predicate   join predicate
 * @return number of distinct rows
 */
public static Double getSemiJoinDistinctRowCount(Join semiJoinRel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  // create a RexNode representing the selectivity of the
  // semijoin filter and pass it to getDistinctRowCount
  RexNode newPred = RelMdUtil.makeSemiJoinSelectivityRexNode(mq, semiJoinRel);
  if (predicate != null) {
    RexBuilder rexBuilder = semiJoinRel.getCluster().getRexBuilder();
    newPred =
        rexBuilder.makeCall(
            SqlStdOperatorTable.AND,
            newPred,
            predicate);
  }

  return mq.getDistinctRowCount(semiJoinRel.getLeft(), groupKey, newPred);
}
 
Example 5
Source File: FlinkRelMetadataQuery.java    From flink with Apache License 2.0 6 votes vote down vote up
/**
 * Returns the (minimum) unique groups of the given columns.
 *
 * @param rel the relational expression
 * @param columns the given columns in a specified relational expression.
 *        The given columns should not be null.
 * @return the (minimum) unique columns which should be a sub-collection of the given columns,
 *         and should not be null or empty. If none unique columns can be found, return the
 *         given columns.
 */
public ImmutableBitSet getUniqueGroups(RelNode rel, ImmutableBitSet columns) {
	for (; ; ) {
		try {
			Preconditions.checkArgument(columns != null);
			if (columns.isEmpty()) {
				return columns;
			}
			ImmutableBitSet uniqueGroups =
					uniqueGroupsHandler.getUniqueGroups(rel, this, columns);
			Preconditions.checkArgument(uniqueGroups != null && !uniqueGroups.isEmpty());
			Preconditions.checkArgument(columns.contains(uniqueGroups));
			return uniqueGroups;
		} catch (JaninoRelMetadataProvider.NoHandler e) {
			uniqueGroupsHandler = revise(e.relClass, FlinkMetadata.UniqueGroups.DEF);
		}
	}
}
 
Example 6
Source File: FlinkRelMetadataQuery.java    From flink with Apache License 2.0 6 votes vote down vote up
/**
 * Returns the (minimum) unique groups of the given columns.
 *
 * @param rel the relational expression
 * @param columns the given columns in a specified relational expression.
 *        The given columns should not be null.
 * @return the (minimum) unique columns which should be a sub-collection of the given columns,
 *         and should not be null or empty. If none unique columns can be found, return the
 *         given columns.
 */
public ImmutableBitSet getUniqueGroups(RelNode rel, ImmutableBitSet columns) {
	for (; ; ) {
		try {
			Preconditions.checkArgument(columns != null);
			if (columns.isEmpty()) {
				return columns;
			}
			ImmutableBitSet uniqueGroups =
					uniqueGroupsHandler.getUniqueGroups(rel, this, columns);
			Preconditions.checkArgument(uniqueGroups != null && !uniqueGroups.isEmpty());
			Preconditions.checkArgument(columns.contains(uniqueGroups));
			return uniqueGroups;
		} catch (JaninoRelMetadataProvider.NoHandler e) {
			uniqueGroupsHandler = revise(e.relClass, FlinkMetadata.UniqueGroups.DEF);
		}
	}
}
 
Example 7
Source File: RelMdDistinctRowCount.java    From calcite with Apache License 2.0 5 votes vote down vote up
public Double getDistinctRowCount(Aggregate rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  // determine which predicates can be applied on the child of the
  // aggregate
  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      rel.getGroupSet(),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
  RexNode childPreds =
      RexUtil.composeConjunction(rexBuilder, pushable, true);

  // set the bits as they correspond to the child input
  ImmutableBitSet.Builder childKey = ImmutableBitSet.builder();
  RelMdUtil.setAggChildKeys(groupKey, rel, childKey);

  Double distinctRowCount =
      mq.getDistinctRowCount(rel.getInput(), childKey.build(), childPreds);
  if (distinctRowCount == null) {
    return null;
  } else if (notPushable.isEmpty()) {
    return distinctRowCount;
  } else {
    RexNode preds =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    return distinctRowCount * RelMdUtil.guessSelectivity(preds);
  }
}
 
Example 8
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Infers predicates for an Aggregate.
 *
 * <p>Pulls up predicates that only contains references to columns in the
 * GroupSet. For e.g.
 *
 * <blockquote><pre>
 * inputPullUpExprs : { a &gt; 7, b + c &lt; 10, a + e = 9}
 * groupSet         : { a, b}
 * pulledUpExprs    : { a &gt; 7}
 * </pre></blockquote>
 */
public RelOptPredicateList getPredicates(Aggregate agg, RelMetadataQuery mq) {
  final RelNode input = agg.getInput();
  final RexBuilder rexBuilder = agg.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> aggPullUpPredicates = new ArrayList<>();

  ImmutableBitSet groupKeys = agg.getGroupSet();
  if (groupKeys.isEmpty()) {
    // "GROUP BY ()" can convert an empty relation to a non-empty relation, so
    // it is not valid to pull up predicates. In particular, consider the
    // predicate "false": it is valid on all input rows (trivially - there are
    // no rows!) but not on the output (there is one row).
    return RelOptPredicateList.EMPTY;
  }
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(), agg.getRowType().getFieldCount());

  int i = 0;
  for (int j : groupKeys) {
    m.set(j, i++);
  }

  for (RexNode r : inputInfo.pulledUpPredicates) {
    ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
    if (groupKeys.contains(rCols)) {
      r = r.accept(new RexPermuteInputsShuttle(m, input));
      aggPullUpPredicates.add(r);
    }
  }
  return RelOptPredicateList.of(rexBuilder, aggPullUpPredicates);
}
 
Example 9
Source File: RelMdRowCount.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public Double getRowCount(Aggregate rel, RelMetadataQuery mq) {
  ImmutableBitSet groupKey = ImmutableBitSet.range(rel.getGroupCount());

  if (groupKey.isEmpty()) {
    return 1.0;
  }

  return rel.estimateRowCount(mq);
}
 
Example 10
Source File: RelMdDistinctRowCount.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
public Double getDistinctRowCount(Join rel, RelMetadataQuery mq,
                                  ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  return getDistinctRowCountFromEstimateRowCount(rel, mq, groupKey, predicate);
}
 
Example 11
Source File: DrillRelMdRowCount.java    From Bats with Apache License 2.0 5 votes vote down vote up
@Override
public Double getRowCount(Aggregate rel, RelMetadataQuery mq) {
  ImmutableBitSet groupKey = ImmutableBitSet.range(rel.getGroupCount());

  if (groupKey.isEmpty()) {
    return 1.0;
  } else {
    return super.getRowCount(rel, mq);
  }
}
 
Example 12
Source File: SqlValidatorUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/** Computes the rollup of bit sets.
 *
 * <p>For example, <code>rollup({0}, {1})</code>
 * returns <code>({0, 1}, {0}, {})</code>.
 *
 * <p>Bit sets are not necessarily singletons:
 * <code>rollup({0, 2}, {3, 5})</code>
 * returns <code>({0, 2, 3, 5}, {0, 2}, {})</code>. */
@VisibleForTesting
public static ImmutableList<ImmutableBitSet> rollup(
    List<ImmutableBitSet> bitSets) {
  Set<ImmutableBitSet> builder = new LinkedHashSet<>();
  for (;;) {
    final ImmutableBitSet union = ImmutableBitSet.union(bitSets);
    builder.add(union);
    if (union.isEmpty()) {
      break;
    }
    bitSets = bitSets.subList(0, bitSets.size() - 1);
  }
  return ImmutableList.copyOf(builder);
}
 
Example 13
Source File: RelMdPredicates.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Infers predicates for an Aggregate.
 *
 * <p>Pulls up predicates that only contains references to columns in the
 * GroupSet. For e.g.
 *
 * <blockquote><pre>
 * inputPullUpExprs : { a &gt; 7, b + c &lt; 10, a + e = 9}
 * groupSet         : { a, b}
 * pulledUpExprs    : { a &gt; 7}
 * </pre></blockquote>
 */
public RelOptPredicateList getPredicates(Aggregate agg, RelMetadataQuery mq) {
  final RelNode input = agg.getInput();
  final RexBuilder rexBuilder = agg.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> aggPullUpPredicates = new ArrayList<>();

  ImmutableBitSet groupKeys = agg.getGroupSet();
  if (groupKeys.isEmpty()) {
    // "GROUP BY ()" can convert an empty relation to a non-empty relation, so
    // it is not valid to pull up predicates. In particular, consider the
    // predicate "false": it is valid on all input rows (trivially - there are
    // no rows!) but not on the output (there is one row).
    return RelOptPredicateList.EMPTY;
  }
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(), agg.getRowType().getFieldCount());

  int i = 0;
  for (int j : groupKeys) {
    m.set(j, i++);
  }

  for (RexNode r : inputInfo.pulledUpPredicates) {
    ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
    if (groupKeys.contains(rCols)) {
      r = r.accept(new RexPermuteInputsShuttle(m, input));
      aggPullUpPredicates.add(r);
    }
  }
  return RelOptPredicateList.of(rexBuilder, aggPullUpPredicates);
}
 
Example 14
Source File: SqlValidatorUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/** Computes the rollup of bit sets.
 *
 * <p>For example, <code>rollup({0}, {1})</code>
 * returns <code>({0, 1}, {0}, {})</code>.
 *
 * <p>Bit sets are not necessarily singletons:
 * <code>rollup({0, 2}, {3, 5})</code>
 * returns <code>({0, 2, 3, 5}, {0, 2}, {})</code>. */
@VisibleForTesting
public static ImmutableList<ImmutableBitSet> rollup(
    List<ImmutableBitSet> bitSets) {
  Set<ImmutableBitSet> builder = new LinkedHashSet<>();
  for (;;) {
    final ImmutableBitSet union = ImmutableBitSet.union(bitSets);
    builder.add(union);
    if (union.isEmpty()) {
      break;
    }
    bitSets = bitSets.subList(0, bitSets.size() - 1);
  }
  return ImmutableList.copyOf(builder);
}
 
Example 15
Source File: RelMdDistinctRowCount.java    From Bats with Apache License 2.0 5 votes vote down vote up
public Double getDistinctRowCount(Join rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  return RelMdUtil.getJoinDistinctRowCount(mq, rel, rel.getJoinType(),
      groupKey, predicate, false);
}
 
Example 16
Source File: RelMdDistinctRowCount.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Double getDistinctRowCount(Project rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
  ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
  List<RexNode> projExprs = rel.getProjects();
  RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);

  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

  // get the distinct row count of the child input, passing in the
  // columns and filters that only reference the child; convert the
  // filter to reference the children projection expressions
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);
  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double distinctRowCount =
      mq.getDistinctRowCount(rel.getInput(), baseCols.build(),
          modifiedPred);

  if (distinctRowCount == null) {
    return null;
  } else if (!notPushable.isEmpty()) {
    RexNode preds =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    distinctRowCount *= RelMdUtil.guessSelectivity(preds);
  }

  // No further computation required if the projection expressions
  // are all column references
  if (projCols.cardinality() == 0) {
    return distinctRowCount;
  }

  // multiply by the cardinality of the non-child projection expressions
  for (int bit : projCols.build()) {
    Double subRowCount =
        RelMdUtil.cardOfProjExpr(mq, rel, projExprs.get(bit));
    if (subRowCount == null) {
      return null;
    }
    distinctRowCount *= subRowCount;
  }

  return RelMdUtil.numDistinctVals(distinctRowCount, mq.getRowCount(rel));
}
 
Example 17
Source File: ReduceExpressionsRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
/** Pushes predicates into a CASE.
 *
 * <p>We have a loose definition of 'predicate': any boolean expression will
 * do, except CASE. For example '(CASE ...) = 5' or '(CASE ...) IS NULL'.
 */
public static RexCall pushPredicateIntoCase(RexCall call) {
  if (call.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
    return call;
  }
  switch (call.getKind()) {
  case CASE:
  case AND:
  case OR:
    return call; // don't push CASE into CASE!
  case EQUALS: {
    // checks that the EQUALS operands may be splitted and
    // doesn't push EQUALS into CASE
    List<RexNode> equalsOperands = call.getOperands();
    ImmutableBitSet left = RelOptUtil.InputFinder.bits(equalsOperands.get(0));
    ImmutableBitSet right = RelOptUtil.InputFinder.bits(equalsOperands.get(1));
    if (!left.isEmpty() && !right.isEmpty() && left.intersect(right).isEmpty()) {
      return call;
    }
  }
  }
  int caseOrdinal = -1;
  final List<RexNode> operands = call.getOperands();
  for (int i = 0; i < operands.size(); i++) {
    RexNode operand = operands.get(i);
    switch (operand.getKind()) {
    case CASE:
      caseOrdinal = i;
    }
  }
  if (caseOrdinal < 0) {
    return call;
  }
  // Convert
  //   f(CASE WHEN p1 THEN v1 ... END, arg)
  // to
  //   CASE WHEN p1 THEN f(v1, arg) ... END
  final RexCall case_ = (RexCall) operands.get(caseOrdinal);
  final List<RexNode> nodes = new ArrayList<>();
  for (int i = 0; i < case_.getOperands().size(); i++) {
    RexNode node = case_.getOperands().get(i);
    if (!RexUtil.isCasePredicate(case_, i)) {
      node = substitute(call, caseOrdinal, node);
    }
    nodes.add(node);
  }
  return case_.clone(call.getType(), nodes);
}
 
Example 18
Source File: RelMdDistinctRowCount.java    From Bats with Apache License 2.0 4 votes vote down vote up
public Double getDistinctRowCount(Project rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
  ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
  List<RexNode> projExprs = rel.getProjects();
  RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);

  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

  // get the distinct row count of the child input, passing in the
  // columns and filters that only reference the child; convert the
  // filter to reference the children projection expressions
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);
  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double distinctRowCount =
      mq.getDistinctRowCount(rel.getInput(), baseCols.build(),
          modifiedPred);

  if (distinctRowCount == null) {
    return null;
  } else if (!notPushable.isEmpty()) {
    RexNode preds =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    distinctRowCount *= RelMdUtil.guessSelectivity(preds);
  }

  // No further computation required if the projection expressions
  // are all column references
  if (projCols.cardinality() == 0) {
    return distinctRowCount;
  }

  // multiply by the cardinality of the non-child projection expressions
  for (int bit : projCols.build()) {
    Double subRowCount =
        RelMdUtil.cardOfProjExpr(mq, rel, projExprs.get(bit));
    if (subRowCount == null) {
      return null;
    }
    distinctRowCount *= subRowCount;
  }

  return RelMdUtil.numDistinctVals(distinctRowCount, mq.getRowCount(rel));
}
 
Example 19
Source File: RelMdUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Computes the number of distinct rows for a set of keys returned from a
 * join. Also known as NDV (number of distinct values).
 *
 * @param joinRel   RelNode representing the join
 * @param joinType  type of join
 * @param groupKey  keys that the distinct row count will be computed for
 * @param predicate join predicate
 * @param useMaxNdv If true use formula <code>max(left NDV, right NDV)</code>,
 *                  otherwise use <code>left NDV * right NDV</code>.
 * @return number of distinct rows
 */
public static Double getJoinDistinctRowCount(RelMetadataQuery mq,
    RelNode joinRel, JoinRelType joinType, ImmutableBitSet groupKey,
    RexNode predicate, boolean useMaxNdv) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  Join join = (Join) joinRel;
  if (join.isSemiJoin()) {
    return getSemiJoinDistinctRowCount(join, mq, groupKey, predicate);
  }
  Double distRowCount;
  ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
  ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
  RelNode left = joinRel.getInputs().get(0);
  RelNode right = joinRel.getInputs().get(1);

  RelMdUtil.setLeftRightBitmaps(
      groupKey,
      leftMask,
      rightMask,
      left.getRowType().getFieldCount());

  // determine which filters apply to the left vs right
  RexNode leftPred = null;
  RexNode rightPred = null;
  if (predicate != null) {
    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,
        predList,
        joinType,
        !joinType.isOuterJoin(),
        !joinType.generatesNullsOnLeft(),
        !joinType.generatesNullsOnRight(),
        joinFilters,
        leftFilters,
        rightFilters);

    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    leftPred =
        RexUtil.composeConjunction(rexBuilder, leftFilters, true);
    rightPred =
        RexUtil.composeConjunction(rexBuilder, rightFilters, true);
  }

  if (useMaxNdv) {
    distRowCount = Math.max(
        mq.getDistinctRowCount(left, leftMask.build(), leftPred),
        mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  } else {
    distRowCount =
      NumberUtil.multiply(
          mq.getDistinctRowCount(left, leftMask.build(), leftPred),
          mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  }

  return RelMdUtil.numDistinctVals(distRowCount, mq.getRowCount(joinRel));
}
 
Example 20
Source File: RelMdUniqueKeys.java    From calcite with Apache License 2.0 4 votes vote down vote up
private Set<ImmutableBitSet> getProjectUniqueKeys(SingleRel rel, RelMetadataQuery mq,
    boolean ignoreNulls, List<RexNode> projExprs) {
  // 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
  // info from the child of a project when the mapping is f(a) => a.
  //
  // Further more, the unique bitset coming from the child needs
  // to be mapped to match the output of the project.

  // Single input can be mapped to multiple outputs
  ImmutableMultimap.Builder<Integer, Integer> inToOutPosBuilder = ImmutableMultimap.builder();
  ImmutableBitSet.Builder mappedInColumnsBuilder = ImmutableBitSet.builder();

  // Build an input to output position map.
  for (int i = 0; i < projExprs.size(); i++) {
    RexNode projExpr = projExprs.get(i);
    if (projExpr instanceof RexInputRef) {
      int inputIndex = ((RexInputRef) projExpr).getIndex();
      inToOutPosBuilder.put(inputIndex, i);
      mappedInColumnsBuilder.set(inputIndex);
    }
  }
  ImmutableBitSet inColumnsUsed = mappedInColumnsBuilder.build();

  if (inColumnsUsed.isEmpty()) {
    // if there's no RexInputRef in the projected expressions
    // return empty set.
    return ImmutableSet.of();
  }

  Set<ImmutableBitSet> childUniqueKeySet =
      mq.getUniqueKeys(rel.getInput(), ignoreNulls);

  if (childUniqueKeySet == null) {
    return ImmutableSet.of();
  }

  Map<Integer, ImmutableBitSet> mapInToOutPos =
      Maps.transformValues(inToOutPosBuilder.build().asMap(), ImmutableBitSet::of);

  ImmutableSet.Builder<ImmutableBitSet> resultBuilder = ImmutableSet.builder();
  // Now add to the projUniqueKeySet the child keys that are fully
  // projected.
  for (ImmutableBitSet colMask : childUniqueKeySet) {
    ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
    if (!inColumnsUsed.contains(colMask)) {
      // colMask contains a column that is not projected as RexInput => the key is not unique
      continue;
    }
    // colMask is mapped to output project, however, the column can be mapped more than once:
    // select id, id, id, unique2, unique2
    // the resulting unique keys would be {{0},{3}}, {{0},{4}}, {{0},{1},{4}}, ...

    Iterable<List<ImmutableBitSet>> product = Linq4j.product(
        Iterables.transform(colMask,
            in -> Iterables.filter(mapInToOutPos.get(in).powerSet(), bs -> !bs.isEmpty())));

    resultBuilder.addAll(Iterables.transform(product, ImmutableBitSet::union));
  }
  return resultBuilder.build();
}