Skip to content

Commit aaad2c0

Browse files
committed
add regression test to align with GroupValueRows & re-order overflow check
1 parent dc097bd commit aaad2c0

1 file changed

Lines changed: 44 additions & 10 deletions

File tree

  • datafusion/physical-plan/src/aggregates/group_values/multi_group_by

datafusion/physical-plan/src/aggregates/group_values/multi_group_by/dictionary.rs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ impl<K: ArrowDictionaryKeyType + Send + Sync> DictionaryGroupValuesColumn<K> {
5858

5959
/// Returns an error if adding `additional` groups would overflow the key type's range.
6060
// https://github.com/apache/datafusion/issues/23127
61-
fn check_key_overflow(current_len: usize, additional: usize) -> Result<()> {
62-
if !Self::valid_bounds::<K>(current_len + additional) {
61+
fn check_key_overflow(current_len: usize) -> Result<()> {
62+
if !Self::valid_bounds::<K>(current_len) {
6363
return exec_err!(
6464
"Dictionary key type {:?} cannot represent {} groups",
6565
K::DATA_TYPE,
66-
current_len + additional
66+
current_len
6767
);
6868
}
6969
Ok(())
@@ -97,12 +97,12 @@ impl<K: ArrowDictionaryKeyType + Send + Sync> GroupColumn
9797
}
9898

9999
fn append_val(&mut self, array: &ArrayRef, row: usize) -> Result<()> {
100-
Self::check_key_overflow(self.inner.len(), 1)?;
101100
let dict = array.as_dictionary::<K>();
102101
match dict.key(row) {
103-
None => self.inner.append_val(&self.null_array, 0),
104-
Some(key) => self.inner.append_val(dict.values(), key),
102+
None => self.inner.append_val(&self.null_array, 0)?,
103+
Some(key) => self.inner.append_val(dict.values(), key)?,
105104
}
105+
Self::check_key_overflow(self.inner.len())
106106
}
107107

108108
fn vectorized_equal_to(
@@ -161,7 +161,6 @@ impl<K: ArrowDictionaryKeyType + Send + Sync> GroupColumn
161161
}
162162

163163
fn vectorized_append(&mut self, array: &ArrayRef, rows: &[usize]) -> Result<()> {
164-
Self::check_key_overflow(self.inner.len(), rows.len())?;
165164
let dict = array.as_dictionary::<K>();
166165
let dict_keys = dict.keys();
167166

@@ -170,15 +169,17 @@ impl<K: ArrowDictionaryKeyType + Send + Sync> GroupColumn
170169
.iter()
171170
.map(|&row_index| dict_keys.value(row_index).as_usize())
172171
.collect();
173-
self.inner.vectorized_append(dict.values(), &value_indices)
172+
self.inner
173+
.vectorized_append(dict.values(), &value_indices)?;
174174
} else if let Some(sentinel) = Self::null_sentinel_index(dict.values()) {
175175
// Values already contains a null entry; reuse its position as the
176176
// sentinel so null keys map there without any allocation.
177177
let value_indices: Vec<usize> = rows
178178
.iter()
179179
.map(|&row_index| dict.key(row_index).unwrap_or(sentinel))
180180
.collect();
181-
self.inner.vectorized_append(dict.values(), &value_indices)
181+
self.inner
182+
.vectorized_append(dict.values(), &value_indices)?;
182183
} else {
183184
// Null keys but values has no null entry: scalar fallback per row.
184185
for &row_index in rows {
@@ -187,8 +188,8 @@ impl<K: ArrowDictionaryKeyType + Send + Sync> GroupColumn
187188
Some(key) => self.inner.append_val(dict.values(), key)?,
188189
}
189190
}
190-
Ok(())
191191
}
192+
Self::check_key_overflow(self.inner.len())
192193
}
193194

194195
fn len(&self) -> usize {
@@ -370,4 +371,37 @@ mod tests {
370371
assert!(out.as_dictionary::<Int32Type>().key(2).is_none());
371372
assert_eq!(u64_val(&out, 3), 99);
372373
}
374+
375+
// Regression test for https://github.com/apache/datafusion/issues/23127 —
376+
// we should fail early when we can't produce the correct output schema.
377+
#[test]
378+
fn uint8_key_overflow() {
379+
use arrow::array::UInt8Array;
380+
use arrow::datatypes::UInt8Type;
381+
use datafusion_physical_expr::binary_map::OutputType;
382+
383+
let field = Field::new("", DataType::Utf8, true);
384+
let mut col = DictionaryGroupValuesColumn::<UInt8Type>::new(
385+
Box::new(ByteGroupValueBuilder::<i32>::new(OutputType::Utf8)),
386+
&field,
387+
);
388+
389+
// fill all 256 distinct values (u8 key range 0..=255)
390+
let strs: Vec<String> = (0..=255u16).map(|i| i.to_string()).collect();
391+
let str_refs: Vec<&str> = strs.iter().map(|s| s.as_str()).collect();
392+
let full: ArrayRef = Arc::new(DictionaryArray::<UInt8Type>::new(
393+
UInt8Array::from((0..=255u8).map(Some).collect::<Vec<_>>()),
394+
Arc::new(StringArray::from(str_refs)),
395+
));
396+
let rows: Vec<usize> = (0..256).collect();
397+
col.vectorized_append(&full, &rows).unwrap();
398+
assert_eq!(col.len(), 256);
399+
400+
// one more must overflow the key range
401+
let extra: ArrayRef = Arc::new(DictionaryArray::<UInt8Type>::new(
402+
UInt8Array::from(vec![Some(0u8)]),
403+
Arc::new(StringArray::from(vec!["overflow"])),
404+
));
405+
assert!(col.append_val(&extra, 0).is_err());
406+
}
373407
}

0 commit comments

Comments
 (0)