Search in sources :

Example 21 with SqlBasicCall

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

the class SqlToRelConverter method substituteSubQuery.

private void substituteSubQuery(Blackboard bb, SubQuery subQuery) {
    final RexNode expr = subQuery.expr;
    if (expr != null) {
        // Already done.
        return;
    }
    final SqlBasicCall call;
    final RelNode rel;
    final SqlNode query;
    final RelOptUtil.Exists converted;
    switch(subQuery.node.getKind()) {
        case CURSOR:
            convertCursor(bb, subQuery);
            return;
        case ARRAY_QUERY_CONSTRUCTOR:
        case MAP_QUERY_CONSTRUCTOR:
        case MULTISET_QUERY_CONSTRUCTOR:
            if (!config.isExpand()) {
                return;
            }
        // fall through
        case MULTISET_VALUE_CONSTRUCTOR:
            rel = convertMultisets(ImmutableList.of(subQuery.node), bb);
            subQuery.expr = bb.register(rel, JoinRelType.INNER);
            return;
        case IN:
        case NOT_IN:
        case SOME:
        case ALL:
            call = (SqlBasicCall) subQuery.node;
            query = call.operand(1);
            if (!config.isExpand() && !(query instanceof SqlNodeList)) {
                return;
            }
            final SqlNode leftKeyNode = call.operand(0);
            final List<RexNode> leftKeys;
            switch(leftKeyNode.getKind()) {
                case ROW:
                    leftKeys = new ArrayList<>();
                    for (SqlNode sqlExpr : ((SqlBasicCall) leftKeyNode).getOperandList()) {
                        leftKeys.add(bb.convertExpression(sqlExpr));
                    }
                    break;
                default:
                    leftKeys = ImmutableList.of(bb.convertExpression(leftKeyNode));
            }
            if (query instanceof SqlNodeList) {
                SqlNodeList valueList = (SqlNodeList) query;
                // When the list size under the threshold or the list references columns, we convert to OR.
                if (valueList.size() < config.getInSubQueryThreshold() || valueList.accept(new SqlIdentifierFinder())) {
                    subQuery.expr = convertInToOr(bb, leftKeys, valueList, (SqlInOperator) call.getOperator());
                    return;
                }
            // Otherwise, let convertExists translate
            // values list into an inline table for the
            // reference to Q below.
            }
            // and it makes no sense to do the sub-query substitution.
            if (bb.root == null) {
                return;
            }
            final RelDataType targetRowType = SqlTypeUtil.promoteToRowType(typeFactory, validator().getValidatedNodeType(leftKeyNode), null);
            final boolean notIn = call.getOperator().kind == SqlKind.NOT_IN;
            converted = convertExists(query, RelOptUtil.SubQueryType.IN, subQuery.logic, notIn, targetRowType);
            if (converted.indicator) {
                // Generate
                // emp CROSS JOIN (SELECT COUNT(*) AS c,
                // COUNT(deptno) AS ck FROM dept)
                final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
                // fragile
                final RelNode seek = converted.r.getInput(0);
                final int keyCount = leftKeys.size();
                final List<Integer> args = ImmutableIntList.range(0, keyCount);
                LogicalAggregate aggregate = LogicalAggregate.create(seek, ImmutableList.of(), ImmutableBitSet.of(), null, ImmutableList.of(AggregateCall.create(SqlStdOperatorTable.COUNT, false, false, false, ImmutableList.of(), -1, null, RelCollations.EMPTY, longType, null), AggregateCall.create(SqlStdOperatorTable.COUNT, false, false, false, args, -1, null, RelCollations.EMPTY, longType, null)));
                LogicalJoin join = LogicalJoin.create(bb.root(), aggregate, ImmutableList.of(), rexBuilder.makeLiteral(true), ImmutableSet.of(), JoinRelType.INNER);
                bb.setRoot(join, false);
            }
            final RexNode rex = bb.register(converted.r, converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER, leftKeys);
            RelOptUtil.Logic logic = subQuery.logic;
            switch(logic) {
                case TRUE_FALSE_UNKNOWN:
                case UNKNOWN_AS_TRUE:
                    if (!converted.indicator) {
                        logic = RelOptUtil.Logic.TRUE_FALSE;
                    }
                    break;
                default:
                    break;
            }
            subQuery.expr = translateIn(logic, bb.root, rex);
            if (notIn) {
                subQuery.expr = rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
            }
            return;
        case EXISTS:
            // boolean indicating whether the sub-query returned 0 or >= 1 row.
            if (!config.isExpand()) {
                return;
            }
            call = (SqlBasicCall) subQuery.node;
            query = call.operand(0);
            final SqlValidatorScope seekScope = (query instanceof SqlSelect) ? validator().getSelectScope((SqlSelect) query) : null;
            final Blackboard seekBb = createBlackboard(seekScope, null, false);
            final RelNode seekRel = convertQueryOrInList(seekBb, query, null);
            requireNonNull(seekRel, () -> "seekRel is null for query " + query);
            // An EXIST sub-query whose inner child has at least 1 tuple
            // (e.g. an Aggregate with no grouping columns or non-empty Values
            // node) should be simplified to a Boolean constant expression.
            final RelMetadataQuery mq = seekRel.getCluster().getMetadataQuery();
            final Double minRowCount = mq.getMinRowCount(seekRel);
            if (minRowCount != null && minRowCount >= 1D) {
                subQuery.expr = rexBuilder.makeLiteral(true);
                return;
            }
            converted = RelOptUtil.createExistsPlan(seekRel, RelOptUtil.SubQueryType.EXISTS, subQuery.logic, true, relBuilder);
            assert !converted.indicator;
            if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
                return;
            }
            subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
            return;
        case UNIQUE:
            return;
        case SCALAR_QUERY:
            // to a constant expression.
            if (!config.isExpand()) {
                return;
            }
            call = (SqlBasicCall) subQuery.node;
            query = call.operand(0);
            converted = convertExists(query, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
            assert !converted.indicator;
            if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
                return;
            }
            rel = convertToSingleValueSubq(query, converted.r);
            subQuery.expr = bb.register(rel, JoinRelType.LEFT);
            return;
        case SELECT:
            // This is used when converting multiset queries:
            // 
            // select * from unnest(select multiset[deptno] from emps);
            // 
            converted = convertExists(subQuery.node, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
            assert !converted.indicator;
            subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
            // This is used when converting window table functions:
            // 
            // select * from table(tumble(table emps, descriptor(deptno), interval '3' DAY))
            // 
            bb.cursors.add(converted.r);
            return;
        default:
            throw new AssertionError("unexpected kind of sub-query: " + subQuery.node);
    }
}
Also used : SqlValidatorScope(org.apache.calcite.sql.validate.SqlValidatorScope) RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) SqlInOperator(org.apache.calcite.sql.fun.SqlInOperator) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlSelect(org.apache.calcite.sql.SqlSelect) SqlNode(org.apache.calcite.sql.SqlNode) RelOptUtil(org.apache.calcite.plan.RelOptUtil) RelHint(org.apache.calcite.rel.hint.RelHint) LogicalAggregate(org.apache.calcite.rel.logical.LogicalAggregate) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) RelNode(org.apache.calcite.rel.RelNode) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) SqlNodeList(org.apache.calcite.sql.SqlNodeList) RexNode(org.apache.calcite.rex.RexNode)

Example 22 with SqlBasicCall

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

the class SqlToRelConverter method convertInToOr.

/**
 * Converts "x IN (1, 2, ...)" to "x=1 OR x=2 OR ...".
 *
 * @param leftKeys   LHS
 * @param valuesList RHS
 * @param op         The operator (IN, NOT IN, &gt; SOME, ...)
 * @return converted expression
 */
@Nullable
private RexNode convertInToOr(final Blackboard bb, final List<RexNode> leftKeys, SqlNodeList valuesList, SqlInOperator op) {
    final List<RexNode> comparisons = new ArrayList<>();
    for (SqlNode rightVals : valuesList) {
        RexNode rexComparison;
        final SqlOperator comparisonOp;
        if (op instanceof SqlQuantifyOperator) {
            comparisonOp = RelOptUtil.op(((SqlQuantifyOperator) op).comparisonKind, SqlStdOperatorTable.EQUALS);
        } else {
            comparisonOp = SqlStdOperatorTable.EQUALS;
        }
        if (leftKeys.size() == 1) {
            rexComparison = rexBuilder.makeCall(comparisonOp, leftKeys.get(0), ensureSqlType(leftKeys.get(0).getType(), bb.convertExpression(rightVals)));
        } else {
            assert rightVals instanceof SqlCall;
            final SqlBasicCall call = (SqlBasicCall) rightVals;
            assert (call.getOperator() instanceof SqlRowOperator) && call.operandCount() == leftKeys.size();
            rexComparison = RexUtil.composeConjunction(rexBuilder, Util.transform(Pair.zip(leftKeys, call.getOperandList()), pair -> rexBuilder.makeCall(comparisonOp, pair.left, // TODO: remove requireNonNull when checkerframework issue resolved
            ensureSqlType(requireNonNull(pair.left, "pair.left").getType(), bb.convertExpression(pair.right)))));
        }
        comparisons.add(rexComparison);
    }
    switch(op.kind) {
        case ALL:
            return RexUtil.composeConjunction(rexBuilder, comparisons, true);
        case NOT_IN:
            return rexBuilder.makeCall(SqlStdOperatorTable.NOT, RexUtil.composeDisjunction(rexBuilder, comparisons));
        case IN:
        case SOME:
            return RexUtil.composeDisjunction(rexBuilder, comparisons, true);
        default:
            throw new AssertionError();
    }
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlOperator(org.apache.calcite.sql.SqlOperator) SqlQuantifyOperator(org.apache.calcite.sql.fun.SqlQuantifyOperator) SqlCall(org.apache.calcite.sql.SqlCall) ArrayList(java.util.ArrayList) SqlRowOperator(org.apache.calcite.sql.fun.SqlRowOperator) RexNode(org.apache.calcite.rex.RexNode) SqlNode(org.apache.calcite.sql.SqlNode) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 23 with SqlBasicCall

use of org.apache.calcite.sql.SqlBasicCall in project flink-mirror by flink-ci.

the class SqlValidatorImpl method performUnconditionalRewrites.

/**
 * Performs expression rewrites which are always used unconditionally. These rewrites massage
 * the expression tree into a standard form so that the rest of the validation logic can be
 * simpler.
 *
 * @param node expression to be rewritten
 * @param underFrom whether node appears directly under a FROM clause
 * @return rewritten expression
 */
protected SqlNode performUnconditionalRewrites(SqlNode node, boolean underFrom) {
    if (node == null) {
        return null;
    }
    SqlNode newOperand;
    // first transform operands and invoke generic call rewrite
    if (node instanceof SqlCall) {
        if (node instanceof SqlMerge) {
            validatingSqlMerge = true;
        }
        SqlCall call = (SqlCall) node;
        final SqlKind kind = call.getKind();
        final List<SqlNode> operands = call.getOperandList();
        for (int i = 0; i < operands.size(); i++) {
            SqlNode operand = operands.get(i);
            boolean childUnderFrom;
            if (kind == SqlKind.SELECT) {
                childUnderFrom = i == SqlSelect.FROM_OPERAND;
            } else if (kind == SqlKind.AS && (i == 0)) {
                // for an aliased expression, it is under FROM if
                // the AS expression is under FROM
                childUnderFrom = underFrom;
            } else {
                childUnderFrom = false;
            }
            newOperand = performUnconditionalRewrites(operand, childUnderFrom);
            if (newOperand != null && newOperand != operand) {
                call.setOperand(i, newOperand);
            }
        }
        if (call.getOperator() instanceof SqlUnresolvedFunction) {
            assert call instanceof SqlBasicCall;
            final SqlUnresolvedFunction function = (SqlUnresolvedFunction) call.getOperator();
            // This function hasn't been resolved yet.  Perform
            // a half-hearted resolution now in case it's a
            // builtin function requiring special casing.  If it's
            // not, we'll handle it later during overload resolution.
            final List<SqlOperator> overloads = new ArrayList<>();
            opTab.lookupOperatorOverloads(function.getNameAsId(), function.getFunctionType(), SqlSyntax.FUNCTION, overloads, catalogReader.nameMatcher());
            if (overloads.size() == 1) {
                ((SqlBasicCall) call).setOperator(overloads.get(0));
            }
        }
        if (config.callRewrite()) {
            node = call.getOperator().rewriteCall(this, call);
        }
    } else if (node instanceof SqlNodeList) {
        SqlNodeList list = (SqlNodeList) node;
        for (int i = 0, count = list.size(); i < count; i++) {
            SqlNode operand = list.get(i);
            newOperand = performUnconditionalRewrites(operand, false);
            if (newOperand != null) {
                list.getList().set(i, newOperand);
            }
        }
    }
    // now transform node itself
    final SqlKind kind = node.getKind();
    switch(kind) {
        case VALUES:
            // CHECKSTYLE: IGNORE 1
            if (underFrom || true) {
                // over and over
                return node;
            } else {
                final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
                selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
                return new SqlSelect(node.getParserPosition(), null, selectList, node, null, null, null, null, null, null, null, null);
            }
        case ORDER_BY:
            {
                SqlOrderBy orderBy = (SqlOrderBy) node;
                handleOffsetFetch(orderBy.offset, orderBy.fetch);
                if (orderBy.query instanceof SqlSelect) {
                    SqlSelect select = (SqlSelect) orderBy.query;
                    // an order-sensitive function like RANK.
                    if (select.getOrderList() == null) {
                        // push ORDER BY into existing select
                        select.setOrderBy(orderBy.orderList);
                        select.setOffset(orderBy.offset);
                        select.setFetch(orderBy.fetch);
                        return select;
                    }
                }
                if (orderBy.query instanceof SqlWith && ((SqlWith) orderBy.query).body instanceof SqlSelect) {
                    SqlWith with = (SqlWith) orderBy.query;
                    SqlSelect select = (SqlSelect) with.body;
                    // an order-sensitive function like RANK.
                    if (select.getOrderList() == null) {
                        // push ORDER BY into existing select
                        select.setOrderBy(orderBy.orderList);
                        select.setOffset(orderBy.offset);
                        select.setFetch(orderBy.fetch);
                        return with;
                    }
                }
                final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
                selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
                final SqlNodeList orderList;
                if (getInnerSelect(node) != null && isAggregate(getInnerSelect(node))) {
                    orderList = SqlNode.clone(orderBy.orderList);
                    // We assume that ORDER BY item is present in SELECT list.
                    for (int i = 0; i < orderList.size(); i++) {
                        SqlNode sqlNode = orderList.get(i);
                        SqlNodeList selectList2 = getInnerSelect(node).getSelectList();
                        for (Ord<SqlNode> sel : Ord.zip(selectList2)) {
                            if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) {
                                orderList.set(i, SqlLiteral.createExactNumeric(Integer.toString(sel.i + 1), SqlParserPos.ZERO));
                            }
                        }
                    }
                } else {
                    orderList = orderBy.orderList;
                }
                return new SqlSelect(SqlParserPos.ZERO, null, selectList, orderBy.query, null, null, null, null, orderList, orderBy.offset, orderBy.fetch, null);
            }
        case EXPLICIT_TABLE:
            {
                // (TABLE t) is equivalent to (SELECT * FROM t)
                SqlCall call = (SqlCall) node;
                final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
                selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
                return new SqlSelect(SqlParserPos.ZERO, null, selectList, call.operand(0), null, null, null, null, null, null, null, null);
            }
        case DELETE:
            {
                SqlDelete call = (SqlDelete) node;
                SqlSelect select = createSourceSelectForDelete(call);
                call.setSourceSelect(select);
                break;
            }
        case UPDATE:
            {
                SqlUpdate call = (SqlUpdate) node;
                SqlSelect select = createSourceSelectForUpdate(call);
                call.setSourceSelect(select);
                // in which case leave it alone).
                if (!validatingSqlMerge) {
                    SqlNode selfJoinSrcExpr = getSelfJoinExprForUpdate(call.getTargetTable(), UPDATE_SRC_ALIAS);
                    if (selfJoinSrcExpr != null) {
                        node = rewriteUpdateToMerge(call, selfJoinSrcExpr);
                    }
                }
                break;
            }
        case MERGE:
            {
                SqlMerge call = (SqlMerge) node;
                rewriteMerge(call);
                break;
            }
    }
    return node;
}
Also used : Ord(org.apache.calcite.linq4j.Ord) SqlCall(org.apache.calcite.sql.SqlCall) SqlOperator(org.apache.calcite.sql.SqlOperator) SqlWith(org.apache.calcite.sql.SqlWith) ArrayList(java.util.ArrayList) SqlKind(org.apache.calcite.sql.SqlKind) SqlUpdate(org.apache.calcite.sql.SqlUpdate) SqlMerge(org.apache.calcite.sql.SqlMerge) SqlSelect(org.apache.calcite.sql.SqlSelect) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlDelete(org.apache.calcite.sql.SqlDelete) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlOrderBy(org.apache.calcite.sql.SqlOrderBy) SqlNode(org.apache.calcite.sql.SqlNode) SqlUnresolvedFunction(org.apache.calcite.sql.SqlUnresolvedFunction)

Example 24 with SqlBasicCall

use of org.apache.calcite.sql.SqlBasicCall in project flink-mirror by flink-ci.

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 25 with SqlBasicCall

use of org.apache.calcite.sql.SqlBasicCall in project flink-mirror by flink-ci.

the class FlinkCalciteSqlValidator method validateJoin.

@Override
protected void validateJoin(SqlJoin join, SqlValidatorScope scope) {
    // temporarily forbid the common predicates until the problem is fixed (see FLINK-7865).
    if (join.getJoinType() == JoinType.LEFT && SqlUtil.stripAs(join.getRight()).getKind() == SqlKind.COLLECTION_TABLE) {
        SqlNode right = SqlUtil.stripAs(join.getRight());
        if (right instanceof SqlBasicCall) {
            SqlBasicCall call = (SqlBasicCall) right;
            SqlNode operand0 = call.operand(0);
            if (operand0 instanceof SqlBasicCall && ((SqlBasicCall) operand0).getOperator() instanceof SqlWindowTableFunction) {
                return;
            }
        }
        final SqlNode condition = join.getCondition();
        if (condition != null && (!SqlUtil.isLiteral(condition) || ((SqlLiteral) condition).getValueAs(Boolean.class) != Boolean.TRUE)) {
            throw new ValidationException(String.format("Left outer joins with a table function do not accept a predicate such as %s. " + "Only literal TRUE is accepted.", condition));
        }
    }
    super.validateJoin(join, scope);
}
Also used : ValidationException(org.apache.flink.table.api.ValidationException) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlLiteral(org.apache.calcite.sql.SqlLiteral) SqlWindowTableFunction(org.apache.calcite.sql.SqlWindowTableFunction) SqlNode(org.apache.calcite.sql.SqlNode)

Aggregations

SqlBasicCall (org.apache.calcite.sql.SqlBasicCall)67 SqlNode (org.apache.calcite.sql.SqlNode)50 SqlOperator (org.apache.calcite.sql.SqlOperator)27 ArrayList (java.util.ArrayList)26 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