This is an automated email from the ASF dual-hosted git repository.
szehon-ho 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 25cc463c0d Core: Preserve manifest content pruning when ignoring
residuals (#17443)
25cc463c0d is described below
commit 25cc463c0d2108db6a9427b7f8e2b191f7913061
Author: yangshangqing <[email protected]>
AuthorDate: Fri Jul 31 13:44:19 2026 -0400
Core: Preserve manifest content pruning when ignoring residuals (#17443)
---
.../java/org/apache/iceberg/BaseEntriesTable.java | 7 +++--
.../apache/iceberg/TestEntriesMetadataTable.java | 35 ++++++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/apache/iceberg/BaseEntriesTable.java
b/core/src/main/java/org/apache/iceberg/BaseEntriesTable.java
index 1d125a9119..a4ee6eec32 100644
--- a/core/src/main/java/org/apache/iceberg/BaseEntriesTable.java
+++ b/core/src/main/java/org/apache/iceberg/BaseEntriesTable.java
@@ -71,7 +71,6 @@ abstract class BaseEntriesTable extends BaseMetadataTable {
Expression rowFilter = context.rowFilter();
boolean caseSensitive = context.caseSensitive();
boolean ignoreResiduals = context.ignoreResiduals();
- Expression filter = ignoreResiduals ? Expressions.alwaysTrue() : rowFilter;
LoadingCache<Integer, ManifestEvaluator> evalCache =
Caffeine.newBuilder()
@@ -82,7 +81,7 @@ abstract class BaseEntriesTable extends BaseMetadataTable {
return ManifestEvaluator.forRowFilter(rowFilter,
transformedSpec, caseSensitive);
});
ManifestContentEvaluator manifestContentEvaluator =
- new ManifestContentEvaluator(filter, tableSchema.asStruct(),
caseSensitive);
+ new ManifestContentEvaluator(rowFilter, tableSchema.asStruct(),
caseSensitive);
CloseableIterable<ManifestFile> filteredManifests =
CloseableIterable.filter(
@@ -91,9 +90,11 @@ abstract class BaseEntriesTable extends BaseMetadataTable {
evalCache.get(manifest.partitionSpecId()).eval(manifest)
&& manifestContentEvaluator.eval(manifest));
+ Expression residual = ignoreResiduals ? Expressions.alwaysTrue() :
rowFilter;
+
return CloseableIterable.transform(
filteredManifests,
- manifest -> new ManifestReadTask(table, manifest, projectedSchema,
filter));
+ manifest -> new ManifestReadTask(table, manifest, projectedSchema,
residual));
}
/**
diff --git
a/core/src/test/java/org/apache/iceberg/TestEntriesMetadataTable.java
b/core/src/test/java/org/apache/iceberg/TestEntriesMetadataTable.java
index 25e138f962..f80f29256d 100644
--- a/core/src/test/java/org/apache/iceberg/TestEntriesMetadataTable.java
+++ b/core/src/test/java/org/apache/iceberg/TestEntriesMetadataTable.java
@@ -22,6 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import java.util.List;
+import org.apache.iceberg.expressions.Expressions;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
import org.apache.iceberg.types.TypeUtil;
@@ -152,4 +153,38 @@ public class TestEntriesMetadataTable extends TestBase {
.as("Should contain 1 delete file record")
.isEqualTo(1);
}
+
+ @TestTemplate
+ public void testIgnoreResidualsPreservesManifestContentPruning() {
+ assumeThat(formatVersion).as("Only V2 Tables Support
Deletes").isGreaterThanOrEqualTo(2);
+
+ table.newAppend().appendFile(FILE_A).appendFile(FILE_B).commit();
+ table.newRowDelta().addDeletes(fileADeletes()).commit();
+
+ String dataManifestPath =
table.currentSnapshot().dataManifests(table.io()).get(0).path();
+ String deleteManifestPath =
table.currentSnapshot().deleteManifests(table.io()).get(0).path();
+
+ List<Table> entriesTables =
+ ImmutableList.of(new ManifestEntriesTable(table), new
AllEntriesTable(table));
+
+ for (Table entriesTable : entriesTables) {
+ TableScan scan =
+ entriesTable
+ .newScan()
+ .filter(Expressions.equal("data_file.content",
FileContent.POSITION_DELETES.id()))
+ .ignoreResiduals();
+
+ List<FileScanTask> tasks = ImmutableList.copyOf(scan.planFiles());
+
+ assertThat(tasks)
+ .as("Should retain manifest content pruning for %s",
entriesTable.name())
+ .extracting(task -> task.file().location())
+ .contains(deleteManifestPath)
+ .doesNotContain(dataManifestPath);
+
+ assertThat(tasks)
+ .as("Should ignore residuals for %s", entriesTable.name())
+ .allSatisfy(task ->
assertThat(task.residual()).isEqualTo(Expressions.alwaysTrue()));
+ }
+ }
}