private RelNode genGBHavingLogicalPlan(QB qb, RelNode srcRel) throws SemanticException {
      RelNode gbFilter = null;
      QBParseInfo qbp = getQBParseInfo(qb);
      String destClauseName = qbp.getClauseNames().iterator().next();
      ASTNode havingClause = qbp.getHavingForClause(qbp.getClauseNames().iterator().next());

      if (havingClause != null) {
        if (!(srcRel instanceof HiveAggregate)) {
          // ill-formed query like select * from t1 having c1 > 0;
          throw new CalciteSemanticException("Having clause without any group-by.",
              UnsupportedFeature.Having_clause_without_any_groupby);
        }
        ASTNode targetNode = (ASTNode) havingClause.getChild(0);
        QBParseInfo qbPI = qb.getParseInfo();
        Map<ASTNode, String> exprToAlias = qbPI.getAllExprToColumnAlias();
        RowResolver inputRR = relToHiveRR.get(srcRel);
        inputRR.putAll(exprToAlias);
        if (!qbp.getDestToGroupBy().isEmpty()) {
          final boolean cubeRollupGrpSetPresent = (!qbp.getDestRollups().isEmpty()
                  || !qbp.getDestGroupingSets().isEmpty() || !qbp.getDestCubes().isEmpty());
          // Special handling of grouping function
          targetNode = rewriteGroupingFunctionAST(getGroupByForClause(qbp, destClauseName), targetNode,
              !cubeRollupGrpSetPresent);
        }
        gbFilter = genFilterRelNode(qb, targetNode, srcRel, null, null, true);
      }

      return gbFilter;
    }
NOTE: there can only be one select caluse since we don't handle multi destination insert.
@param isAllColRefRewrite
         when it is true, it means that it is called from group by *, where we use
         genSelectLogicalPlan to rewrite *
@return RelNode: the select relnode RowResolver: i.e., originalRR, the RR after select when there is an order by.
ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java