Search in sources :

Example 66 with SqlBasicCall

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

the class RexSqlStandardConvertletTable method registerTypeAppendOp.

/**
 * Creates and registers a convertlet for an operator in which
 * the SQL representation needs the result type appended
 * as an extra argument (e.g. CAST).
 *
 * @param op operator instance
 */
private void registerTypeAppendOp(final SqlOperator op) {
    registerOp(op, (converter, call) -> {
        @Nullable List<@Nullable SqlNode> operandList = convertExpressionList(converter, call.operands);
        if (operandList == null) {
            return null;
        }
        SqlDataTypeSpec typeSpec = SqlTypeUtil.convertTypeToSpec(call.getType());
        operandList.add(typeSpec);
        return new SqlBasicCall(op, operandList, SqlParserPos.ZERO);
    });
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlDataTypeSpec(org.apache.calcite.sql.SqlDataTypeSpec) Nullable(org.checkerframework.checker.nullness.qual.Nullable) SqlNode(org.apache.calcite.sql.SqlNode)

Example 67 with SqlBasicCall

use of org.apache.calcite.sql.SqlBasicCall 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 = getNamespaceOrThrow(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).operand(0);
            } else {
                identifier = (SqlIdentifier) requireNonNull(node, () -> "order by field is null. All fields: " + orderBy);
            }
            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 = getNamespaceOrThrow(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) {
            String intervalValue = interval.toValue();
            throw newValidationError(interval, RESOURCE.intervalMustBeNonNegative(intervalValue != null ? intervalValue : interval.toString()));
        }
        if (orderBy == null || orderBy.size() == 0) {
            throw newValidationError(interval, RESOURCE.cannotUseWithinWithoutOrderBy());
        }
        SqlNode firstOrderByColumn = orderBy.get(0);
        SqlIdentifier identifier;
        if (firstOrderByColumn instanceof SqlBasicCall) {
            identifier = ((SqlBasicCall) firstOrderByColumn).operand(0);
        } else {
            identifier = (SqlIdentifier) requireNonNull(firstOrderByColumn, "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(getNamespaceOrThrow(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 68 with SqlBasicCall

use of org.apache.calcite.sql.SqlBasicCall 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 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, @Nullable String alias, @Nullable 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 = deriveAliasNonNull(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 UNPIVOT:
            case MATCH_RECOGNIZE:
                // give this anonymous construct a name since later
                // query processing stages rely on it
                alias = deriveAliasNonNull(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;
            default:
                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 = String.valueOf(call.operand(1));
            }
            expr = call.operand(0);
            final boolean needAlias = call.operandCount() > 2 || expr.getKind() == SqlKind.VALUES || expr.getKind() == SqlKind.UNNEST && (((SqlCall) expr).operand(0).getKind() == SqlKind.ARRAY_VALUE_CONSTRUCTOR || ((SqlCall) expr).operand(0).getKind() == SqlKind.MULTISET_VALUE_CONSTRUCTOR);
            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 UNPIVOT:
            registerUnpivot(parentScope, usingScope, (SqlUnpivot) 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;
                default:
                    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, requireNonNull(alias, "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 = deriveAliasNonNull(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 69 with SqlBasicCall

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

the class SqlValidatorImpl method makeNullaryCall.

@Override
@Nullable
public SqlCall makeNullaryCall(SqlIdentifier id) {
    if (id.names.size() == 1 && !id.isComponentQuoted(0)) {
        final List<SqlOperator> list = new ArrayList<>();
        opTab.lookupOperatorOverloads(id, null, SqlSyntax.FUNCTION, list, catalogReader.nameMatcher());
        for (SqlOperator operator : list) {
            if (operator.getSyntax() == SqlSyntax.FUNCTION_ID) {
                // operator validation.
                return new SqlBasicCall(operator, ImmutableList.of(), id.getParserPosition(), null).withExpanded(true);
            }
        }
    }
    return null;
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlOperator(org.apache.calcite.sql.SqlOperator) ArrayList(java.util.ArrayList) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Aggregations

SqlBasicCall (org.apache.calcite.sql.SqlBasicCall)69 SqlNode (org.apache.calcite.sql.SqlNode)52 ArrayList (java.util.ArrayList)28 SqlOperator (org.apache.calcite.sql.SqlOperator)27 SqlCall (org.apache.calcite.sql.SqlCall)25 SqlIdentifier (org.apache.calcite.sql.SqlIdentifier)20 RelDataType (org.apache.calcite.rel.type.RelDataType)19 SqlNodeList (org.apache.calcite.sql.SqlNodeList)17 SqlLiteral (org.apache.calcite.sql.SqlLiteral)14 SqlSelect (org.apache.calcite.sql.SqlSelect)13 SqlKind (org.apache.calcite.sql.SqlKind)12 RexNode (org.apache.calcite.rex.RexNode)8 SqlJoin (org.apache.calcite.sql.SqlJoin)8 SqlWindowTableFunction (org.apache.calcite.sql.SqlWindowTableFunction)8 IdentityHashMap (java.util.IdentityHashMap)6 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)6 SqlWith (org.apache.calcite.sql.SqlWith)6 ImmutableList (com.google.common.collect.ImmutableList)5 HashMap (java.util.HashMap)5 List (java.util.List)5