def generateCast()

in flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/codegen/calls/ScalarOperators.scala [608:816]


  def generateCast(
      nullCheck: Boolean,
      operand: GeneratedExpression,
      targetType: TypeInformation[_])
    : GeneratedExpression = (operand.resultType, targetType) match {

    // special case: cast from TimeIndicatorTypeInfo to SqlTimeTypeInfo
    case (ti: TimeIndicatorTypeInfo, SqlTimeTypeInfo.TIMESTAMP) =>
      operand.copy(resultType = SqlTimeTypeInfo.TIMESTAMP) // just replace the TypeInformation

    // identity casting
    case (fromTp, toTp) if fromTp == toTp =>
      operand

    // array identity casting
    // (e.g. for Integer[] that can be ObjectArrayTypeInfo or BasicArrayTypeInfo)
    case (fromTp, toTp) if isArray(fromTp) && fromTp.getTypeClass == toTp.getTypeClass =>
      operand

    // Date -> String
    case (SqlTimeTypeInfo.DATE, STRING_TYPE_INFO) =>
      val method = qualifyMethod(BuiltInMethod.UNIX_DATE_TO_STRING.method)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$method($operandTerm)"
      }

    // Time -> String
    case (SqlTimeTypeInfo.TIME, STRING_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"${internalToTimePointCode(operand.resultType, operandTerm)}.toString()"
      }

    // Timestamp -> String
    case (SqlTimeTypeInfo.TIMESTAMP, STRING_TYPE_INFO) =>
      val method = qualifyMethod(BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$method($operandTerm, 3)"
      }

    // Interval Months -> String
    case (TimeIntervalTypeInfo.INTERVAL_MONTHS, STRING_TYPE_INFO) =>
      val method = qualifyMethod(BuiltInMethod.INTERVAL_YEAR_MONTH_TO_STRING.method)
      val timeUnitRange = qualifyEnum(TimeUnitRange.YEAR_TO_MONTH)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$method($operandTerm, $timeUnitRange)"
      }

    // Interval Millis -> String
    case (TimeIntervalTypeInfo.INTERVAL_MILLIS, STRING_TYPE_INFO) =>
      val method = qualifyMethod(BuiltInMethod.INTERVAL_DAY_TIME_TO_STRING.method)
      val timeUnitRange = qualifyEnum(TimeUnitRange.DAY_TO_SECOND)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$method($operandTerm, $timeUnitRange, 3)" // milli second precision
      }

    // Object array -> String
    case (_: ObjectArrayTypeInfo[_, _] | _: BasicArrayTypeInfo[_, _], STRING_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"java.util.Arrays.deepToString($operandTerm)"
      }

    // Primitive array -> String
    case (_: PrimitiveArrayTypeInfo[_], STRING_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"java.util.Arrays.toString($operandTerm)"
      }

    // * (not Date/Time/Timestamp) -> String
    case (_, STRING_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s""" "" + $operandTerm"""
      }

    // * -> Character
    case (_, CHAR_TYPE_INFO) =>
      throw new CodeGenException("Character type not supported.")

    // String -> NUMERIC TYPE (not Character), Boolean
    case (STRING_TYPE_INFO, _: NumericTypeInfo[_])
        | (STRING_TYPE_INFO, BOOLEAN_TYPE_INFO) =>
      val wrapperClass = targetType.getTypeClass.getCanonicalName
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$wrapperClass.valueOf($operandTerm)"
      }

    // String -> BigDecimal
    case (STRING_TYPE_INFO, BIG_DEC_TYPE_INFO) =>
      val wrapperClass = targetType.getTypeClass.getCanonicalName
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"new $wrapperClass($operandTerm)"
      }

    // String -> Date
    case (STRING_TYPE_INFO, SqlTimeTypeInfo.DATE) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"${qualifyMethod(BuiltInMethod.STRING_TO_DATE.method)}($operandTerm)"
      }

    // String -> Time
    case (STRING_TYPE_INFO, SqlTimeTypeInfo.TIME) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"${qualifyMethod(BuiltInMethod.STRING_TO_TIME.method)}($operandTerm)"
      }

    // String -> Timestamp
    case (STRING_TYPE_INFO, SqlTimeTypeInfo.TIMESTAMP) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"${qualifyMethod(BuiltInMethod.STRING_TO_TIMESTAMP.method)}" +
          s"($operandTerm)"
      }

    // Boolean -> NUMERIC TYPE
    case (BOOLEAN_TYPE_INFO, nti: NumericTypeInfo[_]) =>
      val targetTypeTerm = primitiveTypeTermForTypeInfo(nti)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"($targetTypeTerm) ($operandTerm ? 1 : 0)"
      }

    // Boolean -> BigDecimal
    case (BOOLEAN_TYPE_INFO, BIG_DEC_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$operandTerm ? java.math.BigDecimal.ONE : java.math.BigDecimal.ZERO"
      }

    // NUMERIC TYPE -> Boolean
    case (_: NumericTypeInfo[_], BOOLEAN_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$operandTerm != 0"
      }

    // BigDecimal -> Boolean
    case (BIG_DEC_TYPE_INFO, BOOLEAN_TYPE_INFO) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$operandTerm.compareTo(java.math.BigDecimal.ZERO) != 0"
      }

    // NUMERIC TYPE, BigDecimal -> NUMERIC TYPE, BigDecimal
    case (_: NumericTypeInfo[_], _: NumericTypeInfo[_])
        | (BIG_DEC_TYPE_INFO, _: NumericTypeInfo[_])
        | (_: NumericTypeInfo[_], BIG_DEC_TYPE_INFO) =>
      val operandCasting = numericCasting(operand.resultType, targetType)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"${operandCasting(operandTerm)}"
      }

    // Date -> Timestamp
    case (SqlTimeTypeInfo.DATE, SqlTimeTypeInfo.TIMESTAMP) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) =>
          s"$operandTerm * ${classOf[DateTimeUtils].getCanonicalName}.MILLIS_PER_DAY"
      }

    // Timestamp -> Date
    case (SqlTimeTypeInfo.TIMESTAMP, SqlTimeTypeInfo.DATE) =>
      val targetTypeTerm = primitiveTypeTermForTypeInfo(targetType)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) =>
          s"($targetTypeTerm) ($operandTerm / " +
            s"${classOf[DateTimeUtils].getCanonicalName}.MILLIS_PER_DAY)"
      }

    // Time -> Timestamp
    case (SqlTimeTypeInfo.TIME, SqlTimeTypeInfo.TIMESTAMP) =>
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) => s"$operandTerm"
      }

    // Timestamp -> Time
    case (SqlTimeTypeInfo.TIMESTAMP, SqlTimeTypeInfo.TIME) =>
      val targetTypeTerm = primitiveTypeTermForTypeInfo(targetType)
      generateUnaryOperatorIfNotNull(nullCheck, targetType, operand) {
        (operandTerm) =>
          s"($targetTypeTerm) ($operandTerm % " +
            s"${classOf[DateTimeUtils].getCanonicalName}.MILLIS_PER_DAY)"
      }

    // internal temporal casting
    // Date -> Integer
    // Time -> Integer
    // Timestamp -> Long
    // Integer -> Date
    // Integer -> Time
    // Long -> Timestamp
    // Integer -> Interval Months
    // Long -> Interval Millis
    // Interval Months -> Integer
    // Interval Millis -> Long
    case (SqlTimeTypeInfo.DATE, INT_TYPE_INFO) |
         (SqlTimeTypeInfo.TIME, INT_TYPE_INFO) |
         (SqlTimeTypeInfo.TIMESTAMP, LONG_TYPE_INFO) |
         (INT_TYPE_INFO, SqlTimeTypeInfo.DATE) |
         (INT_TYPE_INFO, SqlTimeTypeInfo.TIME) |
         (LONG_TYPE_INFO, SqlTimeTypeInfo.TIMESTAMP) |
         (INT_TYPE_INFO, TimeIntervalTypeInfo.INTERVAL_MONTHS) |
         (LONG_TYPE_INFO, TimeIntervalTypeInfo.INTERVAL_MILLIS) |
         (TimeIntervalTypeInfo.INTERVAL_MONTHS, INT_TYPE_INFO) |
         (TimeIntervalTypeInfo.INTERVAL_MILLIS, LONG_TYPE_INFO) =>
      internalExprCasting(operand, targetType)

    // internal reinterpretation of temporal types
    // Date, Time, Interval Months -> Long
    case  (SqlTimeTypeInfo.DATE, LONG_TYPE_INFO)
        | (SqlTimeTypeInfo.TIME, LONG_TYPE_INFO)
        | (TimeIntervalTypeInfo.INTERVAL_MONTHS, LONG_TYPE_INFO) =>
      internalExprCasting(operand, targetType)

    case (from, to) =>
      throw new CodeGenException(s"Unsupported cast from '$from' to '$to'.")
  }