diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala index 19bb44f1e48a..ae676d999f6f 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala @@ -23,6 +23,7 @@ import scala.util.control.NonFatal import org.apache.spark.sql.catalyst.parser.{CatalystSqlParser, ParseException} import org.apache.spark.sql.catalyst.util.DateTimeConstants._ +import org.apache.spark.sql.internal.SQLConf import org.apache.spark.sql.types.Decimal import org.apache.spark.unsafe.types.{CalendarInterval, UTF8String} @@ -203,7 +204,7 @@ object IntervalUtils { try { val sign = if (m.group(1) != null && m.group(1) == "-") -1 else 1 - val days = if (m.group(2) == null) { + var days = if (m.group(2) == null) { 0 } else { toLongWithRange(DAY, m.group(3), 0, Integer.MAX_VALUE).toInt @@ -224,16 +225,27 @@ object IntervalUtils { } // Hive allow nanosecond precision interval var secondsFraction = parseNanos(m.group(9), seconds < 0) - to match { - case HOUR => + val resetValuesUpToFrom = !SQLConf.get.usePostgreSQLDialect + (from, to) match { + case (DAY, SECOND) => // No-op + case (DAY, MINUTE) => + seconds = 0 + secondsFraction = 0 + case (DAY, HOUR) => minutes = 0 seconds = 0 secondsFraction = 0 - case MINUTE => + case (HOUR, SECOND) => + if (resetValuesUpToFrom) days = 0 + case (HOUR, MINUTE) => + if (resetValuesUpToFrom) days = 0 seconds = 0 secondsFraction = 0 - case SECOND => - // No-op + case (MINUTE, SECOND) => + if (resetValuesUpToFrom) { + days = 0 + hours = 0 + } case _ => throw new IllegalArgumentException( s"Cannot support (interval '$input' $from to $to) expression") diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala index 75b0afceca14..7ba4e3f1f838 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala @@ -20,12 +20,14 @@ package org.apache.spark.sql.catalyst.util import java.util.concurrent.TimeUnit import org.apache.spark.SparkFunSuite +import org.apache.spark.sql.catalyst.plans.SQLHelper import org.apache.spark.sql.catalyst.util.DateTimeConstants._ import org.apache.spark.sql.catalyst.util.IntervalUtils._ import org.apache.spark.sql.catalyst.util.IntervalUtils.IntervalUnit._ +import org.apache.spark.sql.internal.SQLConf import org.apache.spark.unsafe.types.{CalendarInterval, UTF8String} -class IntervalUtilsSuite extends SparkFunSuite { +class IntervalUtilsSuite extends SparkFunSuite with SQLHelper { private def checkFromString(input: String, expected: CalendarInterval): Unit = { assert(fromString(input) === expected) @@ -265,4 +267,30 @@ class IntervalUtilsSuite extends SparkFunSuite { assert(e.getMessage.contains("divide by zero")) } } + + test("from bounded day-time string") { + val input = "5 12:40:30.999999999" + + def check(from: IntervalUnit, to: IntervalUnit, expected: String): Unit = { + withClue(s"from = $from, to = $to") { + assert(fromDayTimeString(input, from, to) === fromString(expected)) + } + } + + withSQLConf(SQLConf.DIALECT.key -> "Spark") { + check(HOUR, MINUTE, "12 hours 40 minutes") + check(HOUR, SECOND, "12 hours 40 minutes 30.999999 seconds") + check(MINUTE, SECOND, "40 minutes 30.999999 seconds") + check(DAY, HOUR, "5 days 12 hours") + check(DAY, MINUTE, "5 days 12 hours 40 minutes") + } + + withSQLConf(SQLConf.DIALECT.key -> "PostgreSQL") { + check(HOUR, MINUTE, "5 days 12 hours 40 minutes") + check(HOUR, SECOND, "5 days 12 hours 40 minutes 30.999999 seconds") + check(MINUTE, SECOND, "5 days 12 hours 40 minutes 30.999999 seconds") + check(DAY, HOUR, "5 days 12 hours") + check(DAY, MINUTE, "5 days 12 hours 40 minutes") + } + } } diff --git a/sql/core/src/test/resources/sql-tests/results/literals.sql.out b/sql/core/src/test/resources/sql-tests/results/literals.sql.out index e9aa046717f1..42fd04e5ad6d 100644 --- a/sql/core/src/test/resources/sql-tests/results/literals.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/literals.sql.out @@ -419,9 +419,9 @@ struct<15 hours 40 minutes 32.998999 seconds:interval> -- !query 46 select interval '20 40:32.99899999' minute to second -- !query 46 schema -struct<20 days 40 minutes 32.998999 seconds:interval> +struct<40 minutes 32.998999 seconds:interval> -- !query 46 output -20 days 40 minutes 32.998999 seconds +40 minutes 32.998999 seconds -- !query 47