private boolean isEligibleForBucketSortMergeJoin(
    SortBucketJoinProcCtx smbJoinContext,
    List<ExprNodeDesc> keys,
    Map<String, Operator<? extends OperatorDesc>> aliasToOpInfo,
    String[] aliases,
    int pos,
    List<Order> sortColumnsFirstTable) throws SemanticException {
    String alias = aliases[pos];

    /*
     * Consider a query like:
     *
     * select -- mapjoin(subq1) --  * from
     * (select a.key, a.value from tbl1 a) subq1
     *   join
     * (select a.key, a.value from tbl2 a) subq2
     * on subq1.key = subq2.key;
     *
     * aliasToOpInfo contains the SelectOperator for subq1 and subq2.
     * We need to traverse the tree (using TableAccessAnalyzer) to get to the base
     * table. If the object being map-joined is a base table, then aliasToOpInfo
     * contains the TableScanOperator, and TableAccessAnalyzer is a no-op.
     */
    Operator<? extends OperatorDesc> topOp = aliasToOpInfo.get(alias);
    if (topOp == null) {
      return false;
    }

    // get all join columns from join keys
    List<String> joinCols = toColumns(keys);
    if (joinCols == null || joinCols.isEmpty()) {
      return false;
    }

    if (!MapJoinDesc.isSupportedComplexType(keys)) {
      //TODO : https://issues.apache.org/jira/browse/HIVE-25042
      return false;
    }

    TableScanOperator tso = TableAccessAnalyzer.genRootTableScan(topOp, joinCols);
    if (tso == null) {
      return false;
    }

    // For nested sub-queries, the alias mapping is not maintained in QB currently.
    /*
     * Consider a query like:
     *
     * select count(*) from
     *   (
     *     select key, count(*) from
     *       (
     *         select --mapjoin(a)-- a.key as key, a.value as val1, b.value as val2
     *         from tbl1 a join tbl2 b on a.key = b.key
     *       ) subq1
     *     group by key
     *   ) subq2;
     *
     * The table alias should be subq2:subq1:a which needs to be fetched from topOps.
     */
    if (pGraphContext.getTopOps().containsValue(tso)) {
      for (Map.Entry<String, TableScanOperator> topOpEntry :
        this.pGraphContext.getTopOps().entrySet()) {
        if (topOpEntry.getValue() == tso) {
          alias = topOpEntry.getKey();
          aliases[pos] = alias;
          break;
        }
      }
    }
    else {
      // Ideally, this should never happen, and this should be an assert.
      return false;
    }

    Table tbl = tso.getConf().getTableMetadata();
    if (tbl.isPartitioned()) {
      PrunedPartitionList prunedParts = pGraphContext.getPrunedPartitions(alias, tso);
      List<Partition> partitions = prunedParts.getNotDeniedPartns();
      // Populate the names and order of columns for the first partition of the
      // first table
      if ((pos == 0) && (partitions != null) && (!partitions.isEmpty())) {
        Partition firstPartition = partitions.get(0);
        sortColumnsFirstTable.addAll(firstPartition.getSortCols());
      }

      for (Partition partition : prunedParts.getNotDeniedPartns()) {
        if (!checkSortColsAndJoinCols(partition.getSortCols(),
          joinCols,
          sortColumnsFirstTable)) {
          return false;
        }
      }
      return true;
    }

    // Populate the names and order of columns for the first table
    if (pos == 0) {
      sortColumnsFirstTable.addAll(tbl.getSortCols());
    }

    return checkSortColsAndJoinCols(tbl.getSortCols(),
      joinCols,
      sortColumnsFirstTable);
  }
Whether this table is eligible for a sort-merge join.

@param pctx                  parse context
@param op                    map join operator being considered
@param joinTree              join tree being considered
@param alias                 table alias in the join tree being checked
@param pos                   position of the table
@param sortColumnsFirstTable The names and order of the sorted columns for the first table.
                             It is not initialized when pos = 0.
@return
@throws SemanticException
ql/src/java/org/apache/hadoop/hive/ql/optimizer/AbstractSMBJoinProc.java