@SuppressWarnings("nls")
  void parseJoinCondPopulateAlias(QBJoinTree joinTree, ASTNode condn,
                                  List<String> leftAliases, List<String> rightAliases,
                                  List<String> fields,
                                  Map<String, Operator> aliasToOpInfo) throws SemanticException {
    // String[] allAliases = joinTree.getAllAliases();
    switch (condn.getToken().getType()) {
    case HiveParser.TOK_TABLE_OR_COL:
      String tableOrCol = unescapeIdentifier(condn.getChild(0).getText()
          .toLowerCase());
      unparseTranslator.addIdentifierTranslation((ASTNode) condn.getChild(0));
      if (isPresent(joinTree.getLeftAliases(), tableOrCol)) {
        if (!leftAliases.contains(tableOrCol)) {
          leftAliases.add(tableOrCol);
        }
      } else if (isPresent(joinTree.getRightAliases(), tableOrCol)) {
        if (!rightAliases.contains(tableOrCol)) {
          rightAliases.add(tableOrCol);
        }
      } else {
        tableOrCol = findAlias(condn, aliasToOpInfo);
        if (isPresent(joinTree.getLeftAliases(), tableOrCol)) {
          if (!leftAliases.contains(tableOrCol)) {
            leftAliases.add(tableOrCol);
          }
        } else  {
          if (!rightAliases.contains(tableOrCol)) {
            rightAliases.add(tableOrCol);
          }
          if (joinTree.getNoSemiJoin() == false) {
            // if this is a semijoin, we need to add the condition
            joinTree.addRHSSemijoinColumns(tableOrCol, condn);
          }
        }
      }
      break;

    case HiveParser.Identifier:
      // it may be a field name, return the identifier and let the caller decide
      // whether it is or not
      if (fields != null) {
        fields
            .add(unescapeIdentifier(condn.getToken().getText().toLowerCase()));
      }
      unparseTranslator.addIdentifierTranslation(condn);
      break;
    case HiveParser.TOK_NULL:
    case HiveParser.Number:
    case HiveParser.StringLiteral:
    case HiveParser.IntegralLiteral:
    case HiveParser.NumberLiteral:
    case HiveParser.TOK_STRINGLITERALSEQUENCE:
    case HiveParser.TOK_CHARSETLITERAL:
    case HiveParser.KW_TRUE:
    case HiveParser.KW_FALSE:
    case HiveParser.TOK_DATELITERAL:
    case HiveParser.TOK_TIMESTAMPLITERAL:
    case HiveParser.TOK_TIMESTAMPLOCALTZLITERAL:
    case HiveParser.TOK_INTERVAL_DAY_LITERAL:
    case HiveParser.TOK_INTERVAL_DAY_TIME:
    case HiveParser.TOK_INTERVAL_DAY_TIME_LITERAL:
    case HiveParser.TOK_INTERVAL_HOUR_LITERAL:
    case HiveParser.TOK_INTERVAL_MINUTE_LITERAL:
    case HiveParser.TOK_INTERVAL_MONTH_LITERAL:
    case HiveParser.TOK_INTERVAL_SECOND_LITERAL:
    case HiveParser.TOK_INTERVAL_YEAR_LITERAL:
    case HiveParser.TOK_INTERVAL_YEAR_MONTH:
    case HiveParser.TOK_INTERVAL_YEAR_MONTH_LITERAL:
      break;

    case HiveParser.TOK_FUNCTION:
      // check all the arguments
      for (int i = 1; i < condn.getChildCount(); i++) {
        parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(i),
            leftAliases, rightAliases, null, aliasToOpInfo);
      }
      break;

    default:
      // This is an operator - so check whether it is unary or binary operator
      if (condn.getChildCount() == 1) {
        parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(0),
            leftAliases, rightAliases, null, aliasToOpInfo);
      } else if (condn.getChildCount() == 2) {

        List<String> fields1 = null;
        // if it is a dot operator, remember the field name of the rhs of the
        // left semijoin
        if (joinTree.getNoSemiJoin() == false
            && condn.getToken().getType() == HiveParser.DOT) {
          // get the semijoin rhs table name and field name
          fields1 = new ArrayList<String>();
          int rhssize = rightAliases.size();
          parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(0),
              leftAliases, rightAliases, null, aliasToOpInfo);
          String rhsAlias = null;

          if (rightAliases.size() > rhssize) { // the new table is rhs table
            rhsAlias = rightAliases.get(rightAliases.size() - 1);
          }

          parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(1),
              leftAliases, rightAliases, fields1, aliasToOpInfo);
          if (rhsAlias != null && fields1.size() > 0) {
            joinTree.addRHSSemijoinColumns(rhsAlias, condn);
          }
        } else {
          parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(0),
              leftAliases, rightAliases, null, aliasToOpInfo);
          parseJoinCondPopulateAlias(joinTree, (ASTNode) condn.getChild(1),
              leftAliases, rightAliases, fields1, aliasToOpInfo);
        }
      } else {
        throw new SemanticException(condn.toStringTree() + " encountered with "
            + condn.getChildCount() + " children");
      }
      break;
    }
  }
Gets the staging directory where MR files will be stored temporary.
It walks through the QB plan to find the correct location where save temporary files. This
temporary location (or staging directory) may be created inside encrypted tables locations for
security reasons. If the QB has read-only tables, then the older scratch directory will be used,
or a permission error will be thrown if the requested query table is encrypted and the old scratch
directory is not.

@param qb The QB object that contains a list of all table locations.
@return The path to the staging directory.
@throws HiveException If an error occurs while identifying the correct staging location.
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java