Skip to content

Commit

Permalink
Improve SQL Server type mapping tests
Browse files Browse the repository at this point in the history
This commit includes:

- Add separate tests for SQL Server bit/tinyint/smallint/integer/bigint
- Add min/max/min-1/max+1 test cases
- Cover more tests using trinoCreateAndInsert in BaseSqlServerTypeMapping
  • Loading branch information
tangjiangling authored and ebyhr committed Mar 1, 2022
1 parent 7a03f95 commit 03f17e7
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 22 deletions.
6 changes: 6 additions & 0 deletions plugin/trino-sqlserver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mssqlserver</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.trino.testing.sql.SqlExecutor;
import io.trino.testing.sql.TestTable;
import io.trino.testing.sql.TrinoSqlExecutor;
import org.intellij.lang.annotations.Language;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -55,6 +56,7 @@
import static io.trino.testing.sql.TestTable.randomTableSuffix;
import static java.lang.String.format;
import static java.time.ZoneOffset.UTC;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public abstract class BaseSqlServerTypeMapping
extends AbstractTestQueryFramework
Expand Down Expand Up @@ -89,21 +91,114 @@ public void setUp()
}

@Test
public void testBasicTypes()
public void testTrinoBoolean()
{
SqlDataTypeTest.create()
.addRoundTrip("boolean", "null", BOOLEAN, "CAST(NULL AS BOOLEAN)")
.addRoundTrip("boolean", "true", BOOLEAN)
.addRoundTrip("boolean", "false", BOOLEAN)
.addRoundTrip("bigint", "null", BIGINT, "CAST(NULL AS BIGINT)")
.addRoundTrip("bigint", "123456789012", BIGINT)
.addRoundTrip("integer", "null", INTEGER, "CAST(NULL AS INTEGER)")
.addRoundTrip("integer", "123456789", INTEGER)
.addRoundTrip("smallint", "null", SMALLINT, "CAST(NULL AS SMALLINT)")
.addRoundTrip("smallint", "32456", SMALLINT, "SMALLINT '32456'")
.addRoundTrip("tinyint", "null", TINYINT, "CAST(NULL AS TINYINT)")
.execute(getQueryRunner(), trinoCreateAsSelect("test_boolean"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_boolean"));
}

@Test
public void testSqlServerBit()
{
SqlDataTypeTest.create()
.addRoundTrip("bit", "null", BOOLEAN, "CAST(NULL AS BOOLEAN)")
.addRoundTrip("bit", "1", BOOLEAN, "true")
.addRoundTrip("bit", "0", BOOLEAN, "false")
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_bit"));
}

@Test
public void testTinyint()
{
// TODO: Add min/max/min-1/max+1 tests (https://github.com/trinodb/trino/issues/11209)
SqlDataTypeTest.create()
.addRoundTrip("tinyint", "NULL", TINYINT, "CAST(NULL AS TINYINT)")
.addRoundTrip("tinyint", "5", TINYINT, "TINYINT '5'")
.execute(getQueryRunner(), trinoCreateAsSelect("test_basic_types"));
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_tinyint"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_tinyint"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_tinyint"));
}

@Test
public void testSmallint()
{
SqlDataTypeTest.create()
.addRoundTrip("smallint", "NULL", SMALLINT, "CAST(NULL AS SMALLINT)")
.addRoundTrip("smallint", "-32768", SMALLINT, "SMALLINT '-32768'") // min value in SQL Server and Trino
.addRoundTrip("smallint", "32456", SMALLINT, "SMALLINT '32456'")
.addRoundTrip("smallint", "32767", SMALLINT, "SMALLINT '32767'") // max value in SQL Server and Trino
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_smallint"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_smallint"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_smallint"));
}

@Test
public void testUnsupportedSmallint()
{
try (TestTable table = new TestTable(onRemoteDatabase(), "test_unsupported_smallint", "(data smallint)")) {
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (-32769)", table.getName()), // min - 1
"Arithmetic overflow error for data type smallint, value = -32769.");
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (32768)", table.getName()), // max + 1
"Arithmetic overflow error for data type smallint, value = 32768.");
}
}

@Test
public void testInteger()
{
SqlDataTypeTest.create()
.addRoundTrip("integer", "NULL", INTEGER, "CAST(NULL AS INTEGER)")
.addRoundTrip("integer", "-2147483648", INTEGER, "-2147483648") // min value in SQL Server and Trino
.addRoundTrip("integer", "1234567890", INTEGER, "1234567890")
.addRoundTrip("integer", "2147483647", INTEGER, "2147483647") // max value in SQL Server and Trino
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_int"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_int"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_int"));
}

@Test
public void testUnsupportedInteger()
{
try (TestTable table = new TestTable(onRemoteDatabase(), "test_unsupported_integer", "(data integer)")) {
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (-2147483649)", table.getName()), // min - 1
"Arithmetic overflow error converting expression to data type int.");
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (2147483648)", table.getName()), // max + 1
"Arithmetic overflow error converting expression to data type int.");
}
}

@Test
public void testBigint()
{
SqlDataTypeTest.create()
.addRoundTrip("bigint", "NULL", BIGINT, "CAST(NULL AS BIGINT)")
.addRoundTrip("bigint", "-9223372036854775808", BIGINT, "-9223372036854775808") // min value in SQL Server and Trino
.addRoundTrip("bigint", "123456789012", BIGINT, "123456789012")
.addRoundTrip("bigint", "9223372036854775807", BIGINT, "9223372036854775807") // max value in SQL Server and Trino
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_bigint"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_bigint"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_bigint"));
}

@Test
public void testUnsupportedBigint()
{
try (TestTable table = new TestTable(onRemoteDatabase(), "test_unsupported_bigint", "(data bigint)")) {
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (-9223372036854775809)", table.getName()), // min - 1
"Arithmetic overflow error converting expression to data type bigint.");
assertSqlServerQueryFails(
format("INSERT INTO %s VALUES (9223372036854775808)", table.getName()), // max + 1
"Arithmetic overflow error converting expression to data type bigint.");
}
}

@Test
Expand All @@ -120,7 +215,8 @@ public void testReal()
.addRoundTrip("real", "NULL", REAL, "CAST(NULL AS real)")
.addRoundTrip("real", "3.14", REAL, "REAL '3.14'")
.addRoundTrip("real", "3.1415927", REAL, "REAL '3.1415927'")
.execute(getQueryRunner(), trinoCreateAsSelect("test_real"));
.execute(getQueryRunner(), trinoCreateAsSelect("test_real"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_real"));
}

@Test
Expand Down Expand Up @@ -178,7 +274,8 @@ public void testDecimal()
.addRoundTrip("decimal(30, 5)", "3141592653589793238462643.38327", createDecimalType(30, 5), "CAST('3141592653589793238462643.38327' AS decimal(30, 5))")
.addRoundTrip("decimal(30, 5)", "-3141592653589793238462643.38327", createDecimalType(30, 5), "CAST('-3141592653589793238462643.38327' AS decimal(30, 5))")
.execute(getQueryRunner(), sqlServerCreateAndInsert("test_decimal"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_decimal"));
.execute(getQueryRunner(), trinoCreateAsSelect("test_decimal"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_decimal"));
}

@Test
Expand All @@ -199,7 +296,7 @@ public void testChar()
.addRoundTrip("char(32)", "CAST('攻殻機動隊' AS char(32))", createCharType(32), "CAST('攻殻機動隊' AS char(32))")
.addRoundTrip("char(20)", "CAST('😂' AS char(20))", createCharType(20), "CAST('😂' AS char(20))")
.addRoundTrip("char(77)", "CAST('Ну, погоди!' AS char(77))", createCharType(77), "CAST('Ну, погоди!' AS char(77))")
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_char"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_char"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_char"));
}

Expand All @@ -219,7 +316,7 @@ public void testTrinoLongChar()
// testing mapping char > 4000 -> varchar(max)
SqlDataTypeTest.create()
.addRoundTrip("char(4001)", "'text_c'", createUnboundedVarcharType(), "VARCHAR 'text_c'")
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_long_char"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_long_char"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_long_char"));
}

Expand All @@ -239,7 +336,7 @@ public void testVarchar()
.addRoundTrip("varchar(32)", "CAST('攻殻機動隊' AS varchar(32))", createVarcharType(32), "CAST('攻殻機動隊' AS varchar(32))")
.addRoundTrip("varchar(20)", "CAST('😂' AS varchar(20))", createVarcharType(20), "CAST('😂' AS varchar(20))")
.addRoundTrip("varchar(77)", "CAST('Ну, погоди!' AS varchar(77))", createVarcharType(77), "CAST('Ну, погоди!' AS varchar(77))")
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_varchar"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_varchar"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_varchar"));
}

Expand All @@ -262,7 +359,7 @@ public void testTrinoLongVarchar()
// testing mapping varchar > 4000 -> varchar(max)
SqlDataTypeTest.create()
.addRoundTrip("varchar(4001)", "'text_c'", createUnboundedVarcharType(), "VARCHAR 'text_c'")
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_long_varchar"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_long_varchar"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_long_varchar"));
}

Expand All @@ -288,7 +385,7 @@ public void testTrinoUnboundedVarchar()
.addRoundTrip("varchar", "VARCHAR '😂'", createUnboundedVarcharType(), "VARCHAR '😂'")
.addRoundTrip("varchar", "VARCHAR 'Ну, погоди!'", createUnboundedVarcharType(), "VARCHAR 'Ну, погоди!'")
.addRoundTrip("varchar", "'text_f'", createUnboundedVarcharType(), "VARCHAR 'text_f'")
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_unbounded_varchar"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_unbounded_varchar"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_unbounded_varchar"));
}

Expand All @@ -303,7 +400,8 @@ public void testVarbinary()
.addRoundTrip("varbinary", "X'4261672066756C6C206F6620F09F92B0'", VARBINARY, "to_utf8('Bag full of 💰')")
.addRoundTrip("varbinary", "X'0001020304050607080DF9367AA7000000'", VARBINARY, "X'0001020304050607080DF9367AA7000000'") // non-text
.addRoundTrip("varbinary", "X'000000000000'", VARBINARY, "X'000000000000'")
.execute(getQueryRunner(), trinoCreateAsSelect("test_varbinary"));
.execute(getQueryRunner(), trinoCreateAsSelect("test_varbinary"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_varbinary"));

// Binary literals must be prefixed with 0x
// https://docs.microsoft.com/en-us/sql/analytics-platform-system/load-with-insert?view=aps-pdw-2016-au7#InsertingLiteralsBinary
Expand Down Expand Up @@ -447,8 +545,8 @@ public void testTime()
.addRoundTrip("TIME '23:59:59.999999'", "TIME '23:59:59.999999'")
.addRoundTrip("TIME '23:59:59.9999999'", "TIME '23:59:59.9999999'")

.execute(getQueryRunner(), trinoCreateAsSelect(getSession(), "test_time"))
.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_time"));
.execute(getQueryRunner(), trinoCreateAsSelect("test_time"))
.execute(getQueryRunner(), trinoCreateAndInsert("test_time"));

SqlDataTypeTest.create()
// round down
Expand Down Expand Up @@ -479,8 +577,8 @@ public void testTime()
// round down
.addRoundTrip("TIME '23:59:59.999999949999'", "TIME '23:59:59.9999999'")

.execute(getQueryRunner(), trinoCreateAndInsert(getSession(), "test_time"))
.execute(getQueryRunner(), trinoCreateAsSelect(getSession(), "test_time"));
.execute(getQueryRunner(), trinoCreateAndInsert("test_time"))
.execute(getQueryRunner(), trinoCreateAsSelect("test_time"));
}

@Test(dataProvider = "sessionZonesDataProvider")
Expand Down Expand Up @@ -583,7 +681,7 @@ public void testTimestamp(ZoneId sessionZone)
.build();

tests.execute(getQueryRunner(), session, trinoCreateAsSelect(session, "test_timestamp"));
tests.execute(getQueryRunner(), session, trinoCreateAsSelect(getSession(), "test_timestamp"));
tests.execute(getQueryRunner(), session, trinoCreateAsSelect("test_timestamp"));
tests.execute(getQueryRunner(), session, trinoCreateAndInsert(session, "test_timestamp"));
}

Expand Down Expand Up @@ -733,6 +831,11 @@ protected DataSetup trinoCreateAsSelect(Session session, String tableNamePrefix)
return new CreateAsSelectDataSetup(new TrinoSqlExecutor(getQueryRunner(), session), tableNamePrefix);
}

protected DataSetup trinoCreateAndInsert(String tableNamePrefix)
{
return new CreateAndInsertDataSetup(new TrinoSqlExecutor(getQueryRunner(), getSession()), tableNamePrefix);
}

protected DataSetup trinoCreateAndInsert(Session session, String tableNamePrefix)
{
return new CreateAndInsertDataSetup(new TrinoSqlExecutor(getQueryRunner(), session), tableNamePrefix);
Expand All @@ -758,6 +861,13 @@ private static void checkIsGap(ZoneId zone, LocalDateTime dateTime)
verify(isGap(zone, dateTime), "Expected %s to be a gap in %s", dateTime, zone);
}

private void assertSqlServerQueryFails(@Language("SQL") String sql, String expectedMessage)
{
assertThatThrownBy(() -> onRemoteDatabase().execute(sql))
.getCause()
.hasMessageContaining(expectedMessage);
}

protected SqlExecutor onRemoteDatabase()
{
return sqlServer::execute;
Expand Down

0 comments on commit 03f17e7

Please sign in to comment.