in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexToLixTranslator.java [221:637]
Expression translateCast(
RelDataType sourceType,
RelDataType targetType,
Expression operand) {
Expression convert = null;
switch (targetType.getSqlTypeName()) {
case ANY:
convert = operand;
break;
case DATE:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert =
Expressions.call(BuiltInMethod.STRING_TO_DATE.method, operand);
break;
case TIMESTAMP:
convert = Expressions.convert_(
Expressions.call(BuiltInMethod.FLOOR_DIV.method,
operand, Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
int.class);
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_DATE.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
}
break;
case TIME:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert =
Expressions.call(BuiltInMethod.STRING_TO_TIME.method, operand);
break;
case TIME_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIME.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
break;
case TIMESTAMP:
convert = Expressions.convert_(
Expressions.call(
BuiltInMethod.FLOOR_MOD.method,
operand,
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
int.class);
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
}
break;
case TIME_WITH_LOCAL_TIME_ZONE:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert =
Expressions.call(BuiltInMethod.STRING_TO_TIME_WITH_LOCAL_TIME_ZONE.method, operand);
break;
case TIME:
convert = Expressions.call(
BuiltInMethod.TIME_STRING_TO_TIME_WITH_LOCAL_TIME_ZONE.method,
RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIME_TO_STRING.method,
operand)),
Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
break;
case TIMESTAMP:
convert = Expressions.call(
BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
operand)),
Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME_WITH_LOCAL_TIME_ZONE.method,
operand));
}
break;
case TIMESTAMP:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert =
Expressions.call(BuiltInMethod.STRING_TO_TIMESTAMP.method, operand);
break;
case DATE:
convert = Expressions.multiply(
Expressions.convert_(operand, long.class),
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY));
break;
case TIME:
convert =
Expressions.add(
Expressions.multiply(
Expressions.convert_(
Expressions.call(BuiltInMethod.CURRENT_DATE.method, root),
long.class),
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
Expressions.convert_(operand, long.class));
break;
case TIME_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
Expressions.call(
BuiltInMethod.UNIX_DATE_TO_STRING.method,
Expressions.call(BuiltInMethod.CURRENT_DATE.method, root)),
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
}
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert =
Expressions.call(
BuiltInMethod.STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
operand);
break;
case DATE:
convert = Expressions.call(
BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
Expressions.multiply(
Expressions.convert_(operand, long.class),
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)))),
Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
break;
case TIME:
convert = Expressions.call(
BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
Expressions.add(
Expressions.multiply(
Expressions.convert_(
Expressions.call(BuiltInMethod.CURRENT_DATE.method, root),
long.class),
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
Expressions.convert_(operand, long.class)))),
Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
break;
case TIME_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
Expressions.call(
BuiltInMethod.UNIX_DATE_TO_STRING.method,
Expressions.call(BuiltInMethod.CURRENT_DATE.method, root)),
operand));
break;
case TIMESTAMP:
convert = Expressions.call(
BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
operand)),
Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
}
break;
case BOOLEAN:
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
convert = Expressions.call(
BuiltInMethod.STRING_TO_BOOLEAN.method,
operand);
}
break;
case CHAR:
case VARCHAR:
final SqlIntervalQualifier interval =
sourceType.getIntervalQualifier();
switch (sourceType.getSqlTypeName()) {
case DATE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_DATE_TO_STRING.method,
operand));
break;
case TIME:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIME_TO_STRING.method,
operand));
break;
case TIME_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_STRING.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
break;
case TIMESTAMP:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
operand));
break;
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_STRING.method,
operand,
Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
break;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.INTERVAL_YEAR_MONTH_TO_STRING.method,
operand,
Expressions.constant(interval.timeUnitRange)));
break;
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
case INTERVAL_DAY_SECOND:
case INTERVAL_HOUR:
case INTERVAL_HOUR_MINUTE:
case INTERVAL_HOUR_SECOND:
case INTERVAL_MINUTE:
case INTERVAL_MINUTE_SECOND:
case INTERVAL_SECOND:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.INTERVAL_DAY_TIME_TO_STRING.method,
operand,
Expressions.constant(interval.timeUnitRange),
Expressions.constant(
interval.getFractionalSecondPrecision(
typeFactory.getTypeSystem()))));
break;
case BOOLEAN:
convert = RexImpTable.optimize2(
operand,
Expressions.call(
BuiltInMethod.BOOLEAN_TO_STRING.method,
operand));
break;
case BINARY:
case VARBINARY:
convert = RexImpTable.optimize2(
operand,
Expressions.call(IgniteMethod.BYTESTRING_TO_STRING.method(), operand));
break;
}
break;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
case INTERVAL_DAY_SECOND:
case INTERVAL_HOUR:
case INTERVAL_HOUR_MINUTE:
case INTERVAL_HOUR_SECOND:
case INTERVAL_MINUTE:
case INTERVAL_MINUTE_SECOND:
case INTERVAL_SECOND:
switch (sourceType.getSqlTypeName().getFamily()) {
case CHARACTER:
SqlIntervalQualifier intervalQualifier = targetType.getIntervalQualifier();
Method method = intervalQualifier.isYearMonth() ?
IgniteMethod.PARSE_INTERVAL_YEAR_MONTH.method() :
IgniteMethod.PARSE_INTERVAL_DAY_TIME.method();
convert = Expressions.call(
method,
operand,
Expressions.new_(SqlIntervalQualifier.class,
Expressions.constant(intervalQualifier.getStartUnit()),
Expressions.constant(intervalQualifier.getStartPrecisionPreservingDefault()),
Expressions.constant(intervalQualifier.getEndUnit()),
Expressions.constant(intervalQualifier.getFractionalSecondPrecisionPreservingDefault()),
Expressions.field(null, SqlParserPos.class, "ZERO")
)
);
break;
case NUMERIC:
BigDecimal multiplier = targetType.getSqlTypeName().getEndUnit().multiplier;
if (SqlTypeName.FRACTIONAL_TYPES.contains(sourceType.getSqlTypeName())) {
convert = sourceType.getSqlTypeName() == SqlTypeName.DECIMAL
? operand
: ConverterUtils.convertToDecimal(operand, typeFactory.createSqlType(SqlTypeName.DECIMAL));
convert = Expressions.call(
convert,
IgniteMethod.BIG_DECIMAL_MULTIPLY.method(),
Expressions.constant(multiplier));
}
else
convert = IgniteExpressions.multiplyExact(operand, Expressions.constant(multiplier.longValue()));
convert = ConverterUtils.convert(convert, targetType);
break;
}
break;
case BINARY:
case VARBINARY:
switch (sourceType.getSqlTypeName().getFamily()) {
case CHARACTER:
convert = Expressions.call(IgniteMethod.STRING_TO_BYTESTRING.method(), operand);
}
break;
}
if (convert == null)
convert = ConverterUtils.convert(operand, targetType);
// Going from anything to CHAR(n) or VARCHAR(n), make sure value is no
// longer than n.
boolean pad = false;
boolean truncate = true;
switch (targetType.getSqlTypeName()) {
case CHAR:
case BINARY:
pad = true;
// fall through
case VARCHAR:
case VARBINARY:
final int targetPrecision = targetType.getPrecision();
if (targetPrecision >= 0) {
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
case BINARY:
case VARBINARY:
// If this is a widening cast, no need to truncate.
final int srcPrecision = sourceType.getPrecision();
if (SqlTypeUtil.comparePrecision(srcPrecision, targetPrecision) <= 0)
truncate = false;
// If this is a widening cast, no need to pad.
if (SqlTypeUtil.comparePrecision(srcPrecision, targetPrecision) >= 0)
pad = false;
// fall through
default:
if (truncate || pad) {
convert =
Expressions.call(
pad
? BuiltInMethod.TRUNCATE_OR_PAD.method
: BuiltInMethod.TRUNCATE.method,
convert,
Expressions.constant(targetPrecision));
}
}
}
break;
case TIMESTAMP:
int targetScale = targetType.getScale();
if (targetScale == RelDataType.SCALE_NOT_SPECIFIED)
targetScale = 0;
if (targetScale < sourceType.getScale()) {
convert =
Expressions.call(
BuiltInMethod.ROUND_LONG.method,
convert,
Expressions.constant(
(long)Math.pow(10, 3 - targetScale)));
}
break;
}
return scaleIntervalToNumber(sourceType, targetType, convert);
}