From 9a43fe6942e9c1ec67bde8d3d02c5870202fb2bf Mon Sep 17 00:00:00 2001 From: Tanner Clary Date: Fri, 22 Nov 2024 10:50:28 -0800 Subject: [PATCH] [CALCITE-6703] RelJson cannot handle timestamps prior to 1970-01-25 20:31:23.648 --- .../calcite/rel/externalize/RelJson.java | 8 ++- .../apache/calcite/plan/RelWriterTest.java | 55 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java index 41262c065ba..1834ff12e11 100644 --- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java +++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java @@ -830,9 +830,15 @@ public RexNode toRex(RelOptCluster cluster, Object o) { Sarg sarg = sargFromJson((Map) literal, type); return rexBuilder.makeSearchArgumentLiteral(sarg, type); } - if (type.getSqlTypeName() == SqlTypeName.SYMBOL) { + SqlTypeName sqlTypeName = type.getSqlTypeName(); + if (sqlTypeName == SqlTypeName.SYMBOL) { literal = RelEnumTypes.toEnum((String) literal); } + if (sqlTypeName == SqlTypeName.TIMESTAMP || sqlTypeName == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) { + if (literal instanceof Integer) { + literal = ((Integer) literal).longValue(); + } + } return rexBuilder.makeLiteral(literal, type); } if (map.containsKey("sargLiteral")) { diff --git a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java index 501b6c0bdeb..32252f89642 100644 --- a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java +++ b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java @@ -740,6 +740,61 @@ private static Fixture relFn(Function relFn) { .assertThatPlan(isLinux(expected)); } + /** Test case for + * [CALCITE-6703] + * RelJson cannot handle timestamps prior to 1970-01-25 20:31:23.648. */ + @Test void testJsonToRexForTimestamp() { + // Below Integer.MAX_VALUE + final String timestampRepresentedAsInt = "{\n" + + " \"literal\": 2129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + // Above Integer.MAX_VALUE + final String timestampRepresentedAsLong = "{\n" + + " \"literal\": 3129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + + // These timestamps were verified using BigQuery's UNIX_MILLIS function. + assertThatReadExpressionResult(timestampRepresentedAsInt, is("1970-01-25 15:30:00")); + assertThatReadExpressionResult(timestampRepresentedAsLong, is("1970-02-06 05:16:40")); + } + + /** Test case for + * [CALCITE-6703] + * RelJson cannot handle timestamps prior to 1970-01-25 20:31:23.648. */ + @Test void testJsonToRexForTimestampWithLocalTimeZone() { + // Below Integer.MAX_VALUE + final String timestampWithLocalTzRepresentedAsInt = "{\n" + + " \"literal\": 2129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP_WITH_LOCAL_TIME_ZONE\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + // Above Integer.MAX_VALUE + final String timestampWithLocalTzRepresentedAsLong = "{\n" + + " \"literal\": 3129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP_WITH_LOCAL_TIME_ZONE\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + + // These timestamps were verified using BigQuery's UNIX_MILLIS function. + assertThatReadExpressionResult(timestampWithLocalTzRepresentedAsInt, + is("1970-01-25 15:30:00:TIMESTAMP_WITH_LOCAL_TIME_ZONE(0)")); + assertThatReadExpressionResult(timestampWithLocalTzRepresentedAsLong, + is("1970-02-06 05:16:40:TIMESTAMP_WITH_LOCAL_TIME_ZONE(0)")); + } + + @Test void testJsonToRex() { // Test simple literal without inputs final String jsonString1 = "{\n"