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);
+ }
}