Skip to content

Commit 76a1413

Browse files
MaxGekkdongjoon-hyun
authored andcommitted
[SPARK-51462][SQL] Support typed literals of the TIME data type
### What changes were proposed in this pull request? In the PR, I propose to support typed literals of the TIME data type, for example: `time'7:36'`. The format of time string value should match to: ``` [h]h:[m]m:[s]s.[ms][ms][ms][us][us][us] ``` ### Why are the changes needed? To improve user experience with Spark SQL, and simplify migrations from other systems where such typed literals are supported. ### Does this PR introduce _any_ user-facing change? Yes, after the changes users can construct new typed literals. ### How was this patch tested? By running the new test: ``` $ build/sbt "test:testOnly *ExpressionParserSuite" ``` ### Was this patch authored or co-authored using generative AI tooling? No. Closes #50228 from MaxGekk/time-literal-constructor. Authored-by: Max Gekk <max.gekk@gmail.com> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
1 parent 0deb4cb commit 76a1413

File tree

3 files changed

+19
-2
lines changed

3 files changed

+19
-2
lines changed

sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ primaryExpression
11901190

11911191
literalType
11921192
: DATE
1193+
| TIME
11931194
| TIMESTAMP | TIMESTAMP_LTZ | TIMESTAMP_NTZ
11941195
| INTERVAL
11951196
| BINARY_HEX

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import org.apache.spark.sql.catalyst.trees.{CurrentOrigin, Origin}
4444
import org.apache.spark.sql.catalyst.trees.TreePattern.PARAMETER
4545
import org.apache.spark.sql.catalyst.types.DataTypeUtils
4646
import org.apache.spark.sql.catalyst.util.{CharVarcharUtils, CollationFactory, DateTimeUtils, IntervalUtils, SparkParserUtils}
47-
import org.apache.spark.sql.catalyst.util.DateTimeUtils.{convertSpecialDate, convertSpecialTimestamp, convertSpecialTimestampNTZ, getZoneId, stringToDate, stringToTimestamp, stringToTimestampWithoutTimeZone}
47+
import org.apache.spark.sql.catalyst.util.DateTimeUtils.{convertSpecialDate, convertSpecialTimestamp, convertSpecialTimestampNTZ, getZoneId, stringToDate, stringToTime, stringToTimestamp, stringToTimestampWithoutTimeZone}
4848
import org.apache.spark.sql.connector.catalog.{CatalogV2Util, SupportsNamespaces, TableCatalog, TableWritePrivilege}
4949
import org.apache.spark.sql.connector.catalog.TableChange.ColumnPosition
5050
import org.apache.spark.sql.connector.expressions.{ApplyTransform, BucketTransform, DaysTransform, Expression => V2Expression, FieldReference, HoursTransform, IdentityTransform, LiteralValue, MonthsTransform, Transform, YearsTransform}
@@ -3347,6 +3347,7 @@ class AstBuilder extends DataTypeAstBuilder
33473347
val zoneId = getZoneId(conf.sessionLocalTimeZone)
33483348
val specialDate = convertSpecialDate(value, zoneId).map(Literal(_, DateType))
33493349
specialDate.getOrElse(toLiteral(stringToDate, DateType))
3350+
case TIME => toLiteral(stringToTime, TimeType())
33503351
case TIMESTAMP_NTZ =>
33513352
convertSpecialTimestampNTZ(value, getZoneId(conf.sessionLocalTimeZone))
33523353
.map(Literal(_, TimestampNTZType))

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/parser/ExpressionParserSuite.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package org.apache.spark.sql.catalyst.parser
1818

1919
import java.sql.{Date, Timestamp}
20-
import java.time.{Duration, LocalDateTime, Period}
20+
import java.time.{Duration, LocalDateTime, LocalTime, Period}
2121
import java.util.concurrent.TimeUnit
2222

2323
import scala.language.implicitConversions
@@ -1238,4 +1238,19 @@ class ExpressionParserSuite extends AnalysisTest {
12381238
stop = 9 + quantifier.length))
12391239
}
12401240
}
1241+
1242+
test("time literals") {
1243+
assertEqual("tIme '12:13:14'", Literal(LocalTime.parse("12:13:14")))
1244+
assertEqual("TIME'23:59:59.999999'", Literal(LocalTime.parse("23:59:59.999999")))
1245+
1246+
checkError(
1247+
exception = parseException("time '12-13.14'"),
1248+
condition = "INVALID_TYPED_LITERAL",
1249+
sqlState = "42604",
1250+
parameters = Map("valueType" -> "\"TIME\"", "value" -> "'12-13.14'"),
1251+
context = ExpectedContext(
1252+
fragment = "time '12-13.14'",
1253+
start = 0,
1254+
stop = 14))
1255+
}
12411256
}

0 commit comments

Comments
 (0)