Search in sources :

Example 51 with SqlIdentifier

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

the class SqlValidatorImpl method validateJoin.

protected void validateJoin(SqlJoin join, SqlValidatorScope scope) {
    SqlNode left = join.getLeft();
    SqlNode right = join.getRight();
    SqlNode condition = join.getCondition();
    boolean natural = join.isNatural();
    final JoinType joinType = join.getJoinType();
    final JoinConditionType conditionType = join.getConditionType();
    final SqlValidatorScope joinScope = scopes.get(join);
    validateFrom(left, unknownType, joinScope);
    validateFrom(right, unknownType, joinScope);
    // Validate condition.
    switch(conditionType) {
        case NONE:
            Preconditions.checkArgument(condition == null);
            break;
        case ON:
            Preconditions.checkArgument(condition != null);
            SqlNode expandedCondition = expand(condition, joinScope);
            join.setOperand(5, expandedCondition);
            condition = join.getCondition();
            validateWhereOrOn(joinScope, condition, "ON");
            checkRollUp(null, join, condition, joinScope, "ON");
            break;
        case USING:
            SqlNodeList list = (SqlNodeList) condition;
            // Parser ensures that using clause is not empty.
            Preconditions.checkArgument(list.size() > 0, "Empty USING clause");
            for (SqlNode node : list) {
                SqlIdentifier id = (SqlIdentifier) node;
                final RelDataType leftColType = validateUsingCol(id, left);
                final RelDataType rightColType = validateUsingCol(id, right);
                if (!SqlTypeUtil.isComparable(leftColType, rightColType)) {
                    throw newValidationError(id, RESOURCE.naturalOrUsingColumnNotCompatible(id.getSimple(), leftColType.toString(), rightColType.toString()));
                }
                checkRollUpInUsing(id, left, scope);
                checkRollUpInUsing(id, right, scope);
            }
            break;
        default:
            throw Util.unexpected(conditionType);
    }
    // Validate NATURAL.
    if (natural) {
        if (condition != null) {
            throw newValidationError(condition, RESOURCE.naturalDisallowsOnOrUsing());
        }
        // Join on fields that occur exactly once on each side. Ignore
        // fields that occur more than once on either side.
        final RelDataType leftRowType = getNamespace(left).getRowType();
        final RelDataType rightRowType = getNamespace(right).getRowType();
        final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
        List<String> naturalColumnNames = SqlValidatorUtil.deriveNaturalJoinColumnList(nameMatcher, leftRowType, rightRowType);
        // Check compatibility of the chosen columns.
        for (String name : naturalColumnNames) {
            final RelDataType leftColType = nameMatcher.field(leftRowType, name).getType();
            final RelDataType rightColType = nameMatcher.field(rightRowType, name).getType();
            if (!SqlTypeUtil.isComparable(leftColType, rightColType)) {
                throw newValidationError(join, RESOURCE.naturalOrUsingColumnNotCompatible(name, leftColType.toString(), rightColType.toString()));
            }
        }
    }
    // a NATURAL keyword?
    switch(joinType) {
        case LEFT_SEMI_JOIN:
            if (!this.config.sqlConformance().isLiberal()) {
                throw newValidationError(join.getJoinTypeNode(), RESOURCE.dialectDoesNotSupportFeature("LEFT SEMI JOIN"));
            }
        // fall through
        case INNER:
        case LEFT:
        case RIGHT:
        case FULL:
            if ((condition == null) && !natural) {
                throw newValidationError(join, RESOURCE.joinRequiresCondition());
            }
            break;
        case COMMA:
        case CROSS:
            if (condition != null) {
                throw newValidationError(join.getConditionTypeNode(), RESOURCE.crossJoinDisallowsCondition());
            }
            if (natural) {
                throw newValidationError(join.getConditionTypeNode(), RESOURCE.crossJoinDisallowsCondition());
            }
            break;
        default:
            throw Util.unexpected(joinType);
    }
}
Also used : JoinConditionType(org.apache.calcite.sql.JoinConditionType) JoinType(org.apache.calcite.sql.JoinType) SqlNodeList(org.apache.calcite.sql.SqlNodeList) RelDataType(org.apache.calcite.rel.type.RelDataType) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlNode(org.apache.calcite.sql.SqlNode)

Example 52 with SqlIdentifier

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

the class SqlValidatorImpl method lookupFromHints.

private void lookupFromHints(SqlNode node, SqlValidatorScope scope, SqlParserPos pos, Collection<SqlMoniker> hintList) {
    if (node == null) {
        // This can happen in cases like "select * _suggest_", so from clause is absent
        return;
    }
    final SqlValidatorNamespace ns = getNamespace(node);
    if (ns.isWrapperFor(IdentifierNamespace.class)) {
        IdentifierNamespace idNs = ns.unwrap(IdentifierNamespace.class);
        final SqlIdentifier id = idNs.getId();
        for (int i = 0; i < id.names.size(); i++) {
            if (pos.toString().equals(id.getComponent(i).getParserPosition().toString())) {
                final List<SqlMoniker> objNames = new ArrayList<>();
                SqlValidatorUtil.getSchemaObjectMonikers(getCatalogReader(), id.names.subList(0, i + 1), objNames);
                for (SqlMoniker objName : objNames) {
                    if (objName.getType() != SqlMonikerType.FUNCTION) {
                        hintList.add(objName);
                    }
                }
                return;
            }
        }
    }
    switch(node.getKind()) {
        case JOIN:
            lookupJoinHints((SqlJoin) node, scope, pos, hintList);
            break;
        default:
            lookupSelectHints(ns, pos, hintList);
            break;
    }
}
Also used : ArrayList(java.util.ArrayList) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier)

Example 53 with SqlIdentifier

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

the class SqlValidatorImpl method expandExprFromJoin.

private static SqlNode expandExprFromJoin(SqlJoin join, SqlIdentifier identifier, SelectScope scope) {
    if (join.getConditionType() != JoinConditionType.USING) {
        return identifier;
    }
    for (SqlNode node : (SqlNodeList) join.getCondition()) {
        final String name = ((SqlIdentifier) node).getSimple();
        if (identifier.getSimple().equals(name)) {
            final List<SqlNode> qualifiedNode = new ArrayList<>();
            for (ScopeChild child : scope.children) {
                if (child.namespace.getRowType().getFieldNames().indexOf(name) >= 0) {
                    final SqlIdentifier exp = new SqlIdentifier(ImmutableList.of(child.name, name), identifier.getParserPosition());
                    qualifiedNode.add(exp);
                }
            }
            assert qualifiedNode.size() == 2;
            final SqlNode finalNode = SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, SqlStdOperatorTable.COALESCE.createCall(SqlParserPos.ZERO, qualifiedNode.get(0), qualifiedNode.get(1)), new SqlIdentifier(name, SqlParserPos.ZERO));
            return finalNode;
        }
    }
    // Only need to try to expand the expr from the left input of join
    // since it is always left-deep join.
    final SqlNode node = join.getLeft();
    if (node instanceof SqlJoin) {
        return expandExprFromJoin((SqlJoin) node, identifier, scope);
    } else {
        return identifier;
    }
}
Also used : SqlJoin(org.apache.calcite.sql.SqlJoin) ArrayList(java.util.ArrayList) SqlNodeList(org.apache.calcite.sql.SqlNodeList) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlNode(org.apache.calcite.sql.SqlNode)

Example 54 with SqlIdentifier

use of org.apache.calcite.sql.SqlIdentifier 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 55 with SqlIdentifier

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

the class SqlValidatorImpl method resolveWindow.

public SqlWindow resolveWindow(SqlNode windowOrRef, SqlValidatorScope scope) {
    SqlWindow window;
    if (windowOrRef instanceof SqlIdentifier) {
        window = getWindowByName((SqlIdentifier) windowOrRef, scope);
    } else {
        window = (SqlWindow) windowOrRef;
    }
    while (true) {
        final SqlIdentifier refId = window.getRefName();
        if (refId == null) {
            break;
        }
        final String refName = refId.getSimple();
        SqlWindow refWindow = scope.lookupWindow(refName);
        if (refWindow == null) {
            throw newValidationError(refId, RESOURCE.windowNotFound(refName));
        }
        window = window.overlay(refWindow, this);
    }
    return window;
}
Also used : SqlWindow(org.apache.calcite.sql.SqlWindow) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier)

Aggregations

SqlIdentifier (org.apache.calcite.sql.SqlIdentifier)131 SqlNode (org.apache.calcite.sql.SqlNode)84 RelDataType (org.apache.calcite.rel.type.RelDataType)46 SqlNodeList (org.apache.calcite.sql.SqlNodeList)43 ArrayList (java.util.ArrayList)41 SqlCall (org.apache.calcite.sql.SqlCall)32 BitString (org.apache.calcite.util.BitString)28 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)21 SqlSelect (org.apache.calcite.sql.SqlSelect)21 SqlParserPos (org.apache.calcite.sql.parser.SqlParserPos)12 SchemaPlus (org.apache.calcite.schema.SchemaPlus)11 SqlOperator (org.apache.calcite.sql.SqlOperator)11 NlsString (org.apache.calcite.util.NlsString)11 List (java.util.List)9 Map (java.util.Map)9 RelOptTable (org.apache.calcite.plan.RelOptTable)9 RexNode (org.apache.calcite.rex.RexNode)9 AbstractSchema (org.apache.drill.exec.store.AbstractSchema)9 ImmutableList (com.google.common.collect.ImmutableList)8 RelNode (org.apache.calcite.rel.RelNode)7