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);