Search in sources :

Example 1 with SqlWindowTableFunction

use of org.apache.calcite.sql.SqlWindowTableFunction in project flink by apache.

the class SqlValidatorImpl method registerFrom.

/**
 * Registers scopes and namespaces implied a relational expression in the FROM clause.
 *
 * <p>{@code parentScope} and {@code usingScope} are often the same. They differ when the
 * namespace are not visible within the parent. (Example needed.)
 *
 * <p>Likewise, {@code enclosingNode} and {@code node} are often the same. {@code enclosingNode}
 * is the topmost node within the FROM clause, from which any decorations like an alias (<code>
 * AS alias</code>) or a table sample clause are stripped away to get {@code node}. Both are
 * recorded in the namespace.
 *
 * @param parentScope Parent scope which this scope turns to in order to resolve objects
 * @param usingScope Scope whose child list this scope should add itself to
 * @param register Whether to register this scope as a child of {@code usingScope}
 * @param node Node which namespace is based on
 * @param enclosingNode Outermost node for namespace, including decorations such as alias and
 *     sample clause
 * @param alias Alias
 * @param extendList Definitions of extended columns
 * @param forceNullable Whether to force the type of namespace to be nullable because it is in
 *     an outer join
 * @param lateral Whether LATERAL is specified, so that items to the left of this in the JOIN
 *     tree are visible in the scope
 * @return registered node, usually the same as {@code node}
 */
private SqlNode registerFrom(SqlValidatorScope parentScope, SqlValidatorScope usingScope, boolean register, final SqlNode node, SqlNode enclosingNode, String alias, 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 = deriveAlias(node, -1);
                if (alias == null) {
                    alias = deriveAlias(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 MATCH_RECOGNIZE:
                // give this anonymous construct a name since later
                // query processing stages rely on it
                alias = deriveAlias(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;
        }
    }
    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 = call.operand(1).toString();
            }
            final boolean needAlias = call.operandCount() > 2;
            expr = call.operand(0);
            newExpr = registerFrom(parentScope, usingScope, !needAlias, expr, enclosingNode, alias, extendList, forceNullable, lateral);
            if (newExpr != expr) {
                call.setOperand(0, newExpr);
            }
            // column names. We skipped registering it just now.
            if (needAlias) {
                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 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;
            }
            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, 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);
            }
            // 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 = deriveAlias(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);
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlOperator(org.apache.calcite.sql.SqlOperator) SqlKind(org.apache.calcite.sql.SqlKind) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlJoin(org.apache.calcite.sql.SqlJoin) SqlWindowTableFunction(org.apache.calcite.sql.SqlWindowTableFunction) SqlNode(org.apache.calcite.sql.SqlNode)

Example 2 with SqlWindowTableFunction

use of org.apache.calcite.sql.SqlWindowTableFunction in project flink by apache.

the class FlinkCalciteSqlValidator method validateJoin.

@Override
protected void validateJoin(SqlJoin join, SqlValidatorScope scope) {
    // temporarily forbid the common predicates until the problem is fixed (see FLINK-7865).
    if (join.getJoinType() == JoinType.LEFT && SqlUtil.stripAs(join.getRight()).getKind() == SqlKind.COLLECTION_TABLE) {
        SqlNode right = SqlUtil.stripAs(join.getRight());
        if (right instanceof SqlBasicCall) {
            SqlBasicCall call = (SqlBasicCall) right;
            SqlNode operand0 = call.operand(0);
            if (operand0 instanceof SqlBasicCall && ((SqlBasicCall) operand0).getOperator() instanceof SqlWindowTableFunction) {
                return;
            }
        }
        final SqlNode condition = join.getCondition();
        if (condition != null && (!SqlUtil.isLiteral(condition) || ((SqlLiteral) condition).getValueAs(Boolean.class) != Boolean.TRUE)) {
            throw new ValidationException(String.format("Left outer joins with a table function do not accept a predicate such as %s. " + "Only literal TRUE is accepted.", condition));
        }
    }
    super.validateJoin(join, scope);
}
Also used : ValidationException(org.apache.flink.table.api.ValidationException) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlLiteral(org.apache.calcite.sql.SqlLiteral) SqlWindowTableFunction(org.apache.calcite.sql.SqlWindowTableFunction) SqlNode(org.apache.calcite.sql.SqlNode)

Aggregations

SqlBasicCall (org.apache.calcite.sql.SqlBasicCall)2 SqlNode (org.apache.calcite.sql.SqlNode)2 SqlWindowTableFunction (org.apache.calcite.sql.SqlWindowTableFunction)2 SqlCall (org.apache.calcite.sql.SqlCall)1 SqlIdentifier (org.apache.calcite.sql.SqlIdentifier)1 SqlJoin (org.apache.calcite.sql.SqlJoin)1 SqlKind (org.apache.calcite.sql.SqlKind)1 SqlLiteral (org.apache.calcite.sql.SqlLiteral)1 SqlOperator (org.apache.calcite.sql.SqlOperator)1 ValidationException (org.apache.flink.table.api.ValidationException)1