From b412fa4ac0b1340a9f4e50c1d7ae4c869dcd1d2f Mon Sep 17 00:00:00 2001 From: Tanner Clary Date: Tue, 12 Mar 2024 10:33:06 -0700 Subject: [PATCH] [CALCITE-6323] Serialize return type during RelJson.toJson(RexNode node) for SqlKind.SAFE_CAST --- .../calcite/rel/externalize/RelJson.java | 1 + .../apache/calcite/plan/RelWriterTest.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) 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 ebc4d2edc23..3f7cbbca973 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 @@ -632,6 +632,7 @@ public Object toJson(RexNode node) { switch (node.getKind()) { case MINUS: case CAST: + case SAFE_CAST: map.put("type", toJson(node.getType())); break; default: 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 9bde84126b1..ccb375503d7 100644 --- a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java +++ b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java @@ -1091,6 +1091,36 @@ void testAggregateWithAlias(SqlExplainFormat format) { assertThat(result, isLinux(expected)); } + /** Test case for + * [CALCITE-6323] + * + *

Before the fix, RelJson.toRex would throw an ArrayIndexOutOfBounds error + * when deserializing SAFE_CAST due to type inference requiring 2 operands. + * + *

The solution is to add in 'type' when serializing to JSON. + */ + @Test void testDeserializeSafeCastOperator() { + final FrameworkConfig config = RelBuilderTest.config().build(); + final RelBuilder builder = RelBuilder.create(config); + final RexBuilder rb = builder.getRexBuilder(); + final RelDataTypeFactory typeFactory = rb.getTypeFactory(); + final RelDataType type = typeFactory.createSqlType(SqlTypeName.DATE); + final RelNode rel = builder + .scan("EMP") + .project(builder.field("JOB"), + rb.makeCall(type, SqlLibraryOperators.SAFE_CAST, + ImmutableList.of(builder.field("SAL")))).build(); + final RelJsonWriter jsonWriter = + new RelJsonWriter(new JsonBuilder(), RelJson::withLibraryOperatorTable); + rel.explain(jsonWriter); + String relJson = jsonWriter.asString(); + String result = deserializeAndDumpToTextFormat(getSchema(rel), relJson); + final String expected = + "LogicalProject(JOB=[$2], $f1=[SAFE_CAST($5)])\n" + + " LogicalTableScan(table=[[scott, EMP]])\n"; + assertThat(result, isLinux(expected)); + } + @Test void testAggregateWithoutAlias() { final FrameworkConfig config = RelBuilderTest.config().build(); final RelBuilder builder = RelBuilder.create(config);