private Operator genJoinOperator(QB qb, QBJoinTree joinTree,
                                   Map<String, Operator> map,
                                   Operator joiningOp, boolean notInCheckPresent) throws SemanticException {
    QBJoinTree leftChild = joinTree.getJoinSrc();
    Operator joinSrcOp = joiningOp instanceof JoinOperator ? joiningOp : null;
    Operator OuterSrcOp = joiningOp;

    if (joinSrcOp == null && leftChild != null) {
      joinSrcOp = genJoinOperator(qb, leftChild, map, null);
    }

    if ( joinSrcOp != null ) {
      List<ASTNode> filter = joinTree.getFiltersForPushing().get(0);
      for (ASTNode cond : filter) {
        joinSrcOp = genFilterPlan(qb, cond, joinSrcOp, false);
      }
    }

    String[] baseSrc = joinTree.getBaseSrc();
    Operator[] srcOps = new Operator[baseSrc.length];

    Set<Integer> omitOpts = null; // set of input to the join that should be
    // omitted by the output
    int pos = 0;
    for (String src : baseSrc) {
      if (src != null) {
        Operator srcOp = map.get(src.toLowerCase());

        // for left-semi join, generate an additional selection & group-by
        // operator before ReduceSink
        List<ASTNode> fields = joinTree.getRHSSemijoinColumns(src);
        if (fields != null) {
          // the RHS table columns should be not be output from the join
          if (omitOpts == null) {
            omitOpts = new HashSet<Integer>();
          }
          omitOpts.add(pos);

          // generate a selection operator for group-by keys only
          srcOp = insertSelectForSemijoin(fields, srcOp);

          // generate a groupby operator (HASH mode) for a map-side partial
          // aggregation for semijoin
          srcOps[pos++] = genMapGroupByForSemijoin(fields, srcOp);
        } else {
          srcOps[pos++] = srcOp;
        }
      } else {
        assert pos == 0;
        srcOps[pos++] = joinSrcOp;
      }
    }

    ExprNodeDesc[][] joinKeys = genJoinKeys(joinTree, srcOps);

    for (int i = 0; i < srcOps.length; i++) {
      // generate a ReduceSink operator for the join
      String[] srcs = baseSrc[i] != null ? new String[] {baseSrc[i]} : joinTree.getLeftAliases();
      if (!isCBOExecuted()) {
        /*
         * The condition srcOps[i] == OuterSrcOp is used to make sure that the predicate for notnull check
         * is added only for the outer query table.outerqueryCol
         * even after the outer join condition
         */
        boolean outerNotInCheck = (notInCheckPresent && (srcOps[i] == OuterSrcOp));
        srcOps[i] = genNotNullFilterForJoinSourcePlan(qb, srcOps[i], joinTree, joinKeys[i], outerNotInCheck);
      }
      srcOps[i] = genJoinReduceSinkChild(joinKeys[i], srcOps[i], srcs, joinTree.getNextTag());
    }

    Operator<?> topOp = genJoinOperatorChildren(joinTree, joinSrcOp, srcOps, omitOpts, joinKeys);
    JoinOperator joinOp;
    if (topOp instanceof JoinOperator) {
      joinOp = (JoinOperator) topOp;
    } else {
      // We might generate a Select operator on top of the join operator for
      // semijoin
      joinOp = (JoinOperator) topOp.getParentOperators().get(0);
    }
    joinOp.getConf().setQBJoinTreeProps(joinTree);
    joinContext.put(joinOp, joinTree);

    if (joinTree.getPostJoinFilters().size() != 0) {
      assert joinTree.getNoOuterJoin();
      if (HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_PUSH_RESIDUAL_INNER)) {
        // Safety check for postconditions
        throw new SemanticException("Post-filtering conditions should have been added to the JOIN operator");
      }
      for(ASTNode condn : joinTree.getPostJoinFilters()) {
        topOp = genFilterPlan(qb, condn, topOp, false);
      }
    }

    return topOp;
  }
Creates an expression for converting from a table column to a row column. For example:
The table column is int but the query provides a string in the row, then we need to cast automatically.
@param tableField The target table column
@param rowField The source row column
@param conversion The value of this boolean is set to true if we detect that a conversion is needed. This is a
                  hidden return value hidden here, to notify the caller that a cast was needed.
@param dest The destination table for the error message
@param columnNum The destination column id for the error message
@return The Expression describing the selected column. Note that `conversion` can be considered as a return value
        as well
@throws SemanticException If conversion were needed, but automatic conversion is not available
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java