public static JoinPredicateInfo constructJoinPredicateInfo(List<RelNode> inputs,
            List<RelDataTypeField> systemFieldList, RexNode predicate) throws CalciteSemanticException {
      JoinPredicateInfo jpi = null;
      JoinLeafPredicateInfo jlpi = null;
      List<JoinLeafPredicateInfo> equiLPIList = new ArrayList<JoinLeafPredicateInfo>();
      List<JoinLeafPredicateInfo> nonEquiLPIList = new ArrayList<JoinLeafPredicateInfo>();
      List<Set<Integer>> projsJoinKeys = new ArrayList<Set<Integer>>();
      for (int i=0; i<inputs.size(); i++) {
        Set<Integer> projsJoinKeysInput = Sets.newHashSet();
        projsJoinKeys.add(projsJoinKeysInput);
      }
      List<Set<Integer>> projsJoinKeysInJoinSchema = new ArrayList<Set<Integer>>();
      for (int i=0; i<inputs.size(); i++) {
        Set<Integer> projsJoinKeysInJoinSchemaInput = Sets.newHashSet();
        projsJoinKeysInJoinSchema.add(projsJoinKeysInJoinSchemaInput);
      }
      Map<Integer, List<JoinLeafPredicateInfo>> tmpMapOfProjIndxInJoinSchemaToLeafPInfo = new HashMap<Integer, List<JoinLeafPredicateInfo>>();
      Map<Integer, ImmutableList<JoinLeafPredicateInfo>> mapOfProjIndxInJoinSchemaToLeafPInfo = new HashMap<Integer, ImmutableList<JoinLeafPredicateInfo>>();
      List<JoinLeafPredicateInfo> tmpJLPILst = null;
      List<RexNode> conjuctiveElements;

      // 1. Decompose Join condition to a number of leaf predicates
      // (conjuctive elements)
      conjuctiveElements = RelOptUtil.conjunctions(predicate);

      // 2. Walk through leaf predicates building up JoinLeafPredicateInfo
      for (RexNode ce : conjuctiveElements) {
        // 2.1 Construct JoinLeafPredicateInfo
        jlpi = JoinLeafPredicateInfo.constructJoinLeafPredicateInfo(inputs, systemFieldList, ce);

        // 2.2 Classify leaf predicate as Equi vs Non Equi
        if (jlpi.comparisonType.equals(SqlKind.EQUALS)) {
          equiLPIList.add(jlpi);

          // 2.2.1 Maintain join keys (in child & Join Schema)
          // 2.2.2 Update Join Key to JoinLeafPredicateInfo map with keys
          for (int i=0; i<inputs.size(); i++) {
            projsJoinKeys.get(i).addAll(jlpi.getProjsJoinKeysInChildSchema(i));
            projsJoinKeysInJoinSchema.get(i).addAll(jlpi.getProjsJoinKeysInJoinSchema(i));

            for (Integer projIndx : jlpi.getProjsJoinKeysInJoinSchema(i)) {
              tmpJLPILst = tmpMapOfProjIndxInJoinSchemaToLeafPInfo.get(projIndx);
              if (tmpJLPILst == null) {
                tmpJLPILst = new ArrayList<JoinLeafPredicateInfo>();
              }
              tmpJLPILst.add(jlpi);
              tmpMapOfProjIndxInJoinSchemaToLeafPInfo.put(projIndx, tmpJLPILst);
            }
          }
        } else {
          nonEquiLPIList.add(jlpi);
        }
      }

      // 3. Update Update Join Key to List<JoinLeafPredicateInfo> to use
      // ImmutableList
      for (Entry<Integer, List<JoinLeafPredicateInfo>> e : tmpMapOfProjIndxInJoinSchemaToLeafPInfo
          .entrySet()) {
        mapOfProjIndxInJoinSchemaToLeafPInfo.put(e.getKey(), ImmutableList.copyOf(e.getValue()));
      }

      // 4. Construct JoinPredicateInfo
      jpi = new JoinPredicateInfo(nonEquiLPIList, equiLPIList, projsJoinKeys,
          projsJoinKeysInJoinSchema, mapOfProjIndxInJoinSchemaToLeafPInfo);
      return jpi;
    }
NOTE: Join Schema = left Schema + (right Schema offset by
left.fieldcount). Hence its ok to return projections from left in child
schema.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveCalciteUtil.java