List<ASTNode> getGroupByForClause(QBParseInfo parseInfo, String dest) throws SemanticException {
    ASTNode selectExpr = parseInfo.getSelForClause(dest);
    Collection<ASTNode> aggregateFunction = parseInfo.getDestToAggregationExprs().get(dest).values();
    if (!(this instanceof CalcitePlanner) && isSelectDistinct(selectExpr) && hasGroupBySibling(selectExpr)) {
      throw new SemanticException("SELECT DISTINCT with GROUP BY is only supported with CBO");
    }

    if (isSelectDistinct(selectExpr) && !hasGroupBySibling(selectExpr) &&
        !isAggregateInSelect(selectExpr, aggregateFunction)) {
      List<ASTNode> result = new ArrayList<ASTNode>(selectExpr.getChildCount());
      for (int i = 0; i < selectExpr.getChildCount(); ++i) {
        if (((ASTNode) selectExpr.getChild(i)).getToken().getType() == HiveParser.QUERY_HINT) {
          continue;
        }
        // table.column AS alias
        ASTNode grpbyExpr = (ASTNode) selectExpr.getChild(i).getChild(0);
        result.add(grpbyExpr);
      }
      return result;
    } else {
      // look for a true GBY
      ASTNode grpByExprs = parseInfo.getGroupByForClause(dest);
      List<ASTNode> result = new ArrayList<ASTNode>(grpByExprs == null ? 0 : grpByExprs.getChildCount());
      if (grpByExprs != null) {
        for (int i = 0; i < grpByExprs.getChildCount(); ++i) {
          ASTNode grpbyExpr = (ASTNode) grpByExprs.getChild(i);
          if (grpbyExpr.getType() != HiveParser.TOK_GROUPING_SETS_EXPRESSION) {
            result.add(grpbyExpr);
          }
        }
      }
      return result;
    }
  }
Returns the GBY, if present;
DISTINCT, if present, will be handled when generating the SELECT.
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java