Conversation
|
Thanks for opening a pull request! This pull request has been automatically converted to a draft because its title doesn't match Arrow's required format. If this is not a minor PR. Could you open an issue for this pull request on GitHub? https://github.com/apache/arrow/issues/new/choose Opening GitHub issues ahead of time contributes to the Openness of the Apache Arrow project. Then could you also rename the pull request title in the following format? or After updating the title, you can mark the pull request as ready for review. See also: |
There was a problem hiding this comment.
Pull request overview
This PR fixes is_null(..., nan_is_null=true) for dictionary-encoded floating-point arrays by detecting NaN values in the dictionary and marking corresponding slots as null in the output.
Changes:
- Added dictionary-aware NaN detection for
is_nullwhennan_is_nullis enabled. - Implemented templated helpers to dispatch over dictionary index integer types and float value types (float/double/half-float).
- Added includes needed for dictionary type inspection and safe casting.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| default: | ||
| SetNanBitsDictionary<int32_t, ValueType>(arr, dict_span, out_bitmap, out_offset); | ||
| break; |
| const IndexType* indices = arr.GetValues<IndexType>(1); | ||
| const ValueType* dict_values = dict_span.GetValues<ValueType>(1); | ||
| for (int64_t i = 0; i < arr.length; ++i) { | ||
| auto dict_index = indices[i]; | ||
| bool is_nan; | ||
| if constexpr (std::is_same_v<ValueType, uint16_t>) { | ||
| is_nan = Float16::FromBits(dict_values[dict_index]).is_nan(); | ||
| } else { | ||
| is_nan = std::isnan(dict_values[dict_index]); | ||
| } |
Reranko05
left a comment
There was a problem hiding this comment.
Could you use the Arrow PR title template:-
GH-<Issue Number>: [<Component>] <Title>
If there isn't an existed issue, you can create a new one.
And could you use Arrow PR template for description
- Rationale for this change
- What changes are included in this PR?
- Are these changes tested?
- Are there any user-facing changes?
|
Updated the title and description to match the template, and fixed both issues from the review: null index slots are now skipped before dereferencing the dictionary, and the default case in the index-type dispatch fails fast instead of assuming int32. |
|
@shoemoney Hi, thanks for submitting this. Some high-level comments after taking a quick look:
@zanmato1984 Thoughts? |
|
Thanks for the look. On (1), opened #51127 and retitled against it. On (2), no: the current patch only skips null index slots, so a null dictionary value referenced by a valid index still gets dereferenced, which is the gap you're pointing at. Your |
|
|
Fix verified RED->GREEN. is_null with nan_is_null=True ignores NaN in dictionary-encoded float arrays at scalar_validity.cc:124
…index types Skip null index slots in SetNanBitsDictionary before dereferencing the dictionary to avoid out-of-bounds reads on arrays with nulls. Make the default case in DispatchIndexType fail fast instead of silently treating unknown index types as int32.
Replace the per-index-type NaN loop with is_null over the dictionary values followed by take through the indices, so null dictionary entries are reported as well as NaN ones.
2ff410b to
1d2b266
Compare
|
Switched to your approach in (3). The NaN loop and its per-index-type dispatch are gone, replaced by That also answers (2): a null dictionary value behind a valid index is reported as null now. New test The path still only runs for Rebased onto main, commit 1d2b266. Local run of |
There was a problem hiding this comment.
🟢 Approval recommended
The functional fix and new coverage align with the issue description, with only a minor performance refinement suggested in review comments.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
The new code uses checked_cast unqualified in two places, which should be ::arrow::internal::checked_cast (or imported), and will otherwise fail to compile.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
cpp/src/arrow/compute/kernels/scalar_validity.cc:171
- Unqualified
checked_casthere should be::arrow::internal::checked_cast(or add ausing internal::checked_cast;in scope); as written this is a compile error.
const auto& dict_type = checked_cast<const DictionaryType&>(*arr.type);
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
| const auto& dict_type = checked_cast<const DictionaryType&>(*arr.type); | ||
| ARROW_ASSIGN_OR_RAISE(Datum dict_is_null, |
There was a problem hiding this comment.
scalar_validity.cc includes common_internal.h, which imports arrow::internal::checked_cast into namespace arrow with using internal::checked_cast (line 51). Both calls are inside namespaces nested in arrow, so unqualified lookup finds that declaration. On September 18, I verified the unchanged commit 8811b9e with a fresh compiler syntax check using the generated build flags and warnings as errors; it passes. The scalar utility suite also passes all 99 tests. No code change is needed for this finding.
Rationale for this change
is_null(..., nan_is_null=true)did not detect NaN values in dictionary-encoded floating-point arrays.IsNullExeconly checked the top-level type id for floating point, so dictionary-encoded arrays (type id DICTIONARY) skipped the NaN path entirely and NaN values in the dictionary were never marked null. A null value in the dictionary, referenced by a valid index, was not reported either.What changes are included in this PR?
SetNullBitsFromDictionary, which callsis_nullon the dictionary values, maps the result through the indices withtake, and ORs the resulting bitmap into the output.IsNullExecto route a DICTIONARY type with floating-point values andnan_is_null=trueto that helper.takeruns with bounds checking, so an out-of-range index returns an error instead of reading past the dictionary.The path only runs for
nan_is_null=truewith a floating-point value type, sois_nullwith default options is unchanged for every dictionary type.Are these changes tested?
Yes.
IsNullDictionaryNullValuescovers a null dictionary value and fails without the kernel change.IsNullDictionaryNanIsNull,IsNullDictionaryNanIsNullHalfFloatandIsNullDictionaryNanIsNullUnsignedIndicescover NaN entries for float64, float16 and a uint8 index type.Are there any user-facing changes?
Yes.
is_null(..., nan_is_null=true)now treats both NaN and null entries of a dictionary-encoded float array as null.Written in conjunction with my pair programmer Claude.