in flink-table/flink-table-common/src/main/java/org/apache/flink/table/expressions/ValueLiteralExpression.java [229:330]
public String asSerializableString(SqlFactory sqlFactory) {
if (value == null && !dataType.getLogicalType().is(LogicalTypeRoot.NULL)) {
return String.format(
"CAST(NULL AS %s)",
// casting does not support nullability
dataType.getLogicalType().copy(true).asSerializableString());
}
final LogicalType logicalType = dataType.getLogicalType();
switch (logicalType.getTypeRoot()) {
case TINYINT:
return String.format("CAST(%s AS TINYINT)", value);
case SMALLINT:
return String.format("CAST(%s AS SMALLINT)", value);
case BIGINT:
return String.format("CAST(%s AS BIGINT)", value);
case FLOAT:
return String.format("CAST(%s AS FLOAT)", value);
case DOUBLE:
return String.format("CAST(%s AS DOUBLE)", value);
case DECIMAL:
DecimalType decimalType = (DecimalType) logicalType;
final BigDecimal decimal = getValueAs(BigDecimal.class).get();
final String decimalString = decimal.toString();
if (decimal.precision() == decimalType.getPrecision()
&& decimal.scale() == decimalType.getScale()) {
return decimalString;
} else {
return String.format(
"CAST(%s AS DECIMAL(%d, %d))",
decimalString, decimalType.getPrecision(), decimalType.getScale());
}
case CHAR:
case VARCHAR:
return "'" + ((String) value).replace("'", "''") + "'";
case INTEGER:
return String.valueOf(value);
case BOOLEAN:
case NULL:
return String.valueOf(value).toUpperCase(Locale.ROOT);
case BINARY:
case VARBINARY:
return String.format("X'%s'", StringUtils.byteToHexString((byte[]) value));
case DATE:
return String.format("DATE '%s'", getValueAs(LocalDate.class).get());
case TIME_WITHOUT_TIME_ZONE:
return String.format("TIME '%s'", getValueAs(LocalTime.class).get());
case TIMESTAMP_WITHOUT_TIME_ZONE:
final LocalDateTime localDateTime = getValueAs(LocalDateTime.class).get();
return String.format(
"TIMESTAMP '%s %s'",
localDateTime.toLocalDate(), localDateTime.toLocalTime());
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
final Instant instant = getValueAs(Instant.class).get();
if (instant.getNano() % 1_000_000 != 0) {
throw new TableException(
"Maximum precision for TIMESTAMP_WITH_LOCAL_TIME_ZONE literals is '3'");
}
return String.format("TO_TIMESTAMP_LTZ(%d, %d)", instant.toEpochMilli(), 3);
case INTERVAL_YEAR_MONTH:
final Period period = getValueAs(Period.class).get().normalized();
return String.format(
"INTERVAL '%d-%d' YEAR TO MONTH", period.getYears(), period.getMonths());
case INTERVAL_DAY_TIME:
final Duration duration = getValueAs(Duration.class).get();
return String.format(
"INTERVAL '%d %02d:%02d:%02d.%d' DAY TO SECOND(3)",
duration.toDays(),
duration.toHours() % 24,
duration.toMinutes() % 60,
duration.getSeconds() % 60,
duration.getNano() / 1_000_000);
case DESCRIPTOR:
final ColumnList columnList = getValueAs(ColumnList.class).get();
if (!columnList.getDataTypes().isEmpty()) {
throw new TableException("Data types in DESCRIPTOR are not supported yet.");
}
return String.format(
"DESCRIPTOR(%s)",
columnList.getNames().stream()
.map(EncodingUtils::escapeBackticks)
.map(c -> String.format("`%s`", c))
.collect(Collectors.joining()));
case ARRAY:
case MULTISET:
case MAP:
case ROW:
throw new TableException(
"Constructed type literals are not SQL serializable. Please use respective"
+ " constructor functions");
case TIMESTAMP_WITH_TIME_ZONE:
case DISTINCT_TYPE:
case STRUCTURED_TYPE:
case RAW:
case SYMBOL:
case UNRESOLVED:
default:
throw new TableException(
"Literals with "
+ dataType.getLogicalType()
+ " are not SQL serializable.");
}
}