@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
                          Object... nodeOutputs) throws SemanticException {

      TypeCheckCtx ctx = (TypeCheckCtx) procCtx;

      T desc = processGByExpr(nd, procCtx);
      if (desc != null) {
        // Here we know nd represents a group by expression.

        // During the DFS traversal of the AST, a descendant of nd likely set an
        // error because a sub-tree of nd is unlikely to also be a group by
        // expression. For example, in a query such as
        // SELECT *concat(key)* FROM src GROUP BY concat(key), 'key' will be
        // processed before 'concat(key)' and since 'key' is not a group by
        // expression, an error will be set in ctx by ColumnExprProcessor.

        // We can clear the global error when we see that it was set in a
        // descendant node of a group by expression because
        // processGByExpr() returns a ExprNodeDesc that effectively ignores
        // its children. Although the error can be set multiple times by
        // descendant nodes, DFS traversal ensures that the error only needs to
        // be cleared once. Also, for a case like
        // SELECT concat(value, concat(value))... the logic still works as the
        // error is only set with the first 'value'; all node processors quit
        // early if the global error is set.

        if (isDescendant(nd, ctx.getErrorSrcNode())) {
          ctx.setError(null, null);
        }
        return desc;
      }

      if (ctx.getError() != null) {
        return null;
      }

      ASTNode expr = (ASTNode) nd;

      /*
       * A Windowing specification get added as a child to a UDAF invocation to distinguish it
       * from similar UDAFs but on different windows.
       * The UDAF is translated to a WindowFunction invocation in the PTFTranslator.
       * So here we just return null for tokens that appear in a Window Specification.
       * When the traversal reaches up to the UDAF invocation its ExprNodeDesc is build using the
       * ColumnInfo in the InputRR. This is similar to how UDAFs are handled in Select lists.
       * The difference is that there is translation for Window related tokens, so we just
       * return null;
       */
      if (WINDOWING_TOKENS.contains(expr.getType())) {
        if (!ctx.getallowWindowing()) {
          throw new SemanticException(SemanticAnalyzer.generateErrorMessage(expr,
              ErrorMsg.INVALID_FUNCTION.getMsg("Windowing is not supported in the context")));
        }

        return null;
      }

      if (expr.getType() == HiveParser.TOK_SUBQUERY_OP || expr.getType() == HiveParser.TOK_QUERY) {
        return null;
      }

      if (expr.getType() == HiveParser.TOK_TABNAME) {
        return null;
      }

      if (expr.getType() == HiveParser.TOK_ALLCOLREF) {
        if (!ctx.getallowAllColRef()) {
          throw new SemanticException(SemanticAnalyzer.generateErrorMessage(expr,
              ErrorMsg.INVALID_COLUMN
                  .getMsg("All column reference is not supported in the context")));
        }

        RowResolver input = ctx.getInputRR();
        T columnList = exprFactory.createExprsListExpr();
        assert expr.getChildCount() <= 1;
        if (expr.getChildCount() == 1) {
          // table aliased (select a.*, for example)
          ASTNode child = (ASTNode) expr.getChild(0);
          assert child.getType() == HiveParser.TOK_TABNAME;
          assert child.getChildCount() == 1;
          String tableAlias = BaseSemanticAnalyzer.unescapeIdentifier(child.getChild(0).getText());
          Map<String, ColumnInfo> columns = input.getFieldMap(tableAlias);
          if (columns == null) {
            throw new SemanticException(ASTErrorUtils.getMsg(
                ErrorMsg.INVALID_TABLE_ALIAS.getMsg(), child));
          }
          for (Map.Entry<String, ColumnInfo> colMap : columns.entrySet()) {
            ColumnInfo colInfo = colMap.getValue();
            if (!colInfo.getIsVirtualCol()) {
              exprFactory.addExprToExprsList(columnList, exprFactory.toExpr(colInfo, input, 0));
            }
          }
        } else {
          // all columns (select *, for example)
          for (ColumnInfo colInfo : input.getColumnInfos()) {
            if (!colInfo.getIsVirtualCol()) {
              exprFactory.addExprToExprsList(columnList, exprFactory.toExpr(colInfo, input, 0));
            }
          }
        }
        return columnList;
      }

      // If the first child is a TOK_TABLE_OR_COL, and nodeOutput[0] is NULL,
      // and the operator is a DOT, then it's a table column reference.
      if (expr.getType() == HiveParser.DOT
          && expr.getChild(0).getType() == HiveParser.TOK_TABLE_OR_COL
          && nodeOutputs[0] == null) {
        return processQualifiedColRef(ctx, expr, nodeOutputs);
      }

      // Return nulls for conversion operators
      if (CONVERSION_FUNCTION_TEXT_MAP.keySet().contains(expr.getType())
          || expr.getToken().getType() == HiveParser.CharSetName
          || expr.getToken().getType() == HiveParser.CharSetLiteral
          || expr.getType() == HiveParser.TOK_TABCOL
          || expr.getType() == HiveParser.TOK_TABCOLLIST) {
        return null;
      }

      boolean isFunction = (expr.getType() == HiveParser.TOK_FUNCTION ||
          expr.getType() == HiveParser.TOK_FUNCTIONSTAR ||
          expr.getType() == HiveParser.TOK_FUNCTIONDI);

      if (!ctx.getAllowDistinctFunctions() && expr.getType() == HiveParser.TOK_FUNCTIONDI) {
        throw new SemanticException(
            SemanticAnalyzer.generateErrorMessage(expr, ErrorMsg.DISTINCT_NOT_SUPPORTED.getMsg()));
      }

      // Create all children
      int childrenBegin = (isFunction ? 1 : 0);
      List<T> children = new ArrayList<T>(
          expr.getChildCount() - childrenBegin);
      for (int ci = childrenBegin; ci < expr.getChildCount(); ci++) {
        if (nodeOutputs[ci] == ALIAS_PLACEHOLDER) {
          continue;
        }

        T nodeOutput = (T) nodeOutputs[ci];
        if (exprFactory.isExprsListExpr(nodeOutput)) {
          children.addAll(exprFactory.getExprChildren(nodeOutput));
        } else {
          children.add(nodeOutput);
        }
      }

      if (expr.getType() == HiveParser.TOK_FUNCTIONSTAR) {
        if (!ctx.getallowFunctionStar()) {
          throw new SemanticException(SemanticAnalyzer.generateErrorMessage(expr,
              ErrorMsg.INVALID_COLUMN
                  .getMsg(".* reference is not supported in the context")));
        }

        RowResolver input = ctx.getInputRR();
        for (ColumnInfo colInfo : input.getColumnInfos()) {
          if (!colInfo.getIsVirtualCol()) {
            children.add(exprFactory.toExpr(colInfo, input, 0));
          }
        }
      }

      // If any of the children contains null, then return a null
      // this is a hack for now to handle the group by case
      if (children.contains(null)) {
        List<String> possibleColumnNames = getReferenceableColumnAliases(ctx);
        String reason = String.format("(possible column names are: %s)",
            StringUtils.join(possibleColumnNames, ", "));
        ctx.setError(ASTErrorUtils.getMsg(
            ErrorMsg.INVALID_COLUMN.getMsg(), expr.getChild(0), reason),
            expr);
        return null;
      }

      // Create function desc
      try {
        return getXpathOrFuncExprNodeDesc(expr, isFunction, children, ctx);
      } catch (UDFArgumentTypeException e) {
        throw new SemanticException(ASTErrorUtils.getMsg(
            ErrorMsg.INVALID_ARGUMENT_TYPE.getMsg(),
            expr.getChild(childrenBegin + e.getArgumentId()), e.getMessage()), e);
      } catch (UDFArgumentLengthException e) {
        throw new SemanticException(ASTErrorUtils.getMsg(
            ErrorMsg.INVALID_ARGUMENT_LENGTH.getMsg(),
            expr, e.getMessage()), e);
      } catch (UDFArgumentException e) {
        throw new SemanticException(ASTErrorUtils.getMsg(
            ErrorMsg.INVALID_ARGUMENT.getMsg(),
            expr, e.getMessage()), e);
      }
    }
Returns true if des is a descendant of ans (ancestor)
ql/src/java/org/apache/hadoop/hive/ql/parse/type/TypeCheckProcFactory.java