You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by et...@apache.org on 2025/11/12 18:03:18 UTC

(iceberg) branch main updated: Core: Fix RESTFileScanTaskParser to handle empty delete file references list (#14568)

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

etudenhoefner 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 dc217b09dd Core: Fix RESTFileScanTaskParser to handle empty delete file references list (#14568)
dc217b09dd is described below

commit dc217b09ddf7824c125d580f42501de36307e9cf
Author: ajreid21 <57...@users.noreply.github.com>
AuthorDate: Wed Nov 12 10:03:12 2025 -0800

    Core: Fix RESTFileScanTaskParser to handle empty delete file references list (#14568)
---
 .../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);
+  }
 }