[SPARK-35771][SQL][FOLLOWUP] IntervalUtils.toYearMonthIntervalString should consider the case year-month type is casted as month type

### What changes were proposed in this pull request?

This PR fixes an issue that `IntervalUtils.toYearMonthIntervalString` doesn't consider the case that year-month interval type is casted as month interval type.
If a year-month interval data is casted as month interval, the value of the year is multiplied by `12` and added to the value of month. For example, `INTERVAL '1-2' YEAR TO MONTH` will be `INTERVAL '14' MONTH` if  it's casted.
If this behavior is intended, it's stringified to be `'INTERVAL 14' MONTH` but currently, it will be `INTERVAL '2' MONTH`

### Why are the changes needed?

It's a bug if the behavior of cast is intended.

### Does this PR introduce _any_ user-facing change?

No, because this feature is not released yet.

### How was this patch tested?

Modified the tests added in SPARK-35771 (#32924).

Closes #32982 from sarutak/fix-toYearMonthIntervalString.

Authored-by: Kousuke Saruta <sarutak@oss.nttdata.com>
Signed-off-by: Max Gekk <max.gekk@gmail.com>
This commit is contained in:
Kousuke Saruta 2021-06-20 10:32:21 +03:00 committed by Max Gekk
parent 6d309914df
commit 4758dc78a2
2 changed files with 9 additions and 10 deletions

View file

@ -987,15 +987,14 @@ object IntervalUtils {
absMonths = -absMonths absMonths = -absMonths
} }
val year = s"$sign${absMonths / MONTHS_PER_YEAR}" val year = s"$sign${absMonths / MONTHS_PER_YEAR}"
val month = s"${absMonths % MONTHS_PER_YEAR}" val yearAndMonth = s"$year-${absMonths % MONTHS_PER_YEAR}"
val yearAndMonth = s"$year-$month"
style match { style match {
case ANSI_STYLE => case ANSI_STYLE =>
val formatBuilder = new StringBuilder("INTERVAL '") val formatBuilder = new StringBuilder("INTERVAL '")
if (startField == endField) { if (startField == endField) {
startField match { startField match {
case YearMonthIntervalType.YEAR => formatBuilder.append(s"$year' YEAR") case YearMonthIntervalType.YEAR => formatBuilder.append(s"$year' YEAR")
case YearMonthIntervalType.MONTH => formatBuilder.append(s"$month' MONTH") case YearMonthIntervalType.MONTH => formatBuilder.append(s"$months' MONTH")
} }
} else { } else {
formatBuilder.append(s"$yearAndMonth' YEAR TO MONTH") formatBuilder.append(s"$yearAndMonth' YEAR TO MONTH")

View file

@ -625,20 +625,20 @@ class IntervalUtilsSuite extends SparkFunSuite with SQLHelper {
Seq( Seq(
0 -> 0 ->
("INTERVAL '0-0' YEAR TO MONTH", "INTERVAL '0' YEAR", "INTERVAL '0' MONTH"), ("INTERVAL '0-0' YEAR TO MONTH", "INTERVAL '0' YEAR", "INTERVAL '0' MONTH"),
-11 -> ("INTERVAL '-0-11' YEAR TO MONTH", "INTERVAL '-0' YEAR", "INTERVAL '11' MONTH"), -11 -> ("INTERVAL '-0-11' YEAR TO MONTH", "INTERVAL '-0' YEAR", "INTERVAL '-11' MONTH"),
11 -> ("INTERVAL '0-11' YEAR TO MONTH", "INTERVAL '0' YEAR", "INTERVAL '11' MONTH"), 11 -> ("INTERVAL '0-11' YEAR TO MONTH", "INTERVAL '0' YEAR", "INTERVAL '11' MONTH"),
-13 -> ("INTERVAL '-1-1' YEAR TO MONTH", "INTERVAL '-1' YEAR", "INTERVAL '1' MONTH"), -13 -> ("INTERVAL '-1-1' YEAR TO MONTH", "INTERVAL '-1' YEAR", "INTERVAL '-13' MONTH"),
13 -> ("INTERVAL '1-1' YEAR TO MONTH", "INTERVAL '1' YEAR", "INTERVAL '1' MONTH"), 13 -> ("INTERVAL '1-1' YEAR TO MONTH", "INTERVAL '1' YEAR", "INTERVAL '13' MONTH"),
-24 -> ("INTERVAL '-2-0' YEAR TO MONTH", "INTERVAL '-2' YEAR", "INTERVAL '0' MONTH"), -24 -> ("INTERVAL '-2-0' YEAR TO MONTH", "INTERVAL '-2' YEAR", "INTERVAL '-24' MONTH"),
24 -> ("INTERVAL '2-0' YEAR TO MONTH", "INTERVAL '2' YEAR", "INTERVAL '0' MONTH"), 24 -> ("INTERVAL '2-0' YEAR TO MONTH", "INTERVAL '2' YEAR", "INTERVAL '24' MONTH"),
Int.MinValue -> Int.MinValue ->
("INTERVAL '-178956970-8' YEAR TO MONTH", ("INTERVAL '-178956970-8' YEAR TO MONTH",
"INTERVAL '-178956970' YEAR", "INTERVAL '-178956970' YEAR",
"INTERVAL '8' MONTH"), "INTERVAL '-2147483648' MONTH"),
Int.MaxValue -> Int.MaxValue ->
("INTERVAL '178956970-7' YEAR TO MONTH", ("INTERVAL '178956970-7' YEAR TO MONTH",
"INTERVAL '178956970' YEAR", "INTERVAL '178956970' YEAR",
"INTERVAL '7' MONTH") "INTERVAL '2147483647' MONTH")
).foreach { case (months, (yearToMonth, year, month)) => ).foreach { case (months, (yearToMonth, year, month)) =>
assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, MONTH) === yearToMonth) assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, MONTH) === yearToMonth)
assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, YEAR) === year) assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, YEAR) === year)