ghoshp83 opened a new pull request, #4292:
URL: https://github.com/apache/iceberg-python/pull/4292

   Closes #4291.
   
   # Rationale for this change
   
   A partial `Table.delete` rewrites each data file that might hold matching 
rows. It reads the whole file with `AlwaysTrue()` and writes back the rows that 
don't match. The files to rewrite were planned with the delete filter, though, 
and that plan also leaves out delete files whose column bounds can't match the 
filter. For a filtered read that's correct, because the residual drops those 
rows anyway. For a full-file rewrite it isn't: the left-out delete files are 
never applied, so the rows they deleted come back in the new data file.
   
   `overwrite(..., overwrite_filter=...)`, `dynamic_partition_overwrite` and 
`upsert` go through `Transaction.delete`, so they're affected too.
   
   The fix keeps the delete filter for choosing data files, but stops pruning 
delete files by their column bounds when planning a rewrite:
   
   - `ManifestGroupPlanner` takes `prune_delete_files: bool = True`. When it's 
`False`, the metrics evaluator is applied to data entries only. Partition 
pruning is unchanged, since a delete file only applies to data files in its own 
partition.
   - `Transaction.delete` plans its rewrite with `prune_delete_files=False`. 
Its scan never has a catalog, so it always planned locally, and server-side 
planning isn't involved.
   
   Scans keep the default, so reads and their planning cost are unchanged.
   
   # Are these changes tested?
   
   Yes. `test_partial_delete_keeps_earlier_deletes_outside_the_filter` in 
`tests/catalog/test_catalog_behaviors.py` runs against each catalog fixture and 
follows case 1 from the issue:
   - it commits a position delete that stores the deleted row `(2, 'b')`, which 
gives it bounds `k = 2`;
   - it checks that a scan for `k = 1` leaves that delete file out;
   - it runs `delete("k = 1")` and checks only `k = 3` is left.
   
   Without the fix the final assertion fails with `[2, 3] == [3]`: the deleted 
row is back. PyIceberg can't write delete manifests yet, so the test's helper 
subclasses `ManifestWriterV2`, as the reproduction in the issue does. Once 
#4002 lands, the helper can pass `content=ManifestContent.DELETES` instead.
   
   The equality-delete case from the issue isn't tested here, because PyIceberg 
can't read equality deletes. With this change, a partial delete over a file 
that has an equality delete now reaches the existing "does not yet support 
equality deletes" error instead of silently writing the deleted rows back.
   
   # Are there any user-facing changes?
   
   Partial deletes, filtered overwrites and upserts no longer resurrect rows 
removed by earlier delete files. A partial delete on a table with equality 
delete files that only the column bounds used to exclude now raises the 
existing unsupported-equality-deletes error, rather than writing incorrect data.
   
   Not in this PR: the issue also points out that the retry conflict check 
(`_filter_manifest_entries` in `table/update/validate.py`) prunes delete 
entries the same way. That's a separate code path, so I'll follow up on it 
separately.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to