Search in sources :

Example 41 with SqlCall

use of org.apache.calcite.sql.SqlCall in project flink 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, String alias, 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 = deriveAlias(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 MATCH_RECOGNIZE:
                // give this anonymous construct a name since later
                // query processing stages rely on it
                alias = deriveAlias(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;
        }
    }
    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 = call.operand(1).toString();
            }
            final boolean needAlias = call.operandCount() > 2;
            expr = call.operand(0);
            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 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;
            }
            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, 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 = deriveAlias(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 42 with SqlCall

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

the class SqlValidatorImpl method registerSetop.

private void registerSetop(SqlValidatorScope parentScope, SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, String alias, boolean forceNullable) {
    SqlCall call = (SqlCall) node;
    final SetopNamespace setopNamespace = createSetopNamespace(call, enclosingNode);
    registerNamespace(usingScope, alias, setopNamespace, forceNullable);
    // A setop is in the same scope as its parent.
    scopes.put(call, parentScope);
    for (SqlNode operand : call.getOperandList()) {
        registerQuery(parentScope, null, operand, operand, null, false);
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlNode(org.apache.calcite.sql.SqlNode)

Example 43 with SqlCall

use of org.apache.calcite.sql.SqlCall in project flink 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 44 with SqlCall

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

the class SqlValidatorImpl method validateNoAggs.

/**
 * Throws an error if there is an aggregate or windowed aggregate in the given clause.
 *
 * @param aggFinder Finder for the particular kind(s) of aggregate function
 * @param node Parse tree
 * @param clause Name of clause: "WHERE", "GROUP BY", "ON"
 */
private void validateNoAggs(AggFinder aggFinder, SqlNode node, String clause) {
    final SqlCall agg = aggFinder.findAgg(node);
    if (agg == null) {
        return;
    }
    final SqlOperator op = agg.getOperator();
    if (op == SqlStdOperatorTable.OVER) {
        throw newValidationError(agg, RESOURCE.windowedAggregateIllegalInClause(clause));
    } else if (op.isGroup() || op.isGroupAuxiliary()) {
        throw newValidationError(agg, RESOURCE.groupFunctionMustAppearInGroupByClause(op.getName()));
    } else {
        throw newValidationError(agg, RESOURCE.aggregateIllegalInClause(clause));
    }
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) SqlOperator(org.apache.calcite.sql.SqlOperator)

Example 45 with SqlCall

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

the class SqlValidatorImpl method validatePivot.

public void validatePivot(SqlPivot pivot) {
    final PivotScope scope = (PivotScope) getJoinScope(pivot);
    final PivotNamespace ns = getNamespace(pivot).unwrap(PivotNamespace.class);
    assert ns.rowType == null;
    // Given
    // query PIVOT (agg1 AS a, agg2 AS b, ...
    // FOR (axis1, ..., axisN)
    // IN ((v11, ..., v1N) AS label1,
    // (v21, ..., v2N) AS label2, ...))
    // the type is
    // k1, ... kN, a_label1, b_label1, ..., a_label2, b_label2, ...
    // where k1, ... kN are columns that are not referenced as an argument to
    // an aggregate or as an axis.
    // Aggregates, e.g. "PIVOT (sum(x) AS sum_x, count(*) AS c)"
    final List<Pair<String, RelDataType>> aggNames = new ArrayList<>();
    pivot.forEachAgg((alias, call) -> {
        call.validate(this, scope);
        final RelDataType type = deriveType(scope, call);
        aggNames.add(Pair.of(alias, type));
        if (!(call instanceof SqlCall) || !(((SqlCall) call).getOperator() instanceof SqlAggFunction)) {
            throw newValidationError(call, RESOURCE.pivotAggMalformed());
        }
    });
    // Axes, e.g. "FOR (JOB, DEPTNO)"
    final List<RelDataType> axisTypes = new ArrayList<>();
    final List<SqlIdentifier> axisIdentifiers = new ArrayList<>();
    for (SqlNode axis : pivot.axisList) {
        SqlIdentifier identifier = (SqlIdentifier) axis;
        identifier.validate(this, scope);
        final RelDataType type = deriveType(scope, identifier);
        axisTypes.add(type);
        axisIdentifiers.add(identifier);
    }
    // Columns that have been seen as arguments to aggregates or as axes
    // do not appear in the output.
    final Set<String> columnNames = pivot.usedColumnNames();
    final RelDataTypeFactory.Builder typeBuilder = typeFactory.builder();
    scope.getChild().getRowType().getFieldList().forEach(field -> {
        if (!columnNames.contains(field.getName())) {
            typeBuilder.add(field);
        }
    });
    // Values, e.g. "IN (('CLERK', 10) AS c10, ('MANAGER, 20) AS m20)"
    pivot.forEachNameValues((alias, nodeList) -> {
        if (nodeList.size() != axisTypes.size()) {
            throw newValidationError(nodeList, RESOURCE.pivotValueArityMismatch(nodeList.size(), axisTypes.size()));
        }
        final SqlOperandTypeChecker typeChecker = OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED;
        Pair.forEach(axisIdentifiers, nodeList, (identifier, subNode) -> {
            subNode.validate(this, scope);
            typeChecker.checkOperandTypes(new SqlCallBinding(this, scope, SqlStdOperatorTable.EQUALS.createCall(subNode.getParserPosition(), identifier, subNode)), true);
        });
        Pair.forEach(aggNames, (aggAlias, aggType) -> typeBuilder.add(aggAlias == null ? alias : alias + "_" + aggAlias, aggType));
    });
    final RelDataType rowType = typeBuilder.build();
    ns.setType(rowType);
}
Also used : SqlCall(org.apache.calcite.sql.SqlCall) ArrayList(java.util.ArrayList) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) BitString(org.apache.calcite.util.BitString) SqlIdentifier(org.apache.calcite.sql.SqlIdentifier) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) SqlCallBinding(org.apache.calcite.sql.SqlCallBinding) SqlOperandTypeChecker(org.apache.calcite.sql.type.SqlOperandTypeChecker) IdPair(org.apache.calcite.sql.util.IdPair) Pair(org.apache.calcite.util.Pair) 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