in core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java [611:706]
private static Expression checkExpressionPadTruncate(
Expression operand,
RelDataType sourceType,
RelDataType 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) {
return operand;
}
switch (sourceType.getSqlTypeName()) {
case CHAR:
case VARCHAR:
case BINARY:
case VARBINARY:
// If this is a widening cast, no need to truncate.
final int sourcePrecision = sourceType.getPrecision();
if (SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision)
<= 0) {
truncate = false;
}
// If this is a narrowing cast, no need to pad.
// However, conversion from VARCHAR(N) to CHAR(N) still requires padding,
// because VARCHAR(N) does not represent the spaces explicitly,
// whereas CHAR(N) does.
if ((SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision) >= 0)
&& (sourceType.getSqlTypeName() != SqlTypeName.VARCHAR)) {
pad = false;
}
// fall through
default:
if (truncate || pad) {
final Method method =
pad ? BuiltInMethod.TRUNCATE_OR_PAD.method
: BuiltInMethod.TRUNCATE.method;
return Expressions.call(method, operand,
Expressions.constant(targetPrecision));
}
return operand;
}
// Checkstyle thinks that the previous branch should have a break, but it
// is mistaken.
// CHECKSTYLE: IGNORE 1
case TIMESTAMP:
int targetScale = targetType.getScale();
if (targetScale == RelDataType.SCALE_NOT_SPECIFIED) {
targetScale = 0;
}
if (targetScale < sourceType.getScale()) {
return Expressions.call(BuiltInMethod.ROUND_LONG.method, operand,
Expressions.constant((long) Math.pow(10, 3 - targetScale)));
}
return operand;
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:
final SqlTypeFamily family =
requireNonNull(sourceType.getSqlTypeName().getFamily(),
() -> "null SqlTypeFamily for " + sourceType + ", SqlTypeName "
+ sourceType.getSqlTypeName());
switch (family) {
case NUMERIC:
final BigDecimal multiplier =
targetType.getSqlTypeName().getEndUnit().multiplier;
final BigDecimal divider = BigDecimal.ONE;
return RexImpTable.multiplyDivide(operand, multiplier, divider);
default:
return operand;
}
default:
return operand;
}
}