[SPARK-35819][SQL] Support Cast between different field YearMonthIntervalType

### What changes were proposed in this pull request?
 Support Cast between different field YearMonthIntervalType

### Why are the changes needed?
Make user convenient to get different field YearMonthIntervalType

### Does this PR introduce _any_ user-facing change?
User can call cast YearMonthIntervalType(YEAR, MONTH) to YearMonthIntervalType(YEAR, YEAR) etc

### How was this patch tested?
Added UT

Closes #32974 from AngersZhuuuu/SPARK-35819.

Authored-by: Angerszhuuuu <angers.zhu@gmail.com>
Signed-off-by: Max Gekk <max.gekk@gmail.com>
This commit is contained in:
Angerszhuuuu 2021-06-19 21:43:06 +03:00 committed by Max Gekk
parent a39f1eadb7
commit 86bcd1fba0
2 changed files with 23 additions and 0 deletions

View file

@ -82,6 +82,8 @@ object Cast {
case (StringType, _: DayTimeIntervalType) => true
case (StringType, _: YearMonthIntervalType) => true
case (_: YearMonthIntervalType, _: YearMonthIntervalType) => true
case (StringType, _: NumericType) => true
case (BooleanType, _: NumericType) => true
case (DateType, _: NumericType) => true
@ -580,6 +582,8 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit
it: YearMonthIntervalType): Any => Any = from match {
case StringType => buildCast[UTF8String](_, s =>
IntervalUtils.castStringToYMInterval(s, it.startField, it.endField))
case _: YearMonthIntervalType => buildCast[Int](_, s =>
IntervalUtils.periodToMonths(IntervalUtils.monthsToPeriod(s), it.endField))
}
// LongConverter
@ -1481,6 +1485,12 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit
code"""
$evPrim = $util.castStringToYMInterval($c, (byte)${it.startField}, (byte)${it.endField});
"""
case _: YearMonthIntervalType =>
val util = IntervalUtils.getClass.getCanonicalName.stripSuffix("$")
(c, evPrim, _) =>
code"""
$evPrim = $util.periodToMonths($util.monthsToPeriod($c), (byte)${it.endField});
"""
}
private[this] def decimalToTimestampCode(d: ExprValue): Block = {
@ -2051,6 +2061,8 @@ object AnsiCast {
case (StringType, _: DayTimeIntervalType) => true
case (StringType, _: YearMonthIntervalType) => true
case (_: YearMonthIntervalType, _: YearMonthIntervalType) => true
case (StringType, DateType) => true
case (TimestampType, DateType) => true
case (TimestampWithoutTZType, DateType) => true

View file

@ -30,6 +30,7 @@ import org.apache.spark.sql.catalyst.util.DateTimeTestUtils._
import org.apache.spark.sql.catalyst.util.DateTimeUtils._
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.types._
import org.apache.spark.sql.types.YearMonthIntervalType._
import org.apache.spark.unsafe.types.UTF8String
/**
@ -662,4 +663,14 @@ class CastSuite extends CastSuiteBase {
checkEvaluation(cast(invalidInput, TimestampWithoutTZType), null)
}
}
test("SPARK-35819: Support cast YearMonthIntervalType in different fields") {
val ym = cast(Literal.create("1-1"), YearMonthIntervalType(YEAR, MONTH))
Seq(YearMonthIntervalType(YEAR, YEAR) -> 12,
YearMonthIntervalType(YEAR, MONTH) -> 13,
YearMonthIntervalType(MONTH, MONTH) -> 13)
.foreach { case (dt, value) =>
checkEvaluation(cast(ym, dt), value)
}
}
}