From d92f4c7f3c30034f2b08eb5e82eaab5943f8ed8c Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Mon, 8 Apr 2024 11:59:47 +0200 Subject: [PATCH 1/5] SNOW-1313555 - make fields metadata visible for customers --- .../client/core/SFArrowResultSet.java | 22 +++++++++---------- .../client/core/SFBaseResultSet.java | 12 ++++++---- .../client/core/SFJsonResultSet.java | 2 +- .../client/core/SFResultSetMetaData.java | 14 ++++++++++++ .../client/jdbc/SnowflakeBaseResultSet.java | 15 +++++++++---- .../jdbc/SnowflakeResultSetMetaData.java | 4 ++++ .../jdbc/SnowflakeResultSetMetaDataV1.java | 6 +++++ 7 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/main/java/net/snowflake/client/core/SFArrowResultSet.java b/src/main/java/net/snowflake/client/core/SFArrowResultSet.java index f237caf13..78019e51a 100644 --- a/src/main/java/net/snowflake/client/core/SFArrowResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFArrowResultSet.java @@ -34,7 +34,6 @@ import net.snowflake.client.jdbc.ArrowResultChunk.ArrowChunkIterator; import net.snowflake.client.jdbc.ErrorCode; import net.snowflake.client.jdbc.FieldMetadata; -import net.snowflake.client.jdbc.SnowflakeColumnMetadata; import net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1; import net.snowflake.client.jdbc.SnowflakeSQLException; import net.snowflake.client.jdbc.SnowflakeSQLLoggedException; @@ -586,19 +585,17 @@ private Object createJsonSqlInput(int columnIndex, Object obj) throws SFExceptio jsonNode, session, converters, - resultSetMetaData.getColumnMetadata().get(columnIndex - 1).getFields(), + resultSetMetaData.getColumnFields(columnIndex), sessionTimeZone); } catch (JsonProcessingException e) { throw new SFException(e, ErrorCode.INVALID_STRUCT_DATA); } } - private Object createArrowSqlInput(int columnIndex, Map input) { + private Object createArrowSqlInput(int columnIndex, Map input) + throws SFException { return new ArrowSqlInput( - input, - session, - converters, - resultSetMetaData.getColumnMetadata().get(columnIndex - 1).getFields()); + input, session, converters, resultSetMetaData.getColumnFields(columnIndex)); } @Override @@ -621,10 +618,13 @@ public Array getArray(int columnIndex) throws SFException { private SfSqlArray getArrowArray(List elements, int columnIndex) throws SFException { try { - SnowflakeColumnMetadata arrayMetadata = - resultSetMetaData.getColumnMetadata().get(columnIndex - 1); - FieldMetadata fieldMetadata = arrayMetadata.getFields().get(0); - + List fieldMetadataList = resultSetMetaData.getColumnFields(columnIndex); + if (fieldMetadataList.size() != 1) { + throw new SFException( + ErrorCode.INVALID_STRUCT_DATA, + "Wrong size of fields for array type " + fieldMetadataList.size()); + } + FieldMetadata fieldMetadata = fieldMetadataList.get(0); int columnSubType = fieldMetadata.getType(); int columnType = ColumnTypeHelper.getColumnType(columnSubType, session); int scale = fieldMetadata.getScale(); diff --git a/src/main/java/net/snowflake/client/core/SFBaseResultSet.java b/src/main/java/net/snowflake/client/core/SFBaseResultSet.java index 0943afb42..1932b7a24 100644 --- a/src/main/java/net/snowflake/client/core/SFBaseResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFBaseResultSet.java @@ -32,7 +32,6 @@ import net.snowflake.client.core.json.Converters; import net.snowflake.client.jdbc.ErrorCode; import net.snowflake.client.jdbc.FieldMetadata; -import net.snowflake.client.jdbc.SnowflakeColumnMetadata; import net.snowflake.client.jdbc.SnowflakeResultSetSerializable; import net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1; import net.snowflake.client.jdbc.SnowflakeSQLException; @@ -275,9 +274,14 @@ protected SQLInput createJsonSqlInputForColumn( @SnowflakeJdbcInternalApi protected SfSqlArray getJsonArray(String obj, int columnIndex) throws SFException { try { - SnowflakeColumnMetadata arrayMetadata = - resultSetMetaData.getColumnMetadata().get(columnIndex - 1); - FieldMetadata fieldMetadata = arrayMetadata.getFields().get(0); + List fieldMetadataList = resultSetMetaData.getColumnFields(columnIndex); + if (fieldMetadataList.size() != 1) { + throw new SFException( + ErrorCode.FEATURE_UNSUPPORTED, + "Wrong size of fields for array type " + fieldMetadataList.size()); + } + + FieldMetadata fieldMetadata = fieldMetadataList.get(0); int columnSubType = fieldMetadata.getType(); int columnType = ColumnTypeHelper.getColumnType(columnSubType, session); diff --git a/src/main/java/net/snowflake/client/core/SFJsonResultSet.java b/src/main/java/net/snowflake/client/core/SFJsonResultSet.java index a9ccc00b9..f4a2fe04b 100644 --- a/src/main/java/net/snowflake/client/core/SFJsonResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFJsonResultSet.java @@ -298,7 +298,7 @@ private Object getSqlInput(String input, int columnIndex) throws SFException { jsonNode, session, converters, - resultSetMetaData.getColumnMetadata().get(columnIndex - 1).getFields(), + resultSetMetaData.getColumnFields(columnIndex), sessionTimeZone); } catch (JsonProcessingException e) { throw new SFException(e, ErrorCode.INVALID_STRUCT_DATA); diff --git a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java index ce129788b..8813290c4 100644 --- a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java +++ b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.TimeZone; import net.snowflake.client.jdbc.ErrorCode; +import net.snowflake.client.jdbc.FieldMetadata; import net.snowflake.client.jdbc.SnowflakeColumnMetadata; import net.snowflake.client.jdbc.SnowflakeUtil; import net.snowflake.client.log.SFLogger; @@ -477,4 +478,17 @@ public List getIsAutoIncrementList() { public List getColumnMetadata() { return columnMetadata; } + + @SnowflakeJdbcInternalApi + public List getColumnFields(int column) throws SFException { + if (column < 1 || column > columnMetadata.size()) { + throw new SFException(ErrorCode.COLUMN_DOES_NOT_EXIST, column); + } + + if (columnMetadata.get(column - 1) == null) { + throw new SFException(ErrorCode.INTERNAL_ERROR, "Missing column fields for column " + column); + } + + return columnMetadata.get(column - 1).getFields(); + } } diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java index ff15ff631..102e27eeb 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java @@ -1419,8 +1419,11 @@ public T[] getArray(int columnIndex, Class type) throws SQLException { if (!StructureTypeHelper.isStructureTypeEnabled()) { throw new SnowflakeLoggedFeatureNotSupportedException(session); } - FieldMetadata fieldMetadata = - sfBaseResultSet.getMetaData().getColumnMetadata().get(columnIndex - 1).getFields().get(0); + List fieldMetadataList = resultSetMetaData.getColumnFields(columnIndex); + if (fieldMetadataList.size() != 1) { + throw new SQLException("Wrong size of fields for array type " + fieldMetadataList.size()); + } + FieldMetadata fieldMetadata = fieldMetadataList.get(0); int columnSubType = fieldMetadata.getType(); int columnType = ColumnTypeHelper.getColumnType(fieldMetadata.getType(), session); int scale = fieldMetadata.getScale(); @@ -1569,8 +1572,12 @@ public Map getMap(int columnIndex, Class type) throws SQLExcep if (!StructureTypeHelper.isStructureTypeEnabled()) { throw new SnowflakeLoggedFeatureNotSupportedException(session); } - FieldMetadata valueFieldMetadata = - sfBaseResultSet.getMetaData().getColumnMetadata().get(columnIndex - 1).getFields().get(1); + List fieldMetadataList = resultSetMetaData.getColumnFields(columnIndex); + if (fieldMetadataList.size() != 2) { + throw new SQLException( + "Wrong size of fields metadata for map type " + fieldMetadataList.size()); + } + FieldMetadata valueFieldMetadata = fieldMetadataList.get(1); int columnSubType = valueFieldMetadata.getType(); int columnType = ColumnTypeHelper.getColumnType(valueFieldMetadata.getType(), session); int scale = valueFieldMetadata.getScale(); diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java index 5b2fc402c..4dfe7b02b 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java @@ -2,6 +2,7 @@ import java.sql.SQLException; import java.util.List; +import net.snowflake.client.core.SnowflakeJdbcInternalApi; public interface SnowflakeResultSetMetaData { String getQueryID() throws SQLException; @@ -11,4 +12,7 @@ public interface SnowflakeResultSetMetaData { int getColumnIndex(String columnName) throws SQLException; int getInternalColumnType(int column) throws SQLException; + + @SnowflakeJdbcInternalApi + List getColumnFields(int column) throws SQLException; } diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java index 4bc90bd54..170188d39 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java @@ -78,6 +78,12 @@ public int getInternalColumnType(int column) throws SQLException { } } + @Override + public List getColumnFields(int column) throws SQLException { + return SnowflakeUtil.mapSFExceptionToSQLException( + () -> resultSetMetaData.getColumnFields(column)); + } + @Override public T unwrap(Class iface) throws SQLException { logger.debug("public T unwrap(Class iface)", false); From 5d77cf93967b9e2e6d3b0c60ad9fbd13b7f99dcb Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Mon, 8 Apr 2024 15:05:04 +0200 Subject: [PATCH 2/5] SNOW-1299790 - make fields metadata available for customer --- .../snowflake/client/jdbc/FieldMetadata.java | 2 -- .../ResultSetStructuredTypesLatestIT.java | 26 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/snowflake/client/jdbc/FieldMetadata.java b/src/main/java/net/snowflake/client/jdbc/FieldMetadata.java index 55979cd83..cf019d62e 100644 --- a/src/main/java/net/snowflake/client/jdbc/FieldMetadata.java +++ b/src/main/java/net/snowflake/client/jdbc/FieldMetadata.java @@ -4,9 +4,7 @@ package net.snowflake.client.jdbc; import java.util.List; -import net.snowflake.client.core.SnowflakeJdbcInternalApi; -@SnowflakeJdbcInternalApi public class FieldMetadata { private String name; 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 b35d8c840..45bd22d56 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java @@ -31,6 +31,7 @@ import net.snowflake.client.core.structs.StructureTypeHelper; import net.snowflake.client.jdbc.BaseJDBCTest; import net.snowflake.client.jdbc.SnowflakeBaseResultSet; +import net.snowflake.client.jdbc.SnowflakeResultSetMetaData; import net.snowflake.client.jdbc.structuredtypes.sqldata.AllTypesClass; import net.snowflake.client.jdbc.structuredtypes.sqldata.FewTypesSqlData; import net.snowflake.client.jdbc.structuredtypes.sqldata.SimpleClass; @@ -663,13 +664,36 @@ public void testColumnTypeWhenStructureTypeIsDisabled() throws Exception { @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) - public void testColumnTypeWhenStructureTypeIsEnabled() throws Exception { + public void testColumnTypeAndFieldsWhenStructureTypeIsEnabled() throws Exception { withStructureTypeTemporaryEnabled( () -> { withFirstRow( "SELECT {'string':'a'}::OBJECT(string VARCHAR)", resultSet -> { assertEquals(Types.STRUCT, resultSet.getMetaData().getColumnType(1)); + assertEquals( + 1, + resultSet + .getMetaData() + .unwrap(SnowflakeResultSetMetaData.class) + .getColumnFields(1) + .size()); + assertEquals( + "VARCHAR", + resultSet + .getMetaData() + .unwrap(SnowflakeResultSetMetaData.class) + .getColumnFields(1) + .get(0) + .getTypeName()); + assertEquals( + "string", + resultSet + .getMetaData() + .unwrap(SnowflakeResultSetMetaData.class) + .getColumnFields(1) + .get(0) + .getName()); }); }); } From 6cda8c49f559ce0af8bf202e9d9e3a4a9e55a84c Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Mon, 8 Apr 2024 22:05:13 +0200 Subject: [PATCH 3/5] SNOW-1299790 - make fields metadata available for customer --- .../java/net/snowflake/client/core/SFResultSetMetaData.java | 5 ----- .../snowflake/client/jdbc/SnowflakeResultSetMetaData.java | 2 -- .../structuredtypes/ResultSetStructuredTypesLatestIT.java | 6 +++--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java index 8813290c4..586768c6a 100644 --- a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java +++ b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java @@ -474,11 +474,6 @@ public List getIsAutoIncrementList() { return isAutoIncrementList; } - @SnowflakeJdbcInternalApi - public List getColumnMetadata() { - return columnMetadata; - } - @SnowflakeJdbcInternalApi public List getColumnFields(int column) throws SFException { if (column < 1 || column > columnMetadata.size()) { diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java index 4dfe7b02b..dcc5250b5 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaData.java @@ -2,7 +2,6 @@ import java.sql.SQLException; import java.util.List; -import net.snowflake.client.core.SnowflakeJdbcInternalApi; public interface SnowflakeResultSetMetaData { String getQueryID() throws SQLException; @@ -13,6 +12,5 @@ public interface SnowflakeResultSetMetaData { int getInternalColumnType(int column) throws SQLException; - @SnowflakeJdbcInternalApi List getColumnFields(int column) throws SQLException; } 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 45bd22d56..07c82262d 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java @@ -651,11 +651,11 @@ public void testMapArrayOfArrays() throws SQLException { } @Test - public void testColumnTypeWhenStructureTypeIsDisabled() throws Exception { + public void testColumnTypeWhenStructureTypeIsNotreturned() throws Exception { withStructureTypeTemporaryDisabled( () -> { withFirstRow( - "SELECT {'string':'a'}::OBJECT(string VARCHAR)", + "SELECT {'string':'a'}", resultSet -> { assertEquals(Types.VARCHAR, resultSet.getMetaData().getColumnType(1)); }); @@ -664,7 +664,7 @@ public void testColumnTypeWhenStructureTypeIsDisabled() throws Exception { @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) - public void testColumnTypeAndFieldsWhenStructureTypeIsEnabled() throws Exception { + public void testColumnTypeAndFieldsWhenStructureTypeIsReturned() throws Exception { withStructureTypeTemporaryEnabled( () -> { withFirstRow( From 991cfe12440cc8197dd2986fada81fcbb18a94b7 Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Tue, 9 Apr 2024 23:31:16 +0200 Subject: [PATCH 4/5] SNOW-1299790 - make fields metadata available for customer --- .../jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java | 1 + 1 file changed, 1 insertion(+) 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 07c82262d..a1c87945b 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java @@ -44,6 +44,7 @@ @RunWith(Parameterized.class) @Category(TestCategoryStructuredType.class) +@Ignore public class ResultSetStructuredTypesLatestIT extends BaseJDBCTest { @Parameterized.Parameters(name = "format={0}") From b38cb1efcd97df301feb80231b8ee424eea81ec6 Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Wed, 10 Apr 2024 13:44:09 +0200 Subject: [PATCH 5/5] SNOW-1299790 - make fields metadata available for customer --- .../jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a1c87945b..d7300732b 100644 --- a/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/structuredtypes/ResultSetStructuredTypesLatestIT.java @@ -652,7 +652,7 @@ public void testMapArrayOfArrays() throws SQLException { } @Test - public void testColumnTypeWhenStructureTypeIsNotreturned() throws Exception { + public void testColumnTypeWhenStructureTypeIsNotReturned() throws Exception { withStructureTypeTemporaryDisabled( () -> { withFirstRow(