Search in sources :

Example 96 with SqlIdentifier

use of org.apache.calcite.sql.SqlIdentifier in project flink 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;
            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 || firstOrderByColumnType.getSqlTypeName() == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)) {
            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 97 with SqlIdentifier

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

the class SqlValidatorImpl method expandStar.

private boolean expandStar(List<SqlNode> selectItems, Set<String> aliases, List<Map.Entry<String, RelDataType>> fields, boolean includeSystemVars, SelectScope scope, SqlNode node) {
    if (!(node instanceof SqlIdentifier)) {
        return false;
    }
    final SqlIdentifier identifier = (SqlIdentifier) node;
    if (!identifier.isStar()) {
        return false;
    }
    final SqlParserPos startPosition = identifier.getParserPosition();
    switch(identifier.names.size()) {
        case 1:
            boolean hasDynamicStruct = false;
            for (ScopeChild child : scope.children) {
                final int before = fields.size();
                if (child.namespace.getRowType().isDynamicStruct()) {
                    hasDynamicStruct = true;
                    // don't expand star if the underneath table is dynamic.
                    // Treat this star as a special field in validation/conversion and
                    // wait until execution time to expand this star.
                    final SqlNode exp = new SqlIdentifier(ImmutableList.of(child.name, DynamicRecordType.DYNAMIC_STAR_PREFIX), startPosition);
                    addToSelectList(selectItems, aliases, fields, exp, scope, includeSystemVars);
                } else {
                    final SqlNode from = child.namespace.getNode();
                    final SqlValidatorNamespace fromNs = getNamespace(from, scope);
                    assert fromNs != null;
                    final RelDataType rowType = fromNs.getRowType();
                    for (RelDataTypeField field : rowType.getFieldList()) {
                        String columnName = field.getName();
                        // TODO: do real implicit collation here
                        final SqlIdentifier exp = new SqlIdentifier(ImmutableList.of(child.name, columnName), startPosition);
                        // Don't add expanded rolled up columns
                        if (!isRolledUpColumn(exp, scope)) {
                            addOrExpandField(selectItems, aliases, fields, includeSystemVars, scope, exp, field);
                        }
                    }
                }
                if (child.nullable) {
                    for (int i = before; i < fields.size(); i++) {
                        final Map.Entry<String, RelDataType> entry = fields.get(i);
                        final RelDataType type = entry.getValue();
                        if (!type.isNullable()) {
                            fields.set(i, Pair.of(entry.getKey(), typeFactory.createTypeWithNullability(type, true)));
                        }
                    }
                }
            }
            // the list, per standard SQL. Disabled if there are dynamic fields.
            if (!hasDynamicStruct || Bug.CALCITE_2400_FIXED) {
                new Permute(scope.getNode().getFrom(), 0).permute(selectItems, fields);
            }
            return true;
        default:
            final SqlIdentifier prefixId = identifier.skipLast(1);
            final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl();
            final SqlNameMatcher nameMatcher = scope.validator.catalogReader.nameMatcher();
            scope.resolve(prefixId.names, nameMatcher, true, resolved);
            if (resolved.count() == 0) {
                // or "select r.* from e"
                throw newValidationError(prefixId, RESOURCE.unknownIdentifier(prefixId.toString()));
            }
            final RelDataType rowType = resolved.only().rowType();
            if (rowType.isDynamicStruct()) {
                // don't expand star if the underneath table is dynamic.
                addToSelectList(selectItems, aliases, fields, prefixId.plus(DynamicRecordType.DYNAMIC_STAR_PREFIX, startPosition), scope, includeSystemVars);
            } else if (rowType.isStruct()) {
                for (RelDataTypeField field : rowType.getFieldList()) {
                    String columnName = field.getName();
                    // TODO: do real implicit collation here
                    addOrExpandField(selectItems, aliases, fields, includeSystemVars, scope, prefixId.plus(columnName, startPosition), field);
                }
            } else {
                throw newValidationError(prefixId, RESOURCE.starRequiresRecordType());
            }
            return true;
    }
}
Also used : SqlParserPos(org.apache.calcite.sql.parser.SqlParserPos) RelDataType(org.apache.calcite.rel.type.RelDataType) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) SqlNode(org.apache.calcite.sql.SqlNode)

Example 98 with SqlIdentifier

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

the class SqlValidatorImpl method deriveConstructorType.

public RelDataType deriveConstructorType(SqlValidatorScope scope, SqlCall call, SqlFunction unresolvedConstructor, SqlFunction resolvedConstructor, List<RelDataType> argTypes) {
    SqlIdentifier sqlIdentifier = unresolvedConstructor.getSqlIdentifier();
    assert sqlIdentifier != null;
    RelDataType type = catalogReader.getNamedType(sqlIdentifier);
    if (type == null) {
        // TODO jvs 12-Feb-2005:  proper type name formatting
        throw newValidationError(sqlIdentifier, RESOURCE.unknownDatatypeName(sqlIdentifier.toString()));
    }
    if (resolvedConstructor == null) {
        if (call.operandCount() > 0) {
            // no user-defined constructor could be found
            throw handleUnresolvedFunction(call, unresolvedConstructor, argTypes, null);
        }
    } else {
        SqlCall testCall = resolvedConstructor.createCall(call.getParserPosition(), call.getOperandList());
        RelDataType returnType = resolvedConstructor.validateOperands(this, scope, testCall);
        assert type == returnType;
    }
    if (config.identifierExpansion()) {
        if (resolvedConstructor != null) {
            ((SqlBasicCall) call).setOperator(resolvedConstructor);
        } else {
            // fake a fully-qualified call to the default constructor
            ((SqlBasicCall) call).setOperator(new SqlFunction(type.getSqlIdentifier(), ReturnTypes.explicit(type), null, null, null, SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR));
        }
    }
    return type;
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlCall(org.apache.calcite.sql.SqlCall) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) SqlFunction(org.apache.calcite.sql.SqlFunction)

Example 99 with SqlIdentifier

use of org.apache.calcite.sql.SqlIdentifier in project flink 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)

Example 100 with SqlIdentifier

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

the class SqlValidatorImpl method validateSelect.

/**
 * Validates a SELECT statement.
 *
 * @param select Select statement
 * @param targetRowType Desired row type, must not be null, may be the data type 'unknown'.
 */
protected void validateSelect(SqlSelect select, RelDataType targetRowType) {
    assert targetRowType != null;
    // Namespace is either a select namespace or a wrapper around one.
    final SelectNamespace ns = getNamespace(select).unwrap(SelectNamespace.class);
    // account.
    assert ns.rowType == null;
    if (select.isDistinct()) {
        validateFeature(RESOURCE.sQLFeature_E051_01(), select.getModifierNode(SqlSelectKeyword.DISTINCT).getParserPosition());
    }
    final SqlNodeList selectItems = select.getSelectList();
    RelDataType fromType = unknownType;
    if (selectItems.size() == 1) {
        final SqlNode selectItem = selectItems.get(0);
        if (selectItem instanceof SqlIdentifier) {
            SqlIdentifier id = (SqlIdentifier) selectItem;
            if (id.isStar() && (id.names.size() == 1)) {
                // Special case: for INSERT ... VALUES(?,?), the SQL
                // standard says we're supposed to propagate the target
                // types down.  So iff the select list is an unqualified
                // star (as it will be after an INSERT ... VALUES has been
                // expanded), then propagate.
                fromType = targetRowType;
            }
        }
    }
    // Make sure that items in FROM clause have distinct aliases.
    final SelectScope fromScope = (SelectScope) getFromScope(select);
    List<String> names = fromScope.getChildNames();
    if (!catalogReader.nameMatcher().isCaseSensitive()) {
        names = names.stream().map(s -> s.toUpperCase(Locale.ROOT)).collect(Collectors.toList());
    }
    final int duplicateAliasOrdinal = Util.firstDuplicate(names);
    if (duplicateAliasOrdinal >= 0) {
        final ScopeChild child = fromScope.children.get(duplicateAliasOrdinal);
        throw newValidationError(child.namespace.getEnclosingNode(), RESOURCE.fromAliasDuplicate(child.name));
    }
    if (select.getFrom() == null) {
        if (this.config.sqlConformance().isFromRequired()) {
            throw newValidationError(select, RESOURCE.selectMissingFrom());
        }
    } else {
        validateFrom(select.getFrom(), fromType, fromScope);
    }
    validateWhereClause(select);
    validateGroupClause(select);
    validateHavingClause(select);
    validateWindowClause(select);
    handleOffsetFetch(select.getOffset(), select.getFetch());
    // Validate the SELECT clause late, because a select item might
    // depend on the GROUP BY list, or the window function might reference
    // window name in the WINDOW clause etc.
    final RelDataType rowType = validateSelectList(selectItems, select, targetRowType);
    ns.setType(rowType);
    // Validate ORDER BY after we have set ns.rowType because in some
    // dialects you can refer to columns of the select list, e.g.
    // "SELECT empno AS x FROM emp ORDER BY x"
    validateOrderList(select);
    if (shouldCheckForRollUp(select.getFrom())) {
        checkRollUpInSelectList(select);
        checkRollUp(null, select, select.getWhere(), getWhereScope(select));
        checkRollUp(null, select, select.getHaving(), getHavingScope(select));
        checkRollUpInWindowDecl(select);
        checkRollUpInGroupBy(select);
        checkRollUpInOrderBy(select);
    }
}
Also used : 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

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