From 8a3013322e29b4ce6cfad51b89a42e3404aea111 Mon Sep 17 00:00:00 2001 From: Honah J Date: Tue, 6 Jan 2026 19:47:08 -0600 Subject: [PATCH 1/2] Fix + integration test --- .../it/test/PolarisSparkIntegrationTest.java | 29 +++++++++++++++++++ .../catalog/iceberg/IcebergCatalog.java | 1 + 2 files changed, 30 insertions(+) diff --git a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java index 2bdd109281..98a21c9bec 100644 --- a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java +++ b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java @@ -147,6 +147,35 @@ public void testCreateView() { assertThat(recordCount).isEqualTo(3); } + @Test + public void testSetWriteDataPathToSubdirectory() { + // Setup: create namespace + onSpark("CREATE NAMESPACE ns1"); + onSpark("USE ns1"); + + // Create a table + onSpark("CREATE TABLE tb1 (col1 integer, col2 string)"); + + // Fetch the current table's location using the loadTable helper + LoadTableResponse tableResponse = loadTable(catalogName, "ns1", "tb1"); + String tableLocation = tableResponse.tableMetadata().location(); + assertThat(tableLocation).isNotNull(); + + + String writeDataPath = tableLocation + "/alternative_data"; + onSpark("ALTER TABLE tb1 SET TBLPROPERTIES ('write.data.path' = '" + writeDataPath + "')"); + + // Verify that the table property is set + tableResponse = loadTable(catalogName, "ns1", "tb1"); + assertThat(tableResponse.tableMetadata().properties()) + .containsEntry("write.data.path", writeDataPath); + + // Insert data and verify it can be read back + onSpark("INSERT INTO tb1 VALUES (1, 'a'), (2, 'b'), (3, 'c')"); + long recordCount = onSpark("SELECT * FROM tb1").count(); + assertThat(recordCount).isEqualTo(3); + } + private LoadTableResponse loadTable(String catalog, String namespace, String table) { try (Response response = catalogApi diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java index 745a9ed4f2..bda38f0095 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java @@ -992,6 +992,7 @@ private void validateNoLocationOverlap( IcebergTableLikeEntity virtualEntity = IcebergTableLikeEntity.of( new PolarisEntity.Builder() + .setName(identifier.name()) .setType(PolarisEntityType.TABLE_LIKE) .setSubType(PolarisEntitySubType.ICEBERG_TABLE) .setParentId(lastNamespace.getId()) From ab87f18bdea14b6e24207e6a9d836ae073907740 Mon Sep 17 00:00:00 2001 From: Honah J Date: Tue, 6 Jan 2026 19:55:16 -0600 Subject: [PATCH 2/2] Add unit test --- .../it/test/PolarisSparkIntegrationTest.java | 8 +--- .../iceberg/IcebergAllowedLocationTest.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java index 98a21c9bec..c12d59acb4 100644 --- a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java +++ b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisSparkIntegrationTest.java @@ -149,28 +149,22 @@ public void testCreateView() { @Test public void testSetWriteDataPathToSubdirectory() { - // Setup: create namespace onSpark("CREATE NAMESPACE ns1"); onSpark("USE ns1"); - - // Create a table onSpark("CREATE TABLE tb1 (col1 integer, col2 string)"); - // Fetch the current table's location using the loadTable helper LoadTableResponse tableResponse = loadTable(catalogName, "ns1", "tb1"); String tableLocation = tableResponse.tableMetadata().location(); assertThat(tableLocation).isNotNull(); - + // Set a custom write data path to a subdirectory within the table location String writeDataPath = tableLocation + "/alternative_data"; onSpark("ALTER TABLE tb1 SET TBLPROPERTIES ('write.data.path' = '" + writeDataPath + "')"); - // Verify that the table property is set tableResponse = loadTable(catalogName, "ns1", "tb1"); assertThat(tableResponse.tableMetadata().properties()) .containsEntry("write.data.path", writeDataPath); - // Insert data and verify it can be read back onSpark("INSERT INTO tb1 VALUES (1, 'a'), (2, 'b'), (3, 'c')"); long recordCount = onSpark("SELECT * FROM tb1").count(); assertThat(recordCount).isEqualTo(3); diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java index 09ae01739b..8251314945 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java @@ -304,6 +304,53 @@ void testViewOutsideAllowedLocations(@TempDir Path tmpDir) { .build(); } + @Test + void testSetWriteDataPathToSubdirectoryUnderTableLocation(@TempDir Path tmpDir) { + var services = getTestServices(); + var tableName = getTableName(); + var tableId = TableIdentifier.of(namespace, tableName); + + var catalogLocation = tmpDir.resolve(catalog).toAbsolutePath().toUri().toString(); + var namespaceLocation = catalogLocation + "/" + namespace; + + createCatalog(services, Map.of(), catalogLocation, List.of(catalogLocation)); + createNamespace(services, namespaceLocation); + + var createTableRequest = + CreateTableRequest.builder().withName(tableName).withSchema(SCHEMA).build(); + + var createResponse = + services + .restApi() + .createTable( + catalog, + namespace, + createTableRequest, + null, + services.realmContext(), + services.securityContext()); + assertThat(createResponse.getStatus()).isEqualTo(Response.Status.OK.getStatusCode()); + var tableLocation = namespaceLocation + "/" + tableName; + + // Update the table to set write.data.path to a subdirectory under the table's location + String writeDataPath = tableLocation + "/alternative_data"; + Map updatedProperties = new HashMap<>(); + updatedProperties.put("write.data.path", writeDataPath); + + var updateRequest = + UpdateTableRequest.create( + tableId, List.of(), List.of(new MetadataUpdate.SetProperties(updatedProperties))); + + var updateResponse = + services + .catalogAdapter() + .newHandlerWrapper(services.securityContext(), catalog) + .updateTable(tableId, updateRequest); + + assertThat(updateResponse.tableMetadata().properties()) + .containsEntry("write.data.path", writeDataPath); + } + private void createCatalog( TestServices services, Map catalogConfig,