Search in sources :

Example 11 with SqlCall

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

the class SqlValidatorImpl method validateValues.

/**
 * Validates a VALUES clause.
 *
 * @param node          Values clause
 * @param targetRowType Row type which expression must conform to
 * @param scope         Scope within which clause occurs
 */
protected void validateValues(SqlCall node, RelDataType targetRowType, final SqlValidatorScope scope) {
    assert node.getKind() == SqlKind.VALUES;
    final List<SqlNode> operands = node.getOperandList();
    for (SqlNode operand : operands) {
        if (!(operand.getKind() == SqlKind.ROW)) {
            throw Util.needToImplement("Values function where operands are scalars");
        }
        SqlCall rowConstructor = (SqlCall) operand;
        if (conformance.isInsertSubsetColumnsAllowed() && targetRowType.isStruct() && rowConstructor.operandCount() < targetRowType.getFieldCount()) {
            targetRowType = typeFactory.createStructType(targetRowType.getFieldList().subList(0, rowConstructor.operandCount()));
        } else if (targetRowType.isStruct() && rowConstructor.operandCount() != targetRowType.getFieldCount()) {
            return;
        }
        inferUnknownTypes(targetRowType, scope, rowConstructor);
        if (targetRowType.isStruct()) {
            for (Pair<SqlNode, RelDataTypeField> pair : Pair.zip(rowConstructor.getOperandList(), targetRowType.getFieldList())) {
                if (!pair.right.getType().isNullable() && SqlUtil.isNullLiteral(pair.left, false)) {
                    throw newValidationError(node, RESOURCE.columnNotNullable(pair.right.getName()));
                }
            }
        }
    }
    for (SqlNode operand : operands) {
        operand.validate(this, scope);
    }
    // validate that all row types have the same number of columns
    // and that expressions in each column are compatible.
    // A values expression is turned into something that looks like
    // ROW(type00, type01,...), ROW(type11,...),...
    final int rowCount = operands.size();
    if (rowCount >= 2) {
        SqlCall firstRow = (SqlCall) operands.get(0);
        final int columnCount = firstRow.operandCount();
        // 1. check that all rows have the same cols length
        for (SqlNode operand : operands) {
            SqlCall thisRow = (SqlCall) operand;
            if (columnCount != thisRow.operandCount()) {
                throw newValidationError(node, RESOURCE.incompatibleValueType(SqlStdOperatorTable.VALUES.getName()));
            }
        }
        // 2. check if types at i:th position in each row are compatible
        for (int col = 0; col < columnCount; col++) {
            final int c = col;
            final RelDataType type = typeFactory.leastRestrictive(new AbstractList<RelDataType>() {

                public RelDataType get(int row) {
                    SqlCall thisRow = (SqlCall) operands.get(row);
                    return deriveType(scope, thisRow.operand(c));
                }

                public int size() {
                    return rowCount;
                }
            });
            if (null == type) {
                throw newValidationError(node, RESOURCE.incompatibleValueType(SqlStdOperatorTable.VALUES.getName()));
            }
        }
    }
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) SqlCall(org.apache.calcite.sql.SqlCall) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlNode(org.apache.calcite.sql.SqlNode)

Example 12 with SqlCall

use of org.apache.calcite.sql.SqlCall 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 SqlCall

use of org.apache.calcite.sql.SqlCall 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)

Example 14 with SqlCall

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

the class SqlValidatorImpl method findTableColumnPair.

private Pair<String, String> findTableColumnPair(SqlIdentifier identifier, SqlValidatorScope scope) {
    SqlCall call = SqlUtil.makeCall(getOperatorTable(), identifier);
    if (call != null) {
        return null;
    }
    SqlQualified qualified = scope.fullyQualify(identifier);
    List<String> names = qualified.identifier.names;
    if (names.size() < 2) {
        return null;
    }
    return new Pair<>(names.get(names.size() - 2), Util.last(names));
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) BitString(org.apache.calcite.util.BitString) Pair(org.apache.calcite.util.Pair)

Example 15 with SqlCall

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

the class SqlValidatorImpl method validateExpr.

/**
 * Validates an expression.
 *
 * @param expr  Expression
 * @param scope Scope in which expression occurs
 */
private void validateExpr(SqlNode expr, SqlValidatorScope scope) {
    if (expr instanceof SqlCall) {
        final SqlOperator op = ((SqlCall) expr).getOperator();
        if (op.isAggregator() && op.requiresOver()) {
            throw newValidationError(expr, RESOURCE.absentOverClause());
        }
    }
    // Call on the expression to validate itself.
    expr.validateExpr(this, scope);
    // Perform any validation specific to the scope. For example, an
    // aggregating scope requires that expressions are valid aggregations.
    scope.validateExpr(expr);
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlOperator(org.apache.calcite.sql.SqlOperator)

Aggregations

SqlCall (org.apache.calcite.sql.SqlCall)108 SqlNode (org.apache.calcite.sql.SqlNode)81 SqlIdentifier (org.apache.calcite.sql.SqlIdentifier)32 SqlNodeList (org.apache.calcite.sql.SqlNodeList)32 RelDataType (org.apache.calcite.rel.type.RelDataType)30 SqlOperator (org.apache.calcite.sql.SqlOperator)26 BitString (org.apache.calcite.util.BitString)19 ArrayList (java.util.ArrayList)18 SqlSelect (org.apache.calcite.sql.SqlSelect)17 RexNode (org.apache.calcite.rex.RexNode)13 SqlBasicCall (org.apache.calcite.sql.SqlBasicCall)12 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)11 SqlLiteral (org.apache.calcite.sql.SqlLiteral)11 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)9 SqlKind (org.apache.calcite.sql.SqlKind)9 SqlParserPos (org.apache.calcite.sql.parser.SqlParserPos)9 List (java.util.List)8 SqlCallBinding (org.apache.calcite.sql.SqlCallBinding)8 Pair (org.apache.calcite.util.Pair)8 RelNode (org.apache.calcite.rel.RelNode)7