Java Code Examples for org.apache.calcite.rel.logical.LogicalJoin#analyzeCondition()

The following examples show how to use org.apache.calcite.rel.logical.LogicalJoin#analyzeCondition() . 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: SqlHintsConverterTest.java    From calcite with Apache License 2.0 6 votes vote down vote up
@Override public RelNode convert(RelNode rel) {
  LogicalJoin join = (LogicalJoin) rel;
  assertThat(join.getHints().size(), is(1));
  assertThat(join.getHints().get(0), is(expectedHint));
  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 RelOptCluster cluster = join.getCluster();
  final RelNode left = newInputs.get(0);
  final RelNode right = newInputs.get(1);
  final JoinInfo info = join.analyzeCondition();
  return EnumerableHashJoin.create(
    left,
    right,
    info.getEquiCondition(left, right, cluster.getRexBuilder()),
    join.getVariablesSet(),
    join.getJoinType());
}
 
Example 2
Source File: LoptSemiJoinOptimizer.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Determines whether a join of the dimension table in a semijoin can be
 * removed. It can be if the dimension keys are unique and the only fields
 * referenced from the dimension table are its semijoin keys. The semijoin
 * keys can be mapped to the corresponding keys from the fact table (because
 * of the equality condition associated with the semijoin keys). Therefore,
 * that's why the dimension table can be removed even though those fields
 * are referenced elsewhere in the query tree.
 *
 * @param multiJoin join factors being optimized
 * @param semiJoin semijoin under consideration
 * @param factIdx id of the fact table in the semijoin
 * @param dimIdx id of the dimension table in the semijoin
 */
private void removeJoin(
    LoptMultiJoin multiJoin,
    LogicalJoin semiJoin,
    int factIdx,
    int dimIdx) {
  // if the dimension can be removed because of another semijoin, then
  // no need to proceed any further
  if (multiJoin.getJoinRemovalFactor(dimIdx) != null) {
    return;
  }

  // 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.analyzeCondition().rightKeys);
  final RelNode dimRel = multiJoin.getJoinFactor(dimIdx);
  if (!RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, dimRel,
      dimKeys)) {
    return;
  }

  // check that the only fields referenced from the dimension table
  // in either its projection or join conditions are the dimension
  // keys
  ImmutableBitSet dimProjRefs = multiJoin.getProjFields(dimIdx);
  if (dimProjRefs == null) {
    int nDimFields = multiJoin.getNumFieldsInJoinFactor(dimIdx);
    dimProjRefs = ImmutableBitSet.range(0, nDimFields);
  }
  if (!dimKeys.contains(dimProjRefs)) {
    return;
  }
  int [] dimJoinRefCounts = multiJoin.getJoinFieldRefCounts(dimIdx);
  for (int i = 0; i < dimJoinRefCounts.length; i++) {
    if (dimJoinRefCounts[i] > 0) {
      if (!dimKeys.get(i)) {
        return;
      }
    }
  }

  // criteria met; keep track of the fact table and the semijoin that
  // allow the join of this dimension table to be removed
  multiJoin.setJoinRemovalFactor(dimIdx, factIdx);
  multiJoin.setJoinRemovalSemiJoin(dimIdx, semiJoin);

  // if the dimension table doesn't reference anything in its projection
  // and the only fields referenced in its joins are the dimension keys
  // of this semijoin, then we can decrement the join reference counts
  // corresponding to the fact table's semijoin keys, since the
  // dimension table doesn't need to use those keys
  if (dimProjRefs.cardinality() != 0) {
    return;
  }
  for (int i = 0; i < dimJoinRefCounts.length; i++) {
    if (dimJoinRefCounts[i] > 1) {
      return;
    } else if (dimJoinRefCounts[i] == 1) {
      if (!dimKeys.get(i)) {
        return;
      }
    }
  }
  int [] factJoinRefCounts = multiJoin.getJoinFieldRefCounts(factIdx);
  for (Integer key : semiJoin.analyzeCondition().leftKeys) {
    factJoinRefCounts[key]--;
  }
}
 
Example 3
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 4
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;
}