diff --git a/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java b/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java index fe88ab339242..e0784159039c 100644 --- a/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java +++ b/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java @@ -131,6 +131,7 @@ import static io.trino.spi.type.Timestamps.round; import static io.trino.spi.type.TinyintType.TINYINT; import static io.trino.spi.type.VarbinaryType.VARBINARY; +import static io.trino.spi.type.VarcharType.UNBOUNDED_LENGTH; import static java.lang.Float.floatToRawIntBits; import static java.lang.Math.max; import static java.lang.Math.min; @@ -310,7 +311,15 @@ public Optional toColumnMapping(ConnectorSession session, Connect return Optional.of(defaultCharColumnMapping(typeHandle.requiredColumnSize(), false)); case Types.VARCHAR: case Types.LONGVARCHAR: - return Optional.of(checkNullUsingBytes(defaultVarcharColumnMapping(typeHandle.requiredColumnSize(), false))); + int columnSize = switch (jdbcTypeName) { + case "TINYTEXT" -> 255; + case "TEXT" -> 65535; + case "MEDIUMTEXT" -> 16777215; + case "LONGTEXT" -> UNBOUNDED_LENGTH; + case "VARCHAR" -> typeHandle.requiredColumnSize(); + default -> throw new IllegalStateException("Unexpected type: " + jdbcTypeName); + }; + return Optional.of(checkNullUsingBytes(defaultVarcharColumnMapping(columnSize, false))); case Types.DECIMAL: int precision = typeHandle.requiredColumnSize(); int decimalDigits = typeHandle.requiredDecimalDigits(); diff --git a/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreLatestTypeMapping.java b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreLatestTypeMapping.java new file mode 100644 index 000000000000..db43725c72ea --- /dev/null +++ b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreLatestTypeMapping.java @@ -0,0 +1,104 @@ +/* + * 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 io.trino.plugin.singlestore; + +import io.trino.testing.QueryRunner; +import io.trino.testing.datatype.SqlDataTypeTest; +import io.trino.testing.sql.TestTable; +import org.junit.jupiter.api.Test; + +import static io.trino.plugin.singlestore.TestingSingleStoreServer.LATEST_TESTED_TAG; +import static io.trino.spi.type.VarcharType.createVarcharType; +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +final class TestSingleStoreLatestTypeMapping + extends BaseSingleStoreTypeMapping +{ + @Override + protected QueryRunner createQueryRunner() + throws Exception + { + singleStoreServer = closeAfterClass(new TestingSingleStoreServer(LATEST_TESTED_TAG)); + return SingleStoreQueryRunner.builder(singleStoreServer).build(); + } + + @Test + void testUnsupportedTinyint() + { + try (TestTable table = new TestTable(getQueryRunner()::execute, "tpch.test_unsupported_tinyint", "(value tinyint)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (-129)", table.getName()))) + .hasMessageContaining("Out of range value"); + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (128)", table.getName()))) + .hasMessageContaining("Out of range value"); + } + } + + @Test + void testUnsupportedSmallint() + { + try (TestTable table = new TestTable(getQueryRunner()::execute, "tpch.test_unsupported_smallint", "(value smallint)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (-32769)", table.getName()))) + .hasMessageContaining("Out of range value"); + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (32768)", table.getName()))) + .hasMessageContaining("Out of range value"); + } + } + + @Test + void testUnsupportedInteger() + { + try (TestTable table = new TestTable(getQueryRunner()::execute, "tpch.test_unsupported_integer", "(value integer)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (-2147483649)", table.getName()))) + .hasMessageContaining("Out of range value"); + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (2147483648)", table.getName()))) + .hasMessageContaining("Out of range value"); + } + } + + @Test + void testUnsupportedBigint() + { + try (TestTable table = new TestTable(getQueryRunner()::execute, "tpch.test_unsupported_bigint", "(value bigint)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (-9223372036854775809)", table.getName()))) + .hasMessageContaining("Out of range value"); + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (9223372036854775808)", table.getName()))) + .hasMessageContaining("Out of range value"); + } + } + + @Test + void testOlderDate() + { + try (TestTable table = new TestTable(singleStoreServer::execute, "tpch.test_unsupported_date", "(value date)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (CAST('0000-01-01' AS date))", table.getName()))) + .hasMessageContaining("Invalid DATE/TIME in type conversion"); + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES (CAST('0001-01-01' AS date))", table.getName()))) + .hasMessageContaining("Invalid DATE/TIME in type conversion"); + } + } + + @Test + void testSingleStoreCreatedParameterizedVarcharUnicodeEmoji() + { + try (TestTable table = new TestTable(singleStoreServer::execute, "tpch.test_unsupported_bigint", "(value varchar(1) CHARACTER SET utf8)")) { + assertThatThrownBy(() -> singleStoreServer.execute(format("INSERT INTO %s VALUES ('😂')", table.getName()))) + .hasMessageContaining("Data invalid"); + } + + SqlDataTypeTest.create() + .addRoundTrip("varchar(1) CHARACTER SET utf8mb4", "'😂'", createVarcharType(1), "CAST('😂' AS varchar(1))") + .execute(getQueryRunner(), singleStoreCreateAndInsert("tpch.singlestore_test_parameterized_varchar_unicode")); + } +} diff --git a/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestingSingleStoreServer.java b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestingSingleStoreServer.java index 13fda3c8e259..c5f8f9910e81 100644 --- a/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestingSingleStoreServer.java +++ b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestingSingleStoreServer.java @@ -31,7 +31,7 @@ public class TestingSingleStoreServer private static final String MEM_SQL_LICENSE = requiredNonEmptySystemProperty("memsql.license"); public static final String DEFAULT_TAG = "memsql/cluster-in-a-box:centos-7.1.13-11ddea2a3a-3.0.0-1.9.0"; - public static final String LATEST_TESTED_TAG = "memsql/cluster-in-a-box:centos-7.3.4-d596a2867a-3.2.4-1.10.1"; + public static final String LATEST_TESTED_TAG = "memsql/cluster-in-a-box:alma-8.0.4-c190bb9c08-4.0.10-1.14.4"; public static final Integer SINGLESTORE_PORT = 3306; @@ -44,13 +44,14 @@ public TestingSingleStoreServer(String dockerImageName) { super(DockerImageName.parse(dockerImageName)); addEnv("ROOT_PASSWORD", "memsql_root_password"); + String option = dockerImageName.equals(LATEST_TESTED_TAG) ? "bash" : ""; withCommand("sh", "-xeuc", - "/startup && " + + option + " /startup && " + // Lower the size of pre-allocated log files to 1MB (minimum allowed) to reduce disk footprint "memsql-admin update-config --yes --all --set-global --key \"log_file_size_partitions\" --value \"1048576\" && " + "memsql-admin update-config --yes --all --set-global --key \"log_file_size_ref_dbs\" --value \"1048576\" && " + // re-execute startup to actually start the nodes (first run performs setup but doesn't start the nodes) - "exec /startup"); + "exec " + option + " /startup"); start(); }