This is an automated email from the ASF dual-hosted git repository.

yzou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new b48cfb654 Add server and client support for the new generic table 
`baseLocation` field (#2122)
b48cfb654 is described below

commit b48cfb654cdd867830ca6105f790104503bfb1b1
Author: Yun Zou <yunzou.colost...@gmail.com>
AuthorDate: Fri Jul 18 18:22:03 2025 -0700

    Add server and client support for the new generic table `baseLocation` 
field (#2122)
---
 .../org/apache/polaris/spark/PolarisCatalog.java   |  6 +++-
 .../apache/polaris/spark/PolarisRESTCatalog.java   |  7 ++++-
 .../apache/polaris/spark/PolarisSparkCatalog.java  | 26 +++++++++++++++++-
 .../polaris/spark/utils/PolarisCatalogUtils.java   |  8 ++++--
 .../polaris/spark/PolarisInMemoryCatalog.java      |  7 ++++-
 .../polaris/spark/rest/DeserializationTest.java    | 28 +++++++++++++------
 .../core/entity/table/GenericTableEntity.java      | 12 ++++++++
 .../core/entity/table/IcebergTableLikeEntity.java  |  3 +-
 .../polaris/core/entity/table/TableLikeEntity.java |  4 +--
 .../quarkus/admin/PolarisAuthzTestBase.java        |  3 +-
 .../AbstractPolarisGenericTableCatalogTest.java    | 32 +++++++++++++---------
 ...PolarisGenericTableCatalogHandlerAuthzTest.java |  7 +++--
 .../catalog/generic/GenericTableCatalog.java       |  6 +++-
 .../generic/GenericTableCatalogAdapter.java        |  1 +
 .../generic/GenericTableCatalogHandler.java        | 11 ++++++--
 .../generic/PolarisGenericTableCatalog.java        |  7 ++++-
 16 files changed, 128 insertions(+), 40 deletions(-)

diff --git 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisCatalog.java
 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisCatalog.java
index 99802d3cb..08116c9e6 100644
--- 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisCatalog.java
+++ 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisCatalog.java
@@ -32,5 +32,9 @@ public interface PolarisCatalog {
   boolean dropGenericTable(TableIdentifier identifier);
 
   GenericTable createGenericTable(
-      TableIdentifier identifier, String format, String doc, Map<String, 
String> props);
+      TableIdentifier identifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> props);
 }
diff --git 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisRESTCatalog.java
 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisRESTCatalog.java
index 5dfd1f898..5be0f6952 100644
--- 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisRESTCatalog.java
+++ 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisRESTCatalog.java
@@ -200,13 +200,18 @@ public class PolarisRESTCatalog implements 
PolarisCatalog, Closeable {
 
   @Override
   public GenericTable createGenericTable(
-      TableIdentifier identifier, String format, String doc, Map<String, 
String> props) {
+      TableIdentifier identifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> props) {
     Endpoint.check(endpoints, PolarisEndpoints.V1_CREATE_GENERIC_TABLE);
     CreateGenericTableRESTRequest request =
         new CreateGenericTableRESTRequest(
             CreateGenericTableRequest.builder()
                 .setName(identifier.name())
                 .setFormat(format)
+                .setBaseLocation(baseLocation)
                 .setDoc(doc)
                 .setProperties(props)
                 .build());
diff --git 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisSparkCatalog.java
 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisSparkCatalog.java
index fe0c6e180..964674e54 100644
--- 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisSparkCatalog.java
+++ 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/PolarisSparkCatalog.java
@@ -38,6 +38,8 @@ import org.apache.spark.sql.connector.catalog.TableChange;
 import org.apache.spark.sql.connector.expressions.Transform;
 import org.apache.spark.sql.types.StructType;
 import org.apache.spark.sql.util.CaseInsensitiveStringMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A spark TableCatalog Implementation interacts with Polaris specific APIs 
only. The APIs it
@@ -45,6 +47,7 @@ import org.apache.spark.sql.util.CaseInsensitiveStringMap;
  * expected to be for non-iceberg tables.
  */
 public class PolarisSparkCatalog implements TableCatalog {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(PolarisSparkCatalog.class);
 
   private PolarisCatalog polarisCatalog = null;
   private String catalogName = null;
@@ -83,9 +86,30 @@ public class PolarisSparkCatalog implements TableCatalog {
       throws TableAlreadyExistsException, NoSuchNamespaceException {
     try {
       String format = properties.get(PolarisCatalogUtils.TABLE_PROVIDER_KEY);
+
+      String baseLocation;
+      // Extract the base table location from the spark properties.
+      // Spark pass the table base location either with the
+      // TableCatalog.PROP_LOCATION key, or with "path" key if created
+      // with the path option.
+      if (properties.get(TableCatalog.PROP_LOCATION) != null) {
+        baseLocation = properties.get(TableCatalog.PROP_LOCATION);
+        if (properties.get(PolarisCatalogUtils.TABLE_PATH_KEY) != null) {
+          LOGGER.debug(
+              "Both location and path are propagated in the table properties, 
location {}, path {}",
+              baseLocation,
+              properties.get(PolarisCatalogUtils.TABLE_PATH_KEY));
+        }
+      } else {
+        baseLocation = properties.get(PolarisCatalogUtils.TABLE_PATH_KEY);
+      }
       GenericTable genericTable =
           this.polarisCatalog.createGenericTable(
-              Spark3Util.identifierToTableIdentifier(identifier), format, 
null, properties);
+              Spark3Util.identifierToTableIdentifier(identifier),
+              format,
+              baseLocation,
+              null,
+              properties);
       return PolarisCatalogUtils.loadSparkTable(genericTable);
     } catch (AlreadyExistsException e) {
       throw new TableAlreadyExistsException(identifier);
diff --git 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/utils/PolarisCatalogUtils.java
 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/utils/PolarisCatalogUtils.java
index e7cd76bca..df433ec9f 100644
--- 
a/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/utils/PolarisCatalogUtils.java
+++ 
b/plugins/spark/v3.5/spark/src/main/java/org/apache/polaris/spark/utils/PolarisCatalogUtils.java
@@ -76,12 +76,16 @@ public class PolarisCatalogUtils {
     boolean hasPathClause = properties.get(TABLE_PATH_KEY) != null;
     Map<String, String> tableProperties = Maps.newHashMap();
     tableProperties.putAll(properties);
-    if (!hasPathClause && hasLocationClause) {
+    if (!hasPathClause) {
       // DataSourceV2 requires the path property on table loading. However, 
spark today
       // doesn't create the corresponding path property if the path keyword is 
not
       // provided by user when location is provided. Here, we duplicate the 
location
       // property as path to make sure the table can be loaded.
-      tableProperties.put(TABLE_PATH_KEY, 
properties.get(TableCatalog.PROP_LOCATION));
+      if (genericTable.getBaseLocation() != null && 
!genericTable.getBaseLocation().isEmpty()) {
+        tableProperties.put(TABLE_PATH_KEY, genericTable.getBaseLocation());
+      } else if (hasLocationClause) {
+        tableProperties.put(TABLE_PATH_KEY, 
properties.get(TableCatalog.PROP_LOCATION));
+      }
     }
     return DataSourceV2Utils.getTableFromProvider(
         provider, new CaseInsensitiveStringMap(tableProperties), 
scala.Option.empty());
diff --git 
a/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/PolarisInMemoryCatalog.java
 
b/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/PolarisInMemoryCatalog.java
index c846659df..2d71d9cb6 100644
--- 
a/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/PolarisInMemoryCatalog.java
+++ 
b/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/PolarisInMemoryCatalog.java
@@ -65,7 +65,11 @@ public class PolarisInMemoryCatalog extends InMemoryCatalog 
implements PolarisCa
 
   @Override
   public GenericTable createGenericTable(
-      TableIdentifier identifier, String format, String doc, Map<String, 
String> props) {
+      TableIdentifier identifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> props) {
     if (!namespaceExists(identifier.namespace())) {
       throw new NoSuchNamespaceException(
           "Cannot create generic table %s. Namespace does not exist: %s",
@@ -78,6 +82,7 @@ public class PolarisInMemoryCatalog extends InMemoryCatalog 
implements PolarisCa
             GenericTable.builder()
                 .setName(identifier.name())
                 .setFormat(format)
+                .setBaseLocation(baseLocation)
                 .setProperties(props)
                 .build());
 
diff --git 
a/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/rest/DeserializationTest.java
 
b/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/rest/DeserializationTest.java
index d4d4da6ab..0f7d3c99b 100644
--- 
a/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/rest/DeserializationTest.java
+++ 
b/plugins/spark/v3.5/spark/src/test/java/org/apache/polaris/spark/rest/DeserializationTest.java
@@ -65,15 +65,19 @@ public class DeserializationTest {
 
   @ParameterizedTest
   @MethodSource("genericTableTestCases")
-  public void testLoadGenericTableRESTResponse(String doc, Map<String, String> 
properties)
+  public void testLoadGenericTableRESTResponse(
+      String baseLocation, String doc, Map<String, String> properties)
       throws JsonProcessingException {
-    GenericTable table =
+    GenericTable.Builder tableBuilder =
         GenericTable.builder()
             .setFormat("delta")
             .setName("test-table")
             .setProperties(properties)
-            .setDoc(doc)
-            .build();
+            .setDoc(doc);
+    if (baseLocation != null) {
+      tableBuilder.setBaseLocation(baseLocation);
+    }
+    GenericTable table = tableBuilder.build();
     LoadGenericTableRESTResponse response = new 
LoadGenericTableRESTResponse(table);
     String json = mapper.writeValueAsString(response);
     LoadGenericTableRESTResponse deserializedResponse =
@@ -82,11 +86,13 @@ public class DeserializationTest {
     
assertThat(deserializedResponse.getTable().getName()).isEqualTo("test-table");
     assertThat(deserializedResponse.getTable().getDoc()).isEqualTo(doc);
     
assertThat(deserializedResponse.getTable().getProperties().size()).isEqualTo(properties.size());
+    
assertThat(deserializedResponse.getTable().getBaseLocation()).isEqualTo(baseLocation);
   }
 
   @ParameterizedTest
   @MethodSource("genericTableTestCases")
-  public void testCreateGenericTableRESTRequest(String doc, Map<String, 
String> properties)
+  public void testCreateGenericTableRESTRequest(
+      String baseLocation, String doc, Map<String, String> properties)
       throws JsonProcessingException {
     CreateGenericTableRESTRequest request =
         new CreateGenericTableRESTRequest(
@@ -94,6 +100,7 @@ public class DeserializationTest {
                 .setName("test-table")
                 .setFormat("delta")
                 .setDoc(doc)
+                .setBaseLocation(baseLocation)
                 .setProperties(properties)
                 .build());
     String json = mapper.writeValueAsString(request);
@@ -103,6 +110,7 @@ public class DeserializationTest {
     assertThat(deserializedRequest.getFormat()).isEqualTo("delta");
     assertThat(deserializedRequest.getDoc()).isEqualTo(doc);
     
assertThat(deserializedRequest.getProperties().size()).isEqualTo(properties.size());
+    assertThat(deserializedRequest.getBaseLocation()).isEqualTo(baseLocation);
   }
 
   @Test
@@ -150,10 +158,12 @@ public class DeserializationTest {
     var doc = "table for testing";
     var properties = Maps.newHashMap();
     properties.put("location", "s3://path/to/table/");
+    var baseLocation = "s3://path/to/table/";
     return Stream.of(
-        Arguments.of(doc, properties),
-        Arguments.of(null, Maps.newHashMap()),
-        Arguments.of(doc, Maps.newHashMap()),
-        Arguments.of(null, properties));
+        Arguments.of(null, doc, properties),
+        Arguments.of(baseLocation, doc, properties),
+        Arguments.of(null, null, Maps.newHashMap()),
+        Arguments.of(baseLocation, doc, Maps.newHashMap()),
+        Arguments.of(baseLocation, null, properties));
   }
 }
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/GenericTableEntity.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/GenericTableEntity.java
index a5eae86fe..5f9250803 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/GenericTableEntity.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/GenericTableEntity.java
@@ -25,6 +25,7 @@ import org.apache.iceberg.rest.RESTUtil;
 import org.apache.polaris.core.entity.NamespaceEntity;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisEntity;
+import org.apache.polaris.core.entity.PolarisEntityConstants;
 import org.apache.polaris.core.entity.PolarisEntitySubType;
 import org.apache.polaris.core.entity.PolarisEntityType;
 
@@ -58,6 +59,12 @@ public class GenericTableEntity extends TableLikeEntity {
     return getInternalPropertiesAsMap().get(GenericTableEntity.DOC_KEY);
   }
 
+  @Override
+  @JsonIgnore
+  public String getBaseLocation() {
+    return 
getInternalPropertiesAsMap().get(PolarisEntityConstants.ENTITY_BASE_LOCATION);
+  }
+
   public static class Builder
       extends PolarisEntity.BaseBuilder<GenericTableEntity, 
GenericTableEntity.Builder> {
     public Builder(TableIdentifier tableIdentifier, String format) {
@@ -79,6 +86,11 @@ public class GenericTableEntity extends TableLikeEntity {
       return this;
     }
 
+    public GenericTableEntity.Builder setBaseLocation(String location) {
+      internalProperties.put(PolarisEntityConstants.ENTITY_BASE_LOCATION, 
location);
+      return this;
+    }
+
     public GenericTableEntity.Builder setTableIdentifier(TableIdentifier 
identifier) {
       Namespace namespace = identifier.namespace();
       setParentNamespace(namespace);
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/IcebergTableLikeEntity.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/IcebergTableLikeEntity.java
index 21e922982..57d15a103 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/IcebergTableLikeEntity.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/IcebergTableLikeEntity.java
@@ -23,7 +23,6 @@ import java.util.Optional;
 import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.rest.RESTUtil;
-import org.apache.polaris.core.entity.LocationBasedEntity;
 import org.apache.polaris.core.entity.NamespaceEntity;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisEntity;
@@ -34,7 +33,7 @@ import org.apache.polaris.core.entity.PolarisEntityType;
  * An entity type for {@link TableLikeEntity} instances that conform to 
iceberg semantics around
  * locations. This includes both Iceberg tables and Iceberg views.
  */
-public class IcebergTableLikeEntity extends TableLikeEntity implements 
LocationBasedEntity {
+public class IcebergTableLikeEntity extends TableLikeEntity {
   // For applicable types, this key on the "internalProperties" map will 
return the location
   // of the internalProperties JSON file.
   public static final String METADATA_LOCATION_KEY = "metadata-location";
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/TableLikeEntity.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/TableLikeEntity.java
index 22808d1a7..21ba80f4a 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/entity/table/TableLikeEntity.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/entity/table/TableLikeEntity.java
@@ -23,16 +23,16 @@ import jakarta.annotation.Nonnull;
 import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.rest.RESTUtil;
+import org.apache.polaris.core.entity.LocationBasedEntity;
 import org.apache.polaris.core.entity.NamespaceEntity;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisEntity;
-import org.apache.polaris.core.entity.PolarisEntityType;
 
 /**
  * An entity type for all table-like entities including Iceberg tables, 
Iceberg views, and generic
  * tables. This entity maps to {@link PolarisEntityType#TABLE_LIKE}
  */
-public abstract class TableLikeEntity extends PolarisEntity {
+public abstract class TableLikeEntity extends PolarisEntity implements 
LocationBasedEntity {
 
   public TableLikeEntity(@Nonnull PolarisBaseEntity sourceEntity) {
     super(sourceEntity);
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java
index 013e2c99e..c86cefe6e 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java
@@ -325,7 +325,8 @@ public abstract class PolarisAuthzTestBase {
     baseCatalog.buildTable(TABLE_NS1B_1, SCHEMA).create();
     baseCatalog.buildTable(TABLE_NS2_1, SCHEMA).create();
 
-    genericTableCatalog.createGenericTable(TABLE_NS1_1_GENERIC, "format", 
"doc", Map.of());
+    genericTableCatalog.createGenericTable(
+        TABLE_NS1_1_GENERIC, "format", "file:///tmp/test_table", "doc", 
Map.of());
 
     policyCatalog.createPolicy(
         POLICY_NS1_1,
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/AbstractPolarisGenericTableCatalogTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/AbstractPolarisGenericTableCatalogTest.java
index ea044fbab..ade4768f4 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/AbstractPolarisGenericTableCatalogTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/AbstractPolarisGenericTableCatalogTest.java
@@ -81,6 +81,9 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.Mockito;
 import software.amazon.awssdk.services.sts.StsClient;
 import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
@@ -277,7 +280,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Assertions.assertThatCode(
             () ->
                 genericTableCatalog.createGenericTable(
-                    TableIdentifier.of("ns", "t1"), "test-format", "doc", 
Map.of()))
+                    TableIdentifier.of("ns", "t1"), "test-format", null, 
"doc", Map.of()))
         .doesNotThrowAnyException();
   }
 
@@ -286,12 +289,12 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Namespace namespace = Namespace.of("ns");
     icebergCatalog.createNamespace(namespace);
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", "t1"), "format1", "doc", Map.of());
+        TableIdentifier.of("ns", "t1"), "format1", null, "doc", Map.of());
 
     Assertions.assertThatCode(
             () ->
                 genericTableCatalog.createGenericTable(
-                    TableIdentifier.of("ns", "t1"), "format2", "doc", 
Map.of()))
+                    TableIdentifier.of("ns", "t1"), "format2", null, "doc", 
Map.of()))
         .hasMessageContaining("already exists");
 
     Assertions.assertThatCode(
@@ -308,7 +311,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Assertions.assertThatCode(
             () ->
                 genericTableCatalog.createGenericTable(
-                    TableIdentifier.of("ns", "t1"), "format2", "doc", 
Map.of()))
+                    TableIdentifier.of("ns", "t1"), "format2", null, "doc", 
Map.of()))
         .hasMessageContaining("already exists");
 
     Assertions.assertThatCode(
@@ -316,8 +319,10 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
         .hasMessageContaining("already exists");
   }
 
-  @Test
-  public void testGenericTableRoundTrip() {
+  @ParameterizedTest
+  @NullSource
+  @ValueSource(strings = {"", "file://path/to/my/table"})
+  public void testGenericTableRoundTrip(String baseLocation) {
     Namespace namespace = Namespace.of("ns");
     icebergCatalog.createNamespace(namespace);
 
@@ -327,7 +332,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     String doc = "round-trip-doc";
 
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", tableName), format, doc, properties);
+        TableIdentifier.of("ns", tableName), format, baseLocation, doc, 
properties);
 
     GenericTableEntity resultEntity =
         genericTableCatalog.loadGenericTable(TableIdentifier.of("ns", 
tableName));
@@ -335,6 +340,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Assertions.assertThat(resultEntity.getFormat()).isEqualTo(format);
     
Assertions.assertThat(resultEntity.getPropertiesAsMap()).isEqualTo(properties);
     Assertions.assertThat(resultEntity.getName()).isEqualTo(tableName);
+    
Assertions.assertThat(resultEntity.getBaseLocation()).isEqualTo(baseLocation);
   }
 
   @Test
@@ -381,7 +387,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     String tableName = "t1";
 
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", tableName), "format", "doc", Map.of());
+        TableIdentifier.of("ns", tableName), "format", null, "doc", Map.of());
     Assertions.assertThatCode(() -> 
icebergCatalog.loadTable(TableIdentifier.of("ns", tableName)))
         .hasMessageContaining("does not exist: ns.t1");
   }
@@ -394,7 +400,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     String tableName = "t1";
 
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", tableName), "format", "doc", Map.of());
+        TableIdentifier.of("ns", tableName), "format", null, "doc", Map.of());
     Assertions.assertThatCode(() -> 
icebergCatalog.loadView(TableIdentifier.of("ns", tableName)))
         .hasMessageContaining("does not exist: ns.t1");
   }
@@ -406,7 +412,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
 
     for (int i = 0; i < 10; i++) {
       genericTableCatalog.createGenericTable(
-          TableIdentifier.of("ns", "t" + i), "format", "doc", Map.of());
+          TableIdentifier.of("ns", "t" + i), "format", null, "doc", Map.of());
     }
 
     List<TableIdentifier> listResult = 
genericTableCatalog.listGenericTables(namespace);
@@ -468,7 +474,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
 
     for (int i = 0; i < 10; i++) {
       genericTableCatalog.createGenericTable(
-          TableIdentifier.of("ns", "g" + i), "format", "doc", Map.of());
+          TableIdentifier.of("ns", "g" + i), "format", null, "doc", Map.of());
     }
 
     
Assertions.assertThat(genericTableCatalog.listGenericTables(namespace).size()).isEqualTo(10);
@@ -514,7 +520,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Namespace namespace = Namespace.of("ns");
     icebergCatalog.createNamespace(namespace);
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", "t1"), "format", "doc", Map.of());
+        TableIdentifier.of("ns", "t1"), "format", null, "doc", Map.of());
 
     Assertions.assertThat(icebergCatalog.dropTable(TableIdentifier.of("ns", 
"t1"))).isFalse();
     
Assertions.assertThat(genericTableCatalog.loadGenericTable(TableIdentifier.of("ns",
 "t1")))
@@ -526,7 +532,7 @@ public abstract class 
AbstractPolarisGenericTableCatalogTest {
     Namespace namespace = Namespace.of("ns");
     icebergCatalog.createNamespace(namespace);
     genericTableCatalog.createGenericTable(
-        TableIdentifier.of("ns", "t1"), "format", "doc", Map.of());
+        TableIdentifier.of("ns", "t1"), "format", null, "doc", Map.of());
 
     Assertions.assertThat(icebergCatalog.dropView(TableIdentifier.of("ns", 
"t1"))).isFalse();
     
Assertions.assertThat(genericTableCatalog.loadGenericTable(TableIdentifier.of("ns",
 "t1")))
diff --git 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogHandlerAuthzTest.java
 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogHandlerAuthzTest.java
index 6deb37bb3..446e5505b 100644
--- 
a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogHandlerAuthzTest.java
+++ 
b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogHandlerAuthzTest.java
@@ -188,7 +188,7 @@ public class PolarisGenericTableCatalogHandlerAuthzTest 
extends PolarisAuthzTest
             PolarisPrivilege.CATALOG_MANAGE_CONTENT),
         () -> {
           newWrapper(Set.of(PRINCIPAL_ROLE1))
-              .createGenericTable(newtable, "format", "doc", Map.of());
+              .createGenericTable(newtable, "format", "file:///temp/", "doc", 
Map.of());
         },
         () -> {
           newWrapper(Set.of(PRINCIPAL_ROLE2)).dropGenericTable(newtable);
@@ -209,7 +209,8 @@ public class PolarisGenericTableCatalogHandlerAuthzTest 
extends PolarisAuthzTest
             PolarisPrivilege.TABLE_LIST),
         () -> {
           newWrapper(Set.of(PRINCIPAL_ROLE1))
-              .createGenericTable(TableIdentifier.of(NS2, "newtable"), 
"format", "doc", Map.of());
+              .createGenericTable(
+                  TableIdentifier.of(NS2, "newtable"), "format", null, "doc", 
Map.of());
         });
   }
 
@@ -256,7 +257,7 @@ public class PolarisGenericTableCatalogHandlerAuthzTest 
extends PolarisAuthzTest
         },
         () -> {
           newWrapper(Set.of(PRINCIPAL_ROLE2))
-              .createGenericTable(TABLE_NS1_1_GENERIC, "format", "doc", 
Map.of());
+              .createGenericTable(TABLE_NS1_1_GENERIC, "format", 
"file:///temp/", "doc", Map.of());
         });
   }
 
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalog.java
 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalog.java
index 197be3645..ff1661290 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalog.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalog.java
@@ -32,7 +32,11 @@ public interface GenericTableCatalog {
 
   /** Create a generic table with the specified identifier */
   GenericTableEntity createGenericTable(
-      TableIdentifier tableIdentifier, String format, String doc, Map<String, 
String> properties);
+      TableIdentifier tableIdentifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> properties);
 
   /** Retrieve a generic table entity with a given identifier */
   GenericTableEntity loadGenericTable(TableIdentifier tableIdentifier);
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
index 0c40960f5..ddc03a291 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
@@ -101,6 +101,7 @@ public class GenericTableCatalogAdapter
         handler.createGenericTable(
             TableIdentifier.of(decodeNamespace(namespace), 
createGenericTableRequest.getName()),
             createGenericTableRequest.getFormat(),
+            createGenericTableRequest.getBaseLocation(),
             createGenericTableRequest.getDoc(),
             
reservedProperties.removeReservedProperties(createGenericTableRequest.getProperties()));
 
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
index 66a2b81d1..670cddbb0 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
@@ -69,16 +69,22 @@ public class GenericTableCatalogHandler extends 
CatalogHandler {
   }
 
   public LoadGenericTableResponse createGenericTable(
-      TableIdentifier identifier, String format, String doc, Map<String, 
String> properties) {
+      TableIdentifier identifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> properties) {
     PolarisAuthorizableOperation op = 
PolarisAuthorizableOperation.CREATE_TABLE_DIRECT;
     authorizeCreateTableLikeUnderNamespaceOperationOrThrow(op, identifier);
 
     GenericTableEntity createdEntity =
-        this.genericTableCatalog.createGenericTable(identifier, format, doc, 
properties);
+        this.genericTableCatalog.createGenericTable(
+            identifier, format, baseLocation, doc, properties);
     GenericTable createdTable =
         GenericTable.builder()
             .setName(createdEntity.getName())
             .setFormat(createdEntity.getFormat())
+            .setBaseLocation(createdEntity.getBaseLocation())
             .setDoc(createdEntity.getDoc())
             .setProperties(createdEntity.getPropertiesAsMap())
             .build();
@@ -102,6 +108,7 @@ public class GenericTableCatalogHandler extends 
CatalogHandler {
         GenericTable.builder()
             .setName(loadedEntity.getName())
             .setFormat(loadedEntity.getFormat())
+            .setBaseLocation(loadedEntity.getBaseLocation())
             .setDoc(loadedEntity.getDoc())
             .setProperties(loadedEntity.getPropertiesAsMap())
             .build();
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
index 2b884e787..a198c6cb3 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
@@ -75,7 +75,11 @@ public class PolarisGenericTableCatalog implements 
GenericTableCatalog {
 
   @Override
   public GenericTableEntity createGenericTable(
-      TableIdentifier tableIdentifier, String format, String doc, Map<String, 
String> properties) {
+      TableIdentifier tableIdentifier,
+      String format,
+      String baseLocation,
+      String doc,
+      Map<String, String> properties) {
     PolarisResolvedPathWrapper resolvedParent =
         resolvedEntityView.getResolvedPath(tableIdentifier.namespace());
     if (resolvedParent == null) {
@@ -105,6 +109,7 @@ public class PolarisGenericTableCatalog implements 
GenericTableCatalog {
                       .getId())
               .setProperties(properties)
               .setDoc(doc)
+              .setBaseLocation(baseLocation)
               .setCreateTimestamp(System.currentTimeMillis())
               .build();
     } else {

Reply via email to