private static @Nullable HiveLoptJoinTree createOrdering(
          RelMetadataQuery mq,
          RelBuilder relBuilder,
          HiveLoptMultiJoin multiJoin,
          HiveLoptSemiJoinOptimizer semiJoinOpt,
          int firstFactor) {
    HiveLoptJoinTree joinTree = null;
    final int nJoinFactors = multiJoin.getNumJoinFactors();
    final BitSet factorsToAdd = BitSets.range(0, nJoinFactors);
    final BitSet factorsAdded = new BitSet(nJoinFactors);
    final List<RexNode> filtersToAdd =
            new ArrayList<>(multiJoin.getJoinFilters());

    int prevFactor = -1;
    while (factorsToAdd.cardinality() > 0) {
      int nextFactor;
      boolean selfJoin = false;
      if (factorsAdded.cardinality() == 0) {
        nextFactor = firstFactor;
      } else {
        // If the factor just added is part of a removable self-join
        // and the other half of the self-join hasn't been added yet,
        // then add it next.  Otherwise, look for the optimal factor
        // to add next.
        Integer selfJoinFactor =
                multiJoin.getOtherSelfJoinFactor(prevFactor);
        if ((selfJoinFactor != null)
                && !factorsAdded.get(selfJoinFactor)) {
          nextFactor = selfJoinFactor;
          selfJoin = true;
        } else {
          nextFactor =
                  getBestNextFactor(
                          mq,
                          multiJoin,
                          factorsToAdd,
                          factorsAdded,
                          semiJoinOpt,
                          joinTree,
                          filtersToAdd);
        }
      }

      // add the factor; pass in a bitmap representing the factors
      // this factor joins with that have already been added to
      // the tree
      BitSet factorsNeeded =
              multiJoin.getFactorsRefByFactor(nextFactor).toBitSet();
      if (multiJoin.isNullGenerating(nextFactor)) {
        factorsNeeded.or(multiJoin.getOuterJoinFactors(nextFactor).toBitSet());
      }
      factorsNeeded.and(factorsAdded);
      joinTree =
              addFactorToTree(
                      mq,
                      relBuilder,
                      multiJoin,
                      semiJoinOpt,
                      joinTree,
                      nextFactor,
                      factorsNeeded,
                      filtersToAdd,
                      selfJoin);
      if (joinTree == null) {
        return null;
      }
      factorsToAdd.clear(nextFactor);
      factorsAdded.set(nextFactor);
      prevFactor = nextFactor;
    }

    assert filtersToAdd.size() == 0;
    return joinTree;
  }
Generates a join tree with a specific factor as the first factor in the
join tree.

@param multiJoin join factors being optimized
@param semiJoinOpt optimal semijoins for each factor
@param firstFactor first factor in the tree

@return constructed join tree or null if it is not possible for
firstFactor to appear as the first factor in the join
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveLoptOptimizeJoinRule.java