private RelNode createValueGenerator(
          Iterable<CorRef> correlations,
          int valueGenFieldOffset,
          SortedMap<CorDef, Integer> corDefOutputs) {
    final Map<RelNode, List<Integer>> mapNewInputToOutputs =
            new HashMap<>();

    final Map<RelNode, Integer> mapNewInputToNewOffset = new HashMap<>();

    // Input provides the definition of a correlated variable.
    // Add to map all the referenced positions (relative to each input rel).
    for (CorRef corVar : correlations) {
      final int oldCorVarOffset = corVar.field;

      final RelNode oldInput = getCorRel(corVar);
      assert oldInput != null;
      final Frame frame = map.get(oldInput);
      assert frame != null;
      final RelNode newInput = frame.r;

      final List<Integer> newLocalOutputs;
      if (!mapNewInputToOutputs.containsKey(newInput)) {
        newLocalOutputs =  new ArrayList<>();
      } else {
        newLocalOutputs =
                mapNewInputToOutputs.get(newInput);
      }

      final int newCorVarOffset = frame.oldToNewOutputs.get(oldCorVarOffset);

      // Add all unique positions referenced.
      if (!newLocalOutputs.contains(newCorVarOffset)) {
        newLocalOutputs.add(newCorVarOffset);
      }
      mapNewInputToOutputs.put(newInput, newLocalOutputs);
    }

    int offset = 0;

    // Project only the correlated fields out of each inputRel
    // and join the projectRel together.
    // To make sure the plan does not change in terms of join order,
    // join these rels based on their occurrence in cor var list which
    // is sorted.
    final Set<RelNode> joinedInputs =  new HashSet<>();

    RelNode r = null;
    for (CorRef corVar : correlations) {
      final RelNode oldInput = getCorRel(corVar);
      assert oldInput != null;
      final RelNode newInput = map.get(oldInput).r;
      assert newInput != null;

      if (!joinedInputs.contains(newInput)) {
        RelNode project = RelOptUtil.createProject(
            HiveRelFactories.HIVE_PROJECT_FACTORY, newInput, mapNewInputToOutputs.get(newInput));
        RelNode distinct = relBuilder.push(project).distinct().build();
        RelOptCluster cluster = distinct.getCluster();

        joinedInputs.add(newInput);
        mapNewInputToNewOffset.put(newInput, offset);
        offset += distinct.getRowType().getFieldCount();

        if (r == null) {
          r = distinct;
        } else {
          r = relBuilder.push(r).push(distinct)
              .join(JoinRelType.INNER, cluster.getRexBuilder().makeLiteral(true)).build();
        }
      }
    }

    // Translate the positions of correlated variables to be relative to
    // the join output, leaving room for valueGenFieldOffset because
    // valueGenerators are joined with the original left input of the rel
    // referencing correlated variables.
    for (CorRef corRef : correlations) {
      // The first input of a Correlator is always the rel defining
      // the correlated variables.
      final RelNode oldInput = getCorRel(corRef);
      assert oldInput != null;
      final Frame frame = map.get(oldInput);
      final RelNode newInput = frame.r;
      assert newInput != null;

      final List<Integer> newLocalOutputs =
              mapNewInputToOutputs.get(newInput);

      final int newLocalOutput = frame.oldToNewOutputs.get(corRef.field);

      // newOutput is the index of the cor var in the referenced
      // position list plus the offset of referenced position list of
      // each newInput.
      final int newOutput =
              newLocalOutputs.indexOf(newLocalOutput)
                      + mapNewInputToNewOffset.get(newInput)
                      + valueGenFieldOffset;

      corDefOutputs.put(corRef.def(), newOutput);
    }

    return r;
  }
Create RelNode tree that produces a list of correlated variables.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveRelDecorrelator.java