Example #1
0
  /**
   * Combines the join filters from the left and right inputs (if they are MultiJoinRels) with the
   * join filter in the joinrel into a single AND'd join filter, unless the inputs correspond to
   * null generating inputs in an outer join
   *
   * @param joinRel join rel
   * @param left left child of the joinrel
   * @param right right child of the joinrel
   * @return combined join filters AND'd together
   */
  private RexNode combineJoinFilters(JoinRel joinRel, RelNode left, RelNode right) {
    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    JoinRelType joinType = joinRel.getJoinType();

    // first need to adjust the RexInputs of the right child, since
    // those need to shift over to the right
    RexNode rightFilter = null;
    if (canCombine(right, joinType.generatesNullsOnRight())) {
      MultiJoinRel multiJoin = (MultiJoinRel) right;
      rightFilter = shiftRightFilter(joinRel, left, multiJoin, multiJoin.getJoinFilter());
    }

    // AND the join condition if this isn't a left or right outer join;
    // in those cases, the outer join condition is already tracked
    // separately
    RexNode newFilter = null;
    if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
      newFilter = joinRel.getCondition();
    }
    if (canCombine(left, joinType.generatesNullsOnLeft())) {
      RexNode leftFilter = ((MultiJoinRel) left).getJoinFilter();
      newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, leftFilter);
    }
    newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, rightFilter);

    return newFilter;
  }
Example #2
0
  /**
   * Copies outer join data from a source MultiJoinRel to a new set of arrays. Also adjusts the
   * conditions to reflect the new position of an input if that input ends up being shifted to the
   * right.
   *
   * @param multiJoinRel the source MultiJoinRel
   * @param destConds the array where the join conditions will be copied
   * @param destJoinTypes the array where the join types will be copied
   * @param destPos starting position in the array where the copying starts
   * @param adjustmentAmount if > 0, the amount the RexInputRefs in the join conditions need to be
   *     adjusted by
   * @param srcFields the source fields that the original join conditions are referencing
   * @param destFields the destination fields that the new join conditions will be referencing
   */
  private void copyOuterJoinInfo(
      MultiJoinRel multiJoinRel,
      RexNode[] destConds,
      JoinRelType[] destJoinTypes,
      int destPos,
      int adjustmentAmount,
      RelDataTypeField[] srcFields,
      RelDataTypeField[] destFields) {
    RexNode[] srcConds = multiJoinRel.getOuterJoinConditions();
    JoinRelType[] srcJoinTypes = multiJoinRel.getJoinTypes();
    RexBuilder rexBuilder = multiJoinRel.getCluster().getRexBuilder();

    int len = srcConds.length;
    System.arraycopy(srcJoinTypes, 0, destJoinTypes, destPos, len);

    if (adjustmentAmount == 0) {
      System.arraycopy(srcConds, 0, destConds, 0, len);
    } else {
      int nFields = srcFields.length;
      int[] adjustments = new int[nFields];
      for (int idx = 0; idx < nFields; idx++) {
        adjustments[idx] = adjustmentAmount;
      }
      for (int i = 0; i < len; i++) {
        if (srcConds[i] != null) {
          destConds[i + destPos] =
              srcConds[i].accept(
                  new RelOptUtil.RexInputConverter(rexBuilder, srcFields, destFields, adjustments));
        }
      }
    }
  }
Example #3
0
  /**
   * Combines the inputs into a JoinRel into an array of inputs.
   *
   * @param join original join
   * @param left left input into join
   * @param right right input into join
   * @param projFieldsList returns a list of the new combined projection fields
   * @param joinFieldRefCountsList returns a list of the new combined join field reference counts
   * @return combined left and right inputs in an array
   */
  private RelNode[] combineInputs(
      JoinRel join,
      RelNode left,
      RelNode right,
      List<BitSet> projFieldsList,
      List<int[]> joinFieldRefCountsList) {
    // leave the null generating sides of an outer join intact; don't
    // pull up those children inputs into the array we're constructing
    int nInputs;
    int nInputsOnLeft;
    MultiJoinRel leftMultiJoin = null;
    JoinRelType joinType = join.getJoinType();
    boolean combineLeft = canCombine(left, joinType.generatesNullsOnLeft());
    if (combineLeft) {
      leftMultiJoin = (MultiJoinRel) left;
      nInputs = left.getInputs().length;
      nInputsOnLeft = nInputs;
    } else {
      nInputs = 1;
      nInputsOnLeft = 1;
    }
    MultiJoinRel rightMultiJoin = null;
    boolean combineRight = canCombine(right, joinType.generatesNullsOnRight());
    if (combineRight) {
      rightMultiJoin = (MultiJoinRel) right;
      nInputs += right.getInputs().length;
    } else {
      nInputs += 1;
    }

    RelNode[] newInputs = new RelNode[nInputs];
    int i = 0;
    if (combineLeft) {
      for (; i < left.getInputs().length; i++) {
        newInputs[i] = leftMultiJoin.getInput(i);
        projFieldsList.add(((MultiJoinRel) left).getProjFields()[i]);
        joinFieldRefCountsList.add(((MultiJoinRel) left).getJoinFieldRefCountsMap().get(i));
      }
    } else {
      newInputs[0] = left;
      i = 1;
      projFieldsList.add(null);
      joinFieldRefCountsList.add(new int[left.getRowType().getFieldCount()]);
    }
    if (combineRight) {
      for (; i < nInputs; i++) {
        newInputs[i] = rightMultiJoin.getInput(i - nInputsOnLeft);
        projFieldsList.add(((MultiJoinRel) right).getProjFields()[i - nInputsOnLeft]);
        joinFieldRefCountsList.add(
            ((MultiJoinRel) right).getJoinFieldRefCountsMap().get(i - nInputsOnLeft));
      }
    } else {
      newInputs[i] = right;
      projFieldsList.add(null);
      joinFieldRefCountsList.add(new int[right.getRowType().getFieldCount()]);
    }

    return newInputs;
  }
  // implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    FilterRel filterRel = call.rel(0);
    MultiJoinRel multiJoinRel = call.rel(1);

    MultiJoinRel newMultiJoinRel =
        new MultiJoinRel(
            multiJoinRel.getCluster(),
            multiJoinRel.getInputs(),
            multiJoinRel.getJoinFilter(),
            multiJoinRel.getRowType(),
            multiJoinRel.isFullOuterJoin(),
            multiJoinRel.getOuterJoinConditions(),
            multiJoinRel.getJoinTypes(),
            multiJoinRel.getProjFields(),
            multiJoinRel.getJoinFieldRefCountsMap(),
            filterRel.getCondition());

    call.transformTo(newMultiJoinRel);
  }
Example #5
0
  /**
   * Shifts a filter originating from the right child of the JoinRel to the right, to reflect the
   * filter now being applied on the resulting MultiJoinRel.
   *
   * @param joinRel the original JoinRel
   * @param left the left child of the JoinRel
   * @param right the right child of the JoinRel
   * @param rightFilter the filter originating from the right child
   * @return the adjusted right filter
   */
  private RexNode shiftRightFilter(
      JoinRel joinRel, RelNode left, MultiJoinRel right, RexNode rightFilter) {
    if (rightFilter == null) {
      return null;
    }

    int nFieldsOnLeft = left.getRowType().getFields().length;
    int nFieldsOnRight = right.getRowType().getFields().length;
    int[] adjustments = new int[nFieldsOnRight];
    for (int i = 0; i < nFieldsOnRight; i++) {
      adjustments[i] = nFieldsOnLeft;
    }
    rightFilter =
        rightFilter.accept(
            new RelOptUtil.RexInputConverter(
                joinRel.getCluster().getRexBuilder(),
                right.getRowType().getFields(),
                joinRel.getRowType().getFields(),
                adjustments));
    return rightFilter;
  }