-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-29864][SPARK-29920][SQL] Strict parsing of day-time strings to intervals #26473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
800f6e5
8cf38db
3a1a710
4e051d6
a1ef591
e88c8e0
c87cf8c
3f66881
da9b801
c8afd33
988d532
ce28745
58ba7b4
60fe0c1
e95068e
880e7ed
d00c95d
a37bad4
8e733c1
6b5b7ef
a2ce9ae
fc77452
6be5f4e
d253094
dfd0dce
d1145cd
c94f1df
833c7b0
5b26335
f401bd2
ca46f44
eadaa92
8f10259
d3d730a
32b4d2f
e39ca52
e012f8b
73ef32f
d27d434
9d8394e
ef2cbe1
f9510e3
c16f2a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
|
@@ -131,43 +133,45 @@ class IntervalUtilsSuite extends SparkFunSuite { | |
| } | ||
| } | ||
|
|
||
| test("from day-time string") { | ||
| assert(fromDayTimeString("5 12:40:30.999999999") === | ||
| new CalendarInterval( | ||
| 0, | ||
| 5, | ||
| 12 * MICROS_PER_HOUR + | ||
| 40 * MICROS_PER_MINUTE + | ||
| 30 * MICROS_PER_SECOND + 999999L)) | ||
| assert(fromDayTimeString("10 0:12:0.888") === | ||
| new CalendarInterval( | ||
| 0, | ||
| 10, | ||
| 12 * MICROS_PER_MINUTE + 888 * MICROS_PER_MILLIS)) | ||
| assert(fromDayTimeString("-3 0:0:0") === new CalendarInterval(0, -3, 0L)) | ||
|
|
||
| try { | ||
| fromDayTimeString("5 30:12:20") | ||
| fail("Expected to throw an exception for the invalid input") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("hour 30 outside range")) | ||
| } | ||
|
|
||
| try { | ||
| fromDayTimeString("5 30-12") | ||
| fail("Expected to throw an exception for the invalid input") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("must match day-time format")) | ||
| } | ||
|
|
||
| try { | ||
| fromDayTimeString("5 1:12:20", HOUR, MICROSECOND) | ||
| fail("Expected to throw an exception for the invalid convention type") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("Cannot support (interval")) | ||
| test("from day-time string - legacy") { | ||
| withSQLConf(SQLConf.LEGACY_FROM_DAYTIME_STRING.key -> "true") { | ||
| assert(fromDayTimeString("5 12:40:30.999999999") === | ||
| new CalendarInterval( | ||
| 0, | ||
| 5, | ||
| 12 * MICROS_PER_HOUR + | ||
| 40 * MICROS_PER_MINUTE + | ||
| 30 * MICROS_PER_SECOND + 999999L)) | ||
| assert(fromDayTimeString("10 0:12:0.888") === | ||
| new CalendarInterval( | ||
| 0, | ||
| 10, | ||
| 12 * MICROS_PER_MINUTE + 888 * MICROS_PER_MILLIS)) | ||
| assert(fromDayTimeString("-3 0:0:0") === new CalendarInterval(0, -3, 0L)) | ||
|
|
||
| try { | ||
| fromDayTimeString("5 30:12:20") | ||
| fail("Expected to throw an exception for the invalid input") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("hour 30 outside range")) | ||
| } | ||
|
|
||
| try { | ||
| fromDayTimeString("5 30-12") | ||
| fail("Expected to throw an exception for the invalid input") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("must match day-time format")) | ||
| } | ||
|
|
||
| try { | ||
| fromDayTimeString("5 1:12:20", HOUR, MICROSECOND) | ||
| fail("Expected to throw an exception for the invalid convention type") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains("Cannot support (interval")) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -266,4 +270,60 @@ class IntervalUtilsSuite extends SparkFunSuite { | |
| assert(e.getMessage.contains("divide by zero")) | ||
| } | ||
| } | ||
|
|
||
| test("from day-time string") { | ||
| def check(input: String, from: IntervalUnit, to: IntervalUnit, expected: String): Unit = { | ||
| withClue(s"from = $from, to = $to") { | ||
| assert(fromDayTimeString(input, from, to) === fromString(expected)) | ||
| } | ||
| } | ||
| def checkFail( | ||
| input: String, | ||
| from: IntervalUnit, | ||
| to: IntervalUnit, | ||
| errMsg: String): Unit = { | ||
| try { | ||
| fromDayTimeString(input, from, to) | ||
| fail("Expected to throw an exception for the invalid input") | ||
| } catch { | ||
| case e: IllegalArgumentException => | ||
| assert(e.getMessage.contains(errMsg)) | ||
| } | ||
| } | ||
|
|
||
| check("12:40", HOUR, MINUTE, "12 hours 40 minutes") | ||
| check("+12:40", HOUR, MINUTE, "12 hours 40 minutes") | ||
| check("-12:40", HOUR, MINUTE, "-12 hours -40 minutes") | ||
| checkFail("5 12:40", HOUR, MINUTE, "must match day-time format") | ||
|
|
||
| check("12:40:30.999999999", HOUR, SECOND, "12 hours 40 minutes 30.999999 seconds") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we test |
||
| check("+12:40:30.999999999", HOUR, SECOND, "12 hours 40 minutes 30.999999 seconds") | ||
| check("-12:40:30.999999999", HOUR, SECOND, "-12 hours -40 minutes -30.999999 seconds") | ||
|
||
| checkFail("5 12:40:30", HOUR, SECOND, "must match day-time format") | ||
| checkFail("12:40:30.0123456789", HOUR, SECOND, "must match day-time format") | ||
|
|
||
| check("40:30.999999999", MINUTE, SECOND, "40 minutes 30.999999 seconds") | ||
| check("+40:30.999999999", MINUTE, SECOND, "40 minutes 30.999999 seconds") | ||
| check("-40:30.999999999", MINUTE, SECOND, "-40 minutes -30.999999 seconds") | ||
| checkFail("12:40:30", MINUTE, SECOND, "must match day-time format") | ||
|
|
||
| check("5 12", DAY, HOUR, "5 days 12 hours") | ||
| check("+5 12", DAY, HOUR, "5 days 12 hours") | ||
| check("-5 12", DAY, HOUR, "-5 days -12 hours") | ||
| checkFail("5 12:30", DAY, HOUR, "must match day-time format") | ||
|
|
||
| check("5 12:40", DAY, MINUTE, "5 days 12 hours 40 minutes") | ||
| check("+5 12:40", DAY, MINUTE, "5 days 12 hours 40 minutes") | ||
| check("-5 12:40", DAY, MINUTE, "-5 days -12 hours -40 minutes") | ||
| checkFail("5 12", DAY, MINUTE, "must match day-time format") | ||
|
|
||
| check("5 12:40:30.123", DAY, SECOND, "5 days 12 hours 40 minutes 30.123 seconds") | ||
| check("+5 12:40:30.123456", DAY, SECOND, "5 days 12 hours 40 minutes 30.123456 seconds") | ||
| check("-5 12:40:30.999999999", DAY, SECOND, "-5 days -12 hours -40 minutes -30.999999 seconds") | ||
| checkFail("5 12", DAY, SECOND, "must match day-time format") | ||
|
|
||
| checkFail("5 30:12:20", DAY, SECOND, "hour 30 outside range") | ||
| checkFail("5 30-12", DAY, SECOND, "must match day-time format") | ||
| checkFail("5 1:12:20", HOUR, MICROSECOND, "Cannot support (interval") | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.