From 1a6d87afd427ed6a2328f486cafa7a95509b6940 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 | 49 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) 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..185800c1ec6 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,53 @@ 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() { + final String timestampRepresentedAsInt = "{\n" + + " \"literal\": 2129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + final String timestampRepresentedAsLong = "{\n" + + " \"literal\": 3129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + + 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() { + final String timestampWithLocalTzRepresentedAsInt = "{\n" + + " \"literal\": 2129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP_WITH_LOCAL_TIME_ZONE\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + final String timestampWithLocalTzRepresentedAsLong = "{\n" + + " \"literal\": 3129400000,\n" + + " \"type\": {\n" + + " \"type\": \"TIMESTAMP_WITH_LOCAL_TIME_ZONE\",\n" + + " \"nullable\": false\n" + + " }\n" + + "}\n"; + + 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" @@ -908,7 +955,7 @@ private static RexNode translateInput(RelJson relJson, int input, // Test Calcite DateString class works in a Range final DateString d1 = DateString.fromCalendarFields( - new TimestampString(1970, 2, 1, 1, 1, 0).toCalendar()); + new TimestampString(1970, 1, 1, 1, 1, 0).toCalendar()); final DateString d2 = DateString.fromDaysSinceEpoch(100); final DateString d3 = DateString.fromDaysSinceEpoch(1000); RexNode dateNode =