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

huaxingao pushed a commit to branch 1.10.x
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/1.10.x by this push:
     new 7e1b63d34f Core: Fix RESTFileScanTaskParser to handle empty delete 
file references list (#14568) (#14576)
7e1b63d34f is described below

commit 7e1b63d34f52a50c1ce41f7abb8492cce4de18d8
Author: Eduard Tudenhoefner <[email protected]>
AuthorDate: Wed Nov 12 20:17:28 2025 +0100

    Core: Fix RESTFileScanTaskParser to handle empty delete file references 
list (#14568) (#14576)
    
    Co-authored-by: ajreid21 <[email protected]>
---
 .../iceberg/rest/RESTFileScanTaskParser.java       |  4 +-
 .../responses/TestPlanTableScanResponseParser.java | 45 ++++++++++++++++++++++
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git 
a/core/src/main/java/org/apache/iceberg/rest/RESTFileScanTaskParser.java 
b/core/src/main/java/org/apache/iceberg/rest/RESTFileScanTaskParser.java
index 0ada9083ee..ccd2872e04 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTFileScanTaskParser.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTFileScanTaskParser.java
@@ -58,7 +58,7 @@ class RESTFileScanTaskParser {
     generator.writeStartObject();
     generator.writeFieldName(DATA_FILE);
     ContentFileParser.toJson(fileScanTask.file(), partitionSpec, generator);
-    if (deleteFileReferences != null) {
+    if (deleteFileReferences != null && !deleteFileReferences.isEmpty()) {
       JsonUtil.writeIntegerArray(DELETE_FILE_REFERENCES, deleteFileReferences, 
generator);
     }
 
@@ -87,7 +87,7 @@ class RESTFileScanTaskParser {
     if (jsonNode.has(DELETE_FILE_REFERENCES)) {
       List<Integer> indices = JsonUtil.getIntegerList(DELETE_FILE_REFERENCES, 
jsonNode);
       Preconditions.checkArgument(
-          Collections.max(indices) < allDeleteFiles.size(),
+          indices.isEmpty() || Collections.max(indices) < 
allDeleteFiles.size(),
           "Invalid delete file references: %s, expected indices < %s",
           indices,
           allDeleteFiles.size());
diff --git 
a/core/src/test/java/org/apache/iceberg/rest/responses/TestPlanTableScanResponseParser.java
 
b/core/src/test/java/org/apache/iceberg/rest/responses/TestPlanTableScanResponseParser.java
index c807bc4655..5ddedcacae 100644
--- 
a/core/src/test/java/org/apache/iceberg/rest/responses/TestPlanTableScanResponseParser.java
+++ 
b/core/src/test/java/org/apache/iceberg/rest/responses/TestPlanTableScanResponseParser.java
@@ -264,4 +264,49 @@ public class TestPlanTableScanResponseParser {
 
     
assertThat(PlanTableScanResponseParser.toJson(copyResponse)).isEqualTo(expectedToJson);
   }
+
+  @Test
+  public void roundTripSerdeWithoutDeleteFiles() {
+    ResidualEvaluator residualEvaluator =
+        ResidualEvaluator.of(SPEC, Expressions.equal("id", 1), true);
+    FileScanTask fileScanTask =
+        new BaseFileScanTask(
+            FILE_A,
+            new DeleteFile[] {},
+            SchemaParser.toJson(SCHEMA),
+            PartitionSpecParser.toJson(SPEC),
+            residualEvaluator);
+    PlanTableScanResponse response =
+        PlanTableScanResponse.builder()
+            .withPlanStatus(PlanStatus.COMPLETED)
+            .withFileScanTasks(List.of(fileScanTask))
+            .withSpecsById(PARTITION_SPECS_BY_ID)
+            .build();
+
+    String expectedJson =
+        "{\"plan-status\":\"completed\","
+            + "\"file-scan-tasks\":["
+            + 
"{\"data-file\":{\"spec-id\":0,\"content\":\"DATA\",\"file-path\":\"/path/to/data-a.parquet\","
+            + "\"file-format\":\"PARQUET\",\"partition\":{\"1000\":0},"
+            + 
"\"file-size-in-bytes\":10,\"record-count\":1,\"sort-order-id\":0},"
+            + 
"\"residual-filter\":{\"type\":\"eq\",\"term\":\"id\",\"value\":1}}]"
+            + "}";
+
+    String json = PlanTableScanResponseParser.toJson(response);
+    assertThat(json).isEqualTo(expectedJson);
+
+    PlanTableScanResponse fromResponse =
+        PlanTableScanResponseParser.fromJson(json, PARTITION_SPECS_BY_ID, 
false);
+    PlanTableScanResponse copyResponse =
+        PlanTableScanResponse.builder()
+            .withPlanStatus(fromResponse.planStatus())
+            .withPlanId(fromResponse.planId())
+            .withPlanTasks(fromResponse.planTasks())
+            .withDeleteFiles(fromResponse.deleteFiles())
+            .withFileScanTasks(fromResponse.fileScanTasks())
+            .withSpecsById(PARTITION_SPECS_BY_ID)
+            .build();
+
+    
assertThat(PlanTableScanResponseParser.toJson(copyResponse)).isEqualTo(expectedJson);
+  }
 }

Reply via email to