Skip to content

Commit 3fefd49

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 3cfe9d7 commit 3fefd49

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
}
@@ -1711,7 +1719,11 @@ mod tests {
17111719
let keys = Int8Array::from(vec![Some(0), Some(1), None, Some(2)]);
17121720
let array: ArrayRef = Arc::new(DictionaryArray::try_new(
17131721
keys.clone(),
1714-
Arc::new(Float64Array::from(vec![-0.0, nan, 1.0])),
1722+
// Numeric casts can leave an all-valid bitmap on dictionary values.
1723+
Arc::new(Float64Array::new(
1724+
vec![-0.0, nan, 1.0].into(),
1725+
Some(NullBuffer::new_valid(3)),
1726+
)),
17151727
)?);
17161728

17171729
let normalized = normalize_float_zero(&array);
@@ -1721,6 +1733,12 @@ mod tests {
17211733
assert_eq!(values.value(0).to_bits(), 0.0_f64.to_bits());
17221734
assert_eq!(values.value(1).to_bits(), nan.to_bits());
17231735
assert_eq!(values.value(2), 1.0);
1736+
assert!(values.nulls().is_none());
1737+
// Logical validity should reuse the keys' bitmap without scanning them.
1738+
assert_eq!(
1739+
dictionary.logical_nulls().unwrap().buffer().as_ptr(),
1740+
keys.nulls().unwrap().buffer().as_ptr()
1741+
);
17241742

17251743
assert!(Arc::ptr_eq(&normalize_float_zero(&normalized), &normalized));
17261744

0 commit comments

Comments
 (0)