public static Expression convert()

in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/ConverterUtils.java [223:428]


    public static Expression convert(Expression operand, Type fromType, Type toType) {
        if (!Types.needTypeCast(fromType, toType))
            return operand;

        if (toType == Void.class)
            return RexImpTable.NULL_EXPR;

        if (toType == BigDecimal.class)
            throw new AssertionError("For conversion to decimal, ConverterUtils#convertToDecimal method should be used instead.");

        // E.g. from "Short" to "int".
        // Generate "x.intValue()".
        final Primitive toPrimitive = Primitive.of(toType);
        final Primitive toBox = Primitive.ofBox(toType);
        final Primitive fromBox = Primitive.ofBox(fromType);
        final Primitive fromPrimitive = Primitive.of(fromType);
        final boolean fromNumber = fromType instanceof Class
            && Number.class.isAssignableFrom((Class<?>)fromType);
        if (fromType == String.class) {
            if (toPrimitive != null) {
                if (toPrimitive.isFixedNumeric())
                    return IgniteExpressions.parseStringChecked(operand, toPrimitive);

                switch (toPrimitive) {
                    case CHAR:
                    case FLOAT:
                    case DOUBLE:
                        // Generate "SqlFunctions.toShort(x)".
                        return Expressions.call(
                            SqlFunctions.class,
                            "to" + SqlFunctions.initcap(toPrimitive.primitiveName),
                            operand);
                    default:
                        // Generate "Short.parseShort(x)".
                        return Expressions.call(
                            toPrimitive.boxClass,
                            "parse" + SqlFunctions.initcap(toPrimitive.primitiveName),
                            operand);
                }
            }
            if (toBox != null) {
                if (toBox.isFixedNumeric())
                    operand = IgniteExpressions.parseStringChecked(operand, toBox);

                switch (toBox) {
                    case CHAR:
                        // Generate "SqlFunctions.toCharBoxed(x)".
                        return Expressions.call(
                            SqlFunctions.class,
                            "to" + SqlFunctions.initcap(toBox.primitiveName) + "Boxed",
                            operand);
                    default:
                        // Generate "Short.valueOf(x)".
                        return Expressions.call(
                            toBox.boxClass,
                            "valueOf",
                            operand);
                }
            }
        }
        if (toPrimitive != null) {
            if (toPrimitive == Primitive.BOOLEAN) {
                if (fromPrimitive != null)
                    return Expressions.notEqual(operand, Expressions.constant(0));

                if (fromNumber) {
                    // Construct "SqlFunctions.ne(val, Number.valueOf(0))" expression.
                    return Expressions.call(SqlFunctions.class, "ne", operand,
                            Expressions.call(fromType, "valueOf", Expressions.constant(0)));
                }

                return Expressions.call(SqlFunctions.class, "toBoolean", operand);
            }

            if (fromPrimitive != null) {
                // E.g. from "float" to "double"
                return IgniteExpressions.convertChecked(operand, fromPrimitive, toPrimitive);
            }
            if (fromNumber) {
                // Generate "x.shortValue()".
                return IgniteExpressions.unboxChecked(operand, fromBox, toPrimitive);
            }
            else {
                // E.g. from "Object" to "short".
                // Generate "SqlFunctions.toShort(x)"
                return Expressions.call(
                    SqlFunctions.class,
                    "to" + SqlFunctions.initcap(toPrimitive.primitiveName),
                    operand);
            }
        }
        else if (fromNumber && toBox != null) {
            // E.g. from "Short" to "Integer"
            // Generate "x == null ? null : Integer.valueOf(x.intValue())"
            return Expressions.condition(
                Expressions.equal(operand, RexImpTable.NULL_EXPR),
                RexImpTable.NULL_EXPR,
                Expressions.box(
                    IgniteExpressions.unboxChecked(operand, fromBox, toBox),
                    toBox));
        }
        else if (fromPrimitive != null && toBox != null) {
            // E.g. from "int" to "Long".
            // Generate Long.valueOf(x)
            // Eliminate primitive casts like Long.valueOf((long) x)
            if (operand instanceof UnaryExpression) {
                UnaryExpression una = (UnaryExpression)operand;
                if (una.nodeType == ExpressionType.Convert
                    && Primitive.of(una.getType()) == toBox) {
                    Primitive origin = Primitive.of(una.expression.type);
                    if (origin != null && toBox.assignableFrom(origin))
                        return Expressions.box(una.expression, toBox);
                }
            }
            if (fromType == toBox.primitiveClass)
                return Expressions.box(operand, toBox);
            // E.g., from "int" to "Byte".
            // Convert it first and generate "Byte.valueOf((byte)x)"
            // Because there is no method "Byte.valueOf(int)" in Byte
            return Expressions.box(
                IgniteExpressions.convertChecked(operand, fromPrimitive, toBox),
                toBox);
        }
        // Convert datetime types to internal storage type:
        // 1. java.sql.Date -> int or Integer
        // 2. java.sql.Time -> int or Integer
        // 3. java.sql.Timestamp -> long or Long
        if (representAsInternalType(fromType)) {
            final Expression internalTypedOperand =
                toInternal(operand, fromType, toType);
            if (operand != internalTypedOperand)
                return internalTypedOperand;
        }
        // Convert internal storage type to datetime types:
        // 1. int or Integer -> java.sql.Date
        // 2. int or Integer -> java.sql.Time
        // 3. long or Long -> java.sql.Timestamp
        if (representAsInternalType(toType)) {
            final Expression originTypedOperand =
                fromInternal(operand, fromType, toType);
            if (operand != originTypedOperand)
                return originTypedOperand;
        }
        else if (toType == String.class) {
            if (fromPrimitive != null) {
                switch (fromPrimitive) {
                    case DOUBLE:
                    case FLOAT:
                        // E.g. from "double" to "String"
                        // Generate "SqlFunctions.toString(x)"
                        return Expressions.call(
                            SqlFunctions.class,
                            "toString",
                            operand);
                    default:
                        // E.g. from "int" to "String"
                        // Generate "Integer.toString(x)"
                        return Expressions.call(
                            fromPrimitive.boxClass,
                            "toString",
                            operand);
                }
            }
            else if (fromType == BigDecimal.class) {
                // E.g. from "BigDecimal" to "String"
                // Generate "SqlFunctions.toString(x)"
                return Expressions.condition(
                    Expressions.equal(operand, RexImpTable.NULL_EXPR),
                    RexImpTable.NULL_EXPR,
                    Expressions.call(
                        IgniteSqlFunctions.class,
                        "toString",
                        operand));
            }
            else {
                Expression result;
                try {
                    // Avoid to generate code like:
                    // "null.toString()" or "(xxx) null.toString()"
                    if (operand instanceof ConstantExpression) {
                        ConstantExpression ce = (ConstantExpression)operand;
                        if (ce.value == null)
                            return Expressions.convert_(operand, toType);
                    }
                    // Try to call "toString()" method
                    // E.g. from "Integer" to "String"
                    // Generate "x == null ? null : x.toString()"
                    result = Expressions.condition(
                        Expressions.equal(operand, RexImpTable.NULL_EXPR),
                        RexImpTable.NULL_EXPR,
                        Expressions.call(operand, "toString"));
                }
                catch (RuntimeException e) {
                    // For some special cases, e.g., "BuiltInMethod.LESSER",
                    // its return type is generic ("Comparable"), which contains
                    // no "toString()" method. We fall through to "(String)x".
                    return Expressions.convert_(operand, toType);
                }
                return result;
            }
        }
        else if (toType == UUID.class && fromType == String.class)
            return Expressions.call(UUID.class, "fromString", operand);

        return Expressions.convert_(operand, toType);
    }