public Frame decorrelateRel(LogicalCorrelate rel) {
    //
    // Rewrite logic:
    //
    // The original left input will be joined with the new right input that
    // has generated correlated variables propagated up. For any generated
    // cor vars that are not used in the join key, pass them along to be
    // joined later with the CorrelatorRels that produce them.
    //

    // the right input to Correlator should produce correlated variables
    final RelNode oldLeft = rel.getInput(0);
    final RelNode oldRight = rel.getInput(1);

    boolean mightRequireValueGen = new findIfValueGenRequired().traverse(oldRight);
    valueGen.push(mightRequireValueGen);

    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.
      valueGen.pop();
      return null;
    }

    if (rightFrame.corDefOutputs.isEmpty()) {
      valueGen.pop();
      return null;
    }

    assert rel.getRequiredColumns().cardinality()
            <= rightFrame.corDefOutputs.keySet().size();

    // Change correlator rel into a join.
    // Join all the correlated variables produced by this correlator rel
    // with the values generated and propagated from the right input
    final SortedMap<CorDef, Integer> corDefOutputs =
            new TreeMap<>(rightFrame.corDefOutputs);
    final List<RexNode> conditions = new ArrayList<>();
    final List<RelDataTypeField> newLeftOutput =
            leftFrame.r.getRowType().getFieldList();
    int newLeftFieldCount = newLeftOutput.size();

    final List<RelDataTypeField> newRightOutput =
            rightFrame.r.getRowType().getFieldList();

    for (Map.Entry<CorDef, Integer> rightOutput
            : new ArrayList<>(corDefOutputs.entrySet())) {
      final CorDef corDef = rightOutput.getKey();
      if (!corDef.corr.equals(rel.getCorrelationId())) {
        continue;
      }
      final int newLeftPos = leftFrame.oldToNewOutputs.get(corDef.field);
      final int newRightPos = rightOutput.getValue();
      SqlOperator callOp = corDef.getPredicateKind() == null ?
          SqlStdOperatorTable.EQUALS: corDef.getPredicateKind();
      if(corDef.isLeft) {
        conditions.add(
            rexBuilder.makeCall(callOp,
                RexInputRef.of(newLeftPos, newLeftOutput),
                new RexInputRef(newLeftFieldCount + newRightPos,
                    newRightOutput.get(newRightPos).getType())));
      } else {
        conditions.add(
            rexBuilder.makeCall(callOp,
                new RexInputRef(newLeftFieldCount + newRightPos,
                    newRightOutput.get(newRightPos).getType()),
                RexInputRef.of(newLeftPos, newLeftOutput)));
      }

      // remove this cor var from output position mapping
      corDefOutputs.remove(corDef);
    }

    // Update the output position for the cor vars: only pass on the cor
    // vars that are not used in the join key.
    for (CorDef corDef : corDefOutputs.keySet()) {
      int newPos = corDefOutputs.get(corDef) + newLeftFieldCount;
      corDefOutputs.put(corDef, newPos);
    }

    // then add any cor var from the left input. Do not need to change
    // output positions.
    corDefOutputs.putAll(leftFrame.corDefOutputs);

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

    int oldLeftFieldCount = oldLeft.getRowType().getFieldCount();

    int oldRightFieldCount = oldRight.getRowType().getFieldCount();

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


    final RexNode condition =
        RexUtil.composeConjunction(rexBuilder, conditions, false);
    RelNode newJoin = null;

    // this indicates original query was either correlated EXISTS or IN
    if(rel.getJoinType() == JoinRelType.SEMI || rel.getJoinType() == JoinRelType.ANTI) {
      final List<Integer> leftKeys = new ArrayList<Integer>();
      final List<Integer> rightKeys = new ArrayList<Integer>();

      RelNode[] inputRels = new RelNode[] {leftFrame.r, rightFrame.r};
      if (rel.getJoinType() == JoinRelType.ANTI) {
        newJoin = HiveAntiJoin.getAntiJoin(rel.getCluster(),
                rel.getCluster().traitSetOf(HiveRelNode.CONVENTION), leftFrame.r, rightFrame.r, condition);
      } else {
        newJoin = HiveSemiJoin.getSemiJoin(rel.getCluster(),
                rel.getCluster().traitSetOf(HiveRelNode.CONVENTION), leftFrame.r, rightFrame.r, condition);
      }
    } else {
      // Right input positions are shifted by newLeftFieldCount.
      for (int i = 0; i < oldRightFieldCount; i++) {
        mapOldToNewOutputs.put(
            i + oldLeftFieldCount,
            rightFrame.oldToNewOutputs.get(i) + newLeftFieldCount);
      }

      newJoin = relBuilder.push(leftFrame.r).push(rightFrame.r)
          .join(rel.getJoinType(), condition).build();
    }

    valueGen.pop();

    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