This is an automated email from the ASF dual-hosted git repository.
huaxingao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new f17f34bce6 Core: Check table UUID in RESTTableOperations (#14363)
f17f34bce6 is described below
commit f17f34bce65567fd1479607038221bcccb594b29
Author: Yuya Ebihara <[email protected]>
AuthorDate: Tue Nov 4 10:45:05 2025 +0900
Core: Check table UUID in RESTTableOperations (#14363)
---
.../apache/iceberg/rest/RESTTableOperations.java | 15 +++++++-
.../org/apache/iceberg/rest/TestRESTCatalog.java | 43 ++++++++++++++++++++++
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git
a/core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java
b/core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java
index 00522fd6e1..38dabc8ae5 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java
@@ -247,12 +247,25 @@ class RESTTableOperations implements TableOperations {
// safely ignored. there is no requirement to update config on refresh or
commit.
if (current == null
|| !Objects.equals(current.metadataFileLocation(),
response.metadataLocation())) {
- this.current = response.tableMetadata();
+ this.current = checkUUID(current, response.tableMetadata());
}
return current;
}
+ private static TableMetadata checkUUID(TableMetadata currentMetadata,
TableMetadata newMetadata) {
+ String newUUID = newMetadata.uuid();
+ if (currentMetadata != null && currentMetadata.uuid() != null && newUUID
!= null) {
+ Preconditions.checkState(
+ newUUID.equals(currentMetadata.uuid()),
+ "Table UUID does not match: current=%s != refreshed=%s",
+ currentMetadata.uuid(),
+ newUUID);
+ }
+
+ return newMetadata;
+ }
+
private static String metadataFileLocation(TableMetadata metadata, String
filename) {
String metadataLocation =
metadata.properties().get(TableProperties.WRITE_METADATA_LOCATION);
diff --git a/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
b/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
index 6f7af7ae75..e4e80348f9 100644
--- a/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
+++ b/core/src/test/java/org/apache/iceberg/rest/TestRESTCatalog.java
@@ -56,6 +56,7 @@ import org.apache.iceberg.PartitionSpec;
import org.apache.iceberg.Schema;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
+import org.apache.iceberg.TableMetadata;
import org.apache.iceberg.Transaction;
import org.apache.iceberg.UpdatePartitionSpec;
import org.apache.iceberg.UpdateSchema;
@@ -2955,6 +2956,48 @@ public class TestRESTCatalog extends
CatalogTests<RESTCatalog> {
any());
}
+ @Test
+ void testDifferentTableUUID() {
+ RESTCatalogAdapter adapter = Mockito.spy(new
RESTCatalogAdapter(backendCatalog));
+ RESTCatalog catalog = catalog(adapter);
+
+ catalog.createNamespace(TABLE.namespace());
+ catalog.createTable(TABLE, SCHEMA);
+
+ // simulate drop and re-create the table with same name
+ String newUUID = "386b9f01-002b-4d8c-b77f-42c3fd3b7c9b";
+ Answer<LoadTableResponse> updateTable =
+ invocation -> {
+ LoadTableResponse loadTable = (LoadTableResponse)
invocation.callRealMethod();
+ TableMetadata current = loadTable.tableMetadata();
+ assertThat(current.uuid()).isNotEqualTo(newUUID);
+ TableMetadata newMetadata =
TableMetadata.buildFrom(current).assignUUID(newUUID).build();
+ return LoadTableResponse.builder()
+ .withTableMetadata(newMetadata)
+ .addAllConfig(loadTable.config())
+ .build();
+ };
+
+ Mockito.doAnswer(updateTable)
+ .when(adapter)
+ .execute(
+ reqMatcher(HTTPMethod.POST, RESOURCE_PATHS.table(TABLE)),
+ eq(LoadTableResponse.class),
+ any(),
+ any());
+
+ DataFile file =
+ DataFiles.builder(PartitionSpec.unpartitioned())
+ .withPath("/path/to/data-a.parquet")
+ .withFileSizeInBytes(10)
+ .withRecordCount(2)
+ .build();
+
+ assertThatThrownBy(() ->
catalog.loadTable(TABLE).newFastAppend().appendFile(file).commit())
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageMatching("Table UUID does not match: current=.* !=
refreshed=" + newUUID);
+ }
+
private RESTCatalog catalogWithResponseHeaders(Map<String, String>
respHeaders) {
RESTCatalogAdapter adapter =
new RESTCatalogAdapter(backendCatalog) {