From 1b01f3b146ff0e1a8d41b1c6ee911ca1a8bfdda6 Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Fri, 17 Nov 2023 05:30:04 +0100 Subject: [PATCH] StructuredType move tests to *LatestIT --- .../client/jdbc/SnowflakeBaseResultSet.java | 21 ++++ .../jdbc/SnowflakeResultSetMetaDataV1.java | 4 +- .../snowflake/client/jdbc/ResultSetIT.java | 100 ---------------- .../client/jdbc/ResultSetLatestIT.java | 107 ++++++++++++++++++ 4 files changed, 131 insertions(+), 101 deletions(-) diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java index 106dd6f1d..315111580 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java @@ -12,6 +12,7 @@ import java.sql.*; import java.sql.Date; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; import java.util.stream.Collectors; import com.fasterxml.jackson.core.type.TypeReference; @@ -1357,6 +1358,26 @@ public List getList(int columnIndex, Class type) throws SQLException { }).collect(Collectors.toList()); } + public T[] getArray(int columnIndex, Class type) throws SQLException { + Optional> typeFactory = SnowflakeObjectTypeFactories.get(type); + List sqlInputs = (List) getObject(columnIndex); + T[] arr = (T[]) java.lang.reflect.Array.newInstance(type, sqlInputs.size()); + AtomicInteger counter = new AtomicInteger(0); + sqlInputs.stream() + .forEach(i -> { + SQLData instance = typeFactory + .map(Supplier::get) + .orElseGet(() -> createUsingReflection((Class) type)); + try { + instance.readSQL(i, null); + } catch (SQLException e) { + throw new RuntimeException(e); + } + arr[counter.getAndIncrement()] = (T) instance; + }); + return arr; + } + public Map getMap(int columnIndex, Class type) throws SQLException { Optional> typeFactory = SnowflakeObjectTypeFactories.get(type); // TODO: structuredType how to get raw json object not as SqlInput diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java index 4ac3a1a14..6796c07a8 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java @@ -106,11 +106,13 @@ public boolean isCaseSensitive(int column) throws SQLException { int colType = getColumnType(column); switch (colType) { - // TODO structuredType fill for Array and Map + // Note: SF types ARRAY, OBJECT, GEOMETRY are also represented as VARCHAR. case Types.VARCHAR: case Types.CHAR: case Types.STRUCT: + // TODO structuredType confirm that ARRAY is case sensitive + case Types.ARRAY: return true; case Types.INTEGER: diff --git a/src/test/java/net/snowflake/client/jdbc/ResultSetIT.java b/src/test/java/net/snowflake/client/jdbc/ResultSetIT.java index a0a12ce45..dd4240a4d 100644 --- a/src/test/java/net/snowflake/client/jdbc/ResultSetIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ResultSetIT.java @@ -51,106 +51,6 @@ public void testFindColumn() throws SQLException { connection.close(); } - public static class TestClass implements SQLData { - - private String x; - - @Override - public String getSQLTypeName() throws SQLException { - return null; - } - - @Override - public void readSQL(SQLInput stream, String typeName) throws SQLException { - x = stream.readString(); - } - - @Override - public void writeSQL(SQLOutput stream) throws SQLException {} - } - - @Test - public void testMapStructToObjectWithFactory() throws SQLException { - testMapJson(true); - } - - @Test - public void testMapStructToObjectWithReflection() throws SQLException { - testMapJson(true); - testMapJson(false); - testMapArray(true); - testMapArray(false); - testReturnAsMap(true); - testReturnAsMap(false); - } - - private void testMapJson(boolean registerFactory) throws SQLException { - if (registerFactory) { - SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); - } else { - SnowflakeObjectTypeFactories.unregister(TestClass.class); - } - Connection connection = init(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("select {'x':'a'}::OBJECT(x VARCHAR)"); - resultSet.next(); - TestClass object = resultSet.getObject(1, TestClass.class); - assertEquals("a", object.x); - statement.close(); - connection.close(); - } - private void testMapArray(boolean registerFactory) throws SQLException { - if (registerFactory) { - SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); - } else { - SnowflakeObjectTypeFactories.unregister(TestClass.class); - } - Connection connection = init(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("select [{'x':'aaa'},{'x': 'bbb'}]::ARRAY(OBJECT(x varchar))"); - resultSet.next(); - List objects = resultSet.unwrap(SnowflakeBaseResultSet.class).getList(1, TestClass.class); - assertEquals(objects.get(0).x, "aaa"); - assertEquals(objects.get(1).x, "bbb"); - statement.close(); - connection.close(); - } - - private void testReturnAsMap(boolean registerFactory) throws SQLException { - if (registerFactory) { - SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); - } else { - SnowflakeObjectTypeFactories.unregister(TestClass.class); - } - Connection connection = init(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("select {'x':{'x':'one'},'y':{'x':'two'},'z':{'x':'three'}}::MAP(VARCHAR, OBJECT(x VARCHAR));"); - resultSet.next(); - Map map = resultSet.unwrap(SnowflakeBaseResultSet.class).getMap(1, TestClass.class); - assertEquals(map.get("x").x, "one"); - assertEquals(map.get("y").x, "two"); - assertEquals(map.get("z").x, "three"); - statement.close(); - connection.close(); - } - - @Test - public void testMapStructsFromChunks() throws SQLException { - - Connection connection = init(); - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "select {'x':'a'}::OBJECT(x VARCHAR) FROM TABLE(GENERATOR(ROWCOUNT=>30000))"); - int i = 0; - while (resultSet.next()) { - TestClass object = resultSet.getObject(1, TestClass.class); - assertEquals("a", object.x); - } - statement.close(); - connection.close(); - } - @Test public void testGetColumnClassNameForBinary() throws Throwable { Connection connection = init(); diff --git a/src/test/java/net/snowflake/client/jdbc/ResultSetLatestIT.java b/src/test/java/net/snowflake/client/jdbc/ResultSetLatestIT.java index 98e7befb5..27f0699e5 100644 --- a/src/test/java/net/snowflake/client/jdbc/ResultSetLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ResultSetLatestIT.java @@ -21,6 +21,7 @@ import net.snowflake.client.category.TestCategoryResultSet; import net.snowflake.client.core.SFBaseSession; import net.snowflake.client.core.SessionUtil; +import net.snowflake.client.core.structs.SnowflakeObjectTypeFactories; import net.snowflake.client.jdbc.telemetry.*; import net.snowflake.common.core.SFBinary; import org.apache.arrow.vector.Float8Vector; @@ -927,4 +928,110 @@ public void testGranularTimeFunctionsInUTC() throws SQLException { connection.close(); } } + + public static class TestClass implements SQLData { + + private String x; + + @Override + public String getSQLTypeName() throws SQLException { + return null; + } + + @Override + public void readSQL(SQLInput stream, String typeName) throws SQLException { + x = stream.readString(); + } + + @Override + public void writeSQL(SQLOutput stream) throws SQLException {} + } + + @Test + public void testMapStructToObjectWithFactory() throws SQLException { + testMapJson(true); + } + + @Test + public void testMapStructToObjectWithReflection() throws SQLException { + testMapJson(true); + testMapJson(false); + } + @Test + public void testMapArrayToListWithReflection() throws SQLException { + testMapArrayAsList(true); + testMapArrayAsList(false); + } + + @Test + public void testMapArrayWithReflection() throws SQLException { + testMapArray(true); + testMapArray(false); + } + + private void testMapJson(boolean registerFactory) throws SQLException { + if (registerFactory) { + SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); + } else { + SnowflakeObjectTypeFactories.unregister(TestClass.class); + } + Connection connection = init(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("select {'x':'a'}::OBJECT(x VARCHAR)"); + resultSet.next(); + TestClass object = resultSet.getObject(1, TestClass.class); + assertEquals("a", object.x); + statement.close(); + connection.close(); + } + private void testMapArrayAsList(boolean registerFactory) throws SQLException { + if (registerFactory) { + SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); + } else { + SnowflakeObjectTypeFactories.unregister(TestClass.class); + } + Connection connection = init(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("select [{'x':'aaa'},{'x': 'bbb'}]::ARRAY(OBJECT(x varchar))"); + resultSet.next(); + List objects = resultSet.unwrap(SnowflakeBaseResultSet.class).getList(1, TestClass.class); + assertEquals(objects.get(0).x, "aaa"); + assertEquals(objects.get(1).x, "bbb"); + statement.close(); + connection.close(); + } + private void testMapArray(boolean registerFactory) throws SQLException { + if (registerFactory) { + SnowflakeObjectTypeFactories.register(TestClass.class, TestClass::new); + } else { + SnowflakeObjectTypeFactories.unregister(TestClass.class); + } + Connection connection = init(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("select [{'x':'aaa'},{'x': 'bbb'}]::ARRAY(OBJECT(x varchar))"); + resultSet.next(); + TestClass[] objects = resultSet.unwrap(SnowflakeBaseResultSet.class).getArray(1, TestClass.class); + assertEquals(objects[0].x, "aaa"); + assertEquals(objects[1].x, "bbb"); + statement.close(); + connection.close(); + } + + @Test + public void testMapStructsFromChunks() throws SQLException { + + Connection connection = init(); + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "select {'x':'a'}::OBJECT(x VARCHAR) FROM TABLE(GENERATOR(ROWCOUNT=>30000))"); + int i = 0; + while (resultSet.next()) { + TestClass object = resultSet.getObject(1, TestClass.class); + assertEquals("a", object.x); + } + statement.close(); + connection.close(); + } + }