Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ public static Block toArray(ArrayType arrayType, BlockBuilderAppender arrayAppen
try (JsonParser jsonParser = createJsonParser(JSON_MAPPER, json)) {
jsonParser.nextToken();
if (jsonParser.getCurrentToken() == JsonToken.VALUE_NULL) {
if (jsonParser.nextToken() != null) {
throw new JsonCastException(format("Unexpected trailing token: %s", jsonParser.getText()));
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public static SqlMap toMap(MapType mapType, BlockBuilderAppender mapAppender, Sl
try (JsonParser jsonParser = createJsonParser(JSON_MAPPER, json)) {
jsonParser.nextToken();
if (jsonParser.getCurrentToken() == JsonToken.VALUE_NULL) {
if (jsonParser.nextToken() != null) {
throw new JsonCastException(format("Unexpected trailing token: %s", jsonParser.getText()));
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ public static SqlRow toRow(RowType rowType, BlockBuilderAppender rowAppender, Sl
try (JsonParser jsonParser = createJsonParser(JSON_MAPPER, json)) {
jsonParser.nextToken();
if (jsonParser.getCurrentToken() == JsonToken.VALUE_NULL) {
if (jsonParser.nextToken() != null) {
throw new JsonCastException(format("Unexpected trailing token: %s", jsonParser.getText()));
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,14 @@ public void testJsonToArraySmoke()
.binding("a", "JSON 'null'"))
.isNull(new ArrayType(BIGINT));

assertThat(assertions.expression("CAST(json_parse(a) AS array(BIGINT))")
.binding("a", "'null'"))
.isNull(new ArrayType(BIGINT));

assertTrinoExceptionThrownBy(assertions.expression("CAST(json_parse(a) AS array(BIGINT))")
.binding("a", "'null 123 some invalid JSON content'")::evaluate)
.hasMessage("Cannot cast to array(bigint). Unexpected trailing token: 123\nnull 123 some invalid JSON content");

assertThat(assertions.expression("CAST(a AS array(BIGINT))")
.binding("a", "JSON '[]'"))
.hasType(new ArrayType(BIGINT))
Expand Down Expand Up @@ -1158,10 +1166,34 @@ public void testCastJsonToArrayVarchar()
.matches("CAST(ARRAY['test', '', 'data'] AS ARRAY(VARCHAR))");

// array with various types including scientific notation and string "null"
String inputJsonArray = "[true, false, 12, 12.3, 1.23E1, 0, 0.000000000000000, 0e1000, 0e-1000, 1, 100000000000000000000000000000000000000000000000000000000000000000000e-68, 0.100000000000000, \"puppies\", \"kittens\", \"null\", null]";
String expectedVarcharArray = "ARRAY[VARCHAR 'true', 'false', '12', '1.23E1', '1.23E1', '0', '0E0', '0E0', '0E0', '1', '1.0E0', '1.0E-1', 'puppies', 'kittens', 'null', null]";
assertThat(assertions.expression("cast(a as ARRAY(VARCHAR))")
.binding("a", "JSON '[true, false, 12, 12.3, 1.23E1, \"puppies\", \"kittens\", \"null\", null]'"))
.binding("a", "JSON '" + inputJsonArray + "'"))
.hasType(new ArrayType(VARCHAR))
.matches(expectedVarcharArray);
// Same with json_parse, exercising SpecializeCastWithJsonParse
assertThat(assertions.expression("cast(json_parse(a) as ARRAY(VARCHAR))")
.binding("a", "'" + inputJsonArray + "'"))
.hasType(new ArrayType(VARCHAR))
.matches("CAST(ARRAY['true', 'false', '12', '1.23E1', '1.23E1', 'puppies', 'kittens', 'null', null] AS ARRAY(VARCHAR))");
.matches(expectedVarcharArray);

// Number with leading zeros
assertTrinoExceptionThrownBy(assertions.expression("cast(a as ARRAY(VARCHAR))")
.binding("a", "JSON '[000]'")::evaluate)
.hasMessage("line 3:16: '[000]' is not a valid JSON literal");
assertTrinoExceptionThrownBy(assertions.expression("cast(a as ARRAY(VARCHAR))")
.binding("a", "JSON '[000.0]'")::evaluate)
.hasMessage("line 3:16: '[000.0]' is not a valid JSON literal");
// Number with leading zeros with json_parse, exercising SpecializeCastWithJsonParse
assertTrinoExceptionThrownBy(assertions.expression("cast(json_parse(a) as ARRAY(VARCHAR))")
.binding("a", "'[000]'")::evaluate)
// TODO the exception message could be better
.hasMessage("Cannot cast to array(varchar).\n[000]");
assertTrinoExceptionThrownBy(assertions.expression("cast(json_parse(a) as ARRAY(VARCHAR))")
.binding("a", "'[000.0]'")::evaluate)
// TODO the exception message could be better
.hasMessage("Cannot cast to array(varchar).\n[000.0]");

// non-array JSON should fail
assertTrinoExceptionThrownBy(() -> assertions.expression("cast(a as ARRAY(VARCHAR))")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,42 @@ public void testCastToVarchar()
.hasType(VARCHAR)
.isEqualTo("128");

// overflow, no loss of precision
assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '0'"))
.hasType(VARCHAR)
.isEqualTo("0");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '0.000000000000000'"))
.hasType(VARCHAR)
.isEqualTo("0E0");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '0e1000'"))
.hasType(VARCHAR)
.isEqualTo("0E0");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '0e-1000'"))
.hasType(VARCHAR)
.isEqualTo("0E0");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '1'"))
.hasType(VARCHAR)
.isEqualTo("1");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '100000000000000000000000000000000000000000000000000000000000000000000e-68'"))
.hasType(VARCHAR)
.isEqualTo("1.0E0");

assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '0.100000000000000'"))
.hasType(VARCHAR)
.isEqualTo("1.0E-1");

// overflow if parsed as long, no loss of precision
assertThat(assertions.expression("cast(a as VARCHAR)")
.binding("a", "JSON '12345678901234567890'"))
.hasType(VARCHAR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,14 @@ public void testJsonToMap()
.binding("a", "JSON 'null'"))
.isNull(mapType(BIGINT, BIGINT));

assertThat(assertions.expression("cast(json_parse(a) as MAP(BIGINT, BIGINT))")
.binding("a", "'null'"))
.isNull(mapType(BIGINT, BIGINT));

assertTrinoExceptionThrownBy(assertions.expression("cast(json_parse(a) as MAP(BIGINT, BIGINT))")
.binding("a", "'null 123 some invalid JSON content'")::evaluate)
.hasMessage("Cannot cast to map(bigint, bigint). Unexpected trailing token: 123\nnull 123 some invalid JSON content");

assertThat(assertions.expression("cast(a as MAP(BIGINT, BIGINT))")
.binding("a", "JSON '{}'"))
.hasType(mapType(BIGINT, BIGINT))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ public void testJsonToRow()
.binding("a", "JSON 'null'"))
.isNull(RowType.anonymous(ImmutableList.of(BIGINT)));

assertThat(assertions.expression("CAST(json_parse(a) as ROW(BIGINT))")
.binding("a", "'null'"))
.isNull(RowType.anonymous(ImmutableList.of(BIGINT)));

assertTrinoExceptionThrownBy(assertions.expression("CAST(json_parse(a) as ROW(BIGINT))")
.binding("a", "'null 123 some invalid JSON content'")::evaluate)
.hasMessage("Cannot cast to row(bigint). Unexpected trailing token: 123\nnull 123 some invalid JSON content");

assertThat(assertions.expression("CAST(a as ROW(VARCHAR, BIGINT))")
.binding("a", "JSON '[null, null]'"))
.hasType(RowType.anonymous(ImmutableList.of(VARCHAR, BIGINT)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,20 @@ void testJsonParseInteger()
}

@Test
void testJsonParseDouble()
void testJsonParseDecimal()
{
assertThat(jsonParse(utf8Slice("3.14")).toStringUtf8())
.isEqualTo("3.14");
assertThat(jsonParse(utf8Slice("-2.5")).toStringUtf8())
.isEqualTo("-2.5");
assertThat(jsonParse(utf8Slice("1.0")).toStringUtf8())
.isEqualTo("1.0");
assertThat(jsonParse(utf8Slice("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-106")).toStringUtf8())
.isEqualTo("10.0");
assertThat(jsonParse(utf8Slice("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-107")).toStringUtf8())
.isEqualTo("1.0");
assertThat(jsonParse(utf8Slice("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-108")).toStringUtf8())
.isEqualTo("0.1");
}

@Test
Expand All @@ -81,6 +87,32 @@ void testJsonParseLargeNumber()
.isEqualTo("1.2345678901234568E29");
}

@Test
void testJsonParseNumberWithLeadingZeros()
{
assertThatThrownBy(() -> jsonParse(utf8Slice("007")))
.isInstanceOf(TrinoException.class)
.hasMessage("Cannot convert value to JSON: '007'");
assertThatThrownBy(() -> jsonParse(utf8Slice("007.0")))
.isInstanceOf(TrinoException.class)
.hasMessage("Cannot convert value to JSON: '007.0'");
}

@Test
void testJsonParseNumberWithTrailingZeros()
{
assertThat(jsonParse(utf8Slice("7000000100000000")).toStringUtf8())
.isEqualTo("7000000100000000");
assertThat(jsonParse(utf8Slice("7010.00")).toStringUtf8())
.isEqualTo("7010.0");
assertThat(jsonParse(utf8Slice("7000000100000000.000000000000")).toStringUtf8())
.isEqualTo("7.0000001E15");
assertThat(jsonParse(utf8Slice("7010.030")).toStringUtf8())
.isEqualTo("7010.03");
assertThat(jsonParse(utf8Slice("7000000100000000.0000030000000")).toStringUtf8())
.isEqualTo("7.0000001E15");
}

@Test
void testJsonParseArray()
{
Expand Down