diff --git a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/BaseJdbcClient.java b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/BaseJdbcClient.java index 1ef97e3a0f6c0..42f257dc63e23 100644 --- a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/BaseJdbcClient.java +++ b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/BaseJdbcClient.java @@ -202,6 +202,7 @@ public List getColumns(ConnectorSession session, JdbcTableHand while (resultSet.next()) { JdbcTypeHandle typeHandle = new JdbcTypeHandle( resultSet.getInt("DATA_TYPE"), + resultSet.getString("TYPE_NAME"), resultSet.getInt("COLUMN_SIZE"), resultSet.getInt("DECIMAL_DIGITS")); Optional columnMapping = toPrestoType(session, typeHandle); diff --git a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcPageSink.java b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcPageSink.java index 97ae81e6c06d8..3625b30ff5a88 100644 --- a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcPageSink.java +++ b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcPageSink.java @@ -44,6 +44,7 @@ import static com.facebook.presto.spi.type.Decimals.readBigDecimal; import static com.facebook.presto.spi.type.DoubleType.DOUBLE; import static com.facebook.presto.spi.type.IntegerType.INTEGER; +import static com.facebook.presto.spi.type.JsonType.JSON; import static com.facebook.presto.spi.type.RealType.REAL; import static com.facebook.presto.spi.type.SmallintType.SMALLINT; import static com.facebook.presto.spi.type.TinyintType.TINYINT; @@ -150,6 +151,9 @@ else if (type instanceof DecimalType) { else if (isVarcharType(type) || isCharType(type)) { statement.setString(parameter, type.getSlice(block, position).toStringUtf8()); } + else if (JSON.equals(type)) { + statement.setString(parameter, type.getSlice(block, position).toStringUtf8()); + } else if (VARBINARY.equals(type)) { statement.setBytes(parameter, type.getSlice(block, position).getBytes()); } diff --git a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcTypeHandle.java b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcTypeHandle.java index 250dbdbbe4c27..64e49774ad826 100644 --- a/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcTypeHandle.java +++ b/presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcTypeHandle.java @@ -23,16 +23,19 @@ public final class JdbcTypeHandle { private final int jdbcType; + private final String jdbcTypeName; private final int columnSize; private final int decimalDigits; @JsonCreator public JdbcTypeHandle( @JsonProperty("jdbcType") int jdbcType, + @JsonProperty("jdbcTypeName") String jdbcTypeName, @JsonProperty("columnSize") int columnSize, @JsonProperty("decimalDigits") int decimalDigits) { this.jdbcType = jdbcType; + this.jdbcTypeName = jdbcTypeName; this.columnSize = columnSize; this.decimalDigits = decimalDigits; } @@ -43,6 +46,12 @@ public int getJdbcType() return jdbcType; } + @JsonProperty + public String getJdbcTypeName() + { + return jdbcTypeName; + } + @JsonProperty public int getColumnSize() { @@ -58,7 +67,7 @@ public int getDecimalDigits() @Override public int hashCode() { - return Objects.hash(jdbcType, columnSize, decimalDigits); + return Objects.hash(jdbcType, jdbcTypeName, columnSize, decimalDigits); } @Override @@ -72,6 +81,7 @@ public boolean equals(Object o) } JdbcTypeHandle that = (JdbcTypeHandle) o; return jdbcType == that.jdbcType && + jdbcTypeName.equals(that.jdbcTypeName) && columnSize == that.columnSize && decimalDigits == that.decimalDigits; } @@ -81,6 +91,7 @@ public String toString() { return toStringHelper(this) .add("jdbcType", jdbcType) + .add("jdbcTypeName", jdbcTypeName) .add("columnSize", columnSize) .add("decimalDigits", decimalDigits) .toString(); diff --git a/presto-base-jdbc/src/test/java/com/facebook/presto/plugin/jdbc/TestingJdbcTypeHandle.java b/presto-base-jdbc/src/test/java/com/facebook/presto/plugin/jdbc/TestingJdbcTypeHandle.java index 55b8b377beb62..1c70a3e7e8ecf 100644 --- a/presto-base-jdbc/src/test/java/com/facebook/presto/plugin/jdbc/TestingJdbcTypeHandle.java +++ b/presto-base-jdbc/src/test/java/com/facebook/presto/plugin/jdbc/TestingJdbcTypeHandle.java @@ -19,20 +19,20 @@ public final class TestingJdbcTypeHandle { private TestingJdbcTypeHandle() {} - public static final JdbcTypeHandle JDBC_BOOLEAN = new JdbcTypeHandle(Types.BOOLEAN, 1, 0); + public static final JdbcTypeHandle JDBC_BOOLEAN = new JdbcTypeHandle(Types.BOOLEAN, "", 1, 0); - public static final JdbcTypeHandle JDBC_SMALLINT = new JdbcTypeHandle(Types.SMALLINT, 1, 0); - public static final JdbcTypeHandle JDBC_TINYINT = new JdbcTypeHandle(Types.TINYINT, 2, 0); - public static final JdbcTypeHandle JDBC_INTEGER = new JdbcTypeHandle(Types.INTEGER, 4, 0); - public static final JdbcTypeHandle JDBC_BIGINT = new JdbcTypeHandle(Types.BIGINT, 8, 0); + public static final JdbcTypeHandle JDBC_SMALLINT = new JdbcTypeHandle(Types.SMALLINT, "", 1, 0); + public static final JdbcTypeHandle JDBC_TINYINT = new JdbcTypeHandle(Types.TINYINT, "", 2, 0); + public static final JdbcTypeHandle JDBC_INTEGER = new JdbcTypeHandle(Types.INTEGER, "", 4, 0); + public static final JdbcTypeHandle JDBC_BIGINT = new JdbcTypeHandle(Types.BIGINT, "", 8, 0); - public static final JdbcTypeHandle JDBC_REAL = new JdbcTypeHandle(Types.REAL, 8, 0); - public static final JdbcTypeHandle JDBC_DOUBLE = new JdbcTypeHandle(Types.DOUBLE, 8, 0); + public static final JdbcTypeHandle JDBC_REAL = new JdbcTypeHandle(Types.REAL, "", 8, 0); + public static final JdbcTypeHandle JDBC_DOUBLE = new JdbcTypeHandle(Types.DOUBLE, "", 8, 0); - public static final JdbcTypeHandle JDBC_CHAR = new JdbcTypeHandle(Types.CHAR, 10, 0); - public static final JdbcTypeHandle JDBC_VARCHAR = new JdbcTypeHandle(Types.VARCHAR, 10, 0); + public static final JdbcTypeHandle JDBC_CHAR = new JdbcTypeHandle(Types.CHAR, "", 10, 0); + public static final JdbcTypeHandle JDBC_VARCHAR = new JdbcTypeHandle(Types.VARCHAR, "", 10, 0); - public static final JdbcTypeHandle JDBC_DATE = new JdbcTypeHandle(Types.DATE, 8, 0); - public static final JdbcTypeHandle JDBC_TIME = new JdbcTypeHandle(Types.TIME, 4, 0); - public static final JdbcTypeHandle JDBC_TIMESTAMP = new JdbcTypeHandle(Types.TIMESTAMP, 8, 0); + public static final JdbcTypeHandle JDBC_DATE = new JdbcTypeHandle(Types.DATE, "", 8, 0); + public static final JdbcTypeHandle JDBC_TIME = new JdbcTypeHandle(Types.TIME, "", 4, 0); + public static final JdbcTypeHandle JDBC_TIMESTAMP = new JdbcTypeHandle(Types.TIMESTAMP, "", 8, 0); } diff --git a/presto-main/src/main/java/com/facebook/presto/testing/MaterializedResult.java b/presto-main/src/main/java/com/facebook/presto/testing/MaterializedResult.java index 962f7127d8091..f52623a120436 100644 --- a/presto-main/src/main/java/com/facebook/presto/testing/MaterializedResult.java +++ b/presto-main/src/main/java/com/facebook/presto/testing/MaterializedResult.java @@ -67,6 +67,7 @@ import static com.facebook.presto.spi.type.RealType.REAL; import static com.facebook.presto.spi.type.SmallintType.SMALLINT; import static com.facebook.presto.spi.type.StandardTypes.ARRAY; +import static com.facebook.presto.spi.type.StandardTypes.JSON; import static com.facebook.presto.spi.type.StandardTypes.MAP; import static com.facebook.presto.spi.type.TimeType.TIME; import static com.facebook.presto.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE; @@ -261,6 +262,9 @@ else if (DOUBLE.equals(type)) { else if (BOOLEAN.equals(type)) { type.writeBoolean(blockBuilder, (Boolean) value); } + else if (JSON.equals(type)) { + type.writeSlice(blockBuilder, Slices.utf8Slice((String) value)); + } else if (type instanceof VarcharType) { type.writeSlice(blockBuilder, Slices.utf8Slice((String) value)); } diff --git a/presto-main/src/main/java/com/facebook/presto/type/JsonType.java b/presto-main/src/main/java/com/facebook/presto/type/JsonType.java index ad7c9e5e5d8ea..198cc119b6896 100644 --- a/presto-main/src/main/java/com/facebook/presto/type/JsonType.java +++ b/presto-main/src/main/java/com/facebook/presto/type/JsonType.java @@ -13,90 +13,11 @@ */ package com.facebook.presto.type; -import com.facebook.presto.spi.ConnectorSession; -import com.facebook.presto.spi.block.Block; -import com.facebook.presto.spi.block.BlockBuilder; -import com.facebook.presto.spi.type.AbstractVariableWidthType; -import com.facebook.presto.spi.type.StandardTypes; -import com.facebook.presto.spi.type.TypeSignature; -import io.airlift.slice.Slice; -import io.airlift.slice.Slices; - /** * The stack representation for JSON objects must have the keys in natural sorted order. */ public class JsonType - extends AbstractVariableWidthType + extends com.facebook.presto.spi.type.JsonType { - public static final JsonType JSON = new JsonType(); - - public JsonType() - { - super(new TypeSignature(StandardTypes.JSON), Slice.class); - } - - @Override - public boolean isComparable() - { - return true; - } - - @Override - public boolean equalTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition) - { - Slice leftValue = leftBlock.getSlice(leftPosition, 0, leftBlock.getSliceLength(leftPosition)); - Slice rightValue = rightBlock.getSlice(rightPosition, 0, rightBlock.getSliceLength(rightPosition)); - return leftValue.equals(rightValue); - } - - @Override - public long hash(Block block, int position) - { - return block.hash(position, 0, block.getSliceLength(position)); - } - - @Override - public Object getObjectValue(ConnectorSession session, Block block, int position) - { - if (block.isNull(position)) { - return null; - } - - return block.getSlice(position, 0, block.getSliceLength(position)).toStringUtf8(); - } - - @Override - public void appendTo(Block block, int position, BlockBuilder blockBuilder) - { - if (block.isNull(position)) { - blockBuilder.appendNull(); - } - else { - block.writeBytesTo(position, 0, block.getSliceLength(position), blockBuilder); - blockBuilder.closeEntry(); - } - } - - @Override - public Slice getSlice(Block block, int position) - { - return block.getSlice(position, 0, block.getSliceLength(position)); - } - - public void writeString(BlockBuilder blockBuilder, String value) - { - writeSlice(blockBuilder, Slices.utf8Slice(value)); - } - - @Override - public void writeSlice(BlockBuilder blockBuilder, Slice value) - { - writeSlice(blockBuilder, value, 0, value.length()); - } - - @Override - public void writeSlice(BlockBuilder blockBuilder, Slice value, int offset, int length) - { - blockBuilder.writeBytes(value, offset, length).closeEntry(); - } + public static final com.facebook.presto.spi.type.JsonType JSON = com.facebook.presto.spi.type.JsonType.JSON; } diff --git a/presto-postgresql/pom.xml b/presto-postgresql/pom.xml index f255e491113ab..0631a8c350c6c 100644 --- a/presto-postgresql/pom.xml +++ b/presto-postgresql/pom.xml @@ -47,6 +47,21 @@ javax.inject + + com.fasterxml.jackson.core + jackson-core + + + + com.fasterxml.jackson.core + jackson-databind + + + + io.airlift + json + + com.facebook.presto @@ -91,12 +106,6 @@ test - - io.airlift - json - test - - com.facebook.presto presto-main diff --git a/presto-postgresql/src/main/java/com/facebook/presto/plugin/postgresql/PostgreSqlClient.java b/presto-postgresql/src/main/java/com/facebook/presto/plugin/postgresql/PostgreSqlClient.java index 4fbb8bf63528a..ff6890d658915 100644 --- a/presto-postgresql/src/main/java/com/facebook/presto/plugin/postgresql/PostgreSqlClient.java +++ b/presto-postgresql/src/main/java/com/facebook/presto/plugin/postgresql/PostgreSqlClient.java @@ -18,18 +18,42 @@ import com.facebook.presto.plugin.jdbc.DriverConnectionFactory; import com.facebook.presto.plugin.jdbc.JdbcConnectorId; import com.facebook.presto.plugin.jdbc.JdbcOutputTableHandle; +import com.facebook.presto.plugin.jdbc.JdbcTypeHandle; +import com.facebook.presto.plugin.jdbc.ReadMapping; +import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.spi.PrestoException; import com.facebook.presto.spi.type.Type; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.airlift.json.ObjectMapperProvider; +import io.airlift.slice.DynamicSliceOutput; +import io.airlift.slice.Slice; +import io.airlift.slice.SliceOutput; import org.postgresql.Driver; import javax.inject.Inject; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Types; +import java.util.Optional; +import static com.facebook.presto.plugin.jdbc.ReadMapping.sliceReadMapping; +import static com.facebook.presto.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT; +import static com.facebook.presto.spi.type.JsonType.JSON; import static com.facebook.presto.spi.type.VarbinaryType.VARBINARY; +import static com.fasterxml.jackson.core.JsonFactory.Feature.CANONICALIZE_FIELD_NAMES; +import static com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS; +import static io.airlift.slice.Slices.utf8Slice; +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; public class PostgreSqlClient extends BaseJdbcClient @@ -87,7 +111,58 @@ protected String toSqlType(Type type) if (VARBINARY.equals(type)) { return "bytea"; } + if (JSON.equals(type)) { + return "jsonb"; + } return super.toSqlType(type); } + + @Override + public Optional toPrestoType(ConnectorSession session, JdbcTypeHandle typeHandle) + { + if (typeHandle.getJdbcType() == Types.OTHER) { + switch (typeHandle.getJdbcTypeName()) { + case "jsonb": + case "json": + return Optional.of(jsonReadMapping()); + } + } + + return super.toPrestoType(session, typeHandle); + } + + private static ReadMapping jsonReadMapping() + { + return sliceReadMapping(JSON, (resultSet, columnIndex) -> jsonParse(utf8Slice(resultSet.getString(columnIndex)))); + } + + private static final JsonFactory JSON_FACTORY = new JsonFactory() + .disable(CANONICALIZE_FIELD_NAMES); + + private static final ObjectMapper SORTED_MAPPER = new ObjectMapperProvider().get().configure(ORDER_MAP_ENTRIES_BY_KEYS, true); + + public static Slice jsonParse(Slice slice) + { + try (JsonParser parser = createJsonParser(JSON_FACTORY, slice)) { + byte[] in = slice.getBytes(); + SliceOutput dynamicSliceOutput = new DynamicSliceOutput(in.length); + SORTED_MAPPER.writeValue((OutputStream) dynamicSliceOutput, SORTED_MAPPER.readValue(parser, Object.class)); + // nextToken() returns null if the input is parsed correctly, + // but will throw an exception if there are trailing characters. + parser.nextToken(); + return dynamicSliceOutput.slice(); + } + catch (Exception e) { + throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Cannot convert '%s' to JSON", slice.toStringUtf8())); + } + } + + public static JsonParser createJsonParser(JsonFactory factory, Slice json) + throws IOException + { + // Jackson tries to detect the character encoding automatically when using InputStream + // so we pass an InputStreamReader instead. + return factory.createParser(new InputStreamReader(json.getInput(), UTF_8)); + } } diff --git a/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/PostgreSqlQueryRunner.java b/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/PostgreSqlQueryRunner.java index f9a8425e03004..ad2dfa62abc4a 100644 --- a/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/PostgreSqlQueryRunner.java +++ b/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/PostgreSqlQueryRunner.java @@ -58,7 +58,7 @@ public static QueryRunner createPostgreSqlQueryRunner(TestingPostgreSqlServer se queryRunner.createCatalog("tpch", "tpch"); Map properties = ImmutableMap.builder() - .put("connection-url", server.getJdbcUrl()) + .put("connection-url", server.getJdbcUrl() + "&stringtype=unspecified") .put("allow-drop-table", "true") .build(); diff --git a/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/TestPostgreSqlTypeMapping.java b/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/TestPostgreSqlTypeMapping.java index 5fe0f83743ae9..710111b9e0dc1 100644 --- a/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/TestPostgreSqlTypeMapping.java +++ b/presto-postgresql/src/test/java/com/facebook/presto/plugin/postgresql/TestPostgreSqlTypeMapping.java @@ -35,6 +35,7 @@ import java.util.function.Function; import static com.facebook.presto.plugin.postgresql.PostgreSqlQueryRunner.createPostgreSqlQueryRunner; +import static com.facebook.presto.spi.type.JsonType.JSON; import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY; import static com.facebook.presto.spi.type.VarbinaryType.VARBINARY; import static com.facebook.presto.tests.datatype.DataType.bigintDataType; @@ -267,6 +268,21 @@ public void testTimestamp() // TODO timestamp is not correctly read (see comment in StandardReadMappings.timestampReadMapping), but testing this is hard because of #7122 } + @Test + public void testJson() + { + JdbcSqlExecutor jdbcSqlExecutor = new JdbcSqlExecutor(postgreSqlServer.getJdbcUrl()); + jdbcSqlExecutor.execute("CREATE TABLE tpch.test_json_data_type(key varchar(5), json_column json, jsonb_column jsonb)"); + try { + assertQuery( + "SELECT COLUMN_NAME,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'tpch' AND TABLE_NAME = 'test_json_data_type'", + "VALUES ('key','varchar(5)'),('json_column','json'),('jsonb_column','json')"); // + } + finally { + jdbcSqlExecutor.execute("DROP TABLE tpch.test_json_data_type"); + } + } + private void testUnsupportedDataType(String databaseDataType) { JdbcSqlExecutor jdbcSqlExecutor = new JdbcSqlExecutor(postgreSqlServer.getJdbcUrl()); @@ -290,11 +306,39 @@ private static DataType byteaDataType() Function.identity()); } + public static DataType jsonDataType() + { + return DataType.dataType( + "json", + JSON, + value -> format("JSON'%s'", value), + Function.identity()); + } + + @Test + public void jsonDataTypeTest() + { + DataTypeTest dataTypeTest = DataTypeTest.create() + .addRoundTrip(jsonDataType(), "{}") + .addRoundTrip(jsonDataType(), "{\"a\":1,\"b\":2}") + .addRoundTrip(jsonDataType(), "{\"a\":[1,2,3],\"b\":{\"aa\":11,\"bb\":[{\"a\":1,\"b\":2},{\"a\":0}]}}") + .addRoundTrip(jsonDataType(), "[]"); + + dataTypeTest.execute(getQueryRunner(), prestoCreateAsSelect("presto_test_json")); + dataTypeTest.execute(getQueryRunner(), postgresCreateAsSelect("tpch.postgresql_test_json1")); + dataTypeTest.execute(getQueryRunner(), postgresCreateAndInsert("tpch.postgresql_test_json2")); + } + private DataSetup prestoCreateAsSelect(String tableNamePrefix) { return new CreateAsSelectDataSetup(new PrestoSqlExecutor(getQueryRunner()), tableNamePrefix); } + private DataSetup postgresCreateAsSelect(String tableNamePrefix) + { + return new CreateAsSelectDataSetup(new JdbcSqlExecutor(postgreSqlServer.getJdbcUrl()), tableNamePrefix); + } + private DataSetup postgresCreateAndInsert(String tableNamePrefix) { return new CreateAndInsertDataSetup(new JdbcSqlExecutor(postgreSqlServer.getJdbcUrl()), tableNamePrefix); diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/type/JsonType.java b/presto-spi/src/main/java/com/facebook/presto/spi/type/JsonType.java new file mode 100644 index 0000000000000..86c744a031efc --- /dev/null +++ b/presto-spi/src/main/java/com/facebook/presto/spi/type/JsonType.java @@ -0,0 +1,99 @@ +/* + * 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.spi.type; + +import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.spi.block.Block; +import com.facebook.presto.spi.block.BlockBuilder; +import io.airlift.slice.Slice; +import io.airlift.slice.Slices; + +/** + * The stack representation for JSON objects must have the keys in natural sorted order. + */ +public class JsonType + extends AbstractVariableWidthType +{ + public static final JsonType JSON = new JsonType(); + + public JsonType() + { + super(new TypeSignature(StandardTypes.JSON), Slice.class); + } + + @Override + public boolean isComparable() + { + return true; + } + + @Override + public boolean equalTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition) + { + Slice leftValue = leftBlock.getSlice(leftPosition, 0, leftBlock.getSliceLength(leftPosition)); + Slice rightValue = rightBlock.getSlice(rightPosition, 0, rightBlock.getSliceLength(rightPosition)); + return leftValue.equals(rightValue); + } + + @Override + public long hash(Block block, int position) + { + return block.hash(position, 0, block.getSliceLength(position)); + } + + @Override + public Object getObjectValue(ConnectorSession session, Block block, int position) + { + if (block.isNull(position)) { + return null; + } + + return block.getSlice(position, 0, block.getSliceLength(position)).toStringUtf8(); + } + + @Override + public void appendTo(Block block, int position, BlockBuilder blockBuilder) + { + if (block.isNull(position)) { + blockBuilder.appendNull(); + } + else { + block.writeBytesTo(position, 0, block.getSliceLength(position), blockBuilder); + blockBuilder.closeEntry(); + } + } + + @Override + public Slice getSlice(Block block, int position) + { + return block.getSlice(position, 0, block.getSliceLength(position)); + } + + public void writeString(BlockBuilder blockBuilder, String value) + { + writeSlice(blockBuilder, Slices.utf8Slice(value)); + } + + @Override + public void writeSlice(BlockBuilder blockBuilder, Slice value) + { + writeSlice(blockBuilder, value, 0, value.length()); + } + + @Override + public void writeSlice(BlockBuilder blockBuilder, Slice value, int offset, int length) + { + blockBuilder.writeBytes(value, offset, length).closeEntry(); + } +} diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/TestingPrestoClient.java b/presto-tests/src/main/java/com/facebook/presto/tests/TestingPrestoClient.java index f9150f17b4838..c6674bad61a84 100644 --- a/presto-tests/src/main/java/com/facebook/presto/tests/TestingPrestoClient.java +++ b/presto-tests/src/main/java/com/facebook/presto/tests/TestingPrestoClient.java @@ -59,6 +59,7 @@ import static com.facebook.presto.spi.type.DateType.DATE; import static com.facebook.presto.spi.type.DoubleType.DOUBLE; import static com.facebook.presto.spi.type.IntegerType.INTEGER; +import static com.facebook.presto.spi.type.JsonType.JSON; import static com.facebook.presto.spi.type.RealType.REAL; import static com.facebook.presto.spi.type.SmallintType.SMALLINT; import static com.facebook.presto.spi.type.TimeType.TIME; @@ -244,6 +245,9 @@ else if (type instanceof DecimalType) { else if (type.getTypeSignature().getBase().equals("ObjectId")) { return value; } + if (JSON.equals(type)) { + return value; + } else { throw new AssertionError("unhandled type: " + type); }