private void registerQuery()

in flink-table/flink-table-planner/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java [2769:3019]


    private void registerQuery(
            SqlValidatorScope parentScope,
            @Nullable SqlValidatorScope usingScope,
            SqlNode node,
            SqlNode enclosingNode,
            @Nullable String alias,
            boolean forceNullable,
            boolean checkUpdate) {
        requireNonNull(node, "node");
        requireNonNull(enclosingNode, "enclosingNode");
        Preconditions.checkArgument(usingScope == null || alias != null);

        SqlCall call;
        List<SqlNode> operands;
        switch (node.getKind()) {
            case SELECT:
                final SqlSelect select = (SqlSelect) node;
                final SelectNamespace selectNs = createSelectNamespace(select, enclosingNode);
                registerNamespace(usingScope, alias, selectNs, forceNullable);
                final SqlValidatorScope windowParentScope =
                        (usingScope != null) ? usingScope : parentScope;
                SelectScope selectScope = new SelectScope(parentScope, windowParentScope, select);
                scopes.put(select, selectScope);

                // Start by registering the WHERE clause
                clauseScopes.put(IdPair.of(select, Clause.WHERE), selectScope);
                registerOperandSubQueries(selectScope, select, SqlSelect.WHERE_OPERAND);

                // Register subqueries in the QUALIFY clause
                registerOperandSubQueries(selectScope, select, SqlSelect.QUALIFY_OPERAND);

                // Register FROM with the inherited scope 'parentScope', not
                // 'selectScope', otherwise tables in the FROM clause would be
                // able to see each other.
                final SqlNode from = select.getFrom();
                if (from != null) {
                    final SqlNode newFrom =
                            registerFrom(
                                    parentScope,
                                    selectScope,
                                    true,
                                    from,
                                    from,
                                    null,
                                    null,
                                    false,
                                    false);
                    if (newFrom != from) {
                        select.setFrom(newFrom);
                    }
                }

                // If this is an aggregating query, the SELECT list and HAVING
                // clause use a different scope, where you can only reference
                // columns which are in the GROUP BY clause.
                SqlValidatorScope aggScope = selectScope;
                if (isAggregate(select)) {
                    aggScope = new AggregatingSelectScope(selectScope, select, false);
                    clauseScopes.put(IdPair.of(select, Clause.SELECT), aggScope);
                } else {
                    clauseScopes.put(IdPair.of(select, Clause.SELECT), selectScope);
                }
                if (select.getGroup() != null) {
                    GroupByScope groupByScope =
                            new GroupByScope(selectScope, select.getGroup(), select);
                    clauseScopes.put(IdPair.of(select, Clause.GROUP_BY), groupByScope);
                    registerSubQueries(groupByScope, select.getGroup());
                }
                registerOperandSubQueries(aggScope, select, SqlSelect.HAVING_OPERAND);
                registerSubQueries(aggScope, SqlNonNullableAccessors.getSelectList(select));
                final SqlNodeList orderList = select.getOrderList();
                if (orderList != null) {
                    // If the query is 'SELECT DISTINCT', restrict the columns
                    // available to the ORDER BY clause.
                    if (select.isDistinct()) {
                        aggScope = new AggregatingSelectScope(selectScope, select, true);
                    }
                    OrderByScope orderScope = new OrderByScope(aggScope, orderList, select);
                    clauseScopes.put(IdPair.of(select, Clause.ORDER), orderScope);
                    registerSubQueries(orderScope, orderList);

                    if (!isAggregate(select)) {
                        // Since this is not an aggregating query,
                        // there cannot be any aggregates in the ORDER BY clause.
                        SqlNode agg = aggFinder.findAgg(orderList);
                        if (agg != null) {
                            throw newValidationError(agg, RESOURCE.aggregateIllegalInOrderBy());
                        }
                    }
                }
                break;

            case INTERSECT:
                validateFeature(RESOURCE.sQLFeature_F302(), node.getParserPosition());
                registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
                break;

            case EXCEPT:
                validateFeature(RESOURCE.sQLFeature_E071_03(), node.getParserPosition());
                registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
                break;

            case UNION:
                registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
                break;

            case WITH:
                registerWith(
                        parentScope,
                        usingScope,
                        (SqlWith) node,
                        enclosingNode,
                        alias,
                        forceNullable,
                        checkUpdate);
                break;

            case VALUES:
                call = (SqlCall) node;
                scopes.put(call, parentScope);
                final TableConstructorNamespace tableConstructorNamespace =
                        new TableConstructorNamespace(this, call, parentScope, enclosingNode);
                registerNamespace(usingScope, alias, tableConstructorNamespace, forceNullable);
                operands = call.getOperandList();
                for (int i = 0; i < operands.size(); ++i) {
                    assert operands.get(i).getKind() == SqlKind.ROW;

                    // FIXME jvs 9-Feb-2005:  Correlation should
                    // be illegal in these sub-queries.  Same goes for
                    // any non-lateral SELECT in the FROM list.
                    registerOperandSubQueries(parentScope, call, i);
                }
                break;

            case INSERT:
                SqlInsert insertCall = (SqlInsert) node;
                InsertNamespace insertNs =
                        new InsertNamespace(this, insertCall, enclosingNode, parentScope);
                registerNamespace(usingScope, null, insertNs, forceNullable);
                registerQuery(
                        parentScope,
                        usingScope,
                        insertCall.getSource(),
                        enclosingNode,
                        null,
                        false);
                break;

            case DELETE:
                SqlDelete deleteCall = (SqlDelete) node;
                DeleteNamespace deleteNs =
                        new DeleteNamespace(this, deleteCall, enclosingNode, parentScope);
                registerNamespace(usingScope, null, deleteNs, forceNullable);
                registerQuery(
                        parentScope,
                        usingScope,
                        SqlNonNullableAccessors.getSourceSelect(deleteCall),
                        enclosingNode,
                        null,
                        false);
                break;

            case UPDATE:
                if (checkUpdate) {
                    validateFeature(RESOURCE.sQLFeature_E101_03(), node.getParserPosition());
                }
                SqlUpdate updateCall = (SqlUpdate) node;
                UpdateNamespace updateNs =
                        new UpdateNamespace(this, updateCall, enclosingNode, parentScope);
                registerNamespace(usingScope, null, updateNs, forceNullable);
                registerQuery(
                        parentScope,
                        usingScope,
                        SqlNonNullableAccessors.getSourceSelect(updateCall),
                        enclosingNode,
                        null,
                        false);
                break;

            case MERGE:
                validateFeature(RESOURCE.sQLFeature_F312(), node.getParserPosition());
                SqlMerge mergeCall = (SqlMerge) node;
                MergeNamespace mergeNs =
                        new MergeNamespace(this, mergeCall, enclosingNode, parentScope);
                registerNamespace(usingScope, null, mergeNs, forceNullable);
                registerQuery(
                        parentScope,
                        usingScope,
                        SqlNonNullableAccessors.getSourceSelect(mergeCall),
                        enclosingNode,
                        null,
                        false);

                // update call can reference either the source table reference
                // or the target table, so set its parent scope to the merge's
                // source select; when validating the update, skip the feature
                // validation check
                SqlUpdate mergeUpdateCall = mergeCall.getUpdateCall();
                if (mergeUpdateCall != null) {
                    registerQuery(
                            getScope(
                                    SqlNonNullableAccessors.getSourceSelect(mergeCall),
                                    Clause.WHERE),
                            null,
                            mergeUpdateCall,
                            enclosingNode,
                            null,
                            false,
                            false);
                }
                SqlInsert mergeInsertCall = mergeCall.getInsertCall();
                if (mergeInsertCall != null) {
                    registerQuery(parentScope, null, mergeInsertCall, enclosingNode, null, false);
                }
                break;

            case UNNEST:
                call = (SqlCall) node;
                final UnnestNamespace unnestNs =
                        new UnnestNamespace(this, call, parentScope, enclosingNode);
                registerNamespace(usingScope, alias, unnestNs, forceNullable);
                registerOperandSubQueries(parentScope, call, 0);
                scopes.put(node, parentScope);
                break;
            case OTHER_FUNCTION:
                call = (SqlCall) node;
                ProcedureNamespace procNs =
                        new ProcedureNamespace(this, parentScope, call, enclosingNode);
                registerNamespace(usingScope, alias, procNs, forceNullable);
                registerSubQueries(parentScope, call);
                break;

            case MULTISET_QUERY_CONSTRUCTOR:
            case MULTISET_VALUE_CONSTRUCTOR:
                validateFeature(RESOURCE.sQLFeature_S271(), node.getParserPosition());
                call = (SqlCall) node;
                CollectScope cs = new CollectScope(parentScope, usingScope, call);
                final CollectNamespace tableConstructorNs =
                        new CollectNamespace(call, cs, enclosingNode);
                final String alias2 = SqlValidatorUtil.alias(node, nextGeneratedId++);
                registerNamespace(usingScope, alias2, tableConstructorNs, forceNullable);
                operands = call.getOperandList();
                for (int i = 0; i < operands.size(); i++) {
                    registerOperandSubQueries(parentScope, call, i);
                }
                break;

            default:
                throw Util.unexpected(node.getKind());
        }
    }