Search in sources :

Example 86 with SqlCall

use of org.apache.calcite.sql.SqlCall in project calcite 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 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
 * @return registered node, usually the same as {@code node}
 */
private SqlNode registerFrom(SqlValidatorScope parentScope, SqlValidatorScope usingScope, final SqlNode node, SqlNode enclosingNode, String alias, SqlNodeList extendList, boolean forceNullable) {
    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 (shouldExpandIdentifiers()) {
                    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 MATCH_RECOGNIZE:
                // give this anonymous construct a name since later
                // query processing stages rely on it
                alias = deriveAlias(node, nextGeneratedId++);
                if (shouldExpandIdentifiers()) {
                    // 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;
        }
    }
    SqlCall call;
    SqlNode operand;
    SqlNode newOperand;
    switch(kind) {
        case AS:
            call = (SqlCall) node;
            if (alias == null) {
                alias = call.operand(1).toString();
            }
            SqlValidatorScope usingScope2 = usingScope;
            if (call.operandCount() > 2) {
                usingScope2 = null;
            }
            expr = call.operand(0);
            newExpr = registerFrom(parentScope, usingScope2, expr, enclosingNode, alias, extendList, forceNullable);
            if (newExpr != expr) {
                call.setOperand(0, newExpr);
            }
            // column names.
            if (call.operandCount() > 2) {
                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 TABLESAMPLE:
            call = (SqlCall) node;
            expr = call.operand(0);
            newExpr = registerFrom(parentScope, usingScope, expr, enclosingNode, alias, extendList, forceNullable);
            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();
            final boolean rightIsLateral = isLateral(right);
            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, left, left, null, null, forceLeftNullable);
            if (newLeft != left) {
                join.setLeft(newLeft);
            }
            final SqlValidatorScope rightParentScope;
            if (rightIsLateral) {
                rightParentScope = joinScope;
            } else {
                rightParentScope = parentScope;
            }
            final SqlNode newRight = registerFrom(rightParentScope, joinScope, right, right, null, null, forceRightNullable);
            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(usingScope, 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:
            if (tableScope != null) {
                tableScope.meetLateral();
            }
            return registerFrom(parentScope, usingScope, ((SqlCall) node).operand(0), enclosingNode, alias, extendList, forceNullable);
        case COLLECTION_TABLE:
            call = (SqlCall) node;
            operand = call.operand(0);
            newOperand = registerFrom(tableScope == null ? parentScope : tableScope, usingScope, operand, enclosingNode, alias, extendList, forceNullable);
            if (newOperand != operand) {
                call.setOperand(0, newOperand);
            }
            scopes.put(node, parentScope);
            return newNode;
        case SELECT:
        case UNION:
        case INTERSECT:
        case EXCEPT:
        case VALUES:
        case WITH:
        case UNNEST:
        case OTHER_FUNCTION:
            if (alias == null) {
                alias = deriveAlias(node, nextGeneratedId++);
            }
            registerQuery(parentScope, usingScope, 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, operand, enclosingNode, alias, extendList, forceNullable);
            if (newOperand != operand) {
                call.setOperand(0, newOperand);
            }
            for (ScopeChild child : overScope.children) {
                registerNamespace(usingScope, child.name, child.namespace, forceNullable);
            }
            return newNode;
        case EXTEND:
            final SqlCall extend = (SqlCall) node;
            return registerFrom(parentScope, usingScope, extend.getOperandList().get(0), extend, alias, (SqlNodeList) extend.getOperandList().get(1), forceNullable);
        default:
            throw Util.unexpected(kind);
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlKind(org.apache.calcite.sql.SqlKind) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlJoin(org.apache.calcite.sql.SqlJoin) SqlNode(org.apache.calcite.sql.SqlNode)

Example 87 with SqlCall

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

the class SqlValidatorImpl method validateMatchRecognize.

@Override
public void validateMatchRecognize(SqlCall call) {
    final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
    final MatchRecognizeScope scope = (MatchRecognizeScope) getMatchRecognizeScope(matchRecognize);
    final MatchRecognizeNamespace ns = getNamespace(call).unwrap(MatchRecognizeNamespace.class);
    assert ns.rowType == null;
    // rows per match
    final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
    final boolean allRows = rowsPerMatch != null && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
    final RelDataTypeFactory.Builder typeBuilder = typeFactory.builder();
    // parse PARTITION BY column
    SqlNodeList partitionBy = matchRecognize.getPartitionList();
    if (partitionBy != null) {
        for (SqlNode node : partitionBy) {
            SqlIdentifier identifier = (SqlIdentifier) node;
            identifier.validate(this, scope);
            RelDataType type = deriveType(scope, identifier);
            String name = identifier.names.get(1);
            typeBuilder.add(name, type);
        }
    }
    // parse ORDER BY column
    SqlNodeList orderBy = matchRecognize.getOrderList();
    if (orderBy != null) {
        for (SqlNode node : orderBy) {
            node.validate(this, scope);
            SqlIdentifier identifier = null;
            if (node instanceof SqlBasicCall) {
                identifier = (SqlIdentifier) ((SqlBasicCall) node).getOperands()[0];
            } else {
                identifier = (SqlIdentifier) node;
            }
            if (allRows) {
                RelDataType type = deriveType(scope, identifier);
                String name = identifier.names.get(1);
                if (!typeBuilder.nameExists(name)) {
                    typeBuilder.add(name, type);
                }
            }
        }
    }
    if (allRows) {
        final SqlValidatorNamespace sqlNs = getNamespace(matchRecognize.getTableRef());
        final RelDataType inputDataType = sqlNs.getRowType();
        for (RelDataTypeField fs : inputDataType.getFieldList()) {
            if (!typeBuilder.nameExists(fs.getName())) {
                typeBuilder.add(fs);
            }
        }
    }
    // retrieve pattern variables used in pattern and subset
    SqlNode pattern = matchRecognize.getPattern();
    PatternVarVisitor visitor = new PatternVarVisitor(scope);
    pattern.accept(visitor);
    SqlLiteral interval = matchRecognize.getInterval();
    if (interval != null) {
        interval.validate(this, scope);
        if (((SqlIntervalLiteral) interval).signum() < 0) {
            throw newValidationError(interval, RESOURCE.intervalMustBeNonNegative(interval.toValue()));
        }
        if (orderBy == null || orderBy.size() == 0) {
            throw newValidationError(interval, RESOURCE.cannotUseWithinWithoutOrderBy());
        }
        SqlNode firstOrderByColumn = orderBy.getList().get(0);
        SqlIdentifier identifier;
        if (firstOrderByColumn instanceof SqlBasicCall) {
            identifier = (SqlIdentifier) ((SqlBasicCall) firstOrderByColumn).getOperands()[0];
        } else {
            identifier = (SqlIdentifier) firstOrderByColumn;
        }
        RelDataType firstOrderByColumnType = deriveType(scope, identifier);
        if (firstOrderByColumnType.getSqlTypeName() != SqlTypeName.TIMESTAMP) {
            throw newValidationError(interval, RESOURCE.firstColumnOfOrderByMustBeTimestamp());
        }
        SqlNode expand = expand(interval, scope);
        RelDataType type = deriveType(scope, expand);
        setValidatedNodeType(interval, type);
    }
    validateDefinitions(matchRecognize, scope);
    SqlNodeList subsets = matchRecognize.getSubsetList();
    if (subsets != null && subsets.size() > 0) {
        for (SqlNode node : subsets) {
            List<SqlNode> operands = ((SqlCall) node).getOperandList();
            String leftString = ((SqlIdentifier) operands.get(0)).getSimple();
            if (scope.getPatternVars().contains(leftString)) {
                throw newValidationError(operands.get(0), RESOURCE.patternVarAlreadyDefined(leftString));
            }
            scope.addPatternVar(leftString);
            for (SqlNode right : (SqlNodeList) operands.get(1)) {
                SqlIdentifier id = (SqlIdentifier) right;
                if (!scope.getPatternVars().contains(id.getSimple())) {
                    throw newValidationError(id, RESOURCE.unknownPattern(id.getSimple()));
                }
                scope.addPatternVar(id.getSimple());
            }
        }
    }
    // validate AFTER ... SKIP TO
    final SqlNode skipTo = matchRecognize.getAfter();
    if (skipTo instanceof SqlCall) {
        final SqlCall skipToCall = (SqlCall) skipTo;
        final SqlIdentifier id = skipToCall.operand(0);
        if (!scope.getPatternVars().contains(id.getSimple())) {
            throw newValidationError(id, RESOURCE.unknownPattern(id.getSimple()));
        }
    }
    List<Map.Entry<String, RelDataType>> measureColumns = validateMeasure(matchRecognize, scope, allRows);
    for (Map.Entry<String, RelDataType> c : measureColumns) {
        if (!typeBuilder.nameExists(c.getKey())) {
            typeBuilder.add(c.getKey(), c.getValue());
        }
    }
    final RelDataType rowType = typeBuilder.build();
    if (matchRecognize.getMeasureList().size() == 0) {
        ns.setType(getNamespace(matchRecognize.getTableRef()).getRowType());
    } else {
        ns.setType(rowType);
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlMatchRecognize(org.apache.calcite.sql.SqlMatchRecognize) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlLiteral(org.apache.calcite.sql.SqlLiteral) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) SqlNode(org.apache.calcite.sql.SqlNode)

Example 88 with SqlCall

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

the class SqlValidatorImpl method validateModality.

/**
 * Validates that a query can deliver the modality it promises. Only called
 * on the top-most SELECT or set operator in the tree.
 */
private void validateModality(SqlNode query) {
    final SqlModality modality = deduceModality(query);
    if (query instanceof SqlSelect) {
        final SqlSelect select = (SqlSelect) query;
        validateModality(select, modality, true);
    } else if (query.getKind() == SqlKind.VALUES) {
        switch(modality) {
            case STREAM:
                throw newValidationError(query, Static.RESOURCE.cannotStreamValues());
        }
    } else {
        assert query.isA(SqlKind.SET_QUERY);
        final SqlCall call = (SqlCall) query;
        for (SqlNode operand : call.getOperandList()) {
            if (deduceModality(operand) != modality) {
                throw newValidationError(operand, Static.RESOURCE.streamSetOpInconsistentInputs());
            }
            validateModality(operand);
        }
    }
}
Also used : SqlSelect(org.apache.calcite.sql.SqlSelect) SqlCall(org.apache.calcite.sql.SqlCall) SqlNode(org.apache.calcite.sql.SqlNode)

Example 89 with SqlCall

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

the class SqlValidatorImpl method checkRollUp.

private void checkRollUp(SqlNode grandParent, SqlNode parent, SqlNode current, SqlValidatorScope scope, String optionalClause) {
    current = stripAs(current);
    if (current instanceof SqlCall && !(current instanceof SqlSelect)) {
        // Validate OVER separately
        checkRollUpInWindow(getWindowInOver(current), scope);
        current = stripOver(current);
        List<SqlNode> children = ((SqlCall) stripDot(current)).getOperandList();
        for (SqlNode child : children) {
            checkRollUp(parent, current, child, scope, optionalClause);
        }
    } else if (current instanceof SqlIdentifier) {
        SqlIdentifier id = (SqlIdentifier) current;
        if (!id.isStar() && isRolledUpColumn(id, scope)) {
            if (!isAggregation(parent.getKind()) || !isRolledUpColumnAllowedInAgg(id, scope, (SqlCall) parent, grandParent)) {
                String context = optionalClause != null ? optionalClause : parent.getKind().toString();
                throw newValidationError(id, RESOURCE.rolledUpNotAllowed(deriveAlias(id, 0), context));
            }
        }
    }
}
Also used : SqlSelect(org.apache.calcite.sql.SqlSelect) SqlCall(org.apache.calcite.sql.SqlCall) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlNode(org.apache.calcite.sql.SqlNode)

Example 90 with SqlCall

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

the class SqlValidatorImpl method validateMeasure.

private List<Map.Entry<String, RelDataType>> validateMeasure(SqlMatchRecognize mr, MatchRecognizeScope scope, boolean allRows) {
    final List<String> aliases = new ArrayList<>();
    final List<SqlNode> sqlNodes = new ArrayList<>();
    final SqlNodeList measures = mr.getMeasureList();
    final List<Map.Entry<String, RelDataType>> fields = new ArrayList<>();
    for (SqlNode measure : measures) {
        assert measure instanceof SqlCall;
        final String alias = deriveAlias(measure, aliases.size());
        aliases.add(alias);
        SqlNode expand = expand(measure, scope);
        expand = navigationInMeasure(expand, allRows);
        setOriginal(expand, measure);
        inferUnknownTypes(unknownType, scope, expand);
        final RelDataType type = deriveType(scope, expand);
        setValidatedNodeType(measure, type);
        fields.add(Pair.of(alias, type));
        sqlNodes.add(SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, expand, new SqlIdentifier(alias, SqlParserPos.ZERO)));
    }
    SqlNodeList list = new SqlNodeList(sqlNodes, measures.getParserPosition());
    inferUnknownTypes(unknownType, scope, list);
    for (SqlNode node : list) {
        validateExpr(node, scope);
    }
    mr.setOperand(SqlMatchRecognize.OPERAND_MEASURES, list);
    return fields;
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) ArrayList(java.util.ArrayList) 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)

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