public Frame decorrelateRel(Join rel) {
    // For SEMI/ANTI join decorrelate it's input directly,
    // because the correlate variables can only be propagated from
    // the left side, which is not supported yet.
    if (cm != null && cm.mapRefRelToCorRef != null &&
      cm.mapRefRelToCorRef.containsKey(rel) && rel.getJoinType().isOuterJoin()) {
      throw new UnsupportedOperationException("Correlated subqueries in outer join conditions not supported yet." +
        " Join condition: " + rel.getCondition());
    }
    if (!rel.getJoinType().projectsRight()) {
      return decorrelateRel((RelNode) rel);
    }
    //
    // Rewrite logic:
    //
    // 1. rewrite join condition.
    // 2. map output positions and produce cor vars if any.
    //

    final RelNode oldLeft = rel.getInput(0);
    final RelNode oldRight = rel.getInput(1);

    final Frame leftFrame = getInvoke(oldLeft, rel);
    final Frame rightFrame = getInvoke(oldRight, rel);

    if (leftFrame == null || rightFrame == null) {
      // If any input has not been rewritten, do not rewrite this rel.
      return null;
    }

    final RelNode newJoin = HiveJoin.getJoin(rel.getCluster(), leftFrame.r, rightFrame.r,
        decorrelateExpr(rel.getCondition()), rel.getJoinType());

    // Create the mapping between the output of the old correlation rel
    // and the new join rel
    Map<Integer, Integer> mapOldToNewOutputs = Maps.newHashMap();

    int oldLeftFieldCount = oldLeft.getRowType().getFieldCount();
    int newLeftFieldCount = leftFrame.r.getRowType().getFieldCount();

    int oldRightFieldCount = oldRight.getRowType().getFieldCount();
    assert rel.getRowType().getFieldCount()
            == oldLeftFieldCount + oldRightFieldCount;

    // Left input positions are not changed.
    mapOldToNewOutputs.putAll(leftFrame.oldToNewOutputs);

    // Right input positions are shifted by newLeftFieldCount.
    for (int i = 0; i < oldRightFieldCount; i++) {
      mapOldToNewOutputs.put(i + oldLeftFieldCount,
              rightFrame.oldToNewOutputs.get(i) + newLeftFieldCount);
    }

    final SortedMap<CorDef, Integer> corDefOutputs =
            new TreeMap<>(leftFrame.corDefOutputs);

    // Right input positions are shifted by newLeftFieldCount.
    for (Map.Entry<CorDef, Integer> entry
            : rightFrame.corDefOutputs.entrySet()) {
      corDefOutputs.put(entry.getKey(),
              entry.getValue() + newLeftFieldCount);
    }
    return register(rel, newJoin, mapOldToNewOutputs, corDefOutputs);
  }
Rewrite Correlator into a left outer join.

@param rel Correlator
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveRelDecorrelator.java