[SPARK-35736][SQL] Parse any day-time interval types in SQL

### What changes were proposed in this pull request?
This PR adda a feature which allow the parser parse any day-time interval types in SQL.

### Why are the changes needed?
To comply with ANSI standard, we additionally need to support the following types.

* INTERVAL DAY
* INTERVAL DAY TO HOUR
* INTERVAL DAY TO MINUTE
* INTERVAL HOUR
* INTERVAL HOUR TO MINUTE
* INTERVAL HOUR TO SECOND
* INTERVAL MINUTE
* INTERVAL MINUTE TO SECOND
* INTERVAL SECOND

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

### How was this patch tested?
New tests.

Closes #32893 from sarutak/parse-any-day-time.

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-14 00:13:50 +03:00 committed by Max Gekk
parent 69aa7ad11f
commit 7978fdc97b
4 changed files with 20 additions and 4 deletions

View file

@ -300,6 +300,7 @@ Below is a list of all the keywords in Spark SQL.
|GROUP|reserved|non-reserved|reserved|
|GROUPING|non-reserved|non-reserved|reserved|
|HAVING|reserved|non-reserved|reserved|
|HOUR|non-reserved|non-reserved|non-reserved|
|IF|non-reserved|non-reserved|not a keyword|
|IGNORE|non-reserved|non-reserved|non-reserved|
|IMPORT|non-reserved|non-reserved|non-reserved|
@ -336,6 +337,7 @@ Below is a list of all the keywords in Spark SQL.
|MAP|non-reserved|non-reserved|non-reserved|
|MATCHED|non-reserved|non-reserved|non-reserved|
|MERGE|non-reserved|non-reserved|non-reserved|
|MINUTE|non-reserved|non-reserved|non-reserved|
|MINUS|non-reserved|strict-non-reserved|non-reserved|
|MONTH|non-reserved|non-reserved|non-reserved|
|MSCK|non-reserved|non-reserved|non-reserved|

View file

@ -905,7 +905,8 @@ dataType
| complex=MAP '<' dataType ',' dataType '>' #complexDataType
| complex=STRUCT ('<' complexColTypeList? '>' | NEQ) #complexDataType
| INTERVAL YEAR TO MONTH #yearMonthIntervalDataType
| INTERVAL DAY TO SECOND #dayTimeIntervalDataType
| INTERVAL from=(DAY | HOUR | MINUTE | SECOND)
(TO to=(HOUR | MINUTE | SECOND))? #dayTimeIntervalDataType
| identifier ('(' INTEGER_VALUE (',' INTEGER_VALUE)* ')')? #primitiveDataType
;
@ -1110,6 +1111,7 @@ ansiNonReserved
| FUNCTIONS
| GLOBAL
| GROUPING
| HOUR
| IF
| IGNORE
| IMPORT
@ -1137,6 +1139,7 @@ ansiNonReserved
| MAP
| MATCHED
| MERGE
| MINUTE
| MONTH
| MSCK
| NAMESPACE
@ -1358,6 +1361,7 @@ nonReserved
| GROUP
| GROUPING
| HAVING
| HOUR
| IF
| IGNORE
| IMPORT
@ -1389,6 +1393,7 @@ nonReserved
| MAP
| MATCHED
| MERGE
| MINUTE
| MONTH
| MSCK
| NAMESPACE
@ -1612,6 +1617,7 @@ GRANT: 'GRANT';
GROUP: 'GROUP';
GROUPING: 'GROUPING';
HAVING: 'HAVING';
HOUR: 'HOUR';
IF: 'IF';
IGNORE: 'IGNORE';
IMPORT: 'IMPORT';
@ -1648,6 +1654,7 @@ MACRO: 'MACRO';
MAP: 'MAP';
MATCHED: 'MATCHED';
MERGE: 'MERGE';
MINUTE: 'MINUTE';
MONTH: 'MONTH';
MSCK: 'MSCK';
NAMESPACE: 'NAMESPACE';

View file

@ -2514,8 +2514,15 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
}
override def visitDayTimeIntervalDataType(ctx: DayTimeIntervalDataTypeContext): DataType = {
// TODO(SPARK-35736): Parse any day-time interval types in SQL
DayTimeIntervalType()
val strToFieldIndex =
DayTimeIntervalType.dayTimeFields.map(i => DayTimeIntervalType.fieldToString(i) -> i).toMap
val start = strToFieldIndex(ctx.from.getText.toLowerCase(Locale.ROOT))
val end = if (ctx.to != null ) {
strToFieldIndex(ctx.to.getText.toLowerCase(Locale.ROOT))
} else {
start
}
DayTimeIntervalType(start, end)
}
/**

View file

@ -257,7 +257,7 @@ class DataTypeSuite extends SparkFunSuite {
checkDataTypeFromDDL(VarcharType(11))
checkDataTypeFromDDL(YearMonthIntervalType)
checkDataTypeFromDDL(DayTimeIntervalType())
dayTimeIntervalTypes.foreach(checkDataTypeFromDDL)
val metadata = new MetadataBuilder()
.putString("name", "age")