in flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/planner/codegen/GenerateUtils.scala [295:460]
def generateLiteral(
ctx: CodeGeneratorContext,
literalType: LogicalType,
literalValue: Any): GeneratedExpression = {
if (literalValue == null) {
return generateNullLiteral(literalType, ctx.nullCheck)
}
// non-null values
literalType.getTypeRoot match {
// ordered by type root definition
case CHAR | VARCHAR =>
val escapedValue = StringEscapeUtils.ESCAPE_JAVA.translate(literalValue.toString)
val field = ctx.addReusableStringConstants(escapedValue)
generateNonNullLiteral(literalType, field, StringData.fromString(escapedValue))
case BOOLEAN =>
generateNonNullLiteral(literalType, literalValue.toString, literalValue)
case BINARY | VARBINARY =>
val bytesVal = literalValue.asInstanceOf[ByteString].getBytes
val fieldTerm = ctx.addReusableObject(
bytesVal, "binary", bytesVal.getClass.getCanonicalName)
generateNonNullLiteral(literalType, fieldTerm, bytesVal)
case DECIMAL =>
val dt = literalType.asInstanceOf[DecimalType]
val precision = dt.getPrecision
val scale = dt.getScale
val fieldTerm = newName("decimal")
val decimalClass = className[DecimalData]
val fieldDecimal =
s"""
|$decimalClass $fieldTerm =
| $DECIMAL_UTIL.castFrom("${literalValue.toString}", $precision, $scale);
|""".stripMargin
ctx.addReusableMember(fieldDecimal)
val value = DecimalData.fromBigDecimal(
literalValue.asInstanceOf[JBigDecimal], precision, scale)
if (value == null) {
generateNullLiteral(literalType, ctx.nullCheck)
} else {
generateNonNullLiteral(literalType, fieldTerm, value)
}
case TINYINT =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
generateNonNullLiteral(literalType, decimal.byteValue().toString, decimal.byteValue())
case SMALLINT =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
generateNonNullLiteral(literalType, decimal.shortValue().toString, decimal.shortValue())
case INTEGER =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
generateNonNullLiteral(literalType, decimal.intValue().toString, decimal.intValue())
case BIGINT =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
generateNonNullLiteral(
literalType, decimal.longValue().toString + "L", decimal.longValue())
case FLOAT =>
val floatValue = literalValue.asInstanceOf[JBigDecimal].floatValue()
floatValue match {
case Float.NegativeInfinity =>
generateNonNullLiteral(
literalType,
"java.lang.Float.NEGATIVE_INFINITY",
Float.NegativeInfinity)
case Float.PositiveInfinity => generateNonNullLiteral(
literalType,
"java.lang.Float.POSITIVE_INFINITY",
Float.PositiveInfinity)
case _ => generateNonNullLiteral(
literalType, floatValue.toString + "f", floatValue)
}
case DOUBLE =>
val doubleValue = literalValue.asInstanceOf[JBigDecimal].doubleValue()
doubleValue match {
case Double.NegativeInfinity =>
generateNonNullLiteral(
literalType,
"java.lang.Double.NEGATIVE_INFINITY",
Double.NegativeInfinity)
case Double.PositiveInfinity =>
generateNonNullLiteral(
literalType,
"java.lang.Double.POSITIVE_INFINITY",
Double.PositiveInfinity)
case _ => generateNonNullLiteral(
literalType, doubleValue.toString + "d", doubleValue)
}
case DATE =>
generateNonNullLiteral(literalType, literalValue.toString, literalValue)
case TIME_WITHOUT_TIME_ZONE =>
generateNonNullLiteral(literalType, literalValue.toString, literalValue)
case TIMESTAMP_WITHOUT_TIME_ZONE =>
val fieldTerm = newName("timestamp")
val ldt = toLocalDateTime(literalValue.asInstanceOf[TimestampString])
val ts = TimestampData.fromLocalDateTime(ldt)
val fieldTimestamp =
s"""
|$TIMESTAMP_DATA $fieldTerm =
| $TIMESTAMP_DATA.fromEpochMillis(${ts.getMillisecond}L, ${ts.getNanoOfMillisecond});
""".stripMargin
ctx.addReusableMember(fieldTimestamp)
generateNonNullLiteral(literalType, fieldTerm, ts)
case TIMESTAMP_WITH_TIME_ZONE =>
throw new UnsupportedOperationException("Unsupported type: " + literalType)
case TIMESTAMP_WITH_LOCAL_TIME_ZONE =>
val fieldTerm = newName("timestampWithLocalZone")
val ins =
toLocalDateTime(literalValue.asInstanceOf[TimestampString])
.atOffset(ZoneOffset.UTC)
.toInstant
val ts = TimestampData.fromInstant(ins)
val fieldTimestampWithLocalZone =
s"""
|$TIMESTAMP_DATA $fieldTerm =
| $TIMESTAMP_DATA.fromEpochMillis(${ts.getMillisecond}L, ${ts.getNanoOfMillisecond});
""".stripMargin
ctx.addReusableMember(fieldTimestampWithLocalZone)
generateNonNullLiteral(literalType, fieldTerm, literalValue)
case INTERVAL_YEAR_MONTH =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
if (decimal.isValidInt) {
generateNonNullLiteral(literalType, decimal.intValue().toString, decimal.intValue())
} else {
throw new CodeGenException(
s"Decimal '$decimal' can not be converted to interval of months.")
}
case INTERVAL_DAY_TIME =>
val decimal = BigDecimal(literalValue.asInstanceOf[JBigDecimal])
if (decimal.isValidLong) {
generateNonNullLiteral(
literalType,
decimal.longValue().toString + "L",
decimal.longValue())
} else {
throw new CodeGenException(
s"Decimal '$decimal' can not be converted to interval of milliseconds.")
}
case DISTINCT_TYPE =>
generateLiteral(ctx, literalType.asInstanceOf[DistinctType].getSourceType, literalValue)
// Symbol type for special flags e.g. TRIM's BOTH, LEADING, TRAILING
case RAW if literalType.asInstanceOf[TypeInformationRawType[_]]
.getTypeInformation.getTypeClass.isAssignableFrom(classOf[Enum[_]]) =>
generateSymbol(literalValue.asInstanceOf[Enum[_]])
case SYMBOL =>
throw new UnsupportedOperationException() // TODO support symbol?
case ARRAY | MULTISET | MAP | ROW | STRUCTURED_TYPE | NULL | UNRESOLVED =>
throw new CodeGenException(s"Type not supported: $literalType")
}
}