private SqlNode registerFrom()

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


    private SqlNode registerFrom(
            SqlValidatorScope parentScope,
            SqlValidatorScope usingScope,
            boolean register,
            final SqlNode node,
            SqlNode enclosingNode,
            @Nullable String alias,
            @Nullable SqlNodeList extendList,
            boolean forceNullable,
            final boolean lateral) {
        final SqlKind kind = node.getKind();

        SqlNode expr;
        SqlNode newExpr;

        // Add an alias if necessary.
        SqlNode newNode = node;
        if (alias == null) {
            switch (kind) {
                case IDENTIFIER:
                case OVER:
                    alias = SqlValidatorUtil.alias(node);
                    if (alias == null) {
                        alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
                    }
                    if (config.identifierExpansion()) {
                        newNode = SqlValidatorUtil.addAlias(node, alias);
                    }
                    break;

                case SELECT:
                case UNION:
                case INTERSECT:
                case EXCEPT:
                case VALUES:
                case UNNEST:
                case OTHER_FUNCTION:
                case COLLECTION_TABLE:
                case PIVOT:
                case UNPIVOT:
                case MATCH_RECOGNIZE:

                    // give this anonymous construct a name since later
                    // query processing stages rely on it
                    alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
                    if (config.identifierExpansion()) {
                        // Since we're expanding identifiers, we should make the
                        // aliases explicit too, otherwise the expanded query
                        // will not be consistent if we convert back to SQL, e.g.
                        // "select EXPR$1.EXPR$2 from values (1)".
                        newNode = SqlValidatorUtil.addAlias(node, alias);
                    }
                    break;
                default:
                    break;
            }
        }

        if (lateral) {
            SqlValidatorScope s = usingScope;
            while (s instanceof JoinScope) {
                s = ((JoinScope) s).getUsingScope();
            }
            final SqlNode node2 = s != null ? s.getNode() : node;
            final TableScope tableScope = new TableScope(parentScope, node2);
            if (usingScope instanceof ListScope) {
                for (ScopeChild child : ((ListScope) usingScope).children) {
                    tableScope.addChild(child.namespace, child.name, child.nullable);
                }
            }
            parentScope = tableScope;
        }

        SqlCall call;
        SqlNode operand;
        SqlNode newOperand;

        switch (kind) {
            case AS:
                call = (SqlCall) node;
                if (alias == null) {
                    alias = String.valueOf(call.operand(1));
                }
                expr = call.operand(0);
                final boolean needAliasNamespace =
                        call.operandCount() > 2
                                || expr.getKind() == SqlKind.VALUES
                                || expr.getKind() == SqlKind.UNNEST;
                newExpr =
                        registerFrom(
                                parentScope,
                                usingScope,
                                !needAliasNamespace,
                                expr,
                                enclosingNode,
                                alias,
                                extendList,
                                forceNullable,
                                lateral);
                if (newExpr != expr) {
                    call.setOperand(0, newExpr);
                }

                // If alias has a column list, introduce a namespace to translate
                // column names. We skipped registering it just now.
                if (needAliasNamespace) {
                    registerNamespace(
                            usingScope,
                            alias,
                            new AliasNamespace(this, call, enclosingNode),
                            forceNullable);
                }
                return node;

            case MATCH_RECOGNIZE:
                registerMatchRecognize(
                        parentScope,
                        usingScope,
                        (SqlMatchRecognize) node,
                        enclosingNode,
                        alias,
                        forceNullable);
                return node;

            case PIVOT:
                registerPivot(
                        parentScope,
                        usingScope,
                        (SqlPivot) node,
                        enclosingNode,
                        alias,
                        forceNullable);
                return node;

            case UNPIVOT:
                registerUnpivot(
                        parentScope,
                        usingScope,
                        (SqlUnpivot) node,
                        enclosingNode,
                        alias,
                        forceNullable);
                return node;

            case TABLESAMPLE:
                call = (SqlCall) node;
                expr = call.operand(0);
                newExpr =
                        registerFrom(
                                parentScope,
                                usingScope,
                                true,
                                expr,
                                enclosingNode,
                                alias,
                                extendList,
                                forceNullable,
                                lateral);
                if (newExpr != expr) {
                    call.setOperand(0, newExpr);
                }
                return node;

            case JOIN:
                final SqlJoin join = (SqlJoin) node;
                final JoinScope joinScope = new JoinScope(parentScope, usingScope, join);
                scopes.put(join, joinScope);
                final SqlNode left = join.getLeft();
                final SqlNode right = join.getRight();
                boolean forceLeftNullable = forceNullable;
                boolean forceRightNullable = forceNullable;
                switch (join.getJoinType()) {
                    case LEFT:
                        forceRightNullable = true;
                        break;
                    case RIGHT:
                        forceLeftNullable = true;
                        break;
                    case FULL:
                        forceLeftNullable = true;
                        forceRightNullable = true;
                        break;
                    default:
                        break;
                }
                final SqlNode newLeft =
                        registerFrom(
                                parentScope,
                                joinScope,
                                true,
                                left,
                                left,
                                null,
                                null,
                                forceLeftNullable,
                                lateral);
                if (newLeft != left) {
                    join.setLeft(newLeft);
                }
                final SqlNode newRight =
                        registerFrom(
                                parentScope,
                                joinScope,
                                true,
                                right,
                                right,
                                null,
                                null,
                                forceRightNullable,
                                lateral);
                if (newRight != right) {
                    join.setRight(newRight);
                }
                registerSubQueries(joinScope, join.getCondition());
                final JoinNamespace joinNamespace = new JoinNamespace(this, join);
                registerNamespace(null, null, joinNamespace, forceNullable);
                return join;

            case IDENTIFIER:
                final SqlIdentifier id = (SqlIdentifier) node;
                final IdentifierNamespace newNs =
                        new IdentifierNamespace(this, id, extendList, enclosingNode, parentScope);
                registerNamespace(register ? usingScope : null, alias, newNs, forceNullable);
                if (tableScope == null) {
                    tableScope = new TableScope(parentScope, node);
                }
                tableScope.addChild(newNs, requireNonNull(alias, "alias"), forceNullable);
                if (extendList != null && extendList.size() != 0) {
                    return enclosingNode;
                }
                return newNode;

            case LATERAL:
                return registerFrom(
                        parentScope,
                        usingScope,
                        register,
                        ((SqlCall) node).operand(0),
                        enclosingNode,
                        alias,
                        extendList,
                        forceNullable,
                        true);

            case COLLECTION_TABLE:
                call = (SqlCall) node;
                operand = call.operand(0);
                newOperand =
                        registerFrom(
                                parentScope,
                                usingScope,
                                register,
                                operand,
                                enclosingNode,
                                alias,
                                extendList,
                                forceNullable,
                                lateral);
                if (newOperand != operand) {
                    call.setOperand(0, newOperand);
                }
                // If the operator is SqlWindowTableFunction, restricts the scope as
                // its first operand's (the table) scope.
                if (operand instanceof SqlBasicCall) {
                    final SqlBasicCall call1 = (SqlBasicCall) operand;
                    final SqlOperator op = call1.getOperator();
                    if (op instanceof SqlWindowTableFunction
                            && call1.operand(0).getKind() == SqlKind.SELECT) {
                        scopes.put(node, getSelectScope(call1.operand(0)));
                        return newNode;
                    }
                }
                // Put the usingScope which can be a JoinScope
                // or a SelectScope, in order to see the left items
                // of the JOIN tree.
                scopes.put(node, usingScope);
                return newNode;

            case UNNEST:
                if (!lateral) {
                    return registerFrom(
                            parentScope,
                            usingScope,
                            register,
                            node,
                            enclosingNode,
                            alias,
                            extendList,
                            forceNullable,
                            true);
                }
            // fall through
            case SELECT:
            case UNION:
            case INTERSECT:
            case EXCEPT:
            case VALUES:
            case WITH:
            case OTHER_FUNCTION:
                if (alias == null) {
                    alias = SqlValidatorUtil.alias(node, nextGeneratedId++);
                }
                registerQuery(
                        parentScope,
                        register ? usingScope : null,
                        node,
                        enclosingNode,
                        alias,
                        forceNullable);
                return newNode;

            case OVER:
                if (!shouldAllowOverRelation()) {
                    throw Util.unexpected(kind);
                }
                call = (SqlCall) node;
                final OverScope overScope = new OverScope(usingScope, call);
                scopes.put(call, overScope);
                operand = call.operand(0);
                newOperand =
                        registerFrom(
                                parentScope,
                                overScope,
                                true,
                                operand,
                                enclosingNode,
                                alias,
                                extendList,
                                forceNullable,
                                lateral);
                if (newOperand != operand) {
                    call.setOperand(0, newOperand);
                }

                for (ScopeChild child : overScope.children) {
                    registerNamespace(
                            register ? usingScope : null,
                            child.name,
                            child.namespace,
                            forceNullable);
                }

                return newNode;

            case TABLE_REF:
                call = (SqlCall) node;
                registerFrom(
                        parentScope,
                        usingScope,
                        register,
                        call.operand(0),
                        enclosingNode,
                        alias,
                        extendList,
                        forceNullable,
                        lateral);
                if (extendList != null && extendList.size() != 0) {
                    return enclosingNode;
                }
                return newNode;

            case EXTEND:
                final SqlCall extend = (SqlCall) node;
                return registerFrom(
                        parentScope,
                        usingScope,
                        true,
                        extend.getOperandList().get(0),
                        extend,
                        alias,
                        (SqlNodeList) extend.getOperandList().get(1),
                        forceNullable,
                        lateral);

            case SNAPSHOT:
                call = (SqlCall) node;
                operand = call.operand(0);
                newOperand =
                        registerFrom(
                                parentScope,
                                usingScope,
                                register,
                                operand,
                                enclosingNode,
                                alias,
                                extendList,
                                forceNullable,
                                lateral);
                if (newOperand != operand) {
                    call.setOperand(0, newOperand);
                }
                // Put the usingScope which can be a JoinScope
                // or a SelectScope, in order to see the left items
                // of the JOIN tree.
                scopes.put(node, usingScope);
                return newNode;

            default:
                throw Util.unexpected(kind);
        }
    }