viirya opened a new pull request, #5769:
URL: https://github.com/apache/datafusion-comet/pull/5769

   ## Which issue does this PR close?
   
   Closes #5768.
   
   ## Rationale for this change
   
   Three places implemented the same Spark rule — a field of a null struct is 
null, so the
   parent's nulls have to reach the children before the children are read — and 
each did it
   slightly differently:
   
   | | union when |
   |---|---|
   | `GetStructField::project_field` | a null buffer is present, via the 
checked `ArrayData` builder |
   | the hash kernels' struct branch | `null_count() > 0`, via 
`StructArray::flatten` |
   | `get_array_struct_fields` | the parent and child null **counts** differ |
   
   The issue was filed as a refactor, on the grounds that all three were 
correct and the risk
   was drift. That turned out to be half right: **the third guard is wrong**. 
Equal null counts
   do not imply the nulls sit at the same rows, so whenever the child had a 
null of its own at a
   different row the counts could match and the parent's null was dropped. 
There is a test for
   exactly that shape, which a count-based check fails.
   
   ## What changes are included in this PR?
   
   `datafusion_comet_common::struct_nulls`, with `child_with_parent_nulls` for 
one field and
   `children_with_parent_nulls` for all of them, and the three call sites 
switched over. Net -41
   lines at the call sites.
   
   The three decisions the issue asked about:
   
   - **Shape.** Both, with the plural built on the singular, since 
`project_field` wants one
     field and the hash path wants all of them.
   - **Checked or unchecked.** Unchecked, as `flatten` already did. The union 
only adds nulls, so
     every data buffer is carried over unchanged and revalidating them is 
wasted work. This
     matters asymmetrically: `project_field` runs once per batch in `evaluate` 
and did not care
     either way, while the hash path reaches this **once per element** of an 
`array<struct<..>>`,
     where re-checking a string child means rescanning its whole UTF-8 values 
buffer. Unifying on
     checked would have pushed the batch-level caller's cost onto the 
element-level one.
   - **The `null_count() > 0` guard.** Applied to all three. It skips the union 
when the parent
     has no null to contribute, which covers both no buffer at all and a 
present-but-all-valid
     buffer — the latter is what slicing leaves behind. `NullBuffer` stores its 
null count, so the
     test is O(1).
   
   It lives in its own module rather than in `schema.rs`, which is about 
reconciling declared and
   runtime *types* rather than null masks.
   
   ## How are these changes tested?
   
   Six unit tests on the helper: a hidden child value under a null parent, no 
parent null buffer
   (asserting the same array comes back rather than a rebuilt one), a 
present-but-all-valid
   buffer, a child's own null surviving the union, an empty struct, and the 
equal-counts-different-rows
   case that pins the guard fix.
   
   Existing coverage for the three call sites passes unchanged: `cargo test` 
gives 720 + 5 in
   `spark-expr` and 40 in `common`, and on the Spark side 
`CometHashExpressionSuite` (40),
   `CometArrayExpressionSuite` (59) and `CometExpressionSuite` (141). `cargo 
fmt --check` and
   `clippy -D warnings` are clean.
   
   ## Additional context
   
   Raised by @andygrove reviewing #5754. The two earlier fixes in this area 
were #4432
   (`GetStructField`) and #5754 (the hash kernels); this unifies them with the 
third site, which
   the issue had not accounted for.
   


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