Java Code Examples for org.apache.calcite.rex.RexUtil#composeConjunction()

The following examples show how to use org.apache.calcite.rex.RexUtil#composeConjunction() . 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: FilterMultiJoinMergeRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  Filter filter = call.rel(0);
  MultiJoin multiJoin = call.rel(1);

  // Create a new post-join filter condition
  // Conditions are nullable, so ImmutableList can't be used here
  List<RexNode> filters = Arrays.asList(
      filter.getCondition(),
      multiJoin.getPostJoinFilter());

  final RexBuilder rexBuilder = multiJoin.getCluster().getRexBuilder();
  MultiJoin newMultiJoin =
      new MultiJoin(
          multiJoin.getCluster(),
          multiJoin.getInputs(),
          multiJoin.getJoinFilter(),
          multiJoin.getRowType(),
          multiJoin.isFullOuterJoin(),
          multiJoin.getOuterJoinConditions(),
          multiJoin.getJoinTypes(),
          multiJoin.getProjFields(),
          multiJoin.getJoinFieldRefCountsMap(),
          RexUtil.composeConjunction(rexBuilder, filters, true));

  call.transformTo(newMultiJoin);
}
 
Example 2
Source File: RelOptUtil.java    From calcite with Apache License 2.0 6 votes vote down vote up
public static RexNode splitCorrelatedFilterCondition(
    Filter filter,
    List<RexNode> joinKeys,
    List<RexNode> correlatedJoinKeys,
    boolean extractCorrelatedFieldAccess) {
  final List<RexNode> nonEquiList = new ArrayList<>();

  splitCorrelatedFilterCondition(
      filter,
      filter.getCondition(),
      joinKeys,
      correlatedJoinKeys,
      nonEquiList,
      extractCorrelatedFieldAccess);

  // Convert the remainders into a list that are AND'ed together.
  return RexUtil.composeConjunction(
      filter.getCluster().getRexBuilder(), nonEquiList, true);
}
 
Example 3
Source File: RelMdPredicates.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Infers predicates for a {@link org.apache.calcite.rel.core.Join} (including
 * {@link org.apache.calcite.rel.core.SemiJoin}).
 */
public RelOptPredicateList getPredicates(Join join, RelMetadataQuery mq) {
  RelOptCluster cluster = join.getCluster();
  RexBuilder rexBuilder = cluster.getRexBuilder();
  final RexExecutor executor =
      Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
  final RelNode left = join.getInput(0);
  final RelNode right = join.getInput(1);

  final RelOptPredicateList leftInfo = mq.getPulledUpPredicates(left);
  final RelOptPredicateList rightInfo = mq.getPulledUpPredicates(right);

  JoinConditionBasedPredicateInference joinInference =
      new JoinConditionBasedPredicateInference(join,
          RexUtil.composeConjunction(rexBuilder, leftInfo.pulledUpPredicates),
          RexUtil.composeConjunction(rexBuilder, rightInfo.pulledUpPredicates),
          new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor));

  return joinInference.inferPredicates(false);
}
 
Example 4
Source File: DrillJoinRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
private RexNode buildJoinCondition(RelNode convertedLeft, RelNode convertedRight, List<Integer> leftKeys,
    List<Integer> rightKeys, List<Boolean> filterNulls, RexBuilder builder) {
  List<RexNode> equijoinList = Lists.newArrayList();
  final int numLeftFields = convertedLeft.getRowType().getFieldCount();
  List<RelDataTypeField> leftTypes = convertedLeft.getRowType().getFieldList();
  List<RelDataTypeField> rightTypes = convertedRight.getRowType().getFieldList();

  for (int i=0; i < leftKeys.size(); i++) {
    int leftKeyOrdinal = leftKeys.get(i);
    int rightKeyOrdinal = rightKeys.get(i);

    equijoinList.add(builder.makeCall(
         filterNulls.get(i) ? SqlStdOperatorTable.EQUALS : SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
         builder.makeInputRef(leftTypes.get(leftKeyOrdinal).getType(), leftKeyOrdinal),
         builder.makeInputRef(rightTypes.get(rightKeyOrdinal).getType(), rightKeyOrdinal + numLeftFields)
    ));
  }
  return RexUtil.composeConjunction(builder, equijoinList, false);
}
 
Example 5
Source File: FilterMultiJoinMergeRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  LogicalFilter filter = call.rel(0);
  MultiJoin multiJoin = call.rel(1);

  // Create a new post-join filter condition
  // Conditions are nullable, so ImmutableList can't be used here
  List<RexNode> filters = Arrays.asList(
      filter.getCondition(),
      multiJoin.getPostJoinFilter());

  final RexBuilder rexBuilder = multiJoin.getCluster().getRexBuilder();
  MultiJoin newMultiJoin =
      new MultiJoin(
          multiJoin.getCluster(),
          multiJoin.getInputs(),
          multiJoin.getJoinFilter(),
          multiJoin.getRowType(),
          multiJoin.isFullOuterJoin(),
          multiJoin.getOuterJoinConditions(),
          multiJoin.getJoinTypes(),
          multiJoin.getProjFields(),
          multiJoin.getJoinFieldRefCountsMap(),
          RexUtil.composeConjunction(rexBuilder, filters, true));

  call.transformTo(newMultiJoin);
}
 
Example 6
Source File: RelMdSelectivity.java    From calcite with Apache License 2.0 6 votes vote down vote up
public Double getSelectivity(Aggregate rel, RelMetadataQuery mq,
    RexNode predicate) {
  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 childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);

  Double selectivity = mq.getSelectivity(rel.getInput(), childPred);
  if (selectivity == null) {
    return null;
  } else {
    RexNode pred =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    return selectivity * RelMdUtil.guessSelectivity(pred);
  }
}
 
Example 7
Source File: SqlSplittableAggFunction.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * {@inheritDoc}
 *
 * <p>{@code COUNT(*)}, and {@code COUNT} applied to all NOT NULL arguments,
 * become {@code 1}; otherwise
 * {@code CASE WHEN arg0 IS NOT NULL THEN 1 ELSE 0 END}.
 */
public RexNode singleton(RexBuilder rexBuilder, RelDataType inputRowType,
    AggregateCall aggregateCall) {
  final List<RexNode> predicates = new ArrayList<>();
  for (Integer arg : aggregateCall.getArgList()) {
    final RelDataType type = inputRowType.getFieldList().get(arg).getType();
    if (type.isNullable()) {
      predicates.add(
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
              rexBuilder.makeInputRef(type, arg)));
    }
  }
  final RexNode predicate =
      RexUtil.composeConjunction(rexBuilder, predicates, true);
  if (predicate == null) {
    return rexBuilder.makeExactLiteral(BigDecimal.ONE);
  } else {
    return rexBuilder.makeCall(SqlStdOperatorTable.CASE, predicate,
        rexBuilder.makeExactLiteral(BigDecimal.ONE),
        rexBuilder.makeExactLiteral(BigDecimal.ZERO));
  }
}
 
Example 8
Source File: RelMdDistinctRowCount.java    From Bats 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 9
Source File: RelMdUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Takes the difference between two predicates, removing from the first any
 * predicates also in the second
 *
 * @param rexBuilder rexBuilder used to construct AND'd RexNode
 * @param pred1      first predicate
 * @param pred2      second predicate
 * @return MINUS'd predicate list
 */
public static RexNode minusPreds(
    RexBuilder rexBuilder,
    RexNode pred1,
    RexNode pred2) {
  final List<RexNode> minusList =
      new ArrayList<>(RelOptUtil.conjunctions(pred1));
  minusList.removeAll(RelOptUtil.conjunctions(pred2));
  return RexUtil.composeConjunction(rexBuilder, minusList, true);
}
 
Example 10
Source File: RelMdUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Takes the difference between two predicates, removing from the first any
 * predicates also in the second
 *
 * @param rexBuilder rexBuilder used to construct AND'd RexNode
 * @param pred1      first predicate
 * @param pred2      second predicate
 * @return MINUS'd predicate list
 */
public static RexNode minusPreds(
    RexBuilder rexBuilder,
    RexNode pred1,
    RexNode pred2) {
  final List<RexNode> minusList =
      new ArrayList<>(RelOptUtil.conjunctions(pred1));
  minusList.removeAll(RelOptUtil.conjunctions(pred2));
  return RexUtil.composeConjunction(rexBuilder, minusList, true);
}
 
Example 11
Source File: FilterRelBase.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private double estimateCpuCost(RelMetadataQuery relMetadataQuery) {
  RelNode child = this.getInput();
  final double rows = relMetadataQuery.getRowCount(child);
  double compNum = rows;
  double rowCompNum = child.getRowType().getFieldCount() * rows ;


  for (int i = 0; i< numConjuncts; i++) {
    RexNode conjFilter = RexUtil.composeConjunction(this.getCluster().getRexBuilder(), conjunctions.subList(0, i + 1), false);
    compNum += RelMdUtil.estimateFilteredRows(child, conjFilter, relMetadataQuery);
  }

  return compNum * DremioCost.COMPARE_CPU_COST + rowCompNum * DremioCost.COPY_COST;
}
 
Example 12
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 13
Source File: CalcPythonCorrelateTransposeRule.java    From flink with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
	FlinkLogicalCorrelate correlate = call.rel(0);
	FlinkLogicalCalc right = call.rel(2);
	RexBuilder rexBuilder = call.builder().getRexBuilder();
	FlinkLogicalCalc mergedCalc = CorrelateUtil.getMergedCalc(right);
	FlinkLogicalTableFunctionScan tableScan = CorrelateUtil.getTableFunctionScan(mergedCalc).get();
	RexProgram mergedCalcProgram = mergedCalc.getProgram();

	InputRefRewriter inputRefRewriter = new InputRefRewriter(
		correlate.getRowType().getFieldCount() - mergedCalc.getRowType().getFieldCount());
	List<RexNode> correlateFilters = RelOptUtil
		.conjunctions(mergedCalcProgram.expandLocalRef(mergedCalcProgram.getCondition()))
		.stream()
		.map(x -> x.accept(inputRefRewriter))
		.collect(Collectors.toList());

	FlinkLogicalCorrelate newCorrelate = new FlinkLogicalCorrelate(
		correlate.getCluster(),
		correlate.getTraitSet(),
		correlate.getLeft(),
		tableScan,
		correlate.getCorrelationId(),
		correlate.getRequiredColumns(),
		correlate.getJoinType());

	RexNode topCalcCondition = RexUtil.composeConjunction(rexBuilder, correlateFilters);
	RexProgram rexProgram = new RexProgramBuilder(
		newCorrelate.getRowType(), rexBuilder).getProgram();
	FlinkLogicalCalc newTopCalc = new FlinkLogicalCalc(
		newCorrelate.getCluster(),
		newCorrelate.getTraitSet(),
		newCorrelate,
		RexProgram.create(
			newCorrelate.getRowType(),
			rexProgram.getExprList(),
			topCalcCondition,
			newCorrelate.getRowType(),
			rexBuilder));

	call.transformTo(newTopCalc);
}
 
Example 14
Source File: JoinNormalizationRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
/**
 * Attempt to create a new join with a canonicalized join expression, and a possible filter
 * on top
 * @param builder
 * @param join
 * @return a new join tree (or same as original argument if no change)
 */
private RelNode getNewJoinCondition(RelBuilder builder, Join join) {
  final List<Integer> leftKeys = Lists.newArrayList();
  final List<Integer> rightKeys = Lists.newArrayList();
  final List<Boolean> filterNulls = Lists.newArrayList();

  final RexNode remaining = RelOptUtil.splitJoinCondition(join.getLeft(), join.getRight(), join.getCondition(), leftKeys, rightKeys, filterNulls);
  final boolean hasEquiJoins = leftKeys.size() == rightKeys.size() && leftKeys.size() > 0 ;
  final JoinRelType joinType = join.getJoinType();

  // If join has no equi-join condition, do not transform
  if (!hasEquiJoins) {
    return join;
  }

  // Create a new partial condition for the equi-join
  final RexNode partialCondition = JoinFilterCanonicalizationRule.buildJoinCondition(
      builder.getRexBuilder(),
      join.getLeft().getRowType(),
      join.getRight().getRowType(),
      leftKeys,
      rightKeys,
      filterNulls);

  // We do not know how to add filter for non-INNER joins (see DRILL-1337)
  if (joinType != JoinRelType.INNER) {
    final RexNode newJoinCondition = RexUtil.composeConjunction(builder.getRexBuilder(), ImmutableList.of(partialCondition, remaining), false);
    if (RexUtil.eq(join.getCondition(), newJoinCondition)) {
      // Condition is the same, do not create a new rel
      return join;
    }
    builder.pushAll(ImmutableList.of(join.getLeft(), join.getRight()));
    builder.join(joinType, newJoinCondition);

    return builder.build();
  }

  // Check if join condition has changed if pure equi-join
  if (remaining.isAlwaysTrue() && RexUtil.eq(join.getCondition(), partialCondition)) {
    return join;
  }

  // Return the new join with a filter on top
  builder.pushAll(ImmutableList.of(join.getLeft(), join.getRight()));
  builder.join(joinType, partialCondition);
  builder.filter(remaining);
  return builder.build();
}
 
Example 15
Source File: EnumerableMergeJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override public RelNode convert(RelNode rel) {
  LogicalJoin join = (LogicalJoin) rel;
  final JoinInfo info = join.analyzeCondition();
  if (!EnumerableMergeJoin.isMergeJoinSupported(join.getJoinType())) {
    // EnumerableMergeJoin only supports certain join types.
    return null;
  }
  if (info.pairs().size() == 0) {
    // EnumerableMergeJoin CAN support cartesian join, but disable it for now.
    return null;
  }
  final List<RelNode> newInputs = new ArrayList<>();
  final List<RelCollation> collations = new ArrayList<>();
  int offset = 0;
  for (Ord<RelNode> ord : Ord.zip(join.getInputs())) {
    RelTraitSet traits = ord.e.getTraitSet()
        .replace(EnumerableConvention.INSTANCE);
    if (!info.pairs().isEmpty()) {
      final List<RelFieldCollation> fieldCollations = new ArrayList<>();
      for (int key : info.keys().get(ord.i)) {
        fieldCollations.add(
            new RelFieldCollation(key, RelFieldCollation.Direction.ASCENDING,
                RelFieldCollation.NullDirection.LAST));
      }
      final RelCollation collation = RelCollations.of(fieldCollations);
      collations.add(RelCollations.shift(collation, offset));
      traits = traits.replace(collation);
    }
    newInputs.add(convert(ord.e, traits));
    offset += ord.e.getRowType().getFieldCount();
  }
  final RelNode left = newInputs.get(0);
  final RelNode right = newInputs.get(1);
  final RelOptCluster cluster = join.getCluster();
  RelNode newRel;

  RelTraitSet traitSet = join.getTraitSet()
      .replace(EnumerableConvention.INSTANCE);
  if (!collations.isEmpty()) {
    traitSet = traitSet.replace(collations);
  }
  // Re-arrange condition: first the equi-join elements, then the non-equi-join ones (if any);
  // this is not strictly necessary but it will be useful to avoid spurious errors in the
  // unit tests when verifying the plan.
  final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RexNode equi = info.getEquiCondition(left, right, rexBuilder);
  final RexNode condition;
  if (info.isEqui()) {
    condition = equi;
  } else {
    final RexNode nonEqui = RexUtil.composeConjunction(rexBuilder, info.nonEquiConditions);
    condition = RexUtil.composeConjunction(rexBuilder, Arrays.asList(equi, nonEqui));
  }
  newRel = new EnumerableMergeJoin(cluster,
      traitSet,
      left,
      right,
      condition,
      join.getVariablesSet(),
      join.getJoinType());
  return newRel;
}
 
Example 16
Source File: JoinPushThroughJoinRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Similar to {@link #onMatch}, but swaps the upper sibling with the left
 * of the two lower siblings, rather than the right.
 */
private void onMatchLeft(RelOptRuleCall call) {
  final Join topJoin = call.rel(0);
  final Join bottomJoin = call.rel(1);
  final RelNode relC = call.rel(2);
  final RelNode relA = bottomJoin.getLeft();
  final RelNode relB = bottomJoin.getRight();
  final RelOptCluster cluster = topJoin.getCluster();

  //        topJoin
  //        /     \
  //   bottomJoin  C
  //    /    \
  //   A      B

  final int aCount = relA.getRowType().getFieldCount();
  final int bCount = relB.getRowType().getFieldCount();
  final int cCount = relC.getRowType().getFieldCount();
  final ImmutableBitSet aBitSet = ImmutableBitSet.range(aCount);

  // becomes
  //
  //        newTopJoin
  //        /        \
  //   newBottomJoin  A
  //    /    \
  //   C      B

  // If either join is not inner, we cannot proceed.
  // (Is this too strict?)
  if (topJoin.getJoinType() != JoinRelType.INNER
      || bottomJoin.getJoinType() != JoinRelType.INNER) {
    return;
  }

  // Split the condition of topJoin into a conjunction. Each of the
  // parts that does not use columns from A can be pushed down.
  final List<RexNode> intersecting = new ArrayList<>();
  final List<RexNode> nonIntersecting = new ArrayList<>();
  split(topJoin.getCondition(), aBitSet, intersecting, nonIntersecting);

  // If there's nothing to push down, it's not worth proceeding.
  if (nonIntersecting.isEmpty()) {
    return;
  }

  // Split the condition of bottomJoin into a conjunction. Each of the
  // parts that use columns from A will need to be pulled up.
  final List<RexNode> bottomIntersecting = new ArrayList<>();
  final List<RexNode> bottomNonIntersecting = new ArrayList<>();
  split(
      bottomJoin.getCondition(), aBitSet, bottomIntersecting,
      bottomNonIntersecting);

  // target: | C      | B |
  // source: | A       | B | C      |
  final Mappings.TargetMapping bottomMapping =
      Mappings.createShiftMapping(
          aCount + bCount + cCount,
          cCount, aCount, bCount,
          0, aCount + bCount, cCount);
  final List<RexNode> newBottomList = new ArrayList<>();
  new RexPermuteInputsShuttle(bottomMapping, relC, relB)
      .visitList(nonIntersecting, newBottomList);
  new RexPermuteInputsShuttle(bottomMapping, relC, relB)
      .visitList(bottomNonIntersecting, newBottomList);
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  RexNode newBottomCondition =
      RexUtil.composeConjunction(rexBuilder, newBottomList);
  final Join newBottomJoin =
      bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC,
          relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());

  // target: | C      | B | A       |
  // source: | A       | B | C      |
  final Mappings.TargetMapping topMapping =
      Mappings.createShiftMapping(
          aCount + bCount + cCount,
          cCount + bCount, 0, aCount,
          cCount, aCount, bCount,
          0, aCount + bCount, cCount);
  final List<RexNode> newTopList = new ArrayList<>();
  new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA)
      .visitList(intersecting, newTopList);
  new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA)
      .visitList(bottomIntersecting, newTopList);
  RexNode newTopCondition =
      RexUtil.composeConjunction(rexBuilder, newTopList);
  @SuppressWarnings("SuspiciousNameCombination")
  final Join newTopJoin =
      topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
          relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());

  final RelBuilder relBuilder = call.builder();
  relBuilder.push(newTopJoin);
  relBuilder.project(relBuilder.fields(topMapping));
  call.transformTo(relBuilder.build());
}
 
Example 17
Source File: EnumerableJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override public RelNode convert(RelNode rel) {
  LogicalJoin join = (LogicalJoin) rel;
  List<RelNode> newInputs = new ArrayList<>();
  for (RelNode input : join.getInputs()) {
    if (!(input.getConvention() instanceof EnumerableConvention)) {
      input =
          convert(
              input,
              input.getTraitSet()
                  .replace(EnumerableConvention.INSTANCE));
    }
    newInputs.add(input);
  }
  final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RelNode left = newInputs.get(0);
  final RelNode right = newInputs.get(1);
  final JoinInfo info = join.analyzeCondition();

  // If the join has equiKeys (i.e. complete or partial equi-join),
  // create an EnumerableHashJoin, which supports all types of joins,
  // even if the join condition contains partial non-equi sub-conditions;
  // otherwise (complete non-equi-join), create an EnumerableNestedLoopJoin,
  // since a hash join strategy in this case would not be beneficial.
  final boolean hasEquiKeys = !info.leftKeys.isEmpty()
      && !info.rightKeys.isEmpty();
  if (hasEquiKeys) {
    // Re-arrange condition: first the equi-join elements, then the non-equi-join ones (if any);
    // this is not strictly necessary but it will be useful to avoid spurious errors in the
    // unit tests when verifying the plan.
    final RexNode equi = info.getEquiCondition(left, right, rexBuilder);
    final RexNode condition;
    if (info.isEqui()) {
      condition = equi;
    } else {
      final RexNode nonEqui = RexUtil.composeConjunction(rexBuilder, info.nonEquiConditions);
      condition = RexUtil.composeConjunction(rexBuilder, Arrays.asList(equi, nonEqui));
    }
    return EnumerableHashJoin.create(
        left,
        right,
        condition,
        join.getVariablesSet(),
        join.getJoinType());
  }
  return EnumerableNestedLoopJoin.create(
      left,
      right,
      join.getCondition(),
      join.getVariablesSet(),
      join.getJoinType());
}
 
Example 18
Source File: RelOptUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Determines whether any of the fields in a given relational expression may
 * contain null values, taking into account constraints on the field types and
 * also deduced predicates.
 *
 * <p>The method is cautious: It may sometimes return {@code true} when the
 * actual answer is {@code false}. In particular, it does this when there
 * is no executor, or the executor is not a sub-class of
 * {@link RexExecutorImpl}.
 */
private static boolean containsNullableFields(RelNode r) {
  final RexBuilder rexBuilder = r.getCluster().getRexBuilder();
  final RelDataType rowType = r.getRowType();
  final List<RexNode> list = new ArrayList<>();
  final RelMetadataQuery mq = r.getCluster().getMetadataQuery();
  for (RelDataTypeField field : rowType.getFieldList()) {
    if (field.getType().isNullable()) {
      list.add(
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
              rexBuilder.makeInputRef(field.getType(), field.getIndex())));
    }
  }
  if (list.isEmpty()) {
    // All columns are declared NOT NULL.
    return false;
  }
  final RelOptPredicateList predicates = mq.getPulledUpPredicates(r);
  if (predicates.pulledUpPredicates.isEmpty()) {
    // We have no predicates, so cannot deduce that any of the fields
    // declared NULL are really NOT NULL.
    return true;
  }
  final RexExecutor executor = r.getCluster().getPlanner().getExecutor();
  if (!(executor instanceof RexExecutorImpl)) {
    // Cannot proceed without an executor.
    return true;
  }
  final RexImplicationChecker checker =
      new RexImplicationChecker(rexBuilder, executor,
          rowType);
  final RexNode first =
      RexUtil.composeConjunction(rexBuilder, predicates.pulledUpPredicates);
  final RexNode second = RexUtil.composeConjunction(rexBuilder, list);
  // Suppose we have EMP(empno INT NOT NULL, mgr INT),
  // and predicates [empno > 0, mgr > 0].
  // We make first: "empno > 0 AND mgr > 0"
  // and second: "mgr IS NOT NULL"
  // and ask whether first implies second.
  // It does, so we have no nullable columns.
  return !checker.implies(first, second);
}
 
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: 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));
}