Java Code Examples for org.apache.calcite.rel.core.Join#analyzeCondition()

The following examples show how to use org.apache.calcite.rel.core.Join#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: JoinAddRedundantSemiJoinRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  Join origJoinRel = call.rel(0);
  if (origJoinRel.isSemiJoinDone()) {
    return;
  }

  // can't process outer joins using semijoins
  if (origJoinRel.getJoinType() != JoinRelType.INNER) {
    return;
  }

  // determine if we have a valid join condition
  final JoinInfo joinInfo = origJoinRel.analyzeCondition();
  if (joinInfo.leftKeys.size() == 0) {
    return;
  }

  RelNode semiJoin =
      SemiJoin.create(origJoinRel.getLeft(),
          origJoinRel.getRight(),
          origJoinRel.getCondition(),
          joinInfo.leftKeys,
          joinInfo.rightKeys);

  RelNode newJoinRel =
      origJoinRel.copy(
          origJoinRel.getTraitSet(),
          origJoinRel.getCondition(),
          semiJoin,
          origJoinRel.getRight(),
          JoinRelType.INNER,
          true);

  call.transformTo(newJoinRel);
}
 
Example 2
Source File: JoinAddRedundantSemiJoinRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  Join origJoinRel = call.rel(0);
  if (origJoinRel.isSemiJoinDone()) {
    return;
  }

  // can't process outer joins using semijoins
  if (origJoinRel.getJoinType() != JoinRelType.INNER) {
    return;
  }

  // determine if we have a valid join condition
  final JoinInfo joinInfo = origJoinRel.analyzeCondition();
  if (joinInfo.leftKeys.size() == 0) {
    return;
  }

  RelNode semiJoin =
      LogicalJoin.create(origJoinRel.getLeft(),
          origJoinRel.getRight(),
          ImmutableList.of(),
          origJoinRel.getCondition(),
          ImmutableSet.of(),
          JoinRelType.SEMI);

  RelNode newJoinRel =
      origJoinRel.copy(
          origJoinRel.getTraitSet(),
          origJoinRel.getCondition(),
          semiJoin,
          origJoinRel.getRight(),
          JoinRelType.INNER,
          true);

  call.transformTo(newJoinRel);
}
 
Example 3
Source File: RelMdUniqueKeys.java    From Bats with Apache License 2.0 4 votes vote down vote up
public Set<ImmutableBitSet> getUniqueKeys(Join rel, RelMetadataQuery mq,
    boolean ignoreNulls) {
  final RelNode left = rel.getLeft();
  final RelNode right = rel.getRight();

  // first add the different combinations of concatenated unique keys
  // from the left and the right, adjusting the right hand side keys to
  // reflect the addition of the left hand side
  //
  // NOTE zfong 12/18/06 - If the number of tables in a join is large,
  // the number of combinations of unique key sets will explode.  If
  // that is undesirable, use RelMetadataQuery.areColumnsUnique() as
  // an alternative way of getting unique key information.

  final Set<ImmutableBitSet> retSet = new HashSet<>();
  final Set<ImmutableBitSet> leftSet = mq.getUniqueKeys(left, ignoreNulls);
  Set<ImmutableBitSet> rightSet = null;

  final Set<ImmutableBitSet> tmpRightSet = mq.getUniqueKeys(right, ignoreNulls);
  int nFieldsOnLeft = left.getRowType().getFieldCount();

  if (tmpRightSet != null) {
    rightSet = new HashSet<>();
    for (ImmutableBitSet colMask : tmpRightSet) {
      ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
      for (int bit : colMask) {
        tmpMask.set(bit + nFieldsOnLeft);
      }
      rightSet.add(tmpMask.build());
    }

    if (leftSet != null) {
      for (ImmutableBitSet colMaskRight : rightSet) {
        for (ImmutableBitSet colMaskLeft : leftSet) {
          retSet.add(colMaskLeft.union(colMaskRight));
        }
      }
    }
  }

  // locate the columns that participate in equijoins
  final JoinInfo joinInfo = rel.analyzeCondition();

  // determine if either or both the LHS and RHS are unique on the
  // equijoin columns
  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
  // generating
  if ((rightUnique != null)
      && rightUnique
      && (leftSet != null)
      && !(rel.getJoinType().generatesNullsOnLeft())) {
    retSet.addAll(leftSet);
  }

  // same as above except left and right are reversed
  if ((leftUnique != null)
      && leftUnique
      && (rightSet != null)
      && !(rel.getJoinType().generatesNullsOnRight())) {
    retSet.addAll(rightSet);
  }

  return retSet;
}
 
Example 4
Source File: RelMdColumnUniqueness.java    From Bats with Apache License 2.0 4 votes vote down vote up
public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq,
    ImmutableBitSet columns, boolean ignoreNulls) {
  if (columns.cardinality() == 0) {
    return false;
  }

  final RelNode left = rel.getLeft();
  final RelNode right = rel.getRight();

  // Divide up the input column mask into column masks for the left and
  // right sides of the join
  final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns =
      splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(),
          columns);
  final ImmutableBitSet leftColumns = leftAndRightColumns.left;
  final ImmutableBitSet rightColumns = leftAndRightColumns.right;

  // If the original column mask contains columns from both the left and
  // right hand side, then the columns are unique if and only if they're
  // unique for their respective join inputs
  Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls);
  Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls);
  if ((leftColumns.cardinality() > 0)
      && (rightColumns.cardinality() > 0)) {
    if ((leftUnique == null) || (rightUnique == null)) {
      return null;
    } else {
      return leftUnique && rightUnique;
    }
  }

  // If we're only trying to determine uniqueness for columns that
  // originate from one join input, then determine if the equijoin
  // columns from the other join input are unique.  If they are, then
  // the columns are unique for the entire join if they're unique for
  // the corresponding join input, provided that input is not null
  // generating.
  final JoinInfo joinInfo = rel.analyzeCondition();
  if (leftColumns.cardinality() > 0) {
    if (rel.getJoinType().generatesNullsOnLeft()) {
      return false;
    }
    Boolean rightJoinColsUnique =
        mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls);
    if ((rightJoinColsUnique == null) || (leftUnique == null)) {
      return null;
    }
    return rightJoinColsUnique && leftUnique;
  } else if (rightColumns.cardinality() > 0) {
    if (rel.getJoinType().generatesNullsOnRight()) {
      return false;
    }
    Boolean leftJoinColsUnique =
        mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls);
    if ((leftJoinColsUnique == null) || (rightUnique == null)) {
      return null;
    }
    return leftJoinColsUnique && rightUnique;
  }

  throw new AssertionError();
}
 
Example 5
Source File: SemiJoinRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
protected void perform(RelOptRuleCall call, Project project,
    Join join, RelNode left, Aggregate aggregate) {
  final RelOptCluster cluster = join.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  if (project != null) {
    final ImmutableBitSet bits =
        RelOptUtil.InputFinder.bits(project.getProjects(), null);
    final ImmutableBitSet rightBits =
        ImmutableBitSet.range(left.getRowType().getFieldCount(),
            join.getRowType().getFieldCount());
    if (bits.intersects(rightBits)) {
      return;
    }
  }
  final JoinInfo joinInfo = join.analyzeCondition();
  if (!joinInfo.rightSet().equals(
      ImmutableBitSet.range(aggregate.getGroupCount()))) {
    // Rule requires that aggregate key to be the same as the join key.
    // By the way, neither a super-set nor a sub-set would work.
    return;
  }
  if (!joinInfo.isEqui()) {
    return;
  }
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(left);
  switch (join.getJoinType()) {
  case INNER:
    final List<Integer> newRightKeyBuilder = new ArrayList<>();
    final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
    for (int key : joinInfo.rightKeys) {
      newRightKeyBuilder.add(aggregateKeys.get(key));
    }
    final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
    relBuilder.push(aggregate.getInput());
    final RexNode newCondition =
        RelOptUtil.createEquiJoinCondition(relBuilder.peek(2, 0),
            joinInfo.leftKeys, relBuilder.peek(2, 1), newRightKeys,
            rexBuilder);
    relBuilder.semiJoin(newCondition);
    break;

  case LEFT:
    // The right-hand side produces no more than 1 row (because of the
    // Aggregate) and no fewer than 1 row (because of LEFT), and therefore
    // we can eliminate the semi-join.
    break;

  default:
    throw new AssertionError(join.getJoinType());
  }
  if (project != null) {
    relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
  }
  call.transformTo(relBuilder.build());
}
 
Example 6
Source File: RelMdUniqueKeys.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Set<ImmutableBitSet> getUniqueKeys(Join rel, RelMetadataQuery mq,
    boolean ignoreNulls) {
  if (!rel.getJoinType().projectsRight()) {
    // only return the unique keys from the LHS since a semijoin only
    // returns the LHS
    return mq.getUniqueKeys(rel.getLeft(), ignoreNulls);
  }

  final RelNode left = rel.getLeft();
  final RelNode right = rel.getRight();

  // first add the different combinations of concatenated unique keys
  // from the left and the right, adjusting the right hand side keys to
  // reflect the addition of the left hand side
  //
  // NOTE zfong 12/18/06 - If the number of tables in a join is large,
  // the number of combinations of unique key sets will explode.  If
  // that is undesirable, use RelMetadataQuery.areColumnsUnique() as
  // an alternative way of getting unique key information.

  final Set<ImmutableBitSet> retSet = new HashSet<>();
  final Set<ImmutableBitSet> leftSet = mq.getUniqueKeys(left, ignoreNulls);
  Set<ImmutableBitSet> rightSet = null;

  final Set<ImmutableBitSet> tmpRightSet = mq.getUniqueKeys(right, ignoreNulls);
  int nFieldsOnLeft = left.getRowType().getFieldCount();

  if (tmpRightSet != null) {
    rightSet = new HashSet<>();
    for (ImmutableBitSet colMask : tmpRightSet) {
      ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
      for (int bit : colMask) {
        tmpMask.set(bit + nFieldsOnLeft);
      }
      rightSet.add(tmpMask.build());
    }

    if (leftSet != null) {
      for (ImmutableBitSet colMaskRight : rightSet) {
        for (ImmutableBitSet colMaskLeft : leftSet) {
          retSet.add(colMaskLeft.union(colMaskRight));
        }
      }
    }
  }

  // locate the columns that participate in equijoins
  final JoinInfo joinInfo = rel.analyzeCondition();

  // determine if either or both the LHS and RHS are unique on the
  // equijoin columns
  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
  // generating
  if ((rightUnique != null)
      && rightUnique
      && (leftSet != null)
      && !(rel.getJoinType().generatesNullsOnLeft())) {
    retSet.addAll(leftSet);
  }

  // same as above except left and right are reversed
  if ((leftUnique != null)
      && leftUnique
      && (rightSet != null)
      && !(rel.getJoinType().generatesNullsOnRight())) {
    retSet.addAll(rightSet);
  }

  return retSet;
}
 
Example 7
Source File: RelMdColumnUniqueness.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq,
    ImmutableBitSet columns, boolean ignoreNulls) {
  columns = decorateWithConstantColumnsFromPredicates(columns, rel, mq);
  if (columns.cardinality() == 0) {
    return false;
  }

  final RelNode left = rel.getLeft();
  final RelNode right = rel.getRight();

  // Semi or anti join should ignore uniqueness of the right input.
  if (!rel.getJoinType().projectsRight()) {
    return mq.areColumnsUnique(left, columns, ignoreNulls);
  }

  // Divide up the input column mask into column masks for the left and
  // right sides of the join
  final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns =
      splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(),
          columns);
  final ImmutableBitSet leftColumns = leftAndRightColumns.left;
  final ImmutableBitSet rightColumns = leftAndRightColumns.right;

  // for FULL OUTER JOIN if columns contain column from both inputs it is not
  // guaranteed that the result will be unique
  if (!ignoreNulls && rel.getJoinType() == JoinRelType.FULL
      && leftColumns.cardinality() > 0 && rightColumns.cardinality() > 0) {
    return false;
  }

  // If the original column mask contains columns from both the left and
  // right hand side, then the columns are unique if and only if they're
  // unique for their respective join inputs
  Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls);
  Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls);
  if ((leftColumns.cardinality() > 0)
      && (rightColumns.cardinality() > 0)) {
    if ((leftUnique == null) || (rightUnique == null)) {
      return null;
    } else {
      return leftUnique && rightUnique;
    }
  }

  // If we're only trying to determine uniqueness for columns that
  // originate from one join input, then determine if the equijoin
  // columns from the other join input are unique.  If they are, then
  // the columns are unique for the entire join if they're unique for
  // the corresponding join input, provided that input is not null
  // generating.
  final JoinInfo joinInfo = rel.analyzeCondition();
  if (leftColumns.cardinality() > 0) {
    if (rel.getJoinType().generatesNullsOnLeft()) {
      return false;
    }
    Boolean rightJoinColsUnique =
        mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls);
    if ((rightJoinColsUnique == null) || (leftUnique == null)) {
      return null;
    }
    return rightJoinColsUnique && leftUnique;
  } else if (rightColumns.cardinality() > 0) {
    if (rel.getJoinType().generatesNullsOnRight()) {
      return false;
    }
    Boolean leftJoinColsUnique =
        mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls);
    if ((leftJoinColsUnique == null) || (rightUnique == null)) {
      return null;
    }
    return leftJoinColsUnique && rightUnique;
  }

  throw new AssertionError();
}
 
Example 8
Source File: SemiJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
protected void perform(RelOptRuleCall call, Project project,
    Join join, RelNode left, Aggregate aggregate) {
  final RelOptCluster cluster = join.getCluster();
  final RexBuilder rexBuilder = cluster.getRexBuilder();
  if (project != null) {
    final ImmutableBitSet bits =
        RelOptUtil.InputFinder.bits(project.getProjects(), null);
    final ImmutableBitSet rightBits =
        ImmutableBitSet.range(left.getRowType().getFieldCount(),
            join.getRowType().getFieldCount());
    if (bits.intersects(rightBits)) {
      return;
    }
  } else {
    if (join.getJoinType().projectsRight()
        && !IS_EMPTY_AGGREGATE.test(aggregate)) {
      return;
    }
  }
  final JoinInfo joinInfo = join.analyzeCondition();
  if (!joinInfo.rightSet().equals(
      ImmutableBitSet.range(aggregate.getGroupCount()))) {
    // Rule requires that aggregate key to be the same as the join key.
    // By the way, neither a super-set nor a sub-set would work.
    return;
  }
  if (!joinInfo.isEqui()) {
    return;
  }
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(left);
  switch (join.getJoinType()) {
  case SEMI:
  case INNER:
    final List<Integer> newRightKeyBuilder = new ArrayList<>();
    final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
    for (int key : joinInfo.rightKeys) {
      newRightKeyBuilder.add(aggregateKeys.get(key));
    }
    final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
    relBuilder.push(aggregate.getInput());
    final RexNode newCondition =
        RelOptUtil.createEquiJoinCondition(relBuilder.peek(2, 0),
            joinInfo.leftKeys, relBuilder.peek(2, 1), newRightKeys,
            rexBuilder);
    relBuilder.semiJoin(newCondition);
    break;

  case LEFT:
    // The right-hand side produces no more than 1 row (because of the
    // Aggregate) and no fewer than 1 row (because of LEFT), and therefore
    // we can eliminate the semi-join.
    break;

  default:
    throw new AssertionError(join.getJoinType());
  }
  if (project != null) {
    relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
  }
  final RelNode relNode = relBuilder.build();
  call.transformTo(relNode);
}