/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.type;
import com.facebook.presto.operator.scalar.AbstractTestFunctions;
import com.facebook.presto.spi.type.SqlTimestamp;
import org.testng.annotations.Test;
import static com.facebook.presto.SessionTestUtils.TEST_SESSION;
import static com.facebook.presto.spi.StandardErrorCode.INVALID_CAST_ARGUMENT;
import static com.facebook.presto.spi.type.BigintType.BIGINT;
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
import static com.facebook.presto.spi.type.DecimalType.createDecimalType;
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
import static com.facebook.presto.spi.type.RealType.REAL;
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
import static com.facebook.presto.type.JsonType.JSON;
import static java.lang.Double.NEGATIVE_INFINITY;
import static java.lang.Double.POSITIVE_INFINITY;
public class TestJsonOperators
extends AbstractTestFunctions
{
// Some of the tests in this class are expected to fail when coercion between primitive presto types changes behavior
@Test
public void testCastToBigint()
{
assertFunction("cast(JSON 'null' as BIGINT)", BIGINT, null);
assertFunction("cast(JSON '128' as BIGINT)", BIGINT, 128L);
assertInvalidFunction("cast(JSON '12345678901234567890' as BIGINT)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON '128.9' as BIGINT)", BIGINT, 129L);
assertFunction("cast(JSON '1234567890123456789.0' as BIGINT)", BIGINT, 1234567890123456768L); // loss of precision
assertFunction("cast(JSON '12345678901234567890.0' as BIGINT)", BIGINT, 9223372036854775807L); // overflow. unexpected behavior. coherent with rest of Presto.
assertFunction("cast(JSON '1e-324' as BIGINT)", BIGINT, 0L);
assertInvalidFunction("cast(JSON '1e309' as BIGINT)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON 'true' as BIGINT)", BIGINT, 1L);
assertFunction("cast(JSON 'false' as BIGINT)", BIGINT, 0L);
assertFunction("cast(JSON '\"128\"' as BIGINT)", BIGINT, 128L);
assertInvalidFunction("cast(JSON '\"12345678901234567890\"' as BIGINT)", INVALID_CAST_ARGUMENT);
assertInvalidFunction("cast(JSON '\"128.9\"' as BIGINT)", INVALID_CAST_ARGUMENT);
assertInvalidFunction("cast(JSON '\"true\"' as BIGINT)", INVALID_CAST_ARGUMENT);
assertInvalidFunction("cast(JSON '\"false\"' as BIGINT)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON ' 128' as BIGINT)", BIGINT, 128L); // leading space
assertFunction("cast(json_extract('{\"x\":999}', '$.x') as BIGINT)", BIGINT, 999L);
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as BIGINT)");
}
@Test
public void testTypeConstructor()
throws Exception
{
assertFunction("JSON '123'", JSON, "123");
assertFunction("JSON '[4,5,6]'", JSON, "[4,5,6]");
assertFunction("JSON '{ \"a\": 789 }'", JSON, "{\"a\":789}");
}
@Test
public void testCastFromIntegrals()
{
assertFunction("cast(cast (null as integer) as JSON)", JSON, null);
assertFunction("cast(cast (null as bigint) as JSON)", JSON, null);
assertFunction("cast(128 as JSON)", JSON, "128");
assertFunction("cast(BIGINT '128' as JSON)", JSON, "128");
}
@Test
public void testCastToDouble()
throws Exception
{
assertFunction("cast(JSON 'null' as DOUBLE)", DOUBLE, null);
assertFunction("cast(JSON '128' as DOUBLE)", DOUBLE, 128.0);
assertFunction("cast(JSON '12345678901234567890' as DOUBLE)", DOUBLE, 1.2345678901234567e19);
assertFunction("cast(JSON '128.9' as DOUBLE)", DOUBLE, 128.9);
assertFunction("cast(JSON '1e-324' as DOUBLE)", DOUBLE, 0.0); // smaller than minimum subnormal positive
assertFunction("cast(JSON '1e309' as DOUBLE)", DOUBLE, POSITIVE_INFINITY); // overflow
assertFunction("cast(JSON '-1e309' as DOUBLE)", DOUBLE, NEGATIVE_INFINITY); // underflow
assertFunction("cast(JSON 'true' as DOUBLE)", DOUBLE, 1.0);
assertFunction("cast(JSON 'false' as DOUBLE)", DOUBLE, 0.0);
assertFunction("cast(JSON '\"128\"' as DOUBLE)", DOUBLE, 128.0);
assertFunction("cast(JSON '\"12345678901234567890\"' as DOUBLE)", DOUBLE, 1.2345678901234567e19);
assertFunction("cast(JSON '\"128.9\"' as DOUBLE)", DOUBLE, 128.9);
assertFunction("cast(JSON '\"NaN\"' as DOUBLE)", DOUBLE, Double.NaN);
assertFunction("cast(JSON '\"Infinity\"' as DOUBLE)", DOUBLE, POSITIVE_INFINITY);
assertFunction("cast(JSON '\"-Infinity\"' as DOUBLE)", DOUBLE, NEGATIVE_INFINITY);
assertInvalidFunction("cast(JSON '\"true\"' as DOUBLE)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON ' 128.9' as DOUBLE)", DOUBLE, 128.9); // leading space
assertFunction("cast(json_extract('{\"x\":1.23}', '$.x') as DOUBLE)", DOUBLE, 1.23);
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as DOUBLE)");
}
@Test
public void testCastFromDouble()
throws Exception
{
assertFunction("cast(cast (null as double) as JSON)", JSON, null);
assertFunction("cast(3.14 as JSON)", JSON, "3.14");
assertFunction("cast(nan() as JSON)", JSON, "\"NaN\"");
assertFunction("cast(infinity() as JSON)", JSON, "\"Infinity\"");
assertFunction("cast(-infinity() as JSON)", JSON, "\"-Infinity\"");
}
@Test
public void testCastToReal()
throws Exception
{
assertFunction("cast(JSON 'null' as REAL)", REAL, null);
assertFunction("cast(JSON '-128' as REAL)", REAL, -128.0f);
assertFunction("cast(JSON '128' as REAL)", REAL, 128.0f);
assertFunction("cast(JSON '12345678901234567890' as REAL)", REAL, 1.2345679e19f);
assertFunction("cast(JSON '128.9' as REAL)", REAL, 128.9f);
assertFunction("cast(JSON '1e-46' as REAL)", REAL, 0.0f); // smaller than minimum subnormal positive
assertFunction("cast(JSON '1e39' as REAL)", REAL, Float.POSITIVE_INFINITY); // overflow
assertFunction("cast(JSON '-1e39' as REAL)", REAL, Float.NEGATIVE_INFINITY); // underflow
assertFunction("cast(JSON 'true' as REAL)", REAL, 1.0f);
assertFunction("cast(JSON 'false' as REAL)", REAL, 0.0f);
assertFunction("cast(JSON '\"128\"' as REAL)", REAL, 128.0f);
assertFunction("cast(JSON '\"12345678901234567890\"' as REAL)", REAL, 1.2345679e19f);
assertFunction("cast(JSON '\"128.9\"' as REAL)", REAL, 128.9f);
assertFunction("cast(JSON '\"NaN\"' as REAL)", REAL, Float.NaN);
assertFunction("cast(JSON '\"Infinity\"' as REAL)", REAL, Float.POSITIVE_INFINITY);
assertFunction("cast(JSON '\"-Infinity\"' as REAL)", REAL, Float.NEGATIVE_INFINITY);
assertInvalidFunction("cast(JSON '\"true\"' as REAL)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON ' 128.9' as REAL)", REAL, 128.9f); // leading space
assertFunction("cast(json_extract('{\"x\":1.23}', '$.x') as REAL)", REAL, 1.23f);
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as REAL)");
}
@Test
public void testCastToDecimal()
throws Exception
{
assertFunction("cast(JSON 'null' as DECIMAL(10,3))", createDecimalType(10, 3), null);
assertFunction("cast(JSON '128' as DECIMAL(10,3))", createDecimalType(10, 3), decimal("128.000"));
assertFunction("cast(cast(DECIMAL '123456789012345678901234567890.12345678' as JSON) as DECIMAL(38,8))", createDecimalType(38, 8), decimal("123456789012345678901234567890.12345678"));
assertFunction("cast(JSON '123.456' as DECIMAL(10,5))", createDecimalType(10, 5), decimal("123.45600"));
assertFunction("cast(JSON 'true' as DECIMAL(10,5))", createDecimalType(10, 5), decimal("1.00000"));
assertFunction("cast(JSON 'false' as DECIMAL(10,5))", createDecimalType(10, 5), decimal("0.00000"));
assertInvalidCast("cast(JSON '1234567890123456' as DECIMAL(10,3))", "Cannot cast input json to DECIMAL(10,3)");
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as DECIMAL(10,3))", "Cannot cast '{\"x\":123}' to DECIMAL(10,3)");
assertInvalidCast("cast(JSON '\"abc\"' as DECIMAL(10,3))", "Cannot cast '\"abc\"' to DECIMAL(10,3)");
}
@Test
public void testCastFromDecimal()
throws Exception
{
assertFunction("cast(cast(null as decimal(5,2)) as JSON)", JSON, null);
assertFunction("cast(DECIMAL '3.14' as JSON)", JSON, "3.14");
assertFunction("cast(DECIMAL '12345678901234567890.123456789012345678' as JSON)", JSON, "12345678901234567890.123456789012345678");
}
@Test
public void testCastToBoolean()
{
assertFunction("cast(JSON 'null' as BOOLEAN)", BOOLEAN, null);
assertFunction("cast(JSON '0' as BOOLEAN)", BOOLEAN, false);
assertFunction("cast(JSON '128' as BOOLEAN)", BOOLEAN, true);
assertInvalidFunction("cast(JSON '12345678901234567890' as BOOLEAN)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON '128.9' as BOOLEAN)", BOOLEAN, true);
assertFunction("cast(JSON '1e-324' as BOOLEAN)", BOOLEAN, false); // smaller than minimum subnormal positive
assertInvalidFunction("cast(JSON '1e309' as BOOLEAN)", INVALID_CAST_ARGUMENT); // overflow
assertFunction("cast(JSON 'true' as BOOLEAN)", BOOLEAN, true);
assertFunction("cast(JSON 'false' as BOOLEAN)", BOOLEAN, false);
assertFunction("cast(JSON '\"True\"' as BOOLEAN)", BOOLEAN, true);
assertFunction("cast(JSON '\"true\"' as BOOLEAN)", BOOLEAN, true);
assertFunction("cast(JSON '\"false\"' as BOOLEAN)", BOOLEAN, false);
assertInvalidFunction("cast(JSON '\"128\"' as BOOLEAN)", INVALID_CAST_ARGUMENT);
assertInvalidFunction("cast(JSON '\"\"' as BOOLEAN)", INVALID_CAST_ARGUMENT);
assertFunction("cast(JSON ' true' as BOOLEAN)", BOOLEAN, true); // leading space
assertFunction("cast(json_extract('{\"x\":true}', '$.x') as BOOLEAN)", BOOLEAN, true);
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as BOOLEAN)");
}
@Test
public void testCastFromBoolean()
{
assertFunction("cast(cast (null as boolean) as JSON)", JSON, null);
assertFunction("cast(TRUE as JSON)", JSON, "true");
assertFunction("cast(FALSE as JSON)", JSON, "false");
}
@Test
public void testCastToVarchar()
{
assertFunction("cast(JSON 'null' as VARCHAR)", VARCHAR, null);
assertFunction("cast(JSON '128' as VARCHAR)", VARCHAR, "128");
assertFunction("cast(JSON '12345678901234567890' as VARCHAR)", VARCHAR, "12345678901234567890"); // overflow, no loss of precision
assertFunction("cast(JSON '128.9' as VARCHAR)", VARCHAR, "128.9");
assertFunction("cast(JSON '1e-324' as VARCHAR)", VARCHAR, "0.0"); // smaller than minimum subnormal positive
assertFunction("cast(JSON '1e309' as VARCHAR)", VARCHAR, "Infinity"); // overflow
assertFunction("cast(JSON '-1e309' as VARCHAR)", VARCHAR, "-Infinity"); // underflow
assertFunction("cast(JSON 'true' as VARCHAR)", VARCHAR, "true");
assertFunction("cast(JSON 'false' as VARCHAR)", VARCHAR, "false");
assertFunction("cast(JSON '\"test\"' as VARCHAR)", VARCHAR, "test");
assertFunction("cast(JSON '\"null\"' as VARCHAR)", VARCHAR, "null");
assertFunction("cast(JSON '\"\"' as VARCHAR)", VARCHAR, "");
assertFunction("cast(JSON ' \"test\"' as VARCHAR)", VARCHAR, "test"); // leading space
assertFunction("cast(json_extract('{\"x\":\"y\"}', '$.x') as VARCHAR)", VARCHAR, "y");
assertInvalidCast("cast(JSON '{ \"x\" : 123}' as VARCHAR)");
}
@Test
public void testCastFromVarchar()
{
assertFunction("cast(cast (null as varchar) as JSON)", JSON, null);
assertFunction("cast('abc' as JSON)", JSON, "\"abc\"");
assertFunction("cast('\"a\":2' as JSON)", JSON, "\"\\\"a\\\":2\"");
}
@Test
public void testCastFromTimestamp()
{
assertFunction("cast(cast (null as timestamp) as JSON)", JSON, null);
assertFunction("CAST(from_unixtime(1) AS JSON)", JSON, "\"" + sqlTimestamp(1000).toString() + "\"");
}
private static SqlTimestamp sqlTimestamp(long millisUtc)
{
return new SqlTimestamp(millisUtc, TEST_SESSION.getTimeZoneKey());
}
}