This is an automated email from the ASF dual-hosted git repository.
adutra pushed a commit to branch feature/iceberg-1.11
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/feature/iceberg-1.11 by this
push:
new 5aadc851e [Iceberg 1.11] Update REST spec (#3687)
5aadc851e is described below
commit 5aadc851e1df24e3e0a99f5d4951e067a69f5984
Author: Alexandre Dutra <[email protected]>
AuthorDate: Tue Feb 10 09:49:25 2026 +0100
[Iceberg 1.11] Update REST spec (#3687)
---
.../catalog/iceberg/IcebergCatalogAdapter.java | 20 +-
.../IcebergRestCatalogEventServiceDelegator.java | 83 +++++-
.../admin/PolarisS3InteroperabilityTest.java | 3 +
.../iceberg/CommitTransactionEventTest.java | 4 +
.../iceberg/IcebergAllowedLocationTest.java | 4 +
.../iceberg/IcebergOverlappingTableTest.java | 3 +
.../service/catalog/io/FileIOExceptionsTest.java | 18 +-
.../generated/bundled-polaris-catalog-service.yaml | 235 +++++++++++++---
spec/iceberg-rest-catalog-open-api.yaml | 296 +++++++++++++++++----
9 files changed, 550 insertions(+), 116 deletions(-)
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
index a240186d0..69735c357 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
@@ -31,6 +31,7 @@ import jakarta.ws.rs.core.SecurityContext;
import java.time.Clock;
import java.util.EnumSet;
import java.util.Optional;
+import java.util.UUID;
import java.util.function.Function;
import org.apache.iceberg.MetadataUpdate;
import org.apache.iceberg.catalog.Namespace;
@@ -141,6 +142,7 @@ public class IcebergCatalogAdapter
public Response createNamespace(
String prefix,
CreateNamespaceRequest createNamespaceRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
validateIcebergProperties(realmConfig,
createNamespaceRequest.properties());
@@ -217,7 +219,11 @@ public class IcebergCatalogAdapter
@Override
public Response dropNamespace(
- String prefix, String namespace, RealmContext realmContext,
SecurityContext securityContext) {
+ String prefix,
+ String namespace,
+ UUID idempotencyKey,
+ RealmContext realmContext,
+ SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
return withCatalog(
securityContext,
@@ -233,6 +239,7 @@ public class IcebergCatalogAdapter
String prefix,
String namespace,
UpdateNamespacePropertiesRequest updateNamespacePropertiesRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
validateIcebergProperties(realmConfig,
updateNamespacePropertiesRequest.updates());
@@ -268,6 +275,7 @@ public class IcebergCatalogAdapter
String namespace,
CreateTableRequest createTableRequest,
String accessDelegationMode,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
validateIcebergProperties(realmConfig, createTableRequest.properties());
@@ -388,6 +396,7 @@ public class IcebergCatalogAdapter
String prefix,
String namespace,
String table,
+ UUID idempotencyKey,
Boolean purgeRequested,
RealmContext realmContext,
SecurityContext securityContext) {
@@ -411,6 +420,8 @@ public class IcebergCatalogAdapter
String prefix,
String namespace,
RegisterTableRequest registerTableRequest,
+ String accessDelegationMode,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
@@ -429,6 +440,7 @@ public class IcebergCatalogAdapter
public Response renameTable(
String prefix,
RenameTableRequest renameTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
return withCatalog(
@@ -446,6 +458,7 @@ public class IcebergCatalogAdapter
String namespace,
String table,
CommitTableRequest commitTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
commitTableRequest.updates().stream()
@@ -515,6 +528,7 @@ public class IcebergCatalogAdapter
String prefix,
String namespace,
String table,
+ String planId,
RealmContext realmContext,
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
@@ -572,6 +586,7 @@ public class IcebergCatalogAdapter
String prefix,
String namespace,
String view,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
@@ -589,6 +604,7 @@ public class IcebergCatalogAdapter
public Response renameView(
String prefix,
RenameTableRequest renameTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
return withCatalog(
@@ -606,6 +622,7 @@ public class IcebergCatalogAdapter
String namespace,
String view,
CommitViewRequest commitViewRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
UpdateTableRequest revisedRequest =
@@ -627,6 +644,7 @@ public class IcebergCatalogAdapter
public Response commitTransaction(
String prefix,
CommitTransactionRequest commitTransactionRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
commitTransactionRequest.tableChanges().stream()
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergRestCatalogEventServiceDelegator.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergRestCatalogEventServiceDelegator.java
index ee3def12a..f4a098105 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergRestCatalogEventServiceDelegator.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergRestCatalogEventServiceDelegator.java
@@ -27,6 +27,7 @@ import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import java.util.List;
+import java.util.UUID;
import org.apache.iceberg.TableMetadata;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.rest.requests.CommitTransactionRequest;
@@ -90,6 +91,7 @@ public class IcebergRestCatalogEventServiceDelegator
public Response createNamespace(
String prefix,
CreateNamespaceRequest createNamespaceRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -101,7 +103,8 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.CATALOG_NAME, catalogName)
.put(EventAttributes.CREATE_NAMESPACE_REQUEST,
createNamespaceRequest)));
Response resp =
- delegate.createNamespace(prefix, createNamespaceRequest, realmContext,
securityContext);
+ delegate.createNamespace(
+ prefix, createNamespaceRequest, idempotencyKey, realmContext,
securityContext);
CreateNamespaceResponse createNamespaceResponse =
(CreateNamespaceResponse) resp.getEntity();
polarisEventListener.onEvent(
new PolarisEvent(
@@ -192,7 +195,11 @@ public class IcebergRestCatalogEventServiceDelegator
@Override
public Response dropNamespace(
- String prefix, String namespace, RealmContext realmContext,
SecurityContext securityContext) {
+ String prefix,
+ String namespace,
+ UUID idempotencyKey,
+ RealmContext realmContext,
+ SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
polarisEventListener.onEvent(
new PolarisEvent(
@@ -201,7 +208,8 @@ public class IcebergRestCatalogEventServiceDelegator
new EventAttributeMap()
.put(EventAttributes.CATALOG_NAME, catalogName)
.put(EventAttributes.NAMESPACE, decodeNamespace(namespace))));
- Response resp = delegate.dropNamespace(prefix, namespace, realmContext,
securityContext);
+ Response resp =
+ delegate.dropNamespace(prefix, namespace, idempotencyKey,
realmContext, securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_DROP_NAMESPACE,
@@ -217,6 +225,7 @@ public class IcebergRestCatalogEventServiceDelegator
String prefix,
String namespace,
UpdateNamespacePropertiesRequest updateNamespacePropertiesRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -233,7 +242,12 @@ public class IcebergRestCatalogEventServiceDelegator
updateNamespacePropertiesRequest)));
Response resp =
delegate.updateProperties(
- prefix, namespace, updateNamespacePropertiesRequest, realmContext,
securityContext);
+ prefix,
+ namespace,
+ updateNamespacePropertiesRequest,
+ idempotencyKey,
+ realmContext,
+ securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_UPDATE_NAMESPACE_PROPERTIES,
@@ -253,6 +267,7 @@ public class IcebergRestCatalogEventServiceDelegator
String namespace,
CreateTableRequest createTableRequest,
String accessDelegationMode,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -272,6 +287,7 @@ public class IcebergRestCatalogEventServiceDelegator
namespace,
createTableRequest,
accessDelegationMode,
+ idempotencyKey,
realmContext,
securityContext);
if (!createTableRequest.stageCreate()) {
@@ -397,6 +413,7 @@ public class IcebergRestCatalogEventServiceDelegator
String prefix,
String namespace,
String table,
+ UUID idempotencyKey,
Boolean purgeRequested,
RealmContext realmContext,
SecurityContext securityContext) {
@@ -412,7 +429,14 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.TABLE_NAME, table)
.put(EventAttributes.PURGE_REQUESTED, purgeRequested)));
Response resp =
- delegate.dropTable(prefix, namespace, table, purgeRequested,
realmContext, securityContext);
+ delegate.dropTable(
+ prefix,
+ namespace,
+ table,
+ idempotencyKey,
+ purgeRequested,
+ realmContext,
+ securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_DROP_TABLE,
@@ -430,6 +454,8 @@ public class IcebergRestCatalogEventServiceDelegator
String prefix,
String namespace,
RegisterTableRequest registerTableRequest,
+ String accessDelegationMode,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -444,7 +470,13 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.REGISTER_TABLE_REQUEST,
registerTableRequest)));
Response resp =
delegate.registerTable(
- prefix, namespace, registerTableRequest, realmContext,
securityContext);
+ prefix,
+ namespace,
+ registerTableRequest,
+ accessDelegationMode,
+ idempotencyKey,
+ realmContext,
+ securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_REGISTER_TABLE,
@@ -461,6 +493,7 @@ public class IcebergRestCatalogEventServiceDelegator
public Response renameTable(
String prefix,
RenameTableRequest renameTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -471,7 +504,9 @@ public class IcebergRestCatalogEventServiceDelegator
new EventAttributeMap()
.put(EventAttributes.CATALOG_NAME, catalogName)
.put(EventAttributes.RENAME_TABLE_REQUEST,
renameTableRequest)));
- Response resp = delegate.renameTable(prefix, renameTableRequest,
realmContext, securityContext);
+ Response resp =
+ delegate.renameTable(
+ prefix, renameTableRequest, idempotencyKey, realmContext,
securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_RENAME_TABLE,
@@ -488,6 +523,7 @@ public class IcebergRestCatalogEventServiceDelegator
String namespace,
String table,
CommitTableRequest commitTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -503,7 +539,13 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.UPDATE_TABLE_REQUEST,
commitTableRequest)));
Response resp =
delegate.updateTable(
- prefix, namespace, table, commitTableRequest, realmContext,
securityContext);
+ prefix,
+ namespace,
+ table,
+ commitTableRequest,
+ idempotencyKey,
+ realmContext,
+ securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_UPDATE_TABLE,
@@ -584,6 +626,7 @@ public class IcebergRestCatalogEventServiceDelegator
String prefix,
String namespace,
String table,
+ String planId,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -597,7 +640,7 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.NAMESPACE, namespaceObj)
.put(EventAttributes.TABLE_NAME, table)));
Response resp =
- delegate.loadCredentials(prefix, namespace, table, realmContext,
securityContext);
+ delegate.loadCredentials(prefix, namespace, table, planId,
realmContext, securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_LOAD_CREDENTIALS,
@@ -673,6 +716,7 @@ public class IcebergRestCatalogEventServiceDelegator
String prefix,
String namespace,
String view,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -685,7 +729,8 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.CATALOG_NAME, catalogName)
.put(EventAttributes.NAMESPACE, namespaceObj)
.put(EventAttributes.VIEW_NAME, view)));
- Response resp = delegate.dropView(prefix, namespace, view, realmContext,
securityContext);
+ Response resp =
+ delegate.dropView(prefix, namespace, view, idempotencyKey,
realmContext, securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_DROP_VIEW,
@@ -701,6 +746,7 @@ public class IcebergRestCatalogEventServiceDelegator
public Response renameView(
String prefix,
RenameTableRequest renameTableRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -711,7 +757,9 @@ public class IcebergRestCatalogEventServiceDelegator
new EventAttributeMap()
.put(EventAttributes.CATALOG_NAME, catalogName)
.put(EventAttributes.RENAME_TABLE_REQUEST,
renameTableRequest)));
- Response resp = delegate.renameView(prefix, renameTableRequest,
realmContext, securityContext);
+ Response resp =
+ delegate.renameView(
+ prefix, renameTableRequest, idempotencyKey, realmContext,
securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_RENAME_VIEW,
@@ -728,6 +776,7 @@ public class IcebergRestCatalogEventServiceDelegator
String namespace,
String view,
CommitViewRequest commitViewRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -743,7 +792,13 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.COMMIT_VIEW_REQUEST, commitViewRequest)));
Response resp =
delegate.replaceView(
- prefix, namespace, view, commitViewRequest, realmContext,
securityContext);
+ prefix,
+ namespace,
+ view,
+ commitViewRequest,
+ idempotencyKey,
+ realmContext,
+ securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_REPLACE_VIEW,
@@ -761,6 +816,7 @@ public class IcebergRestCatalogEventServiceDelegator
public Response commitTransaction(
String prefix,
CommitTransactionRequest commitTransactionRequest,
+ UUID idempotencyKey,
RealmContext realmContext,
SecurityContext securityContext) {
String catalogName = prefixParser.prefixToCatalogName(prefix);
@@ -783,7 +839,8 @@ public class IcebergRestCatalogEventServiceDelegator
.put(EventAttributes.UPDATE_TABLE_REQUEST, req)));
}
Response resp =
- delegate.commitTransaction(prefix, commitTransactionRequest,
realmContext, securityContext);
+ delegate.commitTransaction(
+ prefix, commitTransactionRequest, idempotencyKey, realmContext,
securityContext);
polarisEventListener.onEvent(
new PolarisEvent(
PolarisEventType.AFTER_COMMIT_TRANSACTION,
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisS3InteroperabilityTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisS3InteroperabilityTest.java
index d984234a6..6f849e3ad 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisS3InteroperabilityTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisS3InteroperabilityTest.java
@@ -28,6 +28,7 @@ import jakarta.ws.rs.core.Response;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.function.Supplier;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.exceptions.ForbiddenException;
@@ -134,6 +135,7 @@ public class PolarisS3InteroperabilityTest {
.createNamespace(
catalogName,
createNamespaceRequest,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
@@ -165,6 +167,7 @@ public class PolarisS3InteroperabilityTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/CommitTransactionEventTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/CommitTransactionEventTest.java
index 46822e28e..917bb9367 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/CommitTransactionEventTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/CommitTransactionEventTest.java
@@ -27,6 +27,7 @@ import jakarta.ws.rs.core.Response;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import org.apache.iceberg.MetadataUpdate;
import org.apache.iceberg.TableMetadata;
import org.apache.iceberg.UpdateRequirement;
@@ -177,6 +178,7 @@ public class CommitTransactionEventTest {
.createNamespace(
catalog,
createNamespaceRequest,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
@@ -197,6 +199,7 @@ public class CommitTransactionEventTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext());
}
@@ -235,6 +238,7 @@ public class CommitTransactionEventTest {
.commitTransaction(
catalog,
generateCommitTransactionRequest(shouldFail, table1Name,
table2Name),
+ new UUID(0L, 0L) /* TODO UUID v7 */,
testServices.realmContext(),
testServices.securityContext());
} catch (Exception ignored) {
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 d7a48e481..361b34f79 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
@@ -102,6 +102,7 @@ public class IcebergAllowedLocationTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext()));
}
@@ -131,6 +132,7 @@ public class IcebergAllowedLocationTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext());
@@ -327,6 +329,7 @@ public class IcebergAllowedLocationTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext());
assertThat(createResponse.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
@@ -401,6 +404,7 @@ public class IcebergAllowedLocationTest {
.createNamespace(
catalog,
createNamespaceRequest,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergOverlappingTableTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergOverlappingTableTest.java
index d73fd3d1f..9f9adc94f 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergOverlappingTableTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergOverlappingTableTest.java
@@ -76,6 +76,7 @@ public class IcebergOverlappingTableTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
return response.getStatus();
@@ -99,6 +100,7 @@ public class IcebergOverlappingTableTest {
namespace,
createTableRequest,
null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
if (response.getStatus() != Response.Status.OK.getStatusCode()) {
@@ -149,6 +151,7 @@ public class IcebergOverlappingTableTest {
.createNamespace(
catalog,
createNamespaceRequest,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOExceptionsTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOExceptionsTest.java
index fbc98fa85..3dba4a5f1 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOExceptionsTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/io/FileIOExceptionsTest.java
@@ -30,6 +30,7 @@ import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.UUID;
import java.util.stream.Stream;
import org.apache.iceberg.Schema;
import org.apache.iceberg.catalog.Namespace;
@@ -108,6 +109,7 @@ public class FileIOExceptionsTest {
.createNamespace(
FileIOExceptionsTest.catalog,
CreateNamespaceRequest.builder().withNamespace(Namespace.of("ns1")).build(),
+ new UUID(0L, 0L) /* TODO UUID v7 */,
services.realmContext(),
services.securityContext())) {
assertThat(res.getStatus()).isEqualTo(200);
@@ -128,7 +130,13 @@ public class FileIOExceptionsTest {
services
.restApi()
.createTable(
- catalog, "ns1", request, null, services.realmContext(),
services.securityContext());
+ catalog,
+ "ns1",
+ request,
+ null,
+ new UUID(0L, 0L) /* TODO UUID v7 */,
+ services.realmContext(),
+ services.securityContext());
res.close();
}
@@ -137,7 +145,13 @@ public class FileIOExceptionsTest {
services
.restApi()
.dropTable(
- catalog, "ns1", "t1", false, services.realmContext(),
services.securityContext());
+ catalog,
+ "ns1",
+ "t1",
+ new UUID(0L, 0L) /* TODO UUID v7 */,
+ false,
+ services.realmContext(),
+ services.securityContext());
res.close();
}
diff --git a/spec/generated/bundled-polaris-catalog-service.yaml
b/spec/generated/bundled-polaris-catalog-service.yaml
index 7dffb017d..53cbe35bc 100644
--- a/spec/generated/bundled-polaris-catalog-service.yaml
+++ b/spec/generated/bundled-polaris-catalog-service.yaml
@@ -90,6 +90,7 @@ paths:
warehouse: s3://bucket/warehouse/
defaults:
clients: '4'
+ idempotency-key-lifetime: PT30M
endpoints:
- GET /v1/{prefix}/namespaces/{namespace}
- GET /v1/{prefix}/namespaces
@@ -168,12 +169,10 @@ paths:
parameters:
- $ref: '#/components/parameters/page-token'
- $ref: '#/components/parameters/page-size'
- - $ref: '#/components/parameters/prefix'
- name: parent
in: query
- description: An optional namespace, underneath which to list
namespaces. If not provided or empty, all top-level namespaces should be
listed. If parent is a multipart namespace, the parts must be separated by the
unit separator (`0x1F`) byte.
+ description: An optional namespace, underneath which to list
namespaces. If not provided, all top-level namespaces should be listed. For
backward compatibility, empty string is treated as absent for now. If parent is
a multipart namespace, the parts must be separated by the namespace separator
as indicated via the /config override `namespace-separator`, which defaults to
the unit separator `0x1F` byte (url encoded `%1F`). To be compatible with older
clients, servers must use bo [...]
required: false
- allowEmptyValue: true
schema:
type: string
example: accounting%1Ftax
@@ -205,6 +204,8 @@ paths:
tags:
- Catalog API
summary: Create a namespace
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: Create a namespace, with an optional set of properties. The
server might also add properties, such as `last_modified_time` etc.
operationId: createNamespace
requestBody:
@@ -308,6 +309,8 @@ paths:
- Catalog API
summary: Drop a namespace from the catalog. Namespace must be empty.
operationId: dropNamespace
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
responses:
'204':
description: Success, no content
@@ -326,6 +329,15 @@ paths:
examples:
NoSuchNamespaceExample:
$ref: '#/components/examples/NoSuchNamespaceError'
+ '409':
+ description: Not Empty - Namespace to delete is not empty.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IcebergErrorResponse'
+ examples:
+ NamespaceNotEmptyExample:
+ $ref: '#/components/examples/NamespaceNotEmptyError'
'419':
$ref: '#/components/responses/AuthenticationTimeoutResponse'
'503':
@@ -341,6 +353,8 @@ paths:
- Catalog API
summary: Set or remove properties on a namespace
operationId: updateProperties
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: |-
Set and/or remove properties on a namespace. The request body
specifies a list of properties to remove and a map of key value pairs to update.
Properties that are not in the request are not modified or removed by
this call.
@@ -400,8 +414,6 @@ paths:
description: Return all table identifiers under this namespace
operationId: listTables
parameters:
- - $ref: '#/components/parameters/prefix'
- - $ref: '#/components/parameters/namespace'
- $ref: '#/components/parameters/page-token'
- $ref: '#/components/parameters/page-size'
responses:
@@ -440,9 +452,8 @@ paths:
If `stage-create` is true, the table is not created, but table
metadata is initialized and returned. The service should prepare as needed for
a commit to the table commit endpoint to complete the create transaction. The
client uses the returned metadata to begin a transaction. To commit the
transaction, the client sends all create and subsequent changes to the table
commit route. Changes from the table create operation include changes like
AddSchemaUpdate and SetCurrentSchemaUpda [...]
operationId: createTable
parameters:
- - $ref: '#/components/parameters/prefix'
- - $ref: '#/components/parameters/namespace'
- $ref: '#/components/parameters/data-access'
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
required: true
content:
@@ -474,7 +485,7 @@ paths:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
examples:
- NamespaceAlreadyExists:
+ TableAlreadyExists:
$ref: '#/components/examples/TableAlreadyExistsError'
'419':
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -490,6 +501,9 @@ paths:
tags:
- Catalog API
summary: Register a table in the given namespace using given metadata
file location
+ parameters:
+ - $ref: '#/components/parameters/data-access'
+ - $ref: '#/components/parameters/idempotency-key'
description: Register a table using given metadata file location.
operationId: registerTable
requestBody:
@@ -523,7 +537,7 @@ paths:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
examples:
- NamespaceAlreadyExists:
+ TableAlreadyExists:
$ref: '#/components/examples/TableAlreadyExistsError'
'419':
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -550,13 +564,10 @@ paths:
The catalog configuration may contain credentials that should be used
for subsequent requests for the table. The configuration key "token" is used to
pass an access token to be used as a bearer token for table requests.
Otherwise, a token may be passed using a RFC 8693 token type as a configuration
key. For example, "urn:ietf:params:oauth:token-type:jwt=<JWT-token>".
parameters:
- - $ref: '#/components/parameters/prefix'
- - $ref: '#/components/parameters/namespace'
- - $ref: '#/components/parameters/table'
- $ref: '#/components/parameters/data-access'
- name: If-None-Match
in: header
- description: An optional header that allows the server to return 304
(Not Modified) if the metadata is current. The content is the value of the ETag
received in a CreateTableResponse or LoadTableResponse.
+ description: An optional header that allows the server to return 304
(Not Modified) if the metadata is current. The content is the value of the ETag
received in a CreateTableResponse, LoadTableResponse or CommitTableResponse.
required: false
schema:
type: string
@@ -602,6 +613,8 @@ paths:
- Catalog API
summary: Commit updates to a table
operationId: updateTable
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: |-
Commit updates to a table.
@@ -695,6 +708,7 @@ paths:
operationId: dropTable
description: Remove a table from the catalog
parameters:
+ - $ref: '#/components/parameters/idempotency-key'
- name: purgeRequested
in: query
required: false
@@ -766,6 +780,13 @@ paths:
- Catalog API
summary: Load vended credentials for a table from the catalog
operationId: loadCredentials
+ parameters:
+ - name: planId
+ in: query
+ required: false
+ schema:
+ type: string
+ description: The plan ID that has been used for server-side scan
planning
description: Load vended credentials for a table from the catalog.
responses:
'200':
@@ -798,6 +819,8 @@ paths:
tags:
- Catalog API
summary: Rename a table from its current name to a new name
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: Rename a table from one identifier to another. It's valid
to move a table across namespaces, but the server implementation is not
required to support it.
operationId: renameTable
requestBody:
@@ -900,6 +923,8 @@ paths:
- Catalog API
summary: Commit updates to multiple tables in an atomic operation
operationId: commitTransaction
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
description: |-
Commit updates to multiple tables in an atomic operation
@@ -994,8 +1019,6 @@ paths:
description: Return all view identifiers under this namespace
operationId: listViews
parameters:
- - $ref: '#/components/parameters/prefix'
- - $ref: '#/components/parameters/namespace'
- $ref: '#/components/parameters/page-token'
- $ref: '#/components/parameters/page-size'
responses:
@@ -1059,7 +1082,7 @@ paths:
schema:
$ref: '#/components/schemas/ErrorModel'
examples:
- NamespaceAlreadyExists:
+ ViewAlreadyExists:
$ref: '#/components/examples/ViewAlreadyExistsError'
'419':
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -1114,6 +1137,8 @@ paths:
- Catalog API
summary: Replace a view
operationId: replaceView
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: Commit updates to a view.
requestBody:
required: true
@@ -1199,6 +1224,8 @@ paths:
summary: Drop a view from the catalog
operationId: dropView
description: Remove a view from the catalog
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
responses:
'204':
description: Success, no content
@@ -1253,6 +1280,8 @@ paths:
summary: Rename a view from its current name to a new name
description: Rename a view from one identifier to another. It's valid to
move a view across namespaces, but the server implementation is not required to
support it.
operationId: renameView
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
description: Current view identifier to rename and new view identifier
to rename to
content:
@@ -1959,6 +1988,11 @@ components:
- POST /v1/{prefix}/namespaces
- GET /v1/{prefix}/namespaces/{namespace}/tables/{table}
- GET /v1/{prefix}/namespaces/{namespace}/views/{view}
+ idempotency-key-lifetime:
+ type: string
+ format: duration
+ description: Client reuse window for an Idempotency-Key (ISO-8601
duration, e.g., PT30M, PT24H). Interpreted as the maximum time from the first
submission using a key to the last retry during which a client may reuse that
key. Servers SHOULD accept retries for at least this duration and MAY include a
grace period to account for delays/clock skew. Clients SHOULD NOT reuse an
Idempotency-Key after this window elapses; they SHOULD generate a new key for
any subsequent attempt. Pre [...]
+ example: PT30M
ErrorModel:
type: object
description: JSON error payload returned in a response with further
details on the error
@@ -2355,7 +2389,7 @@ components:
example: 123.456
DecimalTypeValue:
type: string
- description: Decimal type values are serialized as strings. Decimals
with a positive scale serialize as numeric plain text, while decimals with a
negative scale use scientific notation and the exponent will be equal to the
negated scale. For instance, a decimal with a positive scale is '123.4500',
with zero scale is '2', and with a negative scale is '2E+20'
+ description: Decimal type values are serialized as strings. Decimals
with a positive scale serialize as numeric plain text, while decimals with a
negative scale use scientific notation and the exponent will be equal to the
negated scale. For instance, a decimal with a positive scale is '123.4500',
with zero scale is '2', and with a negative scale is '2E+20'
example: '123.4500'
StringTypeValue:
type: string
@@ -2366,7 +2400,7 @@ components:
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
maxLength: 36
minLength: 36
- description: UUID type values are serialized as a 36-character lowercase
string in standard UUID format as specified by RFC-4122
+ description: UUID type values are serialized as a 36-character lowercase
string in standard UUID format as specified by RFC-4122
example: eb26bdb1-a1d8-4aa6-990e-da940875492c
DateTypeValue:
type: string
@@ -2383,7 +2417,7 @@ components:
example: '2007-12-03T10:15:30.123456'
TimestampTzTypeValue:
type: string
- description: TimestampTz type values follow the
'YYYY-MM-DDTHH:MM:SS.ssssss+00:00' ISO-8601 format with microsecond precision,
and a timezone offset (+00:00 for UTC)
+ description: TimestampTz type values follow the
'YYYY-MM-DDTHH:MM:SS.ssssss+00:00' ISO-8601 format with microsecond precision,
and a timezone offset (+00:00 for UTC)
example: '2007-12-03T10:15:30.123456+00:00'
TimestampNanoTypeValue:
type: string
@@ -2391,11 +2425,11 @@ components:
example: '2007-12-03T10:15:30.123456789'
TimestampTzNanoTypeValue:
type: string
- description: Timestamp_ns type values follow the
'YYYY-MM-DDTHH:MM:SS.sssssssss+00:00' ISO-8601 format with nanosecond
precision, and a timezone offset (+00:00 for UTC)
+ description: Timestamp_ns type values follow the
'YYYY-MM-DDTHH:MM:SS.sssssssss+00:00' ISO-8601 format with nanosecond
precision, and a timezone offset (+00:00 for UTC)
example: '2007-12-03T10:15:30.123456789+00:00'
FixedTypeValue:
type: string
- description: Fixed length type values are stored and serialized as an
uppercase hexadecimal string preserving the fixed length
+ description: Fixed length type values are stored and serialized as an
uppercase hexadecimal string preserving the fixed length
example: 78797A
BinaryTypeValue:
type: string
@@ -2551,6 +2585,24 @@ components:
type: object
additionalProperties:
type: string
+ EncryptedKey:
+ type: object
+ required:
+ - key-id
+ - encrypted-key-metadata
+ properties:
+ key-id:
+ type: string
+ encrypted-key-metadata:
+ type: string
+ format: byte
+ contentEncoding: base64
+ encrypted-by-id:
+ type: string
+ properties:
+ type: object
+ additionalProperties:
+ type: string
Snapshot:
type: object
required:
@@ -2574,6 +2626,14 @@ components:
manifest-list:
type: string
description: Location of the snapshot's manifest list file
+ first-row-id:
+ type: integer
+ format: int64
+ description: The first _row_id assigned to the first row in the
first data file in the first manifest
+ added-rows:
+ type: integer
+ format: int64
+ description: The upper bound of the number of rows with assigned row
IDs
summary:
type: object
required:
@@ -2715,7 +2775,7 @@ components:
format-version:
type: integer
minimum: 1
- maximum: 2
+ maximum: 3
table-uuid:
type: string
location:
@@ -2723,6 +2783,10 @@ components:
last-updated-ms:
type: integer
format: int64
+ next-row-id:
+ type: integer
+ format: int64
+ description: A long higher than all assigned row IDs; the next
snapshot's first-row-id.
properties:
type: object
additionalProperties:
@@ -2749,6 +2813,10 @@ components:
$ref: '#/components/schemas/SortOrder'
default-sort-order-id:
type: integer
+ encryption-keys:
+ type: array
+ items:
+ $ref: '#/components/schemas/EncryptedKey'
snapshots:
type: array
items:
@@ -2802,15 +2870,15 @@ components:
## General Configurations
- - `token`: Authorization bearer token to use for table requests if
OAuth2 security is enabled
+ - `token`: Authorization bearer token to use for table requests if
OAuth2 security is enabled
## AWS Configurations
The following configurations should be respected when working with
tables stored in AWS S3
- `client.region`: region to configure client for making requests to
AWS
- `s3.access-key-id`: id for credentials that provide access to the
data in S3
- - `s3.secret-access-key`: secret for credentials that provide access
to data in S3
- - `s3.session-token`: if present, this value should be used for as
the session token
+ - `s3.secret-access-key`: secret for credentials that provide access
to data in S3
+ - `s3.session-token`: if present, this value should be used for as
the session token
- `s3.remote-signing-enabled`: if `true` remote signing should be
performed as described in the `s3-signer-open-api.yaml` specification
- `s3.cross-region-access-enabled`: if `true`, S3 Cross-Region bucket
access is enabled
@@ -2825,6 +2893,7 @@ components:
metadata-location:
type: string
description: May be null if the table is staged as part of a
transaction
+ nullable: true
metadata:
$ref: '#/components/schemas/TableMetadata'
config:
@@ -2845,6 +2914,10 @@ components:
type: string
metadata-location:
type: string
+ overwrite:
+ description: Whether to overwrite table metadata if the table
already exists
+ type: boolean
+ default: false
TableRequirement:
type: object
discriminator:
@@ -2888,7 +2961,10 @@ components:
uuid:
type: string
AssertRefSnapshotId:
- description: The table branch or tag identified by the requirement's
`ref` must reference the requirement's `snapshot-id`; if `snapshot-id` is
`null` or missing, the ref must not already exist
+ description: |
+ The table branch or tag identified by the requirement's `ref` must
reference the requirement's `snapshot-id`.
+ The `snapshot-id` field is required in this object, but in the case of
a `null`
+ the ref must not already exist.
allOf:
- $ref: '#/components/schemas/TableRequirement'
required:
@@ -2903,6 +2979,7 @@ components:
snapshot-id:
type: integer
format: int64
+ nullable: true
AssertLastAssignedFieldId:
description: The table's last assigned column id must match the
requirement's `last-assigned-field-id`
allOf:
@@ -3001,7 +3078,9 @@ components:
set-partition-statistics:
'#/components/schemas/SetPartitionStatisticsUpdate'
remove-partition-statistics:
'#/components/schemas/RemovePartitionStatisticsUpdate'
remove-partition-specs:
'#/components/schemas/RemovePartitionSpecsUpdate'
- enable-row-lineage: '#/components/schemas/EnableRowLineageUpdate'
+ remove-schemas: '#/components/schemas/RemoveSchemasUpdate'
+ add-encryption-key: '#/components/schemas/AddEncryptionKeyUpdate'
+ remove-encryption-key:
'#/components/schemas/RemoveEncryptionKeyUpdate'
type: object
required:
- action
@@ -3312,13 +3391,41 @@ components:
type: array
items:
type: integer
- EnableRowLineageUpdate:
+ RemoveSchemasUpdate:
allOf:
- $ref: '#/components/schemas/BaseUpdate'
+ required:
+ - schema-ids
properties:
action:
type: string
- const: enable-row-lineage
+ const: remove-schemas
+ schema-ids:
+ type: array
+ items:
+ type: integer
+ AddEncryptionKeyUpdate:
+ allOf:
+ - $ref: '#/components/schemas/BaseUpdate'
+ required:
+ - encryption-key
+ properties:
+ action:
+ type: string
+ const: add-encryption-key
+ encryption-key:
+ $ref: '#/components/schemas/EncryptedKey'
+ RemoveEncryptionKeyUpdate:
+ allOf:
+ - $ref: '#/components/schemas/BaseUpdate'
+ required:
+ - key-id
+ properties:
+ action:
+ type: string
+ const: remove-encryption-key
+ key-id:
+ type: string
TableUpdate:
anyOf:
- $ref: '#/components/schemas/AssignUUIDUpdate'
@@ -3338,8 +3445,12 @@ components:
- $ref: '#/components/schemas/RemovePropertiesUpdate'
- $ref: '#/components/schemas/SetStatisticsUpdate'
- $ref: '#/components/schemas/RemoveStatisticsUpdate'
+ - $ref: '#/components/schemas/SetPartitionStatisticsUpdate'
+ - $ref: '#/components/schemas/RemovePartitionStatisticsUpdate'
- $ref: '#/components/schemas/RemovePartitionSpecsUpdate'
- - $ref: '#/components/schemas/EnableRowLineageUpdate'
+ - $ref: '#/components/schemas/RemoveSchemasUpdate'
+ - $ref: '#/components/schemas/AddEncryptionKeyUpdate'
+ - $ref: '#/components/schemas/RemoveEncryptionKeyUpdate'
CommitTableRequest:
type: object
required:
@@ -3499,7 +3610,7 @@ components:
values:
type: array
items:
- type: object
+ $ref: '#/components/schemas/PrimitiveTypeValue'
LiteralExpression:
type: object
required:
@@ -3521,13 +3632,12 @@ components:
term:
$ref: '#/components/schemas/Term'
value:
- type: object
+ $ref: '#/components/schemas/PrimitiveTypeValue'
UnaryExpression:
type: object
required:
- type
- term
- - value
properties:
type:
$ref: '#/components/schemas/ExpressionType'
@@ -3538,8 +3648,6 @@ components:
- not-nan
term:
$ref: '#/components/schemas/Term'
- value:
- type: object
CounterResult:
type: object
required:
@@ -4108,7 +4216,7 @@ components:
type: BadRequestException
code: 400
UnauthorizedResponse:
- description: Unauthorized. Authentication is required and has failed or
has not yet been provided.
+ description: Unauthorized. The REST Catalog SHOULD respond with the 401
UnauthorizedResponse when the access token provided is expired, revoked,
malformed, or invalid for other reasons. The client MAY request a new access
token and retry the request.
content:
application/json:
schema:
@@ -4130,7 +4238,7 @@ components:
type: NotAuthorizedException
code: 403
AuthenticationTimeoutResponse:
- description: Credentials have timed out. If possible, the client should
refresh credentials and retry.
+ description: This is an optional status response type that the REST
Catalog can issue when the token has expired. The client MAY request a new
access token and retry the request. 401 UnauthorizedResponse SHOULD be
preferred over this response type on token expiry.
content:
application/json:
schema:
@@ -4142,9 +4250,8 @@ components:
code: 419
ServiceUnavailableResponse:
description: |-
- The service is not ready to handle the request. The client should wait
and retry.
-
- The service may additionally send a Retry-After header to indicate
when to retry.
+ The service is not ready to handle the request, request could have
been partially processed.
+ The service may additionally send a Retry-After header to indicate
when to retry, a non idempotent request should only be retried by the client
when the Retry-After header is present.
content:
application/json:
schema:
@@ -4268,6 +4375,9 @@ components:
application/json:
schema:
$ref: '#/components/schemas/CommitTableResponse'
+ headers:
+ etag:
+ $ref: '#/components/headers/etag'
LoadCredentialsResponse:
description: Table credentials result when loading credentials for a
table
content:
@@ -4347,7 +4457,6 @@ components:
name: pageToken
in: query
required: false
- allowEmptyValue: true
schema:
$ref: '#/components/schemas/PageToken'
page-size:
@@ -4358,11 +4467,40 @@ components:
schema:
type: integer
minimum: 1
+ idempotency-key:
+ name: Idempotency-Key
+ in: header
+ required: false
+ schema:
+ type: string
+ format: uuid
+ minLength: 36
+ maxLength: 36
+ example: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F
+ description: |
+ Optional client-provided idempotency key for safe request retries.
+
+ When present, the server ensures no additional effects for requests
that carry the same
+ Idempotency-Key. If a prior request with this key has been finalized,
the server returns
+ an equivalent final response without re-running the operation. The
response body may
+ reflect a newer state of the catalog than existed at the time of the
commit.
+
+ Finalization rules:
+ - Finalize & replay: 200, 201, 204, and deterministic terminal 4xx
(including 409
+ such as AlreadyExists, NamespaceNotEmpty, etc.)
+ - Do not finalize (not stored/replayed): 5xx
+
+ Key Requirements:
+ - Key format: UUIDv7 in string form (RFC 9562).
+ - The idempotency key must be globally unique (no reuse across
different operations).
+ - Catalogs SHOULD NOT expire keys before the end of the advertised
token lifetime.
+ - If Idempotency-Key is used, clients MUST reuse the same key when
retrying the same
+ logical operation and MUST generate a new key for a different
operation.
namespace:
name: namespace
in: path
required: true
- description: A namespace identifier as a single string. Multipart
namespace parts should be separated by the unit separator (`0x1F`) byte.
+ description: A namespace identifier as a single string. Multipart
namespace parts must be separated by the namespace separator as indicated via
the /config override `namespace-separator`, which defaults to the unit
separator `0x1F` byte (url encoded `%1F`). To be compatible with older clients,
servers must use both the advertised separator and `0x1F` as valid separators
when decoding namespaces. The `namespace-separator` should be provided in a url
encoded form.
schema:
type: string
examples:
@@ -4378,7 +4516,7 @@ components:
Specific properties and handling for `vended-credentials` is
documented in the `LoadTableResult` schema section of this spec document.
- The protocol and specification for `remote-signing` is documented in
the `s3-signer-open-api.yaml` OpenApi spec in the `aws` module.
+ The protocol and specification for `remote-signing` is documented in
the `s3-signer-open-api.yaml` OpenApi spec in the `aws` module.
required: false
schema:
type: string
@@ -4452,6 +4590,13 @@ components:
message: The given namespace already exists
type: AlreadyExistsException
code: 409
+ NamespaceNotEmptyError:
+ summary: The requested namespace is not empty
+ value:
+ error:
+ message: The given namespace is not empty
+ type: NamespaceNotEmptyException
+ code: 409
UpdateAndRemoveNamespacePropertiesRequest:
summary: An update namespace properties request with both properties to
remove and properties to upsert.
value:
@@ -4606,7 +4751,9 @@ components:
etag:
name: ETag
in: header
- description: Identifies a unique version of the table metadata.
+ description: |-
+ Identifies a unique version of the table metadata.
+ Implementations that support ETags should produce unique tags for
responses that return different metadata content but represent the same version
of table metadata. For example, the `snapshots` query parameter may result in
different metadata representations depending on whether `refs` or `all` is
provided, therefore should have distinct ETags.
required: false
schema:
type: string
diff --git a/spec/iceberg-rest-catalog-open-api.yaml
b/spec/iceberg-rest-catalog-open-api.yaml
index b0140faea..50ed54a6a 100644
--- a/spec/iceberg-rest-catalog-open-api.yaml
+++ b/spec/iceberg-rest-catalog-open-api.yaml
@@ -19,7 +19,8 @@
# CODE_COPIED_TO_POLARIS
-# Apache Iceberg Version: 1.10.0
+# Apache Iceberg Version: 1.11.0
+# commit SHA: 459332131f429484177d45acabea8903a45acc4e
---
openapi: 3.1.1
@@ -151,6 +152,7 @@ paths:
"defaults": {
"clients": "4"
},
+ "idempotency-key-lifetime": "PT30M",
"endpoints": [
"GET /v1/{prefix}/namespaces/{namespace}",
"GET /v1/{prefix}/namespaces",
@@ -199,13 +201,13 @@ paths:
This endpoint is used for three purposes -
1. To exchange client credentials (client ID and secret) for an access
token
- This uses the client credentials flow.
+ This uses the client credentials flow.
2. To exchange a client token and an identity token for a more
specific access token
- This uses the token exchange flow.
+ This uses the token exchange flow.
3. To exchange an access token for one with the same claims and a
refreshed expiration period
- This uses the token exchange flow.
+ This uses the token exchange flow.
For example, a catalog client may be configured with client
credentials from the OAuth2
@@ -264,10 +266,13 @@ paths:
in: query
description:
An optional namespace, underneath which to list namespaces.
- If not provided or empty, all top-level namespaces should be
listed.
- If parent is a multipart namespace, the parts must be separated by
the unit separator (`0x1F`) byte.
+ If not provided, all top-level namespaces should be listed.
+ For backward compatibility, empty string is treated as absent for
now.
+ If parent is a multipart namespace, the parts must be separated by
the namespace separator as
+ indicated via the /config override `namespace-separator`, which
defaults to the unit separator `0x1F` byte (url encoded `%1F`).
+ To be compatible with older clients, servers must use both the
advertised separator and `0x1F` as valid separators when decoding namespaces.
+ The `namespace-separator` should be provided in a url encoded form.
required: false
- allowEmptyValue: true
schema:
type: string
example: "accounting%1Ftax"
@@ -300,6 +305,8 @@ paths:
tags:
- Catalog API
summary: Create a namespace
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description:
Create a namespace, with an optional set of properties.
The server might also add properties, such as `last_modified_time` etc.
@@ -410,6 +417,8 @@ paths:
- Catalog API
summary: Drop a namespace from the catalog. Namespace must be empty.
operationId: dropNamespace
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
responses:
204:
description: Success, no content
@@ -454,6 +463,8 @@ paths:
- Catalog API
summary: Set or remove properties on a namespace
operationId: updateProperties
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description:
Set and/or remove properties on a namespace.
The request body specifies a list of properties to remove and a map
@@ -566,6 +577,7 @@ paths:
operationId: createTable
parameters:
- $ref: '#/components/parameters/data-access'
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
required: true
content:
@@ -597,7 +609,7 @@ paths:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
examples:
- NamespaceAlreadyExists:
+ TableAlreadyExists:
$ref: '#/components/examples/TableAlreadyExistsError'
419:
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -628,7 +640,7 @@ paths:
point-in-time scan of the latest snapshot in the table's main branch.
- Responses must include a valid status listed below. A "cancelled"
status is considered invalid for this endpoint.
+ Responses must include a valid status listed below. A "cancelled"
status is considered invalid for this endpoint.
- When "completed" the planning operation has produced plan tasks and
file scan tasks that must be returned in the response (not fetched
@@ -655,6 +667,8 @@ paths:
needed by calling cancelPlanning. Cancellation is not necessary after
fetchScanTasks has been used to fetch scan tasks for each plan task.
operationId: planTableScan
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
content:
application/json:
@@ -762,6 +776,8 @@ paths:
- Catalog API
summary: Cancels scan planning for a plan-id
operationId: cancelPlanning
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: >
Cancels scan planning for a plan-id.
@@ -790,6 +806,7 @@ paths:
404:
description:
Not Found
+ - NoSuchPlanIdException, the plan-id does not exist
- NoSuchTableException, the table does not exist
- NoSuchNamespaceException, the namespace does not exist
content:
@@ -797,6 +814,8 @@ paths:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
examples:
+ PlanIdDoesNotExist:
+ $ref: '#/components/examples/NoSuchPlanIdError'
TableDoesNotExist:
$ref: '#/components/examples/NoSuchTableError'
NamespaceDoesNotExist:
@@ -820,6 +839,8 @@ paths:
- Catalog API
summary: Fetches result tasks for a plan task
operationId: fetchScanTasks
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description: Fetches result tasks for a plan task.
requestBody:
content:
@@ -859,8 +880,6 @@ paths:
5XX:
$ref: '#/components/responses/ServerErrorResponse'
-
-
/v1/{prefix}/namespaces/{namespace}/register:
parameters:
- $ref: '#/components/parameters/prefix'
@@ -870,6 +889,9 @@ paths:
tags:
- Catalog API
summary: Register a table in the given namespace using given metadata
file location
+ parameters:
+ - $ref: '#/components/parameters/data-access'
+ - $ref: '#/components/parameters/idempotency-key'
description:
Register a table using given metadata file location.
@@ -905,7 +927,7 @@ paths:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
examples:
- NamespaceAlreadyExists:
+ TableAlreadyExists:
$ref: '#/components/examples/TableAlreadyExistsError'
419:
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -947,8 +969,8 @@ paths:
in: header
description:
An optional header that allows the server to return 304 (Not
Modified) if the metadata
- is current. The content is the value of the ETag received in a
CreateTableResponse or
- LoadTableResponse.
+ is current. The content is the value of the ETag received in a
CreateTableResponse,
+ LoadTableResponse or CommitTableResponse.
required: false
schema:
type: string
@@ -958,7 +980,7 @@ paths:
The snapshots to return in the body of the metadata. Setting the
value to `all` would
return the full set of snapshots currently valid for the table.
Setting the value to
`refs` would load all snapshots referenced by branches or tags.
-
+
Default if no param is provided is `all`.
required: false
schema:
@@ -999,6 +1021,8 @@ paths:
- Catalog API
summary: Commit updates to a table
operationId: updateTable
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description:
Commit updates to a table.
@@ -1119,6 +1143,7 @@ paths:
operationId: dropTable
description: Remove a table from the catalog
parameters:
+ - $ref: '#/components/parameters/idempotency-key'
- name: purgeRequested
in: query
required: false
@@ -1196,6 +1221,13 @@ paths:
- Catalog API
summary: Load vended credentials for a table from the catalog
operationId: loadCredentials
+ parameters:
+ - name: planId
+ in: query
+ required: false
+ schema:
+ type: string
+ description: The plan ID that has been used for server-side scan
planning
description: Load vended credentials for a table from the catalog.
responses:
200:
@@ -1231,6 +1263,8 @@ paths:
tags:
- Catalog API
summary: Rename a table from its current name to a new name
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description:
Rename a table from one identifier to another. It's valid to move a
table
across namespaces, but the server implementation is not required to
support it.
@@ -1338,6 +1372,8 @@ paths:
- Catalog API
summary: Commit updates to multiple tables in an atomic operation
operationId: commitTransaction
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
description:
Commit updates to multiple tables in an atomic operation
@@ -1521,7 +1557,7 @@ paths:
schema:
$ref: '#/components/schemas/ErrorModel'
examples:
- NamespaceAlreadyExists:
+ ViewAlreadyExists:
$ref: '#/components/examples/ViewAlreadyExistsError'
419:
$ref: '#/components/responses/AuthenticationTimeoutResponse'
@@ -1587,6 +1623,8 @@ paths:
- Catalog API
summary: Replace a view
operationId: replaceView
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
description:
Commit updates to a view.
requestBody:
@@ -1688,6 +1726,8 @@ paths:
summary: Drop a view from the catalog
operationId: dropView
description: Remove a view from the catalog
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
responses:
204:
description: Success, no content
@@ -1749,6 +1789,8 @@ paths:
Rename a view from one identifier to another. It's valid to move a view
across namespaces, but the server implementation is not required to
support it.
operationId: renameView
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
requestBody:
description: Current view identifier to rename and new view identifier
to rename to
content:
@@ -1799,6 +1841,60 @@ paths:
5XX:
$ref: '#/components/responses/ServerErrorResponse'
+ /v1/{prefix}/namespaces/{namespace}/register-view:
+ parameters:
+ - $ref: '#/components/parameters/prefix'
+ - $ref: '#/components/parameters/namespace'
+
+ post:
+ tags:
+ - Catalog API
+ summary: Register a view in the catalog
+ parameters:
+ - $ref: '#/components/parameters/idempotency-key'
+ description:
+ Register a view in the given namespace using given metadata file
location.
+
+ operationId: registerView
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RegisterViewRequest'
+ responses:
+ 200:
+ $ref: '#/components/responses/LoadViewResponse'
+ 400:
+ $ref: '#/components/responses/BadRequestErrorResponse'
+ 401:
+ $ref: '#/components/responses/UnauthorizedResponse'
+ 403:
+ $ref: '#/components/responses/ForbiddenResponse'
+ 404:
+ description: Not Found - The namespace specified does not exist
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IcebergErrorResponse'
+ examples:
+ NamespaceNotFound:
+ $ref: '#/components/examples/NoSuchNamespaceError'
+ 409:
+ description: Conflict - The identifier already exists as a table or
view
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/IcebergErrorResponse'
+ examples:
+ ViewAlreadyExists:
+ $ref: '#/components/examples/ViewAlreadyExistsError'
+ 419:
+ $ref: '#/components/responses/AuthenticationTimeoutResponse'
+ 503:
+ $ref: '#/components/responses/ServiceUnavailableResponse'
+ 5XX:
+ $ref: '#/components/responses/ServerErrorResponse'
components:
#######################################################
@@ -1811,7 +1907,10 @@ components:
required: true
description:
A namespace identifier as a single string.
- Multipart namespace parts should be separated by the unit separator
(`0x1F`) byte.
+ Multipart namespace parts must be separated by the namespace separator
as
+ indicated via the /config override `namespace-separator`, which
defaults to the unit separator `0x1F` byte (url encoded `%1F`).
+ To be compatible with older clients, servers must use both the
advertised separator and `0x1F` as valid separators when decoding namespaces.
+ The `namespace-separator` should be provided in a url encoded form.
schema:
type: string
examples:
@@ -1861,13 +1960,13 @@ components:
Optional signal to the server that the client supports delegated access
via a comma-separated list of access mechanisms. The server may choose
to supply access via any or none of the requested mechanisms.
-
-
+
+
Specific properties and handling for `vended-credentials` is documented
in the `LoadTableResult` schema section of this spec document.
-
-
- The protocol and specification for `remote-signing` is documented in
+
+
+ The protocol and specification for `remote-signing` is documented in
the `s3-signer-open-api.yaml` OpenApi spec in the `aws` module.
required: false
@@ -1884,7 +1983,6 @@ components:
name: pageToken
in: query
required: false
- allowEmptyValue: true
schema:
$ref: '#/components/schemas/PageToken'
@@ -1902,10 +2000,46 @@ components:
etag:
name: ETag
in: header
- description: Identifies a unique version of the table metadata.
+ description:
+ Identifies a unique version of the table metadata.
+
+ Implementations that support ETags should produce unique tags for
responses that return
+ different metadata content but represent the same version of table
metadata. For example,
+ the `snapshots` query parameter may result in different metadata
representations depending
+ on whether `refs` or `all` is provided, therefore should have distinct
ETags.
+ required: false
+ schema:
+ type: string
+
+ idempotency-key:
+ name: Idempotency-Key
+ in: header
required: false
schema:
type: string
+ format: uuid
+ minLength: 36
+ maxLength: 36
+ example: "017F22E2-79B0-7CC3-98C4-DC0C0C07398F"
+ description: |
+ Optional client-provided idempotency key for safe request retries.
+
+ When present, the server ensures no additional effects for requests
that carry the same
+ Idempotency-Key. If a prior request with this key has been finalized,
the server returns
+ an equivalent final response without re-running the operation. The
response body may
+ reflect a newer state of the catalog than existed at the time of the
commit.
+
+ Finalization rules:
+ - Finalize & replay: 200, 201, 204, and deterministic terminal 4xx
(including 409
+ such as AlreadyExists, NamespaceNotEmpty, etc.)
+ - Do not finalize (not stored/replayed): 5xx
+
+ Key Requirements:
+ - Key format: UUIDv7 in string form (RFC 9562).
+ - The idempotency key must be globally unique (no reuse across
different operations).
+ - Catalogs SHOULD NOT expire keys before the end of the advertised
token lifetime.
+ - If Idempotency-Key is used, clients MUST reuse the same key when
retrying the same
+ logical operation and MUST generate a new key for a different
operation.
##############################
# Application Schema Objects #
@@ -1970,6 +2104,18 @@ components:
"GET /v1/{prefix}/namespaces/{namespace}/tables/{table}",
"GET /v1/{prefix}/namespaces/{namespace}/views/{view}"
]
+ idempotency-key-lifetime:
+ type: string
+ format: duration
+ description:
+ Client reuse window for an Idempotency-Key (ISO-8601 duration,
e.g., PT30M, PT24H).
+ Interpreted as the maximum time from the first submission using a
key to the last retry
+ during which a client may reuse that key. Servers SHOULD accept
retries for at least this
+ duration and MAY include a grace period to account for
delays/clock skew. Clients SHOULD NOT
+ reuse an Idempotency-Key after this window elapses; they SHOULD
generate a new key for any
+ subsequent attempt. Presence of this field indicates the server
supports Idempotency-Key
+ semantics for mutation endpoints. If absent, clients MUST assume
idempotency is not supported.
+ example: PT30M
CreateNamespaceRequest:
type: object
@@ -2024,20 +2170,20 @@ components:
An opaque token that allows clients to make use of pagination for list
APIs
(e.g. ListTables). Clients may initiate the first paginated request by
sending an empty
query parameter `pageToken` to the server.
-
+
Servers that support pagination should identify the `pageToken`
parameter and return a
`next-page-token` in the response if there are more results available.
After the initial
request, the value of `next-page-token` from each response must be
used as the `pageToken`
parameter value for the next request. The server must return `null`
value for the
`next-page-token` in the last response.
-
+
Servers that support pagination must return all results in a single
response with the value
of `next-page-token` set to `null` if the query parameter `pageToken`
is not set in the
request.
-
+
Servers that do not support pagination should ignore the `pageToken`
parameter and return
all results in a single response. The `next-page-token` must be
omitted from the response.
-
+
Clients must interpret either `null` or missing response value of
`next-page-token` as
the end of the listing results.
@@ -2246,15 +2392,12 @@ components:
required:
- type
- term
- - value
properties:
type:
$ref: '#/components/schemas/ExpressionType'
enum: ["is-null", "not-null", "is-nan", "not-nan"]
term:
$ref: '#/components/schemas/Term'
- value:
- type: object
LiteralExpression:
type: object
@@ -2269,7 +2412,7 @@ components:
term:
$ref: '#/components/schemas/Term'
value:
- type: object
+ $ref: '#/components/schemas/PrimitiveTypeValue'
SetExpression:
type: object
@@ -2286,7 +2429,7 @@ components:
values:
type: array
items:
- type: object
+ $ref: '#/components/schemas/PrimitiveTypeValue'
Term:
oneOf:
@@ -2402,7 +2545,7 @@ components:
type: string
encrypted-key-metadata:
type: string
- format: byte # for compatibility
+ format: byte # for compatibility
contentEncoding: base64
encrypted-by-id:
type: string
@@ -2438,6 +2581,10 @@ components:
type: integer
format: int64
description: The first _row_id assigned to the first row in the
first data file in the first manifest
+ added-rows:
+ type: integer
+ format: int64
+ description: The upper bound of the number of rows with assigned row
IDs
summary:
type: object
required:
@@ -3078,6 +3225,8 @@ components:
- $ref: '#/components/schemas/RemovePropertiesUpdate'
- $ref: '#/components/schemas/SetStatisticsUpdate'
- $ref: '#/components/schemas/RemoveStatisticsUpdate'
+ - $ref: '#/components/schemas/SetPartitionStatisticsUpdate'
+ - $ref: '#/components/schemas/RemovePartitionStatisticsUpdate'
- $ref: '#/components/schemas/RemovePartitionSpecsUpdate'
- $ref: '#/components/schemas/RemoveSchemasUpdate'
- $ref: '#/components/schemas/AddEncryptionKeyUpdate'
@@ -3286,21 +3435,21 @@ components:
The `config` map returns table-specific configuration for the table's
resources, including its HTTP client and FileIO. For example, config may
contain a specific FileIO implementation class for the table depending on its
underlying storage.
-
-
+
+
The following configurations should be respected by clients:
-
+
## General Configurations
-
- - `token`: Authorization bearer token to use for table requests if
OAuth2 security is enabled
-
+
+ - `token`: Authorization bearer token to use for table requests if
OAuth2 security is enabled
+
## AWS Configurations
-
+
The following configurations should be respected when working with
tables stored in AWS S3
- `client.region`: region to configure client for making requests to
AWS
- `s3.access-key-id`: id for credentials that provide access to the
data in S3
- - `s3.secret-access-key`: secret for credentials that provide access
to data in S3
- - `s3.session-token`: if present, this value should be used for as
the session token
+ - `s3.secret-access-key`: secret for credentials that provide access
to data in S3
+ - `s3.session-token`: if present, this value should be used for as
the session token
- `s3.remote-signing-enabled`: if `true` remote signing should be
performed as described in the `s3-signer-open-api.yaml` specification
- `s3.cross-region-access-enabled`: if `true`, S3 Cross-Region bucket
access is enabled
@@ -3373,12 +3522,24 @@ components:
status:
$ref: '#/components/schemas/PlanStatus'
const: "completed"
+ storage-credentials:
+ type: array
+ description:
+ Storage credentials for accessing the files returned in the
scan result.
+
+ If the server returns storage credentials as part of the
completed scan
+ planning response, the expectation is for the client to use
these credentials
+ to read the files returned in the FileScanTasks as part of the
scan result.
+ items:
+ $ref: '#/components/schemas/StorageCredential'
CompletedPlanningWithIDResult:
type: object
allOf:
- $ref: '#/components/schemas/CompletedPlanningResult'
- type: object
+ required:
+ - plan-id
properties:
plan-id:
description: ID used to track a planning request
@@ -3401,6 +3562,7 @@ components:
type: object
required:
- status
+ - plan-id
properties:
status:
$ref: '#/components/schemas/PlanStatus'
@@ -3596,6 +3758,17 @@ components:
additionalProperties:
type: string
+ RegisterViewRequest:
+ type: object
+ required:
+ - name
+ - metadata-location
+ properties:
+ name:
+ type: string
+ metadata-location:
+ type: string
+
TokenType:
type: string
enum:
@@ -4112,9 +4285,9 @@ components:
DecimalTypeValue:
type: string
description:
- "Decimal type values are serialized as strings. Decimals with a
positive scale serialize as numeric plain
- text, while decimals with a negative scale use scientific notation and
the exponent will be equal to the
- negated scale. For instance, a decimal with a positive scale is
'123.4500', with zero scale is '2',
+ "Decimal type values are serialized as strings. Decimals with a
positive scale serialize as numeric plain
+ text, while decimals with a negative scale use scientific notation and
the exponent will be equal to the
+ negated scale. For instance, a decimal with a positive scale is
'123.4500', with zero scale is '2',
and with a negative scale is '2E+20'"
example: "123.4500"
@@ -4129,7 +4302,7 @@ components:
maxLength: 36
minLength: 36
description:
- "UUID type values are serialized as a 36-character lowercase string in
standard UUID format as specified
+ "UUID type values are serialized as a 36-character lowercase string in
standard UUID format as specified
by RFC-4122"
example: "eb26bdb1-a1d8-4aa6-990e-da940875492c"
@@ -4155,7 +4328,7 @@ components:
TimestampTzTypeValue:
type: string
description:
- "TimestampTz type values follow the 'YYYY-MM-DDTHH:MM:SS.ssssss+00:00'
ISO-8601 format with microsecond precision,
+ "TimestampTz type values follow the 'YYYY-MM-DDTHH:MM:SS.ssssss+00:00'
ISO-8601 format with microsecond precision,
and a timezone offset (+00:00 for UTC)"
example: "2007-12-03T10:15:30.123456+00:00"
@@ -4168,14 +4341,14 @@ components:
TimestampTzNanoTypeValue:
type: string
description:
- "Timestamp_ns type values follow the
'YYYY-MM-DDTHH:MM:SS.sssssssss+00:00' ISO-8601 format with nanosecond
+ "Timestamp_ns type values follow the
'YYYY-MM-DDTHH:MM:SS.sssssssss+00:00' ISO-8601 format with nanosecond
precision, and a timezone offset (+00:00 for UTC)"
example: "2007-12-03T10:15:30.123456789+00:00"
FixedTypeValue:
type: string
description:
- "Fixed length type values are stored and serialized as an uppercase
hexadecimal string
+ "Fixed length type values are stored and serialized as an uppercase
hexadecimal string
preserving the fixed length"
example: "78797A"
@@ -4201,7 +4374,7 @@ components:
example:
{
"keys": [ 1, 2 ],
- "values": [ 100,200 ]
+ "values": [ 100, 200 ]
}
ValueMap:
@@ -4403,6 +4576,14 @@ components:
description:
Expression used to filter the table data
$ref: '#/components/schemas/Expression'
+ min-rows-requested:
+ description:
+ The minimum number of rows requested for the scan. This is used as
a hint
+ to the server to not have to return more rows than necessary. It
is not required
+ for the server to return that many rows since the scan may not
produce that
+ many rows. The server can also return more rows than requested.
+ type: integer
+ format: int64
case-sensitive:
description: Enables case sensitive field matching for filter and
select
type: boolean
@@ -4440,14 +4621,14 @@ components:
The nested field name follows these rules
- Nested struct fields are named by concatenating field names at each
- struct level using dot (`.`) delimiter, e.g.
- employer.contact_info.address.zip_code
+ struct level using dot (`.`) delimiter, e.g.
+ employer.contact_info.address.zip_code
- Nested fields in a map key are named using the keyword `key`, e.g.
- employee_address_map.key.first_name
+ employee_address_map.key.first_name
- Nested fields in a map value are named using the keyword `value`,
- e.g. employee_address_map.value.zip_code
+ e.g. employee_address_map.value.zip_code
- Nested fields in a list are named using the keyword `element`, e.g.
- employees.element.first_name
+ employees.element.first_name
type: string
FetchScanTasksRequest:
@@ -4756,6 +4937,9 @@ components:
application/json:
schema:
$ref: '#/components/schemas/CommitTableResponse'
+ headers:
+ etag:
+ $ref: '#/components/parameters/etag'
LoadCredentialsResponse:
description: Table credentials result when loading credentials for a
table