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 99802d3cbb..08116c9e66 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 props); + TableIdentifier identifier, + String format, + String baseLocation, + String doc, + Map 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 5dfd1f8981..5be0f6952e 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 boolean dropGenericTable(TableIdentifier identifier) { @Override public GenericTable createGenericTable( - TableIdentifier identifier, String format, String doc, Map props) { + TableIdentifier identifier, + String format, + String baseLocation, + String doc, + Map 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 fe0c6e180f..964674e54a 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.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 @@ * 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 Table createTable( 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 e7cd76bcaf..df433ec9fe 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 static Table loadSparkTable(GenericTable genericTable) { boolean hasPathClause = properties.get(TABLE_PATH_KEY) != null; Map 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 c846659df0..2d71d9cb6e 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 boolean dropGenericTable(TableIdentifier identifier) { @Override public GenericTable createGenericTable( - TableIdentifier identifier, String format, String doc, Map props) { + TableIdentifier identifier, + String format, + String baseLocation, + String doc, + Map props) { if (!namespaceExists(identifier.namespace())) { throw new NoSuchNamespaceException( "Cannot create generic table %s. Namespace does not exist: %s", @@ -78,6 +82,7 @@ public GenericTable createGenericTable( 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 d4d4da6abe..0f7d3c99b3 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 void setUp() { @ParameterizedTest @MethodSource("genericTableTestCases") - public void testLoadGenericTableRESTResponse(String doc, Map properties) + public void testLoadGenericTableRESTResponse( + String baseLocation, String doc, Map 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 void testLoadGenericTableRESTResponse(String doc, Map pro 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 properties) + public void testCreateGenericTableRESTRequest( + String baseLocation, String doc, Map properties) throws JsonProcessingException { CreateGenericTableRESTRequest request = new CreateGenericTableRESTRequest( @@ -94,6 +100,7 @@ public void testCreateGenericTableRESTRequest(String doc, Map pr .setName("test-table") .setFormat("delta") .setDoc(doc) + .setBaseLocation(baseLocation) .setProperties(properties) .build()); String json = mapper.writeValueAsString(request); @@ -103,6 +110,7 @@ public void testCreateGenericTableRESTRequest(String doc, Map pr 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 @@ private static Stream genericTableTestCases() { 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 a5eae86fe8..5f9250803e 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.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 String getDoc() { 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 { public Builder(TableIdentifier tableIdentifier, String format) { @@ -79,6 +86,11 @@ public GenericTableEntity.Builder setDoc(String doc) { 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 21e9229829..57d15a1036 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 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 @@ * 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 22808d1a7b..21ba80f4a9 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 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 013e2c99ef..c86cefe6ec 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 void before(TestInfo testInfo) { 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 ea044fbab1..ade4768f46 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.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 void testCreateGenericTableDoesNotThrow() { 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 void testGenericTableAlreadyExists() { 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 void testIcebergTableAlreadyExists() { 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 void testIcebergTableAlreadyExists() { .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 void testGenericTableRoundTrip() { 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 void testGenericTableRoundTrip() { 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 void testReadGenericAsIcebergTable() { 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 void testReadGenericAsIcebergView() { 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 void testListTables() { 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 listResult = genericTableCatalog.listGenericTables(namespace); @@ -468,7 +474,7 @@ public void testListMixedTables() { 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 void testDropViaIceberg() { 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 void testDropViaIcebergView() { 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 6deb37bb3e..446e5505b0 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 void testCreateGenericTableAllSufficientPrivileges() { 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 void testCreateGenericTableInsufficientPermissions() { 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 void testDropGenericTableAllSufficientPrivileges() { }, () -> { 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 197be36452..ff16612907 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 properties); + TableIdentifier tableIdentifier, + String format, + String baseLocation, + String doc, + Map 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 0c40960f59..ddc03a291c 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 Response createGenericTable( 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 66a2b81d19..670cddbb04 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 ListGenericTablesResponse listGenericTables(Namespace parent) { } public LoadGenericTableResponse createGenericTable( - TableIdentifier identifier, String format, String doc, Map properties) { + TableIdentifier identifier, + String format, + String baseLocation, + String doc, + Map 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 LoadGenericTableResponse loadGenericTable(TableIdentifier identifier) { 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 2b884e787f..a198c6cb34 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 void initialize(String name, Map properties) { @Override public GenericTableEntity createGenericTable( - TableIdentifier tableIdentifier, String format, String doc, Map properties) { + TableIdentifier tableIdentifier, + String format, + String baseLocation, + String doc, + Map properties) { PolarisResolvedPathWrapper resolvedParent = resolvedEntityView.getResolvedPath(tableIdentifier.namespace()); if (resolvedParent == null) { @@ -105,6 +109,7 @@ public GenericTableEntity createGenericTable( .getId()) .setProperties(properties) .setDoc(doc) + .setBaseLocation(baseLocation) .setCreateTimestamp(System.currentTimeMillis()) .build(); } else {