1use crate::utils::make_scalar_function;
21use arrow::array::{
22 Array, ArrayRef, BooleanBufferBuilder, GenericListArray, Int64Array, OffsetSizeTrait,
23 UInt64Array,
24};
25use arrow::buffer::{NullBuffer, OffsetBuffer};
26use arrow::compute;
27use arrow::datatypes::DataType;
28use arrow::datatypes::{
29 DataType::{LargeList, List},
30 Field,
31};
32use datafusion_common::cast::{as_int64_array, as_large_list_array, as_list_array};
33use datafusion_common::types::{NativeType, logical_int64};
34use datafusion_common::{Result, exec_datafusion_err};
35use datafusion_expr::{
36 ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
37 Volatility,
38};
39use datafusion_expr_common::signature::{Coercion, TypeSignatureClass};
40use datafusion_macros::user_doc;
41use std::mem::size_of;
42use std::sync::Arc;
43
44const ARRAY_REPEAT_LENGTH_EXCEEDED: &str =
45 "array_repeat: requested length exceeds maximum array size";
46
47make_udf_expr_and_func!(
48 ArrayRepeat,
49 array_repeat,
50 element count, "returns an array containing element `count` times.", array_repeat_udf );
54
55#[user_doc(
56 doc_section(label = "Array Functions"),
57 description = "Returns an array containing element `count` times.",
58 syntax_example = "array_repeat(element, count)",
59 sql_example = r#"```sql
60> select array_repeat(1, 3);
61+---------------------------------+
62| array_repeat(Int64(1),Int64(3)) |
63+---------------------------------+
64| [1, 1, 1] |
65+---------------------------------+
66> select array_repeat([1, 2], 2);
67+------------------------------------+
68| array_repeat(List([1,2]),Int64(2)) |
69+------------------------------------+
70| [[1, 2], [1, 2]] |
71+------------------------------------+
72```"#,
73 argument(
74 name = "element",
75 description = "Element expression. Can be a constant, column, or function, and any combination of array operators."
76 ),
77 argument(
78 name = "count",
79 description = "Value of how many times to repeat the element."
80 )
81)]
82#[derive(Debug, PartialEq, Eq, Hash)]
83pub struct ArrayRepeat {
84 signature: Signature,
85 aliases: Vec<String>,
86}
87
88impl Default for ArrayRepeat {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl ArrayRepeat {
95 pub fn new() -> Self {
96 Self {
97 signature: Signature::coercible(
98 vec![
99 Coercion::new_exact(TypeSignatureClass::Any),
100 Coercion::new_implicit(
101 TypeSignatureClass::Native(logical_int64()),
102 vec![TypeSignatureClass::Integer],
103 NativeType::Int64,
104 ),
105 ],
106 Volatility::Immutable,
107 ),
108 aliases: vec![String::from("list_repeat")],
109 }
110 }
111}
112
113impl ScalarUDFImpl for ArrayRepeat {
114 fn name(&self) -> &str {
115 "array_repeat"
116 }
117
118 fn signature(&self) -> &Signature {
119 &self.signature
120 }
121
122 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
123 let element_type = &arg_types[0];
124 match element_type {
125 LargeList(_) => Ok(LargeList(Arc::new(Field::new_list_field(
126 element_type.clone(),
127 true,
128 )))),
129 _ => Ok(List(Arc::new(Field::new_list_field(
130 element_type.clone(),
131 true,
132 )))),
133 }
134 }
135
136 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
137 make_scalar_function(array_repeat_inner)(&args.args)
138 }
139
140 fn aliases(&self) -> &[String] {
141 &self.aliases
142 }
143
144 fn documentation(&self) -> Option<&Documentation> {
145 self.doc()
146 }
147}
148
149fn array_repeat_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
150 let element = &args[0];
151 let count_array = as_int64_array(&args[1])?;
152
153 match element.data_type() {
154 List(_) => {
155 let list_array = as_list_array(element)?;
156 general_list_repeat::<i32>(list_array, count_array)
157 }
158 LargeList(_) => {
159 let list_array = as_large_list_array(element)?;
160 general_list_repeat::<i64>(list_array, count_array)
161 }
162 _ => general_repeat::<i32>(element, count_array),
163 }
164}
165
166fn general_repeat<O: OffsetSizeTrait>(
179 array: &ArrayRef,
180 count_array: &Int64Array,
181) -> Result<ArrayRef> {
182 let total_repeated_values =
183 (0..count_array.len()).try_fold(0usize, |total, idx| {
184 total
185 .checked_add(repeat_count(count_array, idx).unwrap_or_default())
186 .ok_or_else(|| {
187 exec_datafusion_err!(
188 "array_repeat: total repeated values overflowed usize"
189 )
190 })
191 })?;
192 ensure_repeated_values_fit::<O>(total_repeated_values)?;
193 let (offsets, _) = build_repeat_offsets::<O>(count_array)?;
194
195 let mut take_indices = Vec::with_capacity(total_repeated_values);
196
197 for idx in 0..count_array.len() {
198 let Some(count) = repeat_count(count_array, idx) else {
199 continue;
200 };
201 take_indices.extend(std::iter::repeat_n(idx as u64, count));
202 }
203
204 let repeated_values = compute::take(
206 array.as_ref(),
207 &UInt64Array::from_iter_values(take_indices),
208 None,
209 )?;
210
211 Ok(Arc::new(GenericListArray::<O>::try_new(
213 Arc::new(Field::new_list_field(array.data_type().to_owned(), true)),
214 OffsetBuffer::new(offsets.into()),
215 repeated_values,
216 count_array.nulls().cloned(),
217 )?))
218}
219
220fn general_list_repeat<O: OffsetSizeTrait>(
231 list_array: &GenericListArray<O>,
232 count_array: &Int64Array,
233) -> Result<ArrayRef> {
234 let list_offsets = list_array.value_offsets();
235 let (outer_offsets, outer_total) = build_repeat_offsets::<O>(count_array)?;
236
237 let mut inner_total = 0usize;
239 for i in 0..count_array.len() {
240 let Some(count) = repeat_count(count_array, i) else {
241 continue;
242 };
243 if count > 0 && list_array.is_valid(i) {
244 let len = list_offsets[i + 1].to_usize().unwrap()
245 - list_offsets[i].to_usize().unwrap();
246 inner_total =
247 checked_repeat_len_add(inner_total, checked_repeat_len_mul(len, count)?)?;
248 ensure_repeated_values_fit::<O>(inner_total)?;
249 }
250 }
251
252 let inner_offsets_capacity = checked_offset_slots_capacity::<O>(outer_total)?;
254 let mut inner_offsets = Vec::with_capacity(inner_offsets_capacity);
255 let mut take_indices = Vec::with_capacity(inner_total);
256 let mut inner_nulls = BooleanBufferBuilder::new(outer_total);
257 let mut inner_running = 0usize;
258 inner_offsets.push(O::zero());
259
260 for row_idx in 0..count_array.len() {
261 let Some(count) = repeat_count(count_array, row_idx) else {
262 continue;
263 };
264 let list_is_valid = list_array.is_valid(row_idx);
265 let start = list_offsets[row_idx].to_usize().unwrap();
266 let end = list_offsets[row_idx + 1].to_usize().unwrap();
267 let row_len = end - start;
268
269 for _ in 0..count {
270 inner_running = checked_repeat_len_add(inner_running, row_len)?;
271 ensure_repeated_values_fit::<O>(inner_running)?;
272 let offset = checked_repeat_offset::<O>(inner_running)?;
273 inner_offsets.push(offset);
274 inner_nulls.append(list_is_valid);
275 if list_is_valid {
276 take_indices.extend(start as u64..end as u64);
277 }
278 }
279 }
280
281 let inner_values = compute::take(
283 list_array.values().as_ref(),
284 &UInt64Array::from_iter_values(take_indices),
285 None,
286 )?;
287 let inner_list = GenericListArray::<O>::try_new(
288 Arc::new(Field::new_list_field(list_array.value_type().clone(), true)),
289 OffsetBuffer::new(inner_offsets.into()),
290 inner_values,
291 Some(NullBuffer::new(inner_nulls.finish())),
292 )?;
293
294 Ok(Arc::new(GenericListArray::<O>::try_new(
295 Arc::new(Field::new_list_field(
296 list_array.data_type().to_owned(),
297 true,
298 )),
299 OffsetBuffer::new(outer_offsets.into()),
300 Arc::new(inner_list),
301 count_array.nulls().cloned(),
302 )?))
303}
304
305fn build_repeat_offsets<O: OffsetSizeTrait>(
306 count_array: &Int64Array,
307) -> Result<(Vec<O>, usize)> {
308 let offsets_capacity = checked_offset_slots_capacity::<O>(count_array.len())?;
309 let mut offsets = Vec::with_capacity(offsets_capacity);
310 offsets.push(O::zero());
311 let mut running_offset = 0usize;
312
313 for idx in 0..count_array.len() {
314 let Some(count) = repeat_count(count_array, idx) else {
315 offsets.push(*offsets.last().unwrap());
316 continue;
317 };
318 running_offset = checked_repeat_len_add(running_offset, count)?;
319 ensure_repeated_values_fit::<O>(running_offset)?;
320 let offset = checked_repeat_offset::<O>(running_offset)?;
321 offsets.push(offset);
322 }
323
324 Ok((offsets, running_offset))
325}
326
327fn checked_repeat_len_add(lhs: usize, rhs: usize) -> Result<usize> {
328 lhs.checked_add(rhs)
329 .ok_or_else(|| exec_datafusion_err!("{}", ARRAY_REPEAT_LENGTH_EXCEEDED))
330}
331
332fn checked_repeat_len_mul(lhs: usize, rhs: usize) -> Result<usize> {
333 lhs.checked_mul(rhs)
334 .ok_or_else(|| exec_datafusion_err!("{}", ARRAY_REPEAT_LENGTH_EXCEEDED))
335}
336
337fn ensure_repeated_values_fit<O: OffsetSizeTrait>(len: usize) -> Result<()> {
338 ensure_vec_capacity::<u64>(len)?;
339 checked_repeat_offset::<O>(len)?;
340
341 Ok(())
342}
343
344fn ensure_vec_capacity<T>(len: usize) -> Result<()> {
345 if len > max_vec_elements::<T>() {
346 return Err(exec_datafusion_err!("{}", ARRAY_REPEAT_LENGTH_EXCEEDED));
347 }
348
349 Ok(())
350}
351
352fn checked_offset_slots_capacity<O>(len: usize) -> Result<usize> {
353 let capacity = checked_repeat_len_add(len, 1)?;
354 ensure_vec_capacity::<O>(capacity)?;
355
356 Ok(capacity)
357}
358
359fn checked_repeat_offset<O: OffsetSizeTrait>(offset: usize) -> Result<O> {
360 O::from_usize(offset).ok_or_else(|| {
361 exec_datafusion_err!(
362 "array_repeat: offset {offset} exceeds the maximum value for offset type"
363 )
364 })
365}
366
367fn max_vec_elements<T>() -> usize {
368 let element_size = size_of::<T>();
369 (isize::MAX as usize)
370 .checked_div(element_size)
371 .unwrap_or(usize::MAX)
372}
373
374#[inline]
377fn repeat_count(count_array: &Int64Array, idx: usize) -> Option<usize> {
378 if count_array.is_null(idx) {
379 None
380 } else {
381 let c = count_array.value(idx);
382 Some(if c > 0 { c as usize } else { 0 })
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::{array_repeat_inner, general_list_repeat, general_repeat};
389 use arrow::array::{Array, ArrayRef, AsArray, Int32Array, Int64Array, ListArray};
390 use arrow::buffer::{NullBuffer, OffsetBuffer, ScalarBuffer};
391 use arrow::datatypes::{Field, Int32Type};
392 use datafusion_common::Result;
393 use std::sync::Arc;
394
395 #[test]
396 fn test_array_repeat_null_count_stays_null() -> Result<()> {
397 let array: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3]));
398 let counts = Int64Array::new(
399 ScalarBuffer::from(vec![2, 1, 1]),
400 Some(NullBuffer::from(vec![true, false, true])),
401 );
402
403 let result = general_repeat::<i32>(&array, &counts)?;
404 let expected = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
405 Some(vec![Some(1), Some(1)]),
406 None,
407 Some(vec![Some(3)]),
408 ]);
409
410 assert_eq!(result.as_list::<i32>(), &expected);
411
412 Ok(())
413 }
414
415 #[test]
416 fn test_array_repeat_nested_null_count_stays_null() -> Result<()> {
417 let list_array = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
418 Some(vec![Some(1), Some(2)]),
419 Some(vec![Some(3), Some(4)]),
420 Some(vec![Some(5)]),
421 ]);
422 let counts = Int64Array::new(
423 ScalarBuffer::from(vec![2, 1, 1]),
424 Some(NullBuffer::from(vec![true, false, true])),
425 );
426
427 let result = general_list_repeat::<i32>(&list_array, &counts)?;
428 let repeated_values = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
429 Some(vec![Some(1), Some(2)]),
430 Some(vec![Some(1), Some(2)]),
431 Some(vec![Some(5)]),
432 ]);
433 let expected = ListArray::new(
434 Arc::new(Field::new_list_field(
435 repeated_values.data_type().clone(),
436 true,
437 )),
438 OffsetBuffer::new(ScalarBuffer::from(vec![0, 2, 2, 3])),
439 Arc::new(repeated_values),
440 Some(NullBuffer::from(vec![true, false, true])),
441 );
442
443 assert_eq!(result.as_list::<i32>(), &expected);
444
445 Ok(())
446 }
447
448 #[test]
449 fn scalar_count_exceeding_max_array_size_returns_error() {
450 let element: ArrayRef = Arc::new(Int64Array::from(vec![1]));
451 let count: ArrayRef = Arc::new(Int64Array::from(vec![i64::MAX]));
452
453 let err = array_repeat_inner(&[element, count]).unwrap_err();
454 assert!(
455 err.to_string().starts_with(
456 "Execution error: array_repeat: requested length exceeds maximum array size"
457 ),
458 "unexpected error: {err}"
459 );
460 }
461
462 #[test]
463 fn scalar_count_exceeding_list_offset_limit_returns_error() {
464 let element: ArrayRef = Arc::new(Int64Array::from(vec![1]));
465 let count: ArrayRef = Arc::new(Int64Array::from(vec![i32::MAX as i64 + 1]));
466
467 let err = array_repeat_inner(&[element, count]).unwrap_err();
468 assert!(
469 err.to_string().starts_with(
470 "Execution error: array_repeat: offset 2147483648 exceeds the maximum value for offset type"
471 ),
472 "unexpected error: {err}"
473 );
474 }
475}