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);
}