private static HiveLoptJoinTree createJoinSubtree(
          RelMetadataQuery mq,
          RelBuilder relBuilder,
          HiveLoptMultiJoin multiJoin,
          HiveLoptJoinTree left,
          HiveLoptJoinTree right,
          RexNode condition,
          JoinRelType joinType,
          List<RexNode> filtersToAdd,
          boolean fullAdjust,
          boolean selfJoin) {
    RexBuilder rexBuilder =
            multiJoin.getMultiJoinRel().getCluster().getRexBuilder();

    // swap the inputs if beneficial
    if (swapInputs(mq, multiJoin, left, right, selfJoin)) {
      HiveLoptJoinTree tmp = right;
      right = left;
      left = tmp;
      if (!fullAdjust) {
        condition =
                swapFilter(
                        rexBuilder,
                        multiJoin,
                        right,
                        left,
                        condition);
      }
      if ((joinType != JoinRelType.INNER)
              && (joinType != JoinRelType.FULL)) {
        joinType =
                (joinType == JoinRelType.LEFT) ? JoinRelType.RIGHT
                        : JoinRelType.LEFT;
      }
    }

    if (fullAdjust) {
      int [] adjustments = new int[multiJoin.getNumTotalFields()];
      if (needsAdjustment(
              multiJoin,
              adjustments,
              left,
              right,
              selfJoin)) {
        condition =
                condition.accept(
                        new RelOptUtil.RexInputConverter(
                                rexBuilder,
                                multiJoin.getMultiJoinFields(),
                                left.getJoinTree().getRowType().getFieldList(),
                                right.getJoinTree().getRowType().getFieldList(),
                                adjustments));
      }
    }

    relBuilder.push(left.getJoinTree())
            .push(right.getJoinTree())
            .join(joinType, condition);

    // if this is a left or right outer join, and additional filters can
    // be applied to the resulting join, then they need to be applied
    // as a filter on top of the outer join result
    if ((joinType == JoinRelType.LEFT) || (joinType == JoinRelType.RIGHT)) {
      assert !selfJoin;
      addAdditionalFilters(
              relBuilder,
              multiJoin,
              left,
              right,
              filtersToAdd);
    }

    return new HiveLoptJoinTree(
            relBuilder.build(),
            left.getFactorTree(),
            right.getFactorTree(),
            selfJoin);
  }
Creates a LogicalJoin given left and right operands and a join condition.
Swaps the operands if beneficial.

@param multiJoin join factors being optimized
@param left left operand
@param right right operand
@param condition join condition
@param joinType the join type
@param fullAdjust true if the join condition reflects the original join
ordering and therefore has not gone through any type of adjustment yet;
otherwise, the condition has already been partially adjusted and only
needs to be further adjusted if swapping is done
@param filtersToAdd additional filters that may be added on top of the
resulting LogicalJoin, if the join is a left or right outer join
@param selfJoin true if the join being created is a self-join that's
removable

@return created LogicalJoin
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveLoptOptimizeJoinRule.java