public void analyze()

in fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java [493:785]


    public void analyze(Analyzer analyzer) throws UserException {
        if (isAnalyzed()) {
            return;
        }
        super.analyze(analyzer);

        if (mvSMap.size() != 0) {
            mvSMap.useNotCheckDescIdEquals();
            for (TableRef tableRef : getTableRefs()) {
                if (tableRef.getOnClause() == null) {
                    continue;
                }
                try {
                    Expr expr = tableRef.getOnClause();
                    Expr originalExpr = expr.clone().substituteImpl(mvSMap, null, analyzer);
                    originalExpr.reset();
                    tableRef.setOnClause(originalExpr);
                } catch (Exception e) {
                    LOG.warn("", e);
                }
            }
        }
        fromClause.setNeedToSql(needToSql);
        fromClause.analyze(analyzer);

        if (!isForbiddenMVRewrite()) {
            Boolean haveMv = false;
            for (TableRef tbl : fromClause) {
                if (!tbl.haveDesc() || !(tbl.getTable() instanceof OlapTable)) {
                    continue;
                }
                OlapTable olapTable = (OlapTable) tbl.getTable();
                if (olapTable.getIndexIds().size() != 1) {
                    haveMv = true;
                }
            }

            if (!haveMv) {
                forbiddenMVRewrite();
            }
        }

        // Generate !empty() predicates to filter out empty collections.
        // Skip this step when analyzing a WITH-clause because CollectionTableRefs
        // do not register collection slots in their parent in that context
        // (see CollectionTableRef.analyze()).
        if (!analyzer.isWithClause()) {
            registerIsNotEmptyPredicates(analyzer);
        }
        // populate selectListExprs, aliasSMap, groupingSmap and colNames
        if (selectList.isExcept()) {
            if (needToSql) {
                originalExpr = new ArrayList<>();
            }
            List<SelectListItem> items = selectList.getItems();
            TableName tblName = items.get(0).getTblName();
            if (tblName == null) {
                expandStar(analyzer);
            } else {
                expandStar(analyzer, tblName);
            }

            // get excepted cols
            ArrayList<String> exceptCols = new ArrayList<>();
            for (SelectListItem item : items) {
                Expr expr = item.getExpr();
                if (!(item.getExpr() instanceof SlotRef)) {
                    throw new AnalysisException("`SELECT * EXCEPT` only supports column name.");
                }
                exceptCols.add(expr.toColumnLabel());
            }
            // remove excepted columns
            resultExprs.removeIf(expr -> exceptCols.contains(expr.toColumnLabel()));
            colLabels.removeIf(exceptCols::contains);
            originalExpr = new ArrayList<>(resultExprs);
        } else {
            if (needToSql) {
                originalExpr = new ArrayList<>();
            }
            List<SelectListItem> items = selectList.getItems();
            for (int i = 0; i < items.size(); i++) {
                SelectListItem item = items.get(i);
                if (item.isStar()) {
                    TableName tblName = item.getTblName();
                    if (tblName == null) {
                        expandStar(analyzer);
                    } else {
                        expandStar(analyzer, tblName);
                    }
                } else {
                    // save originalExpr before being analyzed
                    // because analyze may change the expr by adding cast or some other stuff
                    if (needToSql) {
                        originalExpr.add(item.getExpr().clone());
                    }
                    // Analyze the resultExpr before generating a label to ensure enforcement
                    // of expr child and depth limits (toColumn() label may call toSql()).
                    item.getExpr().analyze(analyzer);
                    if (!(item.getExpr() instanceof CaseExpr)
                            && item.getExpr().contains(Predicates.instanceOf(Subquery.class))) {
                        throw new AnalysisException("Subquery is not supported in the select list.");
                    }
                    resultExprs.add(rewriteQueryExprByMvColumnExpr(item.getExpr(), analyzer));
                    String columnLabel = null;
                    Class<? extends StatementBase> statementClazz = analyzer.getRootStatementClazz();
                    if (statementClazz != null
                            && (!QueryStmt.class.isAssignableFrom(statementClazz) || hasOutFileClause())) {
                        // Infer column name when item is expr
                        columnLabel = item.toColumnLabel(i);
                    }
                    if (columnLabel == null) {
                        // use original column label
                        columnLabel = item.toColumnLabel();
                    }
                    SlotRef aliasRef = new SlotRef(null, columnLabel);
                    Expr existingAliasExpr = aliasSMap.get(aliasRef);
                    if (existingAliasExpr != null && !existingAliasExpr.equals(item.getExpr())) {
                        // If we have already seen this alias, it refers to more than one column and
                        // therefore is ambiguous.
                        ambiguousAliasList.add(aliasRef);
                    }
                    aliasSMap.put(aliasRef, item.getExpr().clone());
                    colLabels.add(columnLabel);
                    subColPath.add(item.toSubColumnLabels());
                }
            }
        }
        if (groupByClause != null && groupByClause.isGroupByExtension()) {
            ArrayList<Expr> aggFnExprList = new ArrayList<>();
            for (SelectListItem item : selectList.getItems()) {
                aggFnExprList.clear();
                getAggregateFnExpr(item.getExpr(), aggFnExprList);
                for (Expr aggFnExpr : aggFnExprList) {
                    for (Expr expr : groupByClause.getGroupingExprs()) {
                        if (aggFnExpr.contains(expr)) {
                            throw new AnalysisException("column: " + expr.toSql() + " cannot both in select "
                                    + "list and aggregate functions when using GROUPING SETS/CUBE/ROLLUP, "
                                    + "please use union instead.");
                        }
                    }
                }
            }
            groupingInfo = new GroupingInfo(analyzer, groupByClause);
            groupingInfo.substituteGroupingFn(resultExprs, analyzer);
        } else {
            for (Expr expr : resultExprs) {
                if (checkGroupingFn(expr)) {
                    throw new AnalysisException(
                            "cannot use GROUPING functions without [grouping sets|rollup|cube] "
                                    + "clause or grouping sets only have one element.");
                }
            }
        }

        if (valueList != null) {
            if (!fromInsert) {
                valueList.analyzeForSelect(analyzer);
            }
            for (Expr expr : valueList.getFirstRow()) {
                if (expr instanceof DefaultValueExpr) {
                    resultExprs.add(new StringLiteral(DEFAULT_VALUE));
                } else {
                    resultExprs.add(rewriteQueryExprByMvColumnExpr(expr, analyzer));
                }
                colLabels.add("col_" + colLabels.size());
                subColPath.add(expr.toSubColumnLabel());
            }
        }

        // analyze selectListExprs
        Expr.analyze(resultExprs, analyzer);
        if (TreeNode.contains(resultExprs, AnalyticExpr.class)) {
            if (fromClause.isEmpty()) {
                throw new AnalysisException("Analytic expressions require FROM clause.");
            }

            // do this here, not after analyzeAggregation(), otherwise the AnalyticExprs
            // will get substituted away
            if (selectList.isDistinct()) {
                throw new AnalysisException(
                        "cannot combine SELECT DISTINCT with analytic functions");
            }
        }

        if (whereClause != null) {
            whereClauseRewrite();
            if (checkGroupingFn(whereClause)) {
                throw new AnalysisException("grouping operations are not allowed in WHERE.");
            }
            whereClause.analyze(analyzer);
            if (whereClause.containsAggregate()) {
                ErrorReport.reportAnalysisException(ErrorCode.ERR_INVALID_GROUP_FUNC_USE);
            }

            whereClause.checkReturnsBool("WHERE clause", false);
            Expr e = whereClause.findFirstOf(AnalyticExpr.class);
            if (e != null) {
                throw new AnalysisException(
                        "WHERE clause must not contain analytic expressions: " + e.toSql());
            }
            analyzer.registerConjuncts(whereClause, false, getTableRefIds());
        }

        if (whereClause != null) {
            whereClause = rewriteQueryExprByMvColumnExpr(whereClause, analyzer);
        }

        for (TableRef tableRef : getTableRefs()) {
            if (tableRef.getOnClause() == null) {
                continue;
            }
            tableRef.setOnClause(rewriteQueryExprByMvColumnExpr(tableRef.getOnClause(), analyzer));
        }

        createSortInfo(analyzer);
        if (sortInfo != null && CollectionUtils.isNotEmpty(sortInfo.getOrderingExprs())) {
            if (groupingInfo != null) {
                // List of executable exprs in select clause has been substituted, only the unique expr in Ordering
                // exprs needs to be substituted.
                // Otherwise, if substitute twice for `Grouping Func Expr`, a null pointer will be reported.
                List<Expr> orderingExprNotInSelect = sortInfo.getOrderingExprs().stream()
                        .filter(item -> !resultExprs.contains(item)).collect(Collectors.toList());
                groupingInfo.substituteGroupingFn(orderingExprNotInSelect, analyzer);
            }
        }
        analyzeAggregation(analyzer);
        createAnalyticInfo(analyzer);
        eliminatingSortNode();
        checkAndSetPointQuery();
        if (checkEnableTwoPhaseRead(analyzer)) {
            // If optimize enabled, we try our best to read less columns from ScanNode,
            // here we analyze conjunct exprs and ordering exprs before resultExprs,
            // rest of resultExprs will be marked as `INVALID`, such columns will
            // be prevent from reading from ScanNode.Those columns will be finally
            // read by the second fetch phase
            isTwoPhaseOptEnabled = true;
            if (LOG.isDebugEnabled()) {
                LOG.debug("two phase read optimize enabled");
            }
            // Expr.analyze(resultExprs, analyzer);
            Set<SlotRef> resultSlots = Sets.newHashSet();
            Set<SlotRef> orderingSlots = Sets.newHashSet();
            Set<SlotRef> conjuntSlots = Sets.newHashSet();
            TreeNode.collect(resultExprs, Predicates.instanceOf(SlotRef.class), resultSlots);
            if (sortInfo != null) {
                TreeNode.collect(sortInfo.getOrderingExprs(),
                        Predicates.instanceOf(SlotRef.class), orderingSlots);
            }
            if (whereClause != null) {
                whereClause.collect(SlotRef.class, conjuntSlots);
            }

            if (havingClauseAfterAnalyzed != null) {
                havingClauseAfterAnalyzed.collect(SlotRef.class, conjuntSlots);
            }

            resultSlots.removeAll(orderingSlots);
            resultSlots.removeAll(conjuntSlots);
            // reset slots need to do fetch column
            for (SlotRef slot : resultSlots) {
                // invalid slots will be pruned from reading from ScanNode
                slot.setNeedMaterialize(false);
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("resultsSlots {}", resultSlots);
                LOG.debug("orderingSlots {}", orderingSlots);
                LOG.debug("conjuntSlots {}", conjuntSlots);
            }
        }
        if (evaluateOrderBy) {
            createSortTupleInfo(analyzer);
        }

        if (needToSql) {
            sqlString = toSql();
        }

        resolveInlineViewRefs(analyzer);

        if (analyzer.hasEmptySpjResultSet() && aggInfo == null) {
            analyzer.setHasEmptyResultSet();
        }

        if (aggInfo != null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("post-analysis " + aggInfo.debugString());
            }
        }
        if (hasOutFileClause()) {
            outFileClause.analyze(analyzer, resultExprs, colLabels);
        }
    }