Search in sources :

Example 16 with SqlBasicCall

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

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.
 *
 * <p>Returns null if and only if the original expression is null.
 *
 * @param node      expression to be rewritten
 * @param underFrom whether node appears directly under a FROM clause
 * @return rewritten expression, or null if the original expression is null
 */
@PolyNull
protected SqlNode performUnconditionalRewrites(@PolyNull SqlNode node, boolean underFrom) {
    if (node == null) {
        return null;
    }
    // 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;
            }
            SqlNode 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) {
        final SqlNodeList list = (SqlNodeList) node;
        for (int i = 0; i < list.size(); i++) {
            SqlNode operand = list.get(i);
            SqlNode newOperand = performUnconditionalRewrites(operand, false);
            if (newOperand != null) {
                list.set(i, newOperand);
            }
        }
    }
    // now transform node itself
    final SqlKind kind = node.getKind();
    switch(kind) {
        case VALUES:
            // expression grow indefinitely.
            return node;
        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;
                SqlSelect innerSelect = getInnerSelect(node);
                if (innerSelect != null && isAggregate(innerSelect)) {
                    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 = SqlNonNullableAccessors.getSelectList(innerSelect);
                        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;
            }
        default:
            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) PolyNull(org.checkerframework.checker.nullness.qual.PolyNull)

Example 17 with SqlBasicCall

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

the class StandardConvertletTable method convertSubstring.

/**
 * Converts a SUBSTRING expression.
 *
 * <p>Called automatically via reflection.
 */
public RexNode convertSubstring(SqlRexContext cx, SqlSubstringFunction op, SqlCall call) {
    final SqlLibrary library = cx.getValidator().config().conformance().semantics();
    final SqlBasicCall basicCall = (SqlBasicCall) call;
    switch(library) {
        case BIG_QUERY:
            return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_BIG_QUERY);
        case MYSQL:
            return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_MYSQL);
        case ORACLE:
            return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_ORACLE);
        case POSTGRESQL:
        default:
            return convertFunction(cx, op, call);
    }
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlLibrary(org.apache.calcite.sql.fun.SqlLibrary)

Example 18 with SqlBasicCall

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

the class StandardConvertletTable method toRex.

private RexNode toRex(SqlRexContext cx, SqlBasicCall call, SqlFunction f) {
    final SqlCall call2 = new SqlBasicCall(f, call.getOperandList(), call.getParserPosition());
    final SqlRexConvertlet convertlet = requireNonNull(get(call2));
    return convertlet.convertCall(cx, call2);
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlCall(org.apache.calcite.sql.SqlCall)

Example 19 with SqlBasicCall

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

the class SqlToRelConverter method convertRowValues.

@Nullable
private RelNode convertRowValues(Blackboard bb, SqlNode rowList, Collection<SqlNode> rows, boolean allowLiteralsOnly, @Nullable RelDataType targetRowType) {
    // NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
    // literals into a single LogicalValues; this gives the optimizer a smaller
    // input tree.  For everything else (computed expressions, row
    // sub-queries), we union each row in as a projection on top of a
    // LogicalOneRow.
    final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList = ImmutableList.builder();
    final RelDataType listType = validator().getValidatedNodeType(rowList);
    final RelDataType rowType;
    if (targetRowType != null) {
        rowType = typeFactory.createTypeWithNullability(targetRowType, SqlTypeUtil.containsNullable(listType));
    } else {
        rowType = SqlTypeUtil.promoteToRowType(typeFactory, listType, null);
    }
    final List<RelNode> unionInputs = new ArrayList<>();
    for (SqlNode node : rows) {
        SqlBasicCall call;
        if (isRowConstructor(node)) {
            call = (SqlBasicCall) node;
            ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
            for (Ord<SqlNode> operand : Ord.zip(call.getOperandList())) {
                RexLiteral rexLiteral = convertLiteralInValuesList(operand.e, bb, rowType, operand.i);
                if ((rexLiteral == null) && allowLiteralsOnly) {
                    return null;
                }
                if ((rexLiteral == null) || !config.isCreateValuesRel()) {
                    // fallback to convertRowConstructor
                    tuple = null;
                    break;
                }
                tuple.add(rexLiteral);
            }
            if (tuple != null) {
                tupleList.add(tuple.build());
                continue;
            }
        } else {
            RexLiteral rexLiteral = convertLiteralInValuesList(node, bb, rowType, 0);
            if ((rexLiteral != null) && config.isCreateValuesRel()) {
                tupleList.add(ImmutableList.of(rexLiteral));
                continue;
            } else {
                if ((rexLiteral == null) && allowLiteralsOnly) {
                    return null;
                }
            }
            // convert "1" to "row(1)"
            call = (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(SqlParserPos.ZERO, node);
        }
        unionInputs.add(convertRowConstructor(bb, call));
    }
    LogicalValues values = LogicalValues.create(cluster, rowType, tupleList.build());
    RelNode resultRel;
    if (unionInputs.isEmpty()) {
        resultRel = values;
    } else {
        if (!values.getTuples().isEmpty()) {
            unionInputs.add(values);
        }
        resultRel = LogicalUnion.create(unionInputs, true);
    }
    leaves.put(resultRel, resultRel.getRowType().getFieldCount());
    return resultRel;
}
Also used : RexLiteral(org.apache.calcite.rex.RexLiteral) RelNode(org.apache.calcite.rel.RelNode) SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) ImmutableList(com.google.common.collect.ImmutableList) ArrayList(java.util.ArrayList) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlNode(org.apache.calcite.sql.SqlNode) LogicalValues(org.apache.calcite.rel.logical.LogicalValues) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 20 with SqlBasicCall

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

the class SqlToRelConverter method convertNonCorrelatedSubQuery.

/**
 * Determines if a sub-query is non-correlated and if so, converts it to a
 * constant.
 *
 * @param subQuery  the call that references the sub-query
 * @param bb        blackboard used to convert the sub-query
 * @param converted RelNode tree corresponding to the sub-query
 * @param isExists  true if the sub-query is part of an EXISTS expression
 * @return Whether the sub-query can be converted to a constant
 */
private boolean convertNonCorrelatedSubQuery(SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists) {
    SqlCall call = (SqlBasicCall) subQuery.node;
    if (subQueryConverter.canConvertSubQuery() && isSubQueryNonCorrelated(converted, bb)) {
        // First check if the sub-query has already been converted
        // because it's a nested sub-query.  If so, don't re-evaluate
        // it again.
        RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
        if (constExpr == null) {
            constExpr = subQueryConverter.convertSubQuery(call, this, isExists, config.isExplain());
        }
        if (constExpr != null) {
            subQuery.expr = constExpr;
            mapConvertedNonCorrSubqs.put(call, constExpr);
            return true;
        }
    }
    return false;
}
Also used : SqlBasicCall(org.apache.calcite.sql.SqlBasicCall) SqlCall(org.apache.calcite.sql.SqlCall) RexNode(org.apache.calcite.rex.RexNode)

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