From 362ac93ca0da2137814ffc75ad1eac3c723f2c7a Mon Sep 17 00:00:00 2001 From: Madhav Sainanee Date: Mon, 24 Nov 2025 05:43:24 +0000 Subject: [PATCH 1/2] palantir-fix --- NEXT_CHANGELOG.md | 1 + .../api/impl/DatabricksResultSetMetaData.java | 10 ++- .../impl/DatabricksResultSetMetaDataTest.java | 85 +++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 4d1031971..18a39ea91 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -28,5 +28,6 @@ - Fixed: Errors in table creation when using BIGINT, SMALLINT, TINYINT, or VOID types. - Fixed: PreparedStatement.getMetaData() now correctly reports TINYINT columns as Types.TINYINT (java.lang.Byte) instead of Types.SMALLINT (java.lang.Integer). - Fixed: TINYINT to String conversion to return numeric representation (e.g., "65") instead of character representation (e.g., "A"). +- Fixed: --- *Note: When making changes, please add your change under the appropriate section with a brief description.* diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java index 683625787..45d9f2f10 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java @@ -181,13 +181,21 @@ public DatabricksResultSetMetaData( int precision = precisionAndScale[0]; int scale = precisionAndScale[1]; + // Use arrowMetadata for type text if available, as it contains full type information + String columnTypeText = + (arrowMetadata != null + && columnIndex < arrowMetadata.size() + && arrowMetadata.get(columnIndex) != null) + ? arrowMetadata.get(columnIndex) + : getTypeTextFromTypeDesc(columnDesc.getTypeDesc()); + ImmutableDatabricksColumn.Builder columnBuilder = getColumnBuilder(); columnBuilder .columnName(columnInfo.getName()) .columnTypeClassName( DatabricksTypeUtil.getColumnTypeClassName(columnInfo.getTypeName())) .columnType(DatabricksTypeUtil.getColumnType(columnInfo.getTypeName())) - .columnTypeText(getTypeTextFromTypeDesc(columnDesc.getTypeDesc())) + .columnTypeText(columnTypeText) // columnInfoTypeName does not have BIGINT, SMALLINT. Extracting from thriftType in // typeDesc .typePrecision(precision) diff --git a/src/test/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaDataTest.java b/src/test/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaDataTest.java index 366bfe010..9c62a9637 100644 --- a/src/test/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaDataTest.java +++ b/src/test/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaDataTest.java @@ -444,6 +444,91 @@ public void testSEAInlineComplexType() throws SQLException { assertEquals(Types.VARCHAR, metaData.getColumnType(3)); } + @Test + public void testThriftComplexTypeWithArrowMetadata() throws SQLException { + // Create a Thrift result manifest with ARRAY, MAP, and STRUCT columns + TGetResultSetMetadataResp resultManifest = new TGetResultSetMetadataResp(); + + // Create ARRAY column descriptor (TTypeDesc only has primitive ARRAY_TYPE) + TColumnDesc arrayColumn = new TColumnDesc().setColumnName("array_col").setPosition(1); + TTypeDesc arrayTypeDesc = new TTypeDesc(); + TTypeEntry arrayTypeEntry = new TTypeEntry(); + TPrimitiveTypeEntry arrayPrimitiveEntry = new TPrimitiveTypeEntry(TTypeId.ARRAY_TYPE); + arrayTypeEntry.setPrimitiveEntry(arrayPrimitiveEntry); + arrayTypeDesc.setTypes(Collections.singletonList(arrayTypeEntry)); + arrayColumn.setTypeDesc(arrayTypeDesc); + + // Create MAP column descriptor (TTypeDesc only has primitive MAP_TYPE) + TColumnDesc mapColumn = new TColumnDesc().setColumnName("map_col").setPosition(2); + TTypeDesc mapTypeDesc = new TTypeDesc(); + TTypeEntry mapTypeEntry = new TTypeEntry(); + TPrimitiveTypeEntry mapPrimitiveEntry = new TPrimitiveTypeEntry(TTypeId.MAP_TYPE); + mapTypeEntry.setPrimitiveEntry(mapPrimitiveEntry); + mapTypeDesc.setTypes(Collections.singletonList(mapTypeEntry)); + mapColumn.setTypeDesc(mapTypeDesc); + + // Create STRUCT column descriptor (TTypeDesc only has primitive STRUCT_TYPE) + TColumnDesc structColumn = new TColumnDesc().setColumnName("struct_col").setPosition(3); + TTypeDesc structTypeDesc = new TTypeDesc(); + TTypeEntry structTypeEntry = new TTypeEntry(); + TPrimitiveTypeEntry structPrimitiveEntry = new TPrimitiveTypeEntry(TTypeId.STRUCT_TYPE); + structTypeEntry.setPrimitiveEntry(structPrimitiveEntry); + structTypeDesc.setTypes(Collections.singletonList(structTypeEntry)); + structColumn.setTypeDesc(structTypeDesc); + + TTableSchema schema = + new TTableSchema().setColumns(List.of(arrayColumn, mapColumn, structColumn)); + resultManifest.setSchema(schema); + + // Arrow metadata contains full type information + List arrowMetadata = + List.of("ARRAY", "MAP", "STRUCT"); + + DatabricksResultSetMetaData metaData = + new DatabricksResultSetMetaData( + THRIFT_STATEMENT_ID, resultManifest, 1, 1, arrowMetadata, connectionContext); + + // Verify that arrowMetadata is used for type names (not the primitive types from TTypeDesc) + assertEquals("ARRAY", metaData.getColumnTypeName(1)); + assertEquals("MAP", metaData.getColumnTypeName(2)); + assertEquals("STRUCT", metaData.getColumnTypeName(3)); + + assertEquals("array_col", metaData.getColumnName(1)); + assertEquals("map_col", metaData.getColumnName(2)); + assertEquals("struct_col", metaData.getColumnName(3)); + + assertEquals(Types.ARRAY, metaData.getColumnType(1)); + assertEquals(Types.VARCHAR, metaData.getColumnType(2)); + assertEquals(Types.STRUCT, metaData.getColumnType(3)); + } + + @Test + public void testThriftComplexTypeWithoutArrowMetadata() throws SQLException { + // Test fallback behavior when arrowMetadata is not available + TGetResultSetMetadataResp resultManifest = new TGetResultSetMetadataResp(); + + TColumnDesc arrayColumn = new TColumnDesc().setColumnName("array_col").setPosition(1); + TTypeDesc arrayTypeDesc = new TTypeDesc(); + TTypeEntry arrayTypeEntry = new TTypeEntry(); + TPrimitiveTypeEntry arrayPrimitiveEntry = new TPrimitiveTypeEntry(TTypeId.ARRAY_TYPE); + arrayTypeEntry.setPrimitiveEntry(arrayPrimitiveEntry); + arrayTypeDesc.setTypes(Collections.singletonList(arrayTypeEntry)); + arrayColumn.setTypeDesc(arrayTypeDesc); + + TTableSchema schema = new TTableSchema().setColumns(Collections.singletonList(arrayColumn)); + resultManifest.setSchema(schema); + + // No arrow metadata - should fall back to TTypeDesc + DatabricksResultSetMetaData metaData = + new DatabricksResultSetMetaData( + THRIFT_STATEMENT_ID, resultManifest, 1, 1, null, connectionContext); + + // Without arrowMetadata, falls back to primitive type name from TTypeDesc + assertEquals("ARRAY", metaData.getColumnTypeName(1)); + assertEquals("array_col", metaData.getColumnName(1)); + assertEquals(Types.ARRAY, metaData.getColumnType(1)); + } + private void verifyDefaultMetadataProperties( DatabricksResultSetMetaData metaData, StatementType type) throws SQLException { for (int i = 1; i <= metaData.getColumnCount(); i++) { From 0c5bbd5c7aac4fcae291c7ef64dd45d08306a20c Mon Sep 17 00:00:00 2001 From: Madhav Sainanee Date: Mon, 24 Nov 2025 05:49:11 +0000 Subject: [PATCH 2/2] changelog --- NEXT_CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 18a39ea91..57200a518 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -28,6 +28,6 @@ - Fixed: Errors in table creation when using BIGINT, SMALLINT, TINYINT, or VOID types. - Fixed: PreparedStatement.getMetaData() now correctly reports TINYINT columns as Types.TINYINT (java.lang.Byte) instead of Types.SMALLINT (java.lang.Integer). - Fixed: TINYINT to String conversion to return numeric representation (e.g., "65") instead of character representation (e.g., "A"). -- Fixed: +- Fixed: Thrift Responses involving complex data types now have detailed nested type information. --- *Note: When making changes, please add your change under the appropriate section with a brief description.*