LuciferYang opened a new pull request, #857:
URL: https://github.com/apache/iceberg-cpp/pull/857

   ## What
   
   `internal::CanContainEqDeletesForFile` crashes with 
`std::bad_optional_access` when an equality delete file has lower/upper bounds 
for some of its equality fields but not others. 
`EqualityDeleteFile::LowerBound`/`UpperBound` return 
`Result<std::optional<...>>` (i.e. `std::expected<std::optional<...>, Error>`), 
and a field with no bound yields an engaged `expected` wrapping a disengaged 
`optional`. The guard checked `std::expected::has_value()`, which only reports 
the error state and does not detect the empty inner `optional`, so a missing 
bound slipped past and `->value()` threw at the range check.
   
   The throw is an uncaught exception escaping the `Result`-based call chain, 
so it terminates the caller instead of surfacing as an error. It is reachable 
during scan planning (`ManifestGroup` → `DeleteFileIndex::ForEntry`) and commit 
validation (`MergingSnapshotUpdate::ValidateNoNewDeletesForDataFiles` → 
`ForDataFile`). Equality delete files with bounds for only some fields are 
produced legitimately by per-column metrics modes (`counts`/`none`/`truncate`) 
and by cross-engine writers, so this is reachable in normal reader use.
   
   Fixes #856.
   
   ## How
   
   Unwrap the `expected` with `ICEBERG_ASSIGN_OR_RAISE` before the guard, so 
`has_value()` tests the inner `optional`. This matches the data-side guard 
already used a few lines above in the same function, and matches Java's 
`DeleteFileIndex.canContainEqDeletesForFile`, which guards all four bounds 
uniformly and assumes may-match on any missing bound (it never prunes on 
missing statistics).
   
   As a side effect this propagates a genuine bound-deserialization error 
upward instead of silently treating it as may-match. That is consistent with 
the data-side `Literal::Deserialize` calls in the same function, which already 
propagate via `ICEBERG_ASSIGN_OR_RAISE`.
   
   ## Testing
   
   Added `DeleteFileIndexTest.TestEqualityDeletePartialFieldBounds`: an 
equality delete over fields `{1, 2}` with bounds for field 1 only, evaluated 
against a data file that has bounds for both (field 1's range overlapping so 
evaluation reaches field 2). Verified fail-without (throws 
`std::bad_optional_access`) / pass-with (returns the delete file as may-match). 
`null_value_counts` is pinned to 0 for both fields so the null short-circuits 
cannot mask the range-check path if the schema fields later change nullability. 
Full `manifest_test` passes.
   


-- 
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