Skip to content

Commit 6730aed

Browse files
Avoid redundant dictionary validity after zero normalization
Discard all-valid bitmaps on rewritten dictionary values so comparisons can reuse key validity without rescanning every key. Preserve the no-op path and real value nulls, and extend the existing dictionary regression.
1 parent 54960e8 commit 6730aed

1 file changed

Lines changed: 19 additions & 1 deletion

File tree

  • datafusion/common/src/utils

‎datafusion/common/src/utils/mod.rs‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1456,11 +1456,19 @@ pub fn normalize_float_zero(array: &ArrayRef) -> ArrayRef {
14561456
const NEG_ZERO_F64_BITS: u64 = (-0.0_f64).to_bits();
14571457
match array.data_type() {
14581458
DataType::Dictionary(_, value_type) if has_float_leaf(value_type) => {
1459+
// Reuse the keys: rebuilding dictionary ArrayData revalidates each key.
14591460
let dictionary = array.as_any_dictionary();
14601461
let values = normalize_float_zero(dictionary.values());
14611462
if Arc::ptr_eq(&values, dictionary.values()) {
14621463
Arc::clone(array)
14631464
} else {
1465+
// Drop redundant validity so dictionary comparisons can reuse
1466+
// the keys' nulls instead of scanning every key for value nulls.
1467+
let values = if values.nulls().is_some_and(|n| n.null_count() == 0) {
1468+
make_array(values.to_data())
1469+
} else {
1470+
values
1471+
};
14641472
dictionary.with_values(values)
14651473
}
14661474
}
@@ -1631,7 +1639,11 @@ mod tests {
16311639
let keys = Int8Array::from(vec![Some(0), Some(1), None, Some(2)]);
16321640
let array: ArrayRef = Arc::new(DictionaryArray::try_new(
16331641
keys.clone(),
1634-
Arc::new(Float64Array::from(vec![-0.0, nan, 1.0])),
1642+
// Numeric casts can leave an all-valid bitmap on dictionary values.
1643+
Arc::new(Float64Array::new(
1644+
vec![-0.0, nan, 1.0].into(),
1645+
Some(NullBuffer::new_valid(3)),
1646+
)),
16351647
)?);
16361648

16371649
let normalized = normalize_float_zero(&array);
@@ -1641,6 +1653,12 @@ mod tests {
16411653
assert_eq!(values.value(0).to_bits(), 0.0_f64.to_bits());
16421654
assert_eq!(values.value(1).to_bits(), nan.to_bits());
16431655
assert_eq!(values.value(2), 1.0);
1656+
assert!(values.nulls().is_none());
1657+
// Logical validity should reuse the keys' bitmap without scanning them.
1658+
assert_eq!(
1659+
dictionary.logical_nulls().unwrap().buffer().as_ptr(),
1660+
keys.nulls().unwrap().buffer().as_ptr()
1661+
);
16441662

16451663
assert!(Arc::ptr_eq(&normalize_float_zero(&normalized), &normalized));
16461664

0 commit comments

Comments
 (0)