Search in sources :

Example 11 with SqlNodeList

use of org.apache.calcite.sql.SqlNodeList in project calcite by apache.

the class SqlValidatorImpl method validateOrderList.

/**
 * Validates the ORDER BY clause of a SELECT statement.
 *
 * @param select Select statement
 */
protected void validateOrderList(SqlSelect select) {
    // ORDER BY is validated in a scope where aliases in the SELECT clause
    // are visible. For example, "SELECT empno AS x FROM emp ORDER BY x"
    // is valid.
    SqlNodeList orderList = select.getOrderList();
    if (orderList == null) {
        return;
    }
    if (!shouldAllowIntermediateOrderBy()) {
        if (!cursorSet.contains(select)) {
            throw newValidationError(select, RESOURCE.invalidOrderByPos());
        }
    }
    final SqlValidatorScope orderScope = getOrderScope(select);
    Preconditions.checkNotNull(orderScope);
    List<SqlNode> expandList = new ArrayList<>();
    for (SqlNode orderItem : orderList) {
        SqlNode expandedOrderItem = expand(orderItem, orderScope);
        expandList.add(expandedOrderItem);
    }
    SqlNodeList expandedOrderList = new SqlNodeList(expandList, orderList.getParserPosition());
    select.setOrderBy(expandedOrderList);
    for (SqlNode orderItem : expandedOrderList) {
        validateOrderItem(select, orderItem);
    }
}
Also used : ArrayList(java.util.ArrayList) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlNode(org.apache.calcite.sql.SqlNode)

Example 12 with SqlNodeList

use of org.apache.calcite.sql.SqlNodeList in project calcite by apache.

the class SqlValidatorImpl method registerSubQueries.

private void registerSubQueries(SqlValidatorScope parentScope, SqlNode node) {
    if (node == null) {
        return;
    }
    if (node.getKind().belongsTo(SqlKind.QUERY) || node.getKind() == SqlKind.MULTISET_QUERY_CONSTRUCTOR || node.getKind() == SqlKind.MULTISET_VALUE_CONSTRUCTOR) {
        registerQuery(parentScope, null, node, node, null, false);
    } else if (node instanceof SqlCall) {
        validateNodeFeature(node);
        SqlCall call = (SqlCall) node;
        for (int i = 0; i < call.operandCount(); i++) {
            registerOperandSubQueries(parentScope, call, i);
        }
    } else if (node instanceof SqlNodeList) {
        SqlNodeList list = (SqlNodeList) node;
        for (int i = 0, count = list.size(); i < count; i++) {
            SqlNode listNode = list.get(i);
            if (listNode.getKind().belongsTo(SqlKind.QUERY)) {
                listNode = SqlStdOperatorTable.SCALAR_QUERY.createCall(listNode.getParserPosition(), listNode);
                list.set(i, listNode);
            }
            registerSubQueries(parentScope, listNode);
        }
    } else {
    // atomic node -- can be ignored
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlNode(org.apache.calcite.sql.SqlNode)

Example 13 with SqlNodeList

use of org.apache.calcite.sql.SqlNodeList in project calcite by apache.

the class SqlValidatorImpl method validateModality.

public boolean validateModality(SqlSelect select, SqlModality modality, boolean fail) {
    final SelectScope scope = getRawSelectScope(select);
    switch(modality) {
        case STREAM:
            if (scope.children.size() == 1) {
                for (ScopeChild child : scope.children) {
                    if (!child.namespace.supportsModality(modality)) {
                        if (fail) {
                            throw newValidationError(child.namespace.getNode(), Static.RESOURCE.cannotConvertToStream(child.name));
                        } else {
                            return false;
                        }
                    }
                }
            } else {
                int supportsModalityCount = 0;
                for (ScopeChild child : scope.children) {
                    if (child.namespace.supportsModality(modality)) {
                        ++supportsModalityCount;
                    }
                }
                if (supportsModalityCount == 0) {
                    if (fail) {
                        String inputs = Joiner.on(", ").join(scope.getChildNames());
                        throw newValidationError(select, Static.RESOURCE.cannotStreamResultsForNonStreamingInputs(inputs));
                    } else {
                        return false;
                    }
                }
            }
            break;
        default:
            for (ScopeChild child : scope.children) {
                if (!child.namespace.supportsModality(modality)) {
                    if (fail) {
                        throw newValidationError(child.namespace.getNode(), Static.RESOURCE.cannotConvertToRelation(child.name));
                    } else {
                        return false;
                    }
                }
            }
    }
    // Make sure that aggregation is possible.
    final SqlNode aggregateNode = getAggregate(select);
    if (aggregateNode != null) {
        switch(modality) {
            case STREAM:
                SqlNodeList groupList = select.getGroup();
                if (groupList == null || !SqlValidatorUtil.containsMonotonic(scope, groupList)) {
                    if (fail) {
                        throw newValidationError(aggregateNode, Static.RESOURCE.streamMustGroupByMonotonic());
                    } else {
                        return false;
                    }
                }
        }
    }
    // Make sure that ORDER BY is possible.
    final SqlNodeList orderList = select.getOrderList();
    if (orderList != null && orderList.size() > 0) {
        switch(modality) {
            case STREAM:
                if (!hasSortedPrefix(scope, orderList)) {
                    if (fail) {
                        throw newValidationError(orderList.get(0), Static.RESOURCE.streamMustOrderByMonotonic());
                    } else {
                        return false;
                    }
                }
        }
    }
    return true;
}
Also used : SqlNodeList(org.apache.calcite.sql.SqlNodeList) BitString(org.apache.calcite.util.BitString) SqlNode(org.apache.calcite.sql.SqlNode)

Example 14 with SqlNodeList

use of org.apache.calcite.sql.SqlNodeList in project calcite 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 (int i = 0; i < list.size(); i++) {
                SqlIdentifier id = (SqlIdentifier) list.get(i);
                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);
                checkRollUpInUsing(id, right);
            }
            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();
        List<String> naturalColumnNames = SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType, rightRowType);
        // Check compatibility of the chosen columns.
        final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
        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 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 15 with SqlNodeList

use of org.apache.calcite.sql.SqlNodeList in project calcite by apache.

the class SqlValidatorImpl method registerQuery.

/**
 * Registers a query in a parent scope.
 *
 * @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 node        Query node
 * @param alias       Name of this query within its parent. Must be specified
 *                    if usingScope != null
 * @param checkUpdate if true, validate that the update feature is supported
 *                    if validating the update statement
 */
private void registerQuery(SqlValidatorScope parentScope, SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, String alias, boolean forceNullable, boolean checkUpdate) {
    Preconditions.checkNotNull(node);
    Preconditions.checkNotNull(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
            whereScopes.put(select, selectScope);
            registerOperandSubQueries(selectScope, select, SqlSelect.WHERE_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, from, from, null, null, 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);
                selectScopes.put(select, aggScope);
            } else {
                selectScopes.put(select, selectScope);
            }
            if (select.getGroup() != null) {
                GroupByScope groupByScope = new GroupByScope(selectScope, select.getGroup(), select);
                groupByScopes.put(select, groupByScope);
                registerSubQueries(groupByScope, select.getGroup());
            }
            registerOperandSubQueries(aggScope, select, SqlSelect.HAVING_OPERAND);
            registerSubQueries(aggScope, select.getSelectList());
            final SqlNodeList orderList = select.getOrderList();
            if (orderList != null) {
                // available to the ORDER BY clause.
                if (select.isDistinct()) {
                    aggScope = new AggregatingSelectScope(selectScope, select, true);
                }
                OrderByScope orderScope = new OrderByScope(aggScope, orderList, select);
                orderScopes.put(select, 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, deleteCall.getSourceSelect(), 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, updateCall.getSourceSelect(), 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, mergeCall.getSourceSelect(), enclosingNode, null, false);
            // validation check
            if (mergeCall.getUpdateCall() != null) {
                registerQuery(whereScopes.get(mergeCall.getSourceSelect()), null, mergeCall.getUpdateCall(), enclosingNode, null, false, false);
            }
            if (mergeCall.getInsertCall() != null) {
                registerQuery(parentScope, null, mergeCall.getInsertCall(), 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 = deriveAlias(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());
    }
}
Also used : BitString(org.apache.calcite.util.BitString) SqlInsert(org.apache.calcite.sql.SqlInsert) SqlUpdate(org.apache.calcite.sql.SqlUpdate) SqlSelect(org.apache.calcite.sql.SqlSelect) SqlNode(org.apache.calcite.sql.SqlNode) SqlCall(org.apache.calcite.sql.SqlCall) SqlMerge(org.apache.calcite.sql.SqlMerge) SqlDelete(org.apache.calcite.sql.SqlDelete) SqlNodeList(org.apache.calcite.sql.SqlNodeList)

Aggregations

SqlNodeList (org.apache.calcite.sql.SqlNodeList)123 SqlNode (org.apache.calcite.sql.SqlNode)97 ArrayList (java.util.ArrayList)45 SqlIdentifier (org.apache.calcite.sql.SqlIdentifier)43 RelDataType (org.apache.calcite.rel.type.RelDataType)39 SqlCall (org.apache.calcite.sql.SqlCall)30 SqlSelect (org.apache.calcite.sql.SqlSelect)29 BitString (org.apache.calcite.util.BitString)23 RexNode (org.apache.calcite.rex.RexNode)13 SqlLiteral (org.apache.calcite.sql.SqlLiteral)11 ImmutableList (com.google.common.collect.ImmutableList)10 List (java.util.List)10 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)10 NlsString (org.apache.calcite.util.NlsString)9 RelNode (org.apache.calcite.rel.RelNode)8 SqlUpdate (org.apache.calcite.sql.SqlUpdate)8 SqlBasicCall (org.apache.calcite.sql.SqlBasicCall)7 SqlWriter (org.apache.calcite.sql.SqlWriter)7 SqlParserPos (org.apache.calcite.sql.parser.SqlParserPos)7 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)6