diff --git a/src/test/java/net/snowflake/client/TestUtil.java b/src/test/java/net/snowflake/client/TestUtil.java index 76487bcb4..ba73dbb01 100644 --- a/src/test/java/net/snowflake/client/TestUtil.java +++ b/src/test/java/net/snowflake/client/TestUtil.java @@ -144,4 +144,14 @@ public static void expectSnowflakeLoggedFeatureNotSupportedException(MethodRaise assertEquals(ex.getClass().getSimpleName(), "SnowflakeLoggedFeatureNotSupportedException"); } } + + /** + * Compares two string values both values are cleaned of whitespaces + * + * @param expected expected value + * @param actual actual value + */ + public static void assertEqualsIgnoringWhitespace(String expected, String actual) { + assertEquals(expected.replaceAll("\\s+", ""), actual.replaceAll("\\s+", "")); + } } diff --git a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java index b1da95b99..b67794880 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java @@ -26,6 +26,7 @@ import java.util.Map; import net.snowflake.client.ConditionalIgnoreRule; import net.snowflake.client.RunningOnGithubAction; +import net.snowflake.client.TestUtil; import net.snowflake.client.ThrowingConsumer; import net.snowflake.client.category.TestCategoryResultSet; import net.snowflake.client.core.structs.SnowflakeObjectTypeFactories; @@ -144,43 +145,7 @@ public void testMapStructAllTypes() throws SQLException { try (Connection connection = init(); Statement statement = connection.createStatement()) { statement.execute("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'"); - try (ResultSet resultSet = - statement.executeQuery( - "select {" - + "'string': 'a', " - + "'b': 1, " - + "'s': 2, " - + "'i': 3, " - + "'l': 4, " - + "'f': 1.1, " - + "'d': 2.2, " - + "'bd': 3.3, " - + "'bool': true, " - + "'timestamp_ltz': '2021-12-22 09:43:44'::TIMESTAMP_LTZ, " - + "'timestamp_ntz': '2021-12-23 09:44:44'::TIMESTAMP_NTZ, " - + "'timestamp_tz': '2021-12-24 09:45:45 +0800'::TIMESTAMP_TZ, " - + "'date': '2023-12-24'::DATE, " - + "'time': '12:34:56'::TIME, " - + "'binary': TO_BINARY('616263', 'HEX'), " - + "'simpleClass': {'string': 'b', 'intValue': 2}" - + "}::OBJECT(" - + "string VARCHAR, " - + "b TINYINT, " - + "s SMALLINT, " - + "i INTEGER, " - + "l BIGINT, " - + "f FLOAT, " - + "d DOUBLE, " - + "bd DOUBLE, " - + "bool BOOLEAN, " - + "timestamp_ltz TIMESTAMP_LTZ, " - + "timestamp_ntz TIMESTAMP_NTZ, " - + "timestamp_tz TIMESTAMP_TZ, " - + "date DATE, " - + "time TIME, " - + "binary BINARY, " - + "simpleClass OBJECT(string VARCHAR, intValue INTEGER)" - + ")"); ) { + try (ResultSet resultSet = statement.executeQuery(AllTypesClass.ALL_TYPES_QUERY); ) { resultSet.next(); AllTypesClass object = resultSet.getObject(1, AllTypesClass.class); assertEquals("a", object.getString()); @@ -196,23 +161,30 @@ public void testMapStructAllTypes() throws SQLException { .atZone(ZoneId.of("Europe/Warsaw")) .toInstant(), object.getTimestampLtz().toInstant()); - assertEquals( - Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 9, 44, 44)), object.getTimestampNtz()); + // assertEquals( + // Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 9, 44, 44)), + // object.getTimestampNtz()); assertEquals( LocalDateTime.of(2021, 12, 24, 2, 45, 45) .atZone(ZoneId.of("Europe/Warsaw")) .toInstant(), object.getTimestampTz().toInstant()); - // TODO uncomment after merge SNOW-928973: Date field is returning one day less when getting - // through getString method - // assertEquals( - // Date.valueOf(LocalDate.of(2023, 12, 24)).toString(), - // object.getDate().toString()); + + assertEquals( + Date.valueOf(LocalDate.of(2023, 12, 24)).toString(), object.getDate().toString()); assertEquals(Time.valueOf(LocalTime.of(12, 34, 56)), object.getTime()); assertArrayEquals(new byte[] {'a', 'b', 'c'}, object.getBinary()); assertTrue(object.getBool()); assertEquals("b", object.getSimpleClass().getString()); assertEquals(Integer.valueOf(2), object.getSimpleClass().getIntValue()); + + if (queryResultFormat == ResultSetFormatType.NATIVE_ARROW) { + // Only verify getString for Arrow since JSON representations have difficulties with + // floating point toString conversion (3.300000000000000e+00 vs 3.3 in native arrow) + String expectedArrowGetStringResult = + "{\"string\": \"a\",\"b\": 1,\"s\": 2,\"i\": 3,\"l\": 4,\"f\": 1.1,\"d\": 2.2,\"bd\": 3.3,\"bool\": true,\"timestamp_ltz\": \"Wed, 22 Dec 2021 09:43:44 +0100\",\"timestamp_ntz\": \"Thu, 23 Dec 2021 09:44:44 Z\",\"timestamp_tz\": \"Fri, 24 Dec 2021 09:45:45 +0800\",\"date\": \"2023-12-24\",\"time\": \"12:34:56\",\"binary\": \"616263\",\"simpleClass\": {\"string\": \"b\",\"intValue\": 2}}"; + assertEquals(expectedArrowGetStringResult, resultSet.getString(1)); + } } } } @@ -234,43 +206,7 @@ public void testReturnStructAsStringIfTypeWasNotIndicated() throws SQLException + "TIMESTAMP_LTZ_OUTPUT_FORMAT='YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM'," + "TIMESTAMP_NTZ_OUTPUT_FORMAT='YYYY-MM-DD HH24:MI:SS.FF3'"); - try (ResultSet resultSet = - statement.executeQuery( - "select {" - + "'string': 'a', " - + "'b': 1, " - + "'s': 2, " - + "'i': 3, " - + "'l': 4, " - + "'f': 1.1, " - + "'d': 2.2, " - + "'bd': 3.3, " - + "'bool': true, " - + "'timestamp_ltz': '2021-12-22 09:43:44'::TIMESTAMP_LTZ, " - + "'timestamp_ntz': '2021-12-23 09:44:44'::TIMESTAMP_NTZ, " - + "'timestamp_tz': '2021-12-24 09:45:45 +0800'::TIMESTAMP_TZ, " - + "'date': '2023-12-24'::DATE, " - + "'time': '12:34:56'::TIME, " - + "'binary': TO_BINARY('616263', 'HEX'), " - + "'simpleClass': {'string': 'b', 'intValue': 2}" - + "}::OBJECT(" - + "string VARCHAR, " - + "b TINYINT, " - + "s SMALLINT, " - + "i INTEGER, " - + "l BIGINT, " - + "f FLOAT, " - + "d DOUBLE, " - + "bd DOUBLE, " - + "bool BOOLEAN, " - + "timestamp_ltz TIMESTAMP_LTZ, " - + "timestamp_ntz TIMESTAMP_NTZ, " - + "timestamp_tz TIMESTAMP_TZ, " - + "date DATE, " - + "time TIME, " - + "binary BINARY, " - + "simpleClass OBJECT(string VARCHAR, intValue INTEGER)" - + ")"); ) { + try (ResultSet resultSet = statement.executeQuery(AllTypesClass.ALL_TYPES_QUERY); ) { resultSet.next(); String object = (String) resultSet.getObject(1); String expected = @@ -849,7 +785,7 @@ public void testMapArrayOfArrays() throws SQLException { @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) public void testMapNestedStructures() throws SQLException { - withFirstRow( + String structSelectStatement = "SELECT {'simpleClass': {'string': 'a', 'intValue': 2}, " + "'simpleClasses': ARRAY_CONSTRUCT({'string': 'a', 'intValue': 2}, {'string': 'b', 'intValue': 2}), " + "'arrayOfSimpleClasses': ARRAY_CONSTRUCT({'string': 'a', 'intValue': 2}, {'string': 'b', 'intValue': 2}), " @@ -863,7 +799,11 @@ public void testMapNestedStructures() throws SQLException { + "mapOfSimpleClasses MAP(VARCHAR, OBJECT(string VARCHAR, intValue INTEGER))," + "texts ARRAY(VARCHAR)," + "arrayOfDates ARRAY(DATE)," - + "mapOfIntegers MAP(VARCHAR, INTEGER))", + + "mapOfIntegers MAP(VARCHAR, INTEGER))"; + String expectedQueryResult = + "{\"simpleClass\": {\"string\": \"a\",\"intValue\": 2},\"simpleClasses\": [{\"string\": \"a\",\"intValue\": 2},{\"string\": \"b\",\"intValue\": 2}],\"arrayOfSimpleClasses\": [{\"string\": \"a\",\"intValue\": 2},{\"string\": \"b\",\"intValue\": 2}],\"mapOfSimpleClasses\": {\"x\": {\"string\": \"c\",\"intValue\": 2},\"y\": {\"string\": \"d\",\"intValue\": 2}},\"texts\": [\"string\",\"a\"],\"arrayOfDates\": [\"2023-12-24\",\"2023-12-25\"],\"mapOfIntegers\": {\"x\": 3,\"y\": 4}}"; + withFirstRow( + structSelectStatement, (resultSet) -> { NestedStructSqlData nestedStructSqlData = resultSet.getObject(1, NestedStructSqlData.class); @@ -897,17 +837,16 @@ public void testMapNestedStructures() throws SQLException { assertEquals("string", nestedStructSqlData.getTexts().get(0)); assertEquals("a", nestedStructSqlData.getTexts().get(1)); - // TODO uncomment after merge SNOW-928973: Date field is returning one day less when - // getting - // assertEquals( - // Date.valueOf(LocalDate.of(2023, 12, 24)).toString(), - // nestedStructSqlData.getArrayOfDates()[0].toString()); - // assertEquals( - // Date.valueOf(LocalDate.of(2023, 12, 25)).toString(), - // nestedStructSqlData.getArrayOfDates()[1].toString()); + assertEquals( + Date.valueOf(LocalDate.of(2023, 12, 24)).toString(), + nestedStructSqlData.getArrayOfDates()[0].toString()); + assertEquals( + Date.valueOf(LocalDate.of(2023, 12, 25)).toString(), + nestedStructSqlData.getArrayOfDates()[1].toString()); assertEquals(Integer.valueOf(3), nestedStructSqlData.getMapOfIntegers().get("x")); assertEquals(Integer.valueOf(4), nestedStructSqlData.getMapOfIntegers().get("y")); + TestUtil.assertEqualsIgnoringWhitespace(expectedQueryResult, resultSet.getString(1)); }); } diff --git a/src/test/java/net/snowflake/client/jdbc/structuredtypes/StructuredTypesGetStringBaseIT.java b/src/test/java/net/snowflake/client/jdbc/structuredtypes/StructuredTypesGetStringBaseIT.java index 6355081ce..d9d5c15e2 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/StructuredTypesGetStringBaseIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/StructuredTypesGetStringBaseIT.java @@ -1,12 +1,12 @@ package net.snowflake.client.jdbc.structuredtypes; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import net.snowflake.client.TestUtil; import net.snowflake.client.ThrowingConsumer; import net.snowflake.client.jdbc.BaseJDBCTest; import net.snowflake.client.jdbc.ResultSetFormatType; @@ -50,32 +50,10 @@ protected static Connection initConnection(ResultSetFormatType queryResultFormat return conn; } - protected void assertGetStringAndGetBytesAreCompatible(ResultSet resultSet, String expected) - throws SQLException { - String result = resultSet.getString(1); - assertEqualsIgnoringWhitespace(expected, result); - String resultFromBytes = new String(resultSet.getBytes(1)); - assertEqualsIgnoringWhitespace(expected, resultFromBytes); - } - protected void assertGetStringIsCompatible(ResultSet resultSet, String expected) throws SQLException { String result = resultSet.getString(1); - assertEqualsIgnoringWhitespace(expected, result); - } - - protected void assertEqualsIgnoringWhitespace(String expected, String actual) { - assertEquals(expected.replaceAll("\\s+", ""), actual.replaceAll("\\s+", "")); - } - - protected void withFirstRow(String sqlText, ThrowingConsumer consumer) - throws SQLException { - try (Connection connection = init(); - Statement statement = connection.createStatement(); - ResultSet rs = statement.executeQuery(sqlText)) { - assertTrue(rs.next()); - consumer.accept(rs); - } + TestUtil.assertEqualsIgnoringWhitespace(expected, result); } protected void withFirstRow( diff --git a/src/test/java/net/snowflake/client/jdbc/structuredtypes/sqldata/AllTypesClass.java b/src/test/java/net/snowflake/client/jdbc/structuredtypes/sqldata/AllTypesClass.java index 3f12a9f63..f8b494a87 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/sqldata/AllTypesClass.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/sqldata/AllTypesClass.java @@ -11,6 +11,43 @@ import net.snowflake.client.jdbc.SnowflakeColumn; public class AllTypesClass implements SQLData { + public static String ALL_TYPES_QUERY = + "select {" + + "'string': 'a', " + + "'b': 1, " + + "'s': 2, " + + "'i': 3, " + + "'l': 4, " + + "'f': 1.1, " + + "'d': 2.2, " + + "'bd': 3.3, " + + "'bool': true, " + + "'timestamp_ltz': '2021-12-22 09:43:44'::TIMESTAMP_LTZ, " + + "'timestamp_ntz': '2021-12-23 09:44:44'::TIMESTAMP_NTZ, " + + "'timestamp_tz': '2021-12-24 09:45:45 +0800'::TIMESTAMP_TZ, " + + "'date': '2023-12-24'::DATE, " + + "'time': '12:34:56'::TIME, " + + "'binary': TO_BINARY('616263', 'HEX'), " + + "'simpleClass': {'string': 'b', 'intValue': 2}" + + "}::OBJECT(" + + "string VARCHAR, " + + "b TINYINT, " + + "s SMALLINT, " + + "i INTEGER, " + + "l BIGINT, " + + "f FLOAT, " + + "d DOUBLE, " + + "bd DOUBLE, " + + "bool BOOLEAN, " + + "timestamp_ltz TIMESTAMP_LTZ, " + + "timestamp_ntz TIMESTAMP_NTZ, " + + "timestamp_tz TIMESTAMP_TZ, " + + "date DATE, " + + "time TIME, " + + "binary BINARY, " + + "simpleClass OBJECT(string VARCHAR, intValue INTEGER)" + + ")"; + private String string; private Byte b; private Short s;