[
https://issues.apache.org/jira/browse/CALCITE-7560?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18086030#comment-18086030
]
Ruiqi Dong commented on CALCITE-7560:
-------------------------------------
PR was submitted
> SqlFunctions.DateParseFunction.parseTimestamp(..., timeZone) accepts unknown
> time zones and silently falls back to GMT
> ----------------------------------------------------------------------------------------------------------------------
>
> Key: CALCITE-7560
> URL: https://issues.apache.org/jira/browse/CALCITE-7560
> Project: Calcite
> Issue Type: Bug
> Components: core
> Affects Versions: 1.41.0
> Reporter: Ruiqi Dong
> Priority: Major
> Labels: pull-request-available
>
> *Summary*
> Calcite's runtime implementation of BigQuery-style PARSE_TIMESTAMP(format,
> string [, timezone]) accepts unknown time-zone identifiers and interprets
> them as GMT. This is not just parser behavior. It affects runtime evaluation
> in SqlFunctions.DateParseFunction, so a typo in the time-zone argument
> changes query results instead of raising an error.
>
> *Affected code*
> Files:
> core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
> core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
> {code:java}
> /**
> * The "PARSE_TIMESTAMP(string, string [, timezone])" function (BigQuery);
> * Formats a timestamp object according to the specified string.
> */
> public static final SqlFunction PARSE_TIMESTAMP = ... {code}
> The runtime implementation uses TimeZone.getTimeZone(...) directly:
> {code:java}
> public long parseTimestamp(String fmtString, String timestamp,
> String timeZone) {
> TimeZone tz = TimeZone.getTimeZone(timeZone);
> final long millisSinceEpoch =
> internalParseDatetime(fmtString, timestamp, timeZone);
> return toLong(new java.sql.Timestamp(millisSinceEpoch), tz);
> } {code}
> The cached DateFormat path does the same:
> {code:java}
> TimeZone tz = TimeZone.getTimeZone(timeZone);
> parser.setCalendar(Calendar.getInstance(tz, Locale.ROOT)); {code}
> Because TimeZone.getTimeZone(...) silently falls back to GMT for unknown IDs,
> the user-supplied bad zone is never rejected.
>
> *Reproducer*
> Add the following test to
> core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
> {code:java}
> @Test void testParseTimestampUnknownTimeZoneMatchesGmtFallback() {
> final SqlFunctions.DateParseFunction parse = new
> SqlFunctions.DateParseFunction();
> final long gmt =
> parse.parseTimestamp("%Y-%m-%d %H:%M:%S", "2024-01-01 00:00:00", "GMT");
> final long typo =
> parse.parseTimestamp("%Y-%m-%d %H:%M:%S", "2024-01-01 00:00:00",
> "Asia/Sanghai");
> assertThat(typo, is(gmt));
> }
> @Test void testParseTimestampRejectsUnknownTimeZone() {
> final SqlFunctions.DateParseFunction parse = new
> SqlFunctions.DateParseFunction();
> assertThrows(RuntimeException.class,
> () -> parse.parseTimestamp("%Y-%m-%d %H:%M:%S",
> "2024-01-01 00:00:00", "Asia/Sanghai"));
> } {code}
> Run:
> {code:java}
> ./gradlew :core:test \
> --tests
> org.apache.calcite.test.SqlFunctionsTest.testParseTimestampUnknownTimeZoneMatchesGmtFallback
> \
> --tests
> org.apache.calcite.test.SqlFunctionsTest.testParseTimestampRejectsUnknownTimeZone
> {code}
> Observed behavior:
> The fallback behavior is visible directly
> * parseTimestamp(..., "Asia/Sanghai") returns the same result as
> parseTimestamp(..., "GMT")
> * no exception is thrown for the unknown time-zone identifier.
> The rejecting test fails with
> {code:java}
> Expected java.lang.RuntimeException to be thrown, but nothing was thrown.
> {code}
> Expected behavior:
> An invalid time-zone identifier should be rejected, rather than being
> silently reinterpreted as GMT.
>
> This is a runtime input-validation bug. A misspelled time-zone argument
> changes the meaning of a query result while looking superficially valid,
> which is worse than a hard failure.
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)