[SPARK-35771][SQL] Format year-month intervals using type fields

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

This PR proposes to format year-month interval to strings using the start and end fields of `YearMonthIntervalType`.

### Why are the changes needed?

 Currently, they are ignored, and any `YearMonthIntervalType` is formatted as `INTERVAL YEAR TO MONTH`.

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

No.

### How was this patch tested?

New test.

Closes #32924 from sarutak/year-month-interval-format.

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-16 11:08:02 +03:00 committed by Max Gekk
parent 4530760c40
commit 184f65e7c7
2 changed files with 42 additions and 5 deletions

View file

@ -29,7 +29,7 @@ import org.apache.spark.sql.catalyst.util.DateTimeUtils.millisToMicros
import org.apache.spark.sql.catalyst.util.IntervalStringStyles.{ANSI_STYLE, HIVE_STYLE, IntervalStyle}
import org.apache.spark.sql.errors.QueryExecutionErrors
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.types.{DayTimeIntervalType, Decimal}
import org.apache.spark.sql.types.{DayTimeIntervalType, Decimal, YearMonthIntervalType}
import org.apache.spark.unsafe.types.{CalendarInterval, UTF8String}
// The style of textual representation of intervals
@ -945,7 +945,6 @@ object IntervalUtils {
def toYearMonthIntervalString(
months: Int,
style: IntervalStyle,
// TODO(SPARK-35771): Format year-month intervals using type fields
startField: Byte,
endField: Byte): String = {
var sign = ""
@ -954,10 +953,22 @@ object IntervalUtils {
sign = "-"
absMonths = -absMonths
}
val payload = s"$sign${absMonths / MONTHS_PER_YEAR}-${absMonths % MONTHS_PER_YEAR}"
val year = s"$sign${absMonths / MONTHS_PER_YEAR}"
val month = s"${absMonths % MONTHS_PER_YEAR}"
val yearAndMonth = s"$year-$month"
style match {
case ANSI_STYLE => s"INTERVAL '$payload' YEAR TO MONTH"
case HIVE_STYLE => payload
case ANSI_STYLE =>
val formatBuilder = new StringBuilder("INTERVAL '")
if (startField == endField) {
startField match {
case YearMonthIntervalType.YEAR => formatBuilder.append(s"$year' YEAR")
case YearMonthIntervalType.MONTH => formatBuilder.append(s"$month' MONTH")
}
} else {
formatBuilder.append(s"$yearAndMonth' YEAR TO MONTH")
}
formatBuilder.toString
case HIVE_STYLE => s"$yearAndMonth"
}
}

View file

@ -619,4 +619,30 @@ class IntervalUtilsSuite extends SparkFunSuite with SQLHelper {
assert(toDayTimeIntervalString(micros, ANSI_STYLE, SECOND, SECOND) === sec)
}
}
test("SPARK-35771: Format year-month intervals using type fields") {
import org.apache.spark.sql.types.YearMonthIntervalType._
Seq(
0 ->
("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"),
-13 -> ("INTERVAL '-1-1' YEAR TO MONTH", "INTERVAL '-1' YEAR", "INTERVAL '1' MONTH"),
13 -> ("INTERVAL '1-1' YEAR TO MONTH", "INTERVAL '1' YEAR", "INTERVAL '1' 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 '0' MONTH"),
Int.MinValue ->
("INTERVAL '-178956970-8' YEAR TO MONTH",
"INTERVAL '-178956970' YEAR",
"INTERVAL '8' MONTH"),
Int.MaxValue ->
("INTERVAL '178956970-7' YEAR TO MONTH",
"INTERVAL '178956970' YEAR",
"INTERVAL '7' MONTH")
).foreach { case (months, (yearToMonth, year, month)) =>
assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, MONTH) === yearToMonth)
assert(toYearMonthIntervalString(months, ANSI_STYLE, YEAR, YEAR) === year)
assert(toYearMonthIntervalString(months, ANSI_STYLE, MONTH, MONTH) === month)
}
}
}