private RelNode genJoinRelNode(RelNode leftRel, String leftTableAlias, RelNode rightRel, String rightTableAlias, JoinType hiveJoinType,
        ASTNode joinCond, ImmutableMap<String, Integer> outerNameToPosMap, RowResolver outerRR) throws SemanticException {

      RowResolver leftRR = this.relToHiveRR.get(leftRel);
      RowResolver rightRR = this.relToHiveRR.get(rightRel);

      // 1. Construct ExpressionNodeDesc representing Join Condition
      RexNode calciteJoinCond = null;
      List<String> namedColumns = null;
      if (joinCond != null) {
        JoinTypeCheckCtx jCtx = new JoinTypeCheckCtx(leftRR, rightRR, cluster.getRexBuilder(), hiveJoinType);
        jCtx.setOuterRR(outerRR);
        RowResolver input = jCtx.getInputRR();
        // named columns join
        // TODO: we can also do the same for semi join but it seems that other
        // DBMS does not support it yet.
        if (joinCond.getType() == HiveParser.TOK_TABCOLNAME
            && !hiveJoinType.equals(JoinType.LEFTSEMI)) {
          namedColumns = new ArrayList<>();
          // We will transform using clause and make it look like an on-clause.
          // So, lets generate a valid on-clause AST from using.
          ASTNode and = (ASTNode) ParseDriver.adaptor.create(HiveParser.KW_AND, "and");
          ASTNode equal = null;
          int count = 0;
          for (Node child : joinCond.getChildren()) {
            String columnName = ((ASTNode) child).getText();
            // dealing with views
            if (unparseTranslator != null && unparseTranslator.isEnabled()) {
              unparseTranslator.addIdentifierTranslation((ASTNode) child);
            }
            namedColumns.add(columnName);

            /*
              In case of multiple joins, leftTableAlias can be null
              as for the second join, the left side is a join token.

              For example, if we have 3 tables with the following schemas:
                    t1 - (a), t2 - (a, b), t3 - (a, b, c)
              and we were trying to run the following query:
                    select * from t1
                    join t2 using(a)
                    join t3 using(a);
              For the second join, since left side is a join, leftTableAlias is null, and we have
              to choose the correct alias to use from leftRR. Here we are choosing the rightmost
              table containing column a, i.e., t2 and not t1.

              And, for the query:
                    select * from t2
                    join t1 using(a)
                    join t3 using(b);
              For the second join, leftTableAlias is again null, and the rightmost table containing
              column b is t2 as b is not present in t1.
             */
            if (leftTableAlias == null) {
              leftTableAlias = leftRR.getTableAliasContainingColumn(columnName);
            }
            // if it's still null, throw an exception as column is not present
            // in left row resolver
            if (leftTableAlias == null) {
              throw new SemanticException("column '" + columnName +
                  "' not present in any of these tables: " + leftRR.getTableNames());
            }

            ASTNode left = ASTBuilder.qualifiedName(leftTableAlias, columnName);
            ASTNode right = ASTBuilder.qualifiedName(rightTableAlias, columnName);
            equal = (ASTNode) ParseDriver.adaptor.create(HiveParser.EQUAL, "=");
            ParseDriver.adaptor.addChild(equal, left);
            ParseDriver.adaptor.addChild(equal, right);
            ParseDriver.adaptor.addChild(and, equal);
            count++;
          }
          joinCond = count > 1 ? and : equal;
        } else if (unparseTranslator != null && unparseTranslator.isEnabled()) {
          jCtx.setUnparseTranslator(unparseTranslator);
          genAllRexNode(joinCond, input, jCtx, conf);
        }
        Map<ASTNode, RexNode> exprNodes = RexNodeTypeCheck.genExprNodeJoinCond(
            joinCond, jCtx, cluster.getRexBuilder());
        if (jCtx.getError() != null) {
          throw new SemanticException(SemanticAnalyzer.generateErrorMessage(jCtx.getErrorSrcNode(),
              jCtx.getError()));
        }
        calciteJoinCond = exprNodes.get(joinCond);
      } else {
        calciteJoinCond = cluster.getRexBuilder().makeLiteral(true);
      }

      // 2. Validate that join condition is legal (i.e no function refering to
      // both sides of join, only equi join)
      // TODO: Join filter handling (only supported for OJ by runtime or is it
      // supported for IJ as well)

      // 3. Construct Join Rel Node and RowResolver for the new Join Node
      boolean leftSemiJoin = false;
      JoinRelType calciteJoinType;
      switch (hiveJoinType) {
      case LEFTOUTER:
        calciteJoinType = JoinRelType.LEFT;
        break;
      case RIGHTOUTER:
        calciteJoinType = JoinRelType.RIGHT;
        break;
      case FULLOUTER:
        calciteJoinType = JoinRelType.FULL;
        break;
      case LEFTSEMI:
        calciteJoinType = JoinRelType.SEMI;
        leftSemiJoin = true;
        break;
      case ANTI:
        calciteJoinType = JoinRelType.ANTI;
        leftSemiJoin = true;
        break;
      case INNER:
      default:
        calciteJoinType = JoinRelType.INNER;
        break;
      }

      RelNode topRel = null;
      RowResolver topRR = null;
      if (leftSemiJoin) {
        List<RelDataTypeField> sysFieldList = new ArrayList<RelDataTypeField>();
        List<RexNode> leftJoinKeys = new ArrayList<RexNode>();
        List<RexNode> rightJoinKeys = new ArrayList<RexNode>();

        RexNode nonEquiConds = HiveRelOptUtil.splitHiveJoinCondition(sysFieldList, ImmutableList.of(leftRel, rightRel),
            calciteJoinCond, ImmutableList.of(leftJoinKeys, rightJoinKeys), null, null);

        RelNode[] inputRels = new RelNode[] { leftRel, rightRel };
        final List<Integer> leftKeys = new ArrayList<Integer>();
        final List<Integer> rightKeys = new ArrayList<Integer>();
        RexNode remainingEquiCond = HiveCalciteUtil.projectNonColumnEquiConditions(HiveRelFactories.HIVE_PROJECT_FACTORY,
            inputRels, leftJoinKeys, rightJoinKeys, 0, leftKeys, rightKeys);
        // Adjust right input fields in nonEquiConds if previous call modified the input
        if (inputRels[0] != leftRel) {
          nonEquiConds = RexUtil.shift(nonEquiConds, leftRel.getRowType().getFieldCount(),
              inputRels[0].getRowType().getFieldCount() - leftRel.getRowType().getFieldCount());
        }
        calciteJoinCond = remainingEquiCond != null ?
            RexUtil.composeConjunction(cluster.getRexBuilder(),
                ImmutableList.of(remainingEquiCond, nonEquiConds), false) :
            nonEquiConds;
        final RelDataType combinedRowType = SqlValidatorUtil.createJoinType(
            cluster.getTypeFactory(), inputRels[0].getRowType(), inputRels[1].getRowType(),
            null, ImmutableList.of());

        if (hiveJoinType == JoinType.LEFTSEMI) {
          topRel = HiveSemiJoin.getSemiJoin(cluster, cluster.traitSetOf(HiveRelNode.CONVENTION),
                  inputRels[0], inputRels[1],
                  HiveCalciteUtil.fixNullability(cluster.getRexBuilder(),
                          calciteJoinCond, RelOptUtil.getFieldTypeList(combinedRowType)));
        } else {
          topRel = HiveAntiJoin.getAntiJoin(cluster, cluster.traitSetOf(HiveRelNode.CONVENTION),
                  inputRels[0], inputRels[1],
                  HiveCalciteUtil.fixNullability(cluster.getRexBuilder(),
                          calciteJoinCond, RelOptUtil.getFieldTypeList(combinedRowType)));
        }

        // Create join RR: we need to check whether we need to update left RR in case
        // previous call to projectNonColumnEquiConditions updated it
        if (inputRels[0] != leftRel) {
          RowResolver newLeftRR = new RowResolver();
          if (!RowResolver.add(newLeftRR, leftRR)) {
            LOG.warn(ERROR_MESSAGE_DUPLICATES_DETECTED);
          }
          for (int i = leftRel.getRowType().getFieldCount();
                  i < inputRels[0].getRowType().getFieldCount(); i++) {
            ColumnInfo oColInfo = new ColumnInfo(
                SemanticAnalyzer.getColumnInternalName(i),
                TypeConverter.convert(inputRels[0].getRowType().getFieldList().get(i).getType()),
                null, false);
            newLeftRR.put(oColInfo.getTabAlias(), oColInfo.getInternalName(), oColInfo);
          }

          RowResolver joinRR = new RowResolver();
          if (!RowResolver.add(joinRR, newLeftRR)) {
            LOG.warn(ERROR_MESSAGE_DUPLICATES_DETECTED);
          }
          relToHiveColNameCalcitePosMap.put(topRel, buildHiveToCalciteColumnMap(joinRR));
          relToHiveRR.put(topRel, joinRR);

          // Introduce top project operator to remove additional column(s) that have
          // been introduced
          List<RexNode> topFields = new ArrayList<RexNode>();
          List<String> topFieldNames = new ArrayList<String>();
          for (int i = 0; i < leftRel.getRowType().getFieldCount(); i++) {
            final RelDataTypeField field = leftRel.getRowType().getFieldList().get(i);
            topFields.add(leftRel.getCluster().getRexBuilder().makeInputRef(field.getType(), i));
            topFieldNames.add(field.getName());
          }
          topRel = HiveRelFactories.HIVE_PROJECT_FACTORY.createProject(topRel, Collections.emptyList(), topFields, topFieldNames);
        }

        topRR = new RowResolver();
        if (!RowResolver.add(topRR, leftRR)) {
          LOG.warn(ERROR_MESSAGE_DUPLICATES_DETECTED);
        }
      } else {
        final RelDataType combinedRowType = SqlValidatorUtil.createJoinType(
            cluster.getTypeFactory(), leftRel.getRowType(), rightRel.getRowType(),
            null, ImmutableList.of());
        topRR = RowResolver.getCombinedRR(leftRR, rightRR);
        final ImmutableMap<String, Integer> hiveColNameCalcitePosMap =
          buildHiveToCalciteColumnMap(topRR);
        calciteJoinCond = new CorrelationConverter(
          new InputContext(combinedRowType, hiveColNameCalcitePosMap, topRR),
          outerNameToPosMap, outerRR, subqueryId).apply(calciteJoinCond);
        topRel = HiveJoin.getJoin(
            cluster, leftRel, rightRel,
            HiveCalciteUtil.fixNullability(cluster.getRexBuilder(),
                calciteJoinCond, RelOptUtil.getFieldTypeList(combinedRowType)),
            calciteJoinType);

        if (namedColumns != null) {
          List<String> tableAliases = new ArrayList<>();
          tableAliases.add(leftTableAlias);
          tableAliases.add(rightTableAlias);
          topRR.setNamedJoinInfo(new NamedJoinInfo(tableAliases, namedColumns, hiveJoinType));
        }
      }

      // 4. Add new rel & its RR to the maps
      relToHiveColNameCalcitePosMap.put(topRel, buildHiveToCalciteColumnMap(topRR));
      relToHiveRR.put(topRel, topRR);
      return topRel;
    }
Generate a HEP program with the given rule set.

@param isCollection
@param order
@param rules
ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java