This is an automated email from the ASF dual-hosted git repository. maxgekk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push: new 3f4c32b [SPARK-35099][SQL] Convert ANSI interval literals to SQL string in ANSI style 3f4c32b is described below commit 3f4c32b3ca2d0f20806f81422e086d035b2eb5ce Author: Max Gekk <max.g...@gmail.com> AuthorDate: Fri Apr 16 08:22:25 2021 +0300 [SPARK-35099][SQL] Convert ANSI interval literals to SQL string in ANSI style ### What changes were proposed in this pull request? Handle `YearMonthIntervalType` and `DayTimeIntervalType` in the `sql()` and `toString()` method of `Literal`, and format the ANSI interval in the ANSI style. ### Why are the changes needed? To improve readability and UX with Spark SQL. For example, a test output before the changes: ``` -- !query select timestamp'2011-11-11 11:11:11' - interval '2' day -- !query schema struct<TIMESTAMP '2011-11-11 11:11:11' - 172800000000:timestamp> -- !query output 2011-11-09 11:11:11 ``` ### Does this PR introduce _any_ user-facing change? Should not since the new intervals haven't been released yet. ### How was this patch tested? By running new tests: ``` $ ./build/sbt "test:testOnly *LiteralExpressionSuite" ``` Closes #32196 from MaxGekk/literal-ansi-interval-sql. Authored-by: Max Gekk <max.g...@gmail.com> Signed-off-by: Max Gekk <max.g...@gmail.com> --- .../spark/sql/catalyst/expressions/literals.scala | 7 +++++- .../expressions/LiteralExpressionSuite.scala | 27 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/literals.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/literals.scala index 2ea73e8..47eebc5 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/literals.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/literals.scala @@ -43,7 +43,8 @@ import org.apache.spark.sql.catalyst.{CatalystTypeConverters, InternalRow, Scala import org.apache.spark.sql.catalyst.expressions.codegen._ import org.apache.spark.sql.catalyst.util._ import org.apache.spark.sql.catalyst.util.DateTimeUtils.instantToMicros -import org.apache.spark.sql.catalyst.util.IntervalUtils.{durationToMicros, periodToMonths} +import org.apache.spark.sql.catalyst.util.IntervalStringStyles.ANSI_STYLE +import org.apache.spark.sql.catalyst.util.IntervalUtils.{durationToMicros, periodToMonths, toDayTimeIntervalString, toYearMonthIntervalString} import org.apache.spark.sql.errors.{QueryCompilationErrors, QueryExecutionErrors} import org.apache.spark.sql.internal.SQLConf import org.apache.spark.sql.types._ @@ -317,6 +318,8 @@ case class Literal (value: Any, dataType: DataType) extends LeafExpression { DateFormatter(timeZoneId).format(value.asInstanceOf[Int]) case TimestampType => TimestampFormatter.getFractionFormatter(timeZoneId).format(value.asInstanceOf[Long]) + case DayTimeIntervalType => toDayTimeIntervalString(value.asInstanceOf[Long], ANSI_STYLE) + case YearMonthIntervalType => toYearMonthIntervalString(value.asInstanceOf[Int], ANSI_STYLE) case _ => other.toString } @@ -437,6 +440,8 @@ case class Literal (value: Any, dataType: DataType) extends LeafExpression { case (i: CalendarInterval, CalendarIntervalType) => s"INTERVAL '${i.toString}'" case (v: Array[Byte], BinaryType) => s"X'${DatatypeConverter.printHexBinary(v)}'" + case (i: Long, DayTimeIntervalType) => toDayTimeIntervalString(i, ANSI_STYLE) + case (i: Int, YearMonthIntervalType) => toYearMonthIntervalString(i, ANSI_STYLE) case _ => value.toString } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/LiteralExpressionSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/LiteralExpressionSuite.scala index f8766f3..a5f70fd 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/LiteralExpressionSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/LiteralExpressionSuite.scala @@ -19,6 +19,7 @@ package org.apache.spark.sql.catalyst.expressions import java.nio.charset.StandardCharsets import java.time.{Duration, Instant, LocalDate, LocalDateTime, Period, ZoneOffset} +import java.time.temporal.ChronoUnit import java.util.TimeZone import scala.reflect.runtime.universe.TypeTag @@ -385,4 +386,30 @@ class LiteralExpressionSuite extends SparkFunSuite with ExpressionEvalHelper { val period1 = Period.ofMonths(-1024) checkEvaluation(Literal(Array(period0, period1)), Array(period0, period1)) } + + test("SPARK-35099: convert a literal of day-time interval to SQL string") { + Seq( + Duration.ofDays(-1) -> "-1 00:00:00", + Duration.of(10, ChronoUnit.MICROS) -> "0 00:00:00.00001", + Duration.of(MICROS_PER_DAY - 1, ChronoUnit.MICROS) -> "0 23:59:59.999999" + ).foreach { case (duration, intervalPayload) => + val literal = Literal.apply(duration) + val expected = s"INTERVAL '$intervalPayload' DAY TO SECOND" + assert(literal.sql === expected) + assert(literal.toString === expected) + } + } + + test("SPARK-35099: convert a literal of year-month interval to SQL string") { + Seq( + Period.ofYears(-1) -> "-1-0", + Period.of(9999, 11, 0) -> "9999-11", + Period.ofMonths(-11) -> "-0-11" + ).foreach { case (period, intervalPayload) => + val literal = Literal.apply(period) + val expected = s"INTERVAL '$intervalPayload' YEAR TO MONTH" + assert(literal.sql === expected) + assert(literal.toString === expected) + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org For additional commands, e-mail: commits-h...@spark.apache.org