[SPARK-35037][SQL] Recognize sign before the interval string in literals

### What changes were proposed in this pull request?
1. Extend SQL syntax rules to support a sign before the interval strings of ANSI year-month and day-time intervals.
2. Recognize `-` in `AstBuilder` and negate parsed intervals.

### Why are the changes needed?
To conform to the SQL standard which allows a sign before the string interval, see `"5.3 <literal>"`:
```
<interval literal> ::=
  INTERVAL [ <sign> ] <interval string> <interval qualifier>
<interval string> ::=
  <quote> <unquoted interval string> <quote>
<unquoted interval string> ::=
  [ <sign> ] { <year-month literal> | <day-time literal> }
<sign> ::=
    <plus sign>
  | <minus sign>
```

### Does this PR introduce _any_ user-facing change?
Should not because it just extends supported intervals syntax.

### How was this patch tested?
By running new tests in `interval.sql`:
```
$ build/sbt "sql/testOnly *SQLQueryTestSuite -- -z interval.sql"
```

Closes #32134 from MaxGekk/negative-parsed-intervals.

Authored-by: Max Gekk <max.gekk@gmail.com>
Signed-off-by: Max Gekk <max.gekk@gmail.com>
This commit is contained in:
Max Gekk 2021-04-13 08:55:00 +03:00
parent a392633566
commit 26f312e95f
5 changed files with 109 additions and 5 deletions

View file

@ -883,8 +883,7 @@ unitToUnitInterval
;
intervalValue
: (PLUS | MINUS)? (INTEGER_VALUE | DECIMAL_VALUE)
| STRING
: (PLUS | MINUS)? (INTEGER_VALUE | DECIMAL_VALUE | STRING)
;
colPosition

View file

@ -2377,7 +2377,7 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
try {
val from = ctx.from.getText.toLowerCase(Locale.ROOT)
val to = ctx.to.getText.toLowerCase(Locale.ROOT)
(from, to) match {
val interval = (from, to) match {
case ("year", "month") =>
IntervalUtils.fromYearMonthString(value)
case ("day", "hour") =>
@ -2395,6 +2395,9 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
case _ =>
throw QueryParsingErrors.fromToIntervalUnsupportedError(from, to, ctx)
}
Option(ctx.intervalValue.MINUS)
.map(_ => IntervalUtils.negateExact(interval))
.getOrElse(interval)
} catch {
// Handle Exceptions thrown by CalendarInterval
case e: IllegalArgumentException =>

View file

@ -20,6 +20,12 @@ select -interval '-1 month 1 day -1 second';
select -interval -1 month 1 day -1 second;
select +interval '-1 month 1 day -1 second';
select +interval -1 month 1 day -1 second;
select interval -'1-1' year to month;
select interval -'-1-1' year to month;
select interval +'-1-1' year to month;
select interval - '1 2:3:4.001' day to second;
select interval +'1 2:3:4.001' day to second;
select interval -'-1 2:3:4.001' day to second;
-- make intervals
select make_interval(1);

View file

@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 110
-- Number of queries: 116
-- !query
@ -127,6 +127,54 @@ struct<(+ INTERVAL '-1 months 1 days -1 seconds'):interval>
-1 months 1 days -1 seconds
-- !query
select interval -'1-1' year to month
-- !query schema
struct<INTERVAL '-1 years -1 months':interval>
-- !query output
-1 years -1 months
-- !query
select interval -'-1-1' year to month
-- !query schema
struct<INTERVAL '1 years 1 months':interval>
-- !query output
1 years 1 months
-- !query
select interval +'-1-1' year to month
-- !query schema
struct<INTERVAL '-1 years -1 months':interval>
-- !query output
-1 years -1 months
-- !query
select interval - '1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '-1 days -2 hours -3 minutes -4.001 seconds':interval>
-- !query output
-1 days -2 hours -3 minutes -4.001 seconds
-- !query
select interval +'1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '1 days 2 hours 3 minutes 4.001 seconds':interval>
-- !query output
1 days 2 hours 3 minutes 4.001 seconds
-- !query
select interval -'-1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '1 days 2 hours 3 minutes 4.001 seconds':interval>
-- !query output
1 days 2 hours 3 minutes 4.001 seconds
-- !query
select make_interval(1)
-- !query schema

View file

@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 110
-- Number of queries: 116
-- !query
@ -122,6 +122,54 @@ struct<(+ INTERVAL '-1 months 1 days -1 seconds'):interval>
-1 months 1 days -1 seconds
-- !query
select interval -'1-1' year to month
-- !query schema
struct<INTERVAL '-1 years -1 months':interval>
-- !query output
-1 years -1 months
-- !query
select interval -'-1-1' year to month
-- !query schema
struct<INTERVAL '1 years 1 months':interval>
-- !query output
1 years 1 months
-- !query
select interval +'-1-1' year to month
-- !query schema
struct<INTERVAL '-1 years -1 months':interval>
-- !query output
-1 years -1 months
-- !query
select interval - '1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '-1 days -2 hours -3 minutes -4.001 seconds':interval>
-- !query output
-1 days -2 hours -3 minutes -4.001 seconds
-- !query
select interval +'1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '1 days 2 hours 3 minutes 4.001 seconds':interval>
-- !query output
1 days 2 hours 3 minutes 4.001 seconds
-- !query
select interval -'-1 2:3:4.001' day to second
-- !query schema
struct<INTERVAL '1 days 2 hours 3 minutes 4.001 seconds':interval>
-- !query output
1 days 2 hours 3 minutes 4.001 seconds
-- !query
select make_interval(1)
-- !query schema