public RelNode align(Join rel, List<RelFieldCollation> collations) {
    ImmutableList.Builder<RelFieldCollation> propagateCollationsLeft = ImmutableList.builder();
    ImmutableList.Builder<RelFieldCollation> propagateCollationsRight = ImmutableList.builder();
    final int nLeftColumns = rel.getLeft().getRowType().getFieldList().size();
    Map<Integer,RexNode> idxToConjuncts = new HashMap<>();
    Map<Integer,Integer> refToRef = new HashMap<>();
    // 1) We extract the conditions that can be useful
    List<RexNode> conjuncts = new ArrayList<>();
    List<RexNode> otherConjuncts = new ArrayList<>();
    for (RexNode conj : RelOptUtil.conjunctions(rel.getCondition())) {
      if (conj.getKind() != SqlKind.EQUALS) {
        otherConjuncts.add(conj);
        continue;
      }
      // TODO: Currently we only support EQUAL operator on two references.
      // We might extend the logic to support other (order-preserving)
      // UDFs here.
      RexCall equals = (RexCall) conj;
      if (!(equals.getOperands().get(0) instanceof RexInputRef) ||
              !(equals.getOperands().get(1) instanceof RexInputRef)) {
        otherConjuncts.add(conj);
        continue;
      }
      RexInputRef ref0 = (RexInputRef) equals.getOperands().get(0);
      RexInputRef ref1 = (RexInputRef) equals.getOperands().get(1);
      if ((ref0.getIndex() < nLeftColumns && ref1.getIndex() >= nLeftColumns) ||
              (ref1.getIndex() < nLeftColumns && ref0.getIndex() >= nLeftColumns)) {
        // We made sure the references are for different join inputs
        idxToConjuncts.put(ref0.getIndex(), equals);
        idxToConjuncts.put(ref1.getIndex(), equals);
        refToRef.put(ref0.getIndex(), ref1.getIndex());
        refToRef.put(ref1.getIndex(), ref0.getIndex());
      } else {
        otherConjuncts.add(conj);
      }
    }

    // 2) We extract the collation for this operator and the collations
    // that we will propagate to the inputs of the join
    for (RelFieldCollation c : collations) {
      RexNode equals = idxToConjuncts.get(c.getFieldIndex());
      if (equals != null) {
        conjuncts.add(equals);
        idxToConjuncts.remove(c.getFieldIndex());
        idxToConjuncts.remove(refToRef.get(c.getFieldIndex()));
        if (c.getFieldIndex() < nLeftColumns) {
          propagateCollationsLeft.add(c.copy(c.getFieldIndex()));
          propagateCollationsRight.add(c.copy(refToRef.get(c.getFieldIndex()) - nLeftColumns));
        } else {
          propagateCollationsLeft.add(c.copy(refToRef.get(c.getFieldIndex())));
          propagateCollationsRight.add(c.copy(c.getFieldIndex() - nLeftColumns));
        }
      }
    }
    final Set<RexNode> visited = new HashSet<>();
    for (Entry<Integer,RexNode> e : idxToConjuncts.entrySet()) {
      if (visited.add(e.getValue())) {
        // Not included in the input collations, but can be propagated as this Join
        // might enforce it
        conjuncts.add(e.getValue());
        if (e.getKey() < nLeftColumns) {
          propagateCollationsLeft.add(new RelFieldCollation(e.getKey()));
          propagateCollationsRight.add(new RelFieldCollation(refToRef.get(e.getKey()) - nLeftColumns));
        } else {
          propagateCollationsLeft.add(new RelFieldCollation(refToRef.get(e.getKey())));
          propagateCollationsRight.add(new RelFieldCollation(e.getKey() - nLeftColumns));
        }
      }
    }
    conjuncts.addAll(otherConjuncts);

    // 3) We propagate
    final RelNode newLeftInput = dispatchAlign(rel.getLeft(), propagateCollationsLeft.build());
    final RelNode newRightInput = dispatchAlign(rel.getRight(), propagateCollationsRight.build());

    // 4) We change the Join operator to reflect this info
    final RelNode newJoin = rel.copy(rel.getTraitSet(), RexUtil.composeConjunction(
            relBuilder.getRexBuilder(), conjuncts, false), newLeftInput, newRightInput,
            rel.getJoinType(), rel.isSemiJoinDone());
    return newJoin;
  }
Execute the logic in this class. In particular, make a top-down traversal of the tree
and annotate and recreate appropriate operators.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveRelColumnsAlignment.java