1use crate::utils;
21use arrow::array::{
22 Array, ArrayRef, Capacities, GenericListArray, MutableArrayData, NullBufferBuilder,
23 OffsetSizeTrait, Scalar, cast::AsArray, make_array, new_null_array,
24};
25use arrow::buffer::OffsetBuffer;
26use arrow::datatypes::{DataType, FieldRef};
27use datafusion_common::cast::as_int64_array;
28use datafusion_common::utils::ListCoercion;
29use datafusion_common::{
30 Result, ScalarValue, exec_err, internal_err, utils::take_function_args,
31};
32use datafusion_expr::{
33 ArrayFunctionArgument, ArrayFunctionSignature, ColumnarValue, Documentation,
34 ScalarFunctionArgs, ScalarUDFImpl, Signature, TypeSignature, Volatility,
35};
36use datafusion_macros::user_doc;
37use std::sync::Arc;
38
39make_udf_expr_and_func!(
40 ArrayRemove,
41 array_remove,
42 array element,
43 "removes the first element from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
44 array_remove_udf
45);
46
47#[user_doc(
48 doc_section(label = "Array Functions"),
49 description = "Removes the first element from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
50 syntax_example = "array_remove(array, element)",
51 sql_example = r#"```sql
52> select array_remove([1, 2, 2, 3, 2, 1, 4], 2);
53+----------------------------------------------+
54| array_remove(List([1,2,2,3,2,1,4]),Int64(2)) |
55+----------------------------------------------+
56| [1, 2, 3, 2, 1, 4] |
57+----------------------------------------------+
58
59> select array_remove([1, 2, NULL, 2, 4], 2);
60+---------------------------------------------------+
61| array_remove(List([1,2,NULL,2,4]),Int64(2)) |
62+---------------------------------------------------+
63| [1, NULL, 2, 4] |
64+---------------------------------------------------+
65```"#,
66 argument(
67 name = "array",
68 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
69 ),
70 argument(
71 name = "element",
72 description = "Element to be removed from the array."
73 )
74)]
75#[derive(Debug, PartialEq, Eq, Hash)]
76pub struct ArrayRemove {
77 signature: Signature,
78 aliases: Vec<String>,
79}
80
81impl Default for ArrayRemove {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87impl ArrayRemove {
88 pub fn new() -> Self {
89 Self {
90 signature: Signature::array_and_element(Volatility::Immutable),
91 aliases: vec!["list_remove".to_string()],
92 }
93 }
94}
95
96impl ScalarUDFImpl for ArrayRemove {
97 fn name(&self) -> &str {
98 "array_remove"
99 }
100
101 fn signature(&self) -> &Signature {
102 &self.signature
103 }
104
105 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
106 internal_err!("return_field_from_args should be used instead")
107 }
108
109 fn return_field_from_args(
110 &self,
111 args: datafusion_expr::ReturnFieldArgs,
112 ) -> Result<FieldRef> {
113 let array_field = args.arg_fields[0].as_ref().clone();
114 let nullable = args.arg_fields.iter().any(|f| f.is_nullable());
115 Ok(Arc::new(array_field.with_nullable(nullable)))
116 }
117
118 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
119 let [list_arg, element_arg] = take_function_args(self.name(), &args.args)?;
120 let num_rows = args.number_rows;
121 let list_array = list_arg.to_array(num_rows)?;
122 match element_arg {
123 ColumnarValue::Scalar(scalar_element)
124 if !scalar_element.is_null()
125 && !scalar_element.data_type().is_nested() =>
126 {
127 let result =
128 array_remove_with_scalar_args(&list_array, scalar_element, 1i64)?;
129 Ok(ColumnarValue::Array(result))
130 }
131 element_arg => {
132 let element_array = element_arg.to_array(num_rows)?;
133 let result =
134 array_remove_internal(&list_array, &element_array, &[Some(1)])?;
135 Ok(ColumnarValue::Array(result))
136 }
137 }
138 }
139
140 fn aliases(&self) -> &[String] {
141 &self.aliases
142 }
143
144 fn documentation(&self) -> Option<&Documentation> {
145 self.doc()
146 }
147}
148
149make_udf_expr_and_func!(
150 ArrayRemoveN,
151 array_remove_n,
152 array element max,
153 "removes the first `max` elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
154 array_remove_n_udf
155);
156
157#[user_doc(
158 doc_section(label = "Array Functions"),
159 description = "Removes the first `max` elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
160 syntax_example = "array_remove_n(array, element, max)",
161 sql_example = r#"```sql
162> select array_remove_n([1, 2, 2, 3, 2, 1, 4], 2, 2);
163+---------------------------------------------------------+
164| array_remove_n(List([1,2,2,3,2,1,4]),Int64(2),Int64(2)) |
165+---------------------------------------------------------+
166| [1, 3, 2, 1, 4] |
167+---------------------------------------------------------+
168
169> select array_remove_n([1, 2, NULL, 2, 4], 2, 2);
170+----------------------------------------------------------+
171| array_remove_n(List([1,2,NULL,2,4]),Int64(2),Int64(2)) |
172+----------------------------------------------------------+
173| [1, NULL, 4] |
174+----------------------------------------------------------+
175```"#,
176 argument(
177 name = "array",
178 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
179 ),
180 argument(
181 name = "element",
182 description = "Element to be removed from the array."
183 ),
184 argument(name = "max", description = "Number of first occurrences to remove.")
185)]
186#[derive(Debug, PartialEq, Eq, Hash)]
187pub struct ArrayRemoveN {
188 signature: Signature,
189 aliases: Vec<String>,
190}
191
192impl Default for ArrayRemoveN {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl ArrayRemoveN {
199 pub fn new() -> Self {
200 Self {
201 signature: Signature::new(
202 TypeSignature::ArraySignature(ArrayFunctionSignature::Array {
203 arguments: vec![
204 ArrayFunctionArgument::Array,
205 ArrayFunctionArgument::Element,
206 ArrayFunctionArgument::Index,
207 ],
208 array_coercion: Some(ListCoercion::FixedSizedListToList),
209 }),
210 Volatility::Immutable,
211 ),
212 aliases: vec!["list_remove_n".to_string()],
213 }
214 }
215}
216
217impl ScalarUDFImpl for ArrayRemoveN {
218 fn name(&self) -> &str {
219 "array_remove_n"
220 }
221
222 fn signature(&self) -> &Signature {
223 &self.signature
224 }
225
226 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
227 internal_err!("return_field_from_args should be used instead")
228 }
229
230 fn return_field_from_args(
231 &self,
232 args: datafusion_expr::ReturnFieldArgs,
233 ) -> Result<FieldRef> {
234 let array_field = args.arg_fields[0].as_ref().clone();
235 let nullable = args.arg_fields.iter().any(|f| f.is_nullable());
236 Ok(Arc::new(array_field.with_nullable(nullable)))
237 }
238
239 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
240 let [list_arg, element_arg, max_arg] =
241 take_function_args(self.name(), &args.args)?;
242 let num_rows = args.number_rows;
243 let list_array = list_arg.to_array(num_rows)?;
244 match (element_arg, max_arg) {
245 (
246 ColumnarValue::Scalar(scalar_element),
247 ColumnarValue::Scalar(scalar_max),
248 ) if !scalar_element.is_null() && !scalar_element.data_type().is_nested() => {
249 let ScalarValue::Int64(Some(n)) = scalar_max else {
250 return Ok(ColumnarValue::Array(new_null_array(
251 list_array.data_type(),
252 num_rows,
253 )));
254 };
255 let result =
256 array_remove_with_scalar_args(&list_array, scalar_element, *n)?;
257 Ok(ColumnarValue::Array(result))
258 }
259 (element_arg, max_arg) => {
260 let element_array = element_arg.to_array(num_rows)?;
261 let max_array = max_arg.to_array(num_rows)?;
262 let arr_n = as_int64_array(&max_array)?.iter().collect::<Vec<_>>();
263 let result = array_remove_internal(&list_array, &element_array, &arr_n)?;
264 Ok(ColumnarValue::Array(result))
265 }
266 }
267 }
268
269 fn aliases(&self) -> &[String] {
270 &self.aliases
271 }
272
273 fn documentation(&self) -> Option<&Documentation> {
274 self.doc()
275 }
276}
277
278make_udf_expr_and_func!(
279 ArrayRemoveAll,
280 array_remove_all,
281 array element,
282 "removes all elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
283 array_remove_all_udf
284);
285
286#[user_doc(
287 doc_section(label = "Array Functions"),
288 description = "Removes all elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries.",
289 syntax_example = "array_remove_all(array, element)",
290 sql_example = r#"```sql
291> select array_remove_all([1, 2, 2, 3, 2, 1, 4], 2);
292+--------------------------------------------------+
293| array_remove_all(List([1,2,2,3,2,1,4]),Int64(2)) |
294+--------------------------------------------------+
295| [1, 3, 1, 4] |
296+--------------------------------------------------+
297
298> select array_remove_all([1, 2, NULL, 2, 4], 2);
299+-----------------------------------------------------+
300| array_remove_all(List([1,2,NULL,2,4]),Int64(2)) |
301+-----------------------------------------------------+
302| [1, NULL, 4] |
303+-----------------------------------------------------+
304```"#,
305 argument(
306 name = "array",
307 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
308 ),
309 argument(
310 name = "element",
311 description = "Element to be removed from the array."
312 )
313)]
314#[derive(Debug, PartialEq, Eq, Hash)]
315pub struct ArrayRemoveAll {
316 signature: Signature,
317 aliases: Vec<String>,
318}
319
320impl Default for ArrayRemoveAll {
321 fn default() -> Self {
322 Self::new()
323 }
324}
325
326impl ArrayRemoveAll {
327 pub fn new() -> Self {
328 Self {
329 signature: Signature::array_and_element(Volatility::Immutable),
330 aliases: vec!["list_remove_all".to_string()],
331 }
332 }
333}
334
335impl ScalarUDFImpl for ArrayRemoveAll {
336 fn name(&self) -> &str {
337 "array_remove_all"
338 }
339
340 fn signature(&self) -> &Signature {
341 &self.signature
342 }
343
344 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
345 internal_err!("return_field_from_args should be used instead")
346 }
347
348 fn return_field_from_args(
349 &self,
350 args: datafusion_expr::ReturnFieldArgs,
351 ) -> Result<FieldRef> {
352 let array_field = args.arg_fields[0].as_ref().clone();
353 let nullable = args.arg_fields.iter().any(|f| f.is_nullable());
354 Ok(Arc::new(array_field.with_nullable(nullable)))
355 }
356
357 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
358 let [list_arg, element_arg] = take_function_args(self.name(), &args.args)?;
359 let num_rows = args.number_rows;
360 let list_array = list_arg.to_array(num_rows)?;
361 match element_arg {
362 ColumnarValue::Scalar(scalar_element)
363 if !scalar_element.is_null()
364 && !scalar_element.data_type().is_nested() =>
365 {
366 let result =
367 array_remove_with_scalar_args(&list_array, scalar_element, i64::MAX)?;
368 Ok(ColumnarValue::Array(result))
369 }
370 element_arg => {
371 let element_array = element_arg.to_array(num_rows)?;
372 let result = array_remove_internal(
373 &list_array,
374 &element_array,
375 &[Some(i64::MAX)],
376 )?;
377 Ok(ColumnarValue::Array(result))
378 }
379 }
380 }
381
382 fn aliases(&self) -> &[String] {
383 &self.aliases
384 }
385
386 fn documentation(&self) -> Option<&Documentation> {
387 self.doc()
388 }
389}
390
391fn array_remove_internal(
392 array: &ArrayRef,
393 element_array: &ArrayRef,
394 arr_n: &[Option<i64>],
395) -> Result<ArrayRef> {
396 match array.data_type() {
397 DataType::List(_) => {
398 let list_array = array.as_list::<i32>();
399 general_remove::<i32>(list_array, element_array, arr_n)
400 }
401 DataType::LargeList(_) => {
402 let list_array = array.as_list::<i64>();
403 general_remove::<i64>(list_array, element_array, arr_n)
404 }
405 DataType::Null => Ok(new_null_array(array.data_type(), array.len())),
406 array_type => {
407 exec_err!("array_remove_all does not support type '{array_type}'.")
408 }
409 }
410}
411
412fn array_remove_with_scalar_args(
415 array: &ArrayRef,
416 scalar_needle: &ScalarValue,
417 max_removals: i64,
418) -> Result<ArrayRef> {
419 match array.data_type() {
420 DataType::List(_) => {
421 let list_array = array.as_list::<i32>();
422 general_remove_with_scalar::<i32>(list_array, scalar_needle, max_removals)
423 }
424 DataType::LargeList(_) => {
425 let list_array = array.as_list::<i64>();
426 general_remove_with_scalar::<i64>(list_array, scalar_needle, max_removals)
427 }
428 DataType::Null => Ok(new_null_array(array.data_type(), array.len())),
429 array_type => exec_err!(
430 "array_remove/array_remove_n/array_remove_all does not support type '{array_type}'."
431 ),
432 }
433}
434
435fn general_remove<OffsetSize: OffsetSizeTrait>(
453 list_array: &GenericListArray<OffsetSize>,
454 element_array: &ArrayRef,
455 arr_n: &[Option<i64>],
456) -> Result<ArrayRef> {
457 let list_field = match list_array.data_type() {
458 DataType::List(field) | DataType::LargeList(field) => field,
459 _ => {
460 return exec_err!(
461 "Expected List or LargeList data type, got {:?}",
462 list_array.data_type()
463 );
464 }
465 };
466 let original_data = list_array.values().to_data();
467 let mut offsets = Vec::<OffsetSize>::with_capacity(list_array.len() + 1);
469 offsets.push(OffsetSize::zero());
470
471 let mut mutable = MutableArrayData::with_capacities(
472 vec![&original_data],
473 false,
474 Capacities::Array(original_data.len()),
475 );
476 let mut valid = NullBufferBuilder::new(list_array.len());
477
478 for (row_index, offset_window) in list_array.offsets().windows(2).enumerate() {
479 if list_array.is_null(row_index) || element_array.is_null(row_index) {
480 offsets.push(offsets[row_index]);
481 valid.append_null();
482 continue;
483 }
484
485 let n = if arr_n.len() == 1 {
486 arr_n[0]
487 } else {
488 arr_n[row_index]
489 };
490 let Some(n) = n else {
491 offsets.push(offsets[row_index]);
492 valid.append_null();
493 continue;
494 };
495
496 let start = offset_window[0].to_usize().unwrap();
497 let end = offset_window[1].to_usize().unwrap();
498
499 let eq_array = utils::compare_element_to_list(
501 &list_array.value(row_index),
502 element_array,
503 row_index,
504 false,
505 )?;
506
507 let num_to_remove = eq_array.false_count();
508
509 if num_to_remove == 0 {
511 mutable.try_extend(0, start, end)?;
512 offsets.push(offsets[row_index] + OffsetSize::usize_as(end - start));
513 valid.append_non_null();
514 continue;
515 }
516
517 let max_removals = n.min(num_to_remove as i64);
519 let mut removed = 0i64;
520 let mut copied = 0usize;
521 let mut pending_batch_to_retain: Option<usize> = None;
523 for (i, keep) in eq_array.iter().enumerate() {
524 if keep == Some(false) && removed < max_removals {
525 if let Some(bs) = pending_batch_to_retain {
527 mutable.try_extend(0, start + bs, start + i)?;
528 copied += i - bs;
529 pending_batch_to_retain = None;
530 }
531 removed += 1;
532 } else if pending_batch_to_retain.is_none() {
533 pending_batch_to_retain = Some(i);
534 }
535 }
536
537 if let Some(bs) = pending_batch_to_retain {
539 mutable.try_extend(0, start + bs, start + eq_array.len())?;
540 copied += eq_array.len() - bs;
541 }
542
543 offsets.push(offsets[row_index] + OffsetSize::usize_as(copied));
544 valid.append_non_null();
545 }
546
547 let new_values = make_array(mutable.freeze());
548 Ok(Arc::new(GenericListArray::<OffsetSize>::try_new(
549 Arc::clone(list_field),
550 OffsetBuffer::new(offsets.into()),
551 new_values,
552 valid.finish(),
553 )?))
554}
555
556fn general_remove_with_scalar<OffsetSize: OffsetSizeTrait>(
562 list_array: &GenericListArray<OffsetSize>,
563 scalar_needle: &ScalarValue,
564 max_removals: i64,
565) -> Result<ArrayRef> {
566 if max_removals <= 0 {
567 return Ok(Arc::new(list_array.clone()));
568 }
569
570 let list_field = match list_array.data_type() {
571 DataType::List(field) | DataType::LargeList(field) => field,
572 _ => {
573 return exec_err!(
574 "Expected List or LargeList data type, got {:?}",
575 list_array.data_type()
576 );
577 }
578 };
579
580 let list_offsets = list_array.offsets();
581 let first_offset = list_offsets[0].to_usize().unwrap();
582 let last_offset = list_offsets[list_offsets.len() - 1].to_usize().unwrap();
583 let values_range_len = last_offset - first_offset;
584 let values_slice = list_array.values().slice(first_offset, values_range_len);
585 let original_data = values_slice.to_data();
586 let mut offsets = Vec::<OffsetSize>::with_capacity(list_array.len() + 1);
587 offsets.push(OffsetSize::zero());
588
589 let mut mutable = MutableArrayData::with_capacities(
590 vec![&original_data],
591 false,
592 Capacities::Array(original_data.len()),
593 );
594 let nulls = list_array.nulls().cloned();
595 let needle = scalar_needle.to_array_of_size(1)?;
596 let remove_mask = arrow_ord::cmp::not_distinct(&values_slice, &Scalar::new(needle))?;
597 let remove_bits = remove_mask.values();
598
599 for (row_index, offset_window) in list_offsets.windows(2).enumerate() {
600 if nulls.as_ref().is_some_and(|nulls| nulls.is_null(row_index)) {
601 offsets.push(offsets[row_index]);
602 continue;
603 }
604
605 let start = offset_window[0].to_usize().unwrap() - first_offset;
606 let end = offset_window[1].to_usize().unwrap() - first_offset;
607 let row_len = end - start;
608
609 let row_remove_bits = remove_bits.slice(start, row_len);
610 let num_to_remove = row_remove_bits.count_set_bits();
611
612 if num_to_remove == 0 {
613 mutable.try_extend(0, start, end)?;
614 offsets.push(offsets[row_index] + OffsetSize::usize_as(row_len));
615 continue;
616 }
617
618 let removals_to_apply = max_removals.min(num_to_remove as i64) as usize;
619
620 let mut removed = 0usize;
624 let mut copied = 0usize;
625 let mut prev_end = start;
626 for remove_pos in row_remove_bits.set_indices() {
627 let abs_pos = start + remove_pos;
628 if abs_pos > prev_end {
629 mutable.try_extend(0, prev_end, abs_pos)?;
630 copied += abs_pos - prev_end;
631 }
632 prev_end = abs_pos + 1;
633 removed += 1;
634 if removed == removals_to_apply {
635 break;
636 }
637 }
638 if prev_end < end {
640 mutable.try_extend(0, prev_end, end)?;
641 copied += end - prev_end;
642 }
643
644 offsets.push(offsets[row_index] + OffsetSize::usize_as(copied));
645 }
646
647 let new_values = make_array(mutable.freeze());
648 Ok(Arc::new(GenericListArray::<OffsetSize>::try_new(
649 Arc::clone(list_field),
650 OffsetBuffer::new(offsets.into()),
651 new_values,
652 nulls,
653 )?))
654}
655
656#[cfg(test)]
657mod tests {
658 use crate::remove::{ArrayRemove, ArrayRemoveAll, ArrayRemoveN};
659 use arrow::array::{
660 Array, ArrayRef, AsArray, GenericListArray, Int32Array, Int64Array, ListArray,
661 OffsetSizeTrait,
662 };
663 use arrow::buffer::{NullBuffer, ScalarBuffer};
664 use arrow::datatypes::{DataType, Field, Int32Type};
665 use datafusion_common::ScalarValue;
666 use datafusion_expr::{ReturnFieldArgs, ScalarFunctionArgs, ScalarUDFImpl};
667 use datafusion_expr_common::columnar_value::ColumnarValue;
668 use std::ops::Deref;
669 use std::sync::Arc;
670
671 #[test]
672 fn test_array_remove_nullability() {
673 for nullability in [true, false] {
674 for item_nullability in [true, false] {
675 for element_nullability in [true, false] {
676 let input_field = Arc::new(Field::new(
677 "num",
678 DataType::new_list(DataType::Int32, item_nullability),
679 nullability,
680 ));
681 let args_fields = vec![
682 Arc::clone(&input_field),
683 Arc::new(Field::new("a", DataType::Int32, element_nullability)),
684 ];
685 let scalar_args = vec![None, Some(&ScalarValue::Int32(Some(1)))];
686
687 let result = ArrayRemove::new()
688 .return_field_from_args(ReturnFieldArgs {
689 arg_fields: &args_fields,
690 scalar_arguments: &scalar_args,
691 })
692 .unwrap();
693
694 let expected = Arc::new(
695 input_field
696 .as_ref()
697 .clone()
698 .with_nullable(nullability || element_nullability),
699 );
700
701 assert_eq!(result, expected);
702 }
703 }
704 }
705 }
706
707 #[test]
708 fn test_array_remove_n_nullability() {
709 for nullability in [true, false] {
710 for item_nullability in [true, false] {
711 for element_nullability in [true, false] {
712 for count_nullability in [true, false] {
713 let input_field = Arc::new(Field::new(
714 "num",
715 DataType::new_list(DataType::Int32, item_nullability),
716 nullability,
717 ));
718 let args_fields = vec![
719 Arc::clone(&input_field),
720 Arc::new(Field::new(
721 "a",
722 DataType::Int32,
723 element_nullability,
724 )),
725 Arc::new(Field::new("b", DataType::Int64, count_nullability)),
726 ];
727 let scalar_args = vec![
728 None,
729 Some(&ScalarValue::Int32(Some(1))),
730 Some(&ScalarValue::Int64(Some(1))),
731 ];
732
733 let result = ArrayRemoveN::new()
734 .return_field_from_args(ReturnFieldArgs {
735 arg_fields: &args_fields,
736 scalar_arguments: &scalar_args,
737 })
738 .unwrap();
739
740 let expected_nullable =
741 nullability || element_nullability || count_nullability;
742 let expected = Arc::new(
743 input_field
744 .as_ref()
745 .clone()
746 .with_nullable(expected_nullable),
747 );
748
749 assert_eq!(result, expected);
750 }
751 }
752 }
753 }
754 }
755
756 #[test]
757 fn test_array_remove_all_nullability() {
758 for nullability in [true, false] {
759 for item_nullability in [true, false] {
760 for element_nullability in [true, false] {
761 let input_field = Arc::new(Field::new(
762 "num",
763 DataType::new_list(DataType::Int32, item_nullability),
764 nullability,
765 ));
766 let args_fields = vec![
767 Arc::clone(&input_field),
768 Arc::new(Field::new("a", DataType::Int32, element_nullability)),
769 ];
770 let scalar_args = vec![None, Some(&ScalarValue::Int32(Some(1)))];
771 let result = ArrayRemoveAll::new()
772 .return_field_from_args(ReturnFieldArgs {
773 arg_fields: &args_fields,
774 scalar_arguments: &scalar_args,
775 })
776 .unwrap();
777
778 let expected = Arc::new(
779 input_field
780 .as_ref()
781 .clone()
782 .with_nullable(nullability || element_nullability),
783 );
784
785 assert_eq!(result, expected);
786 }
787 }
788 }
789 }
790
791 fn ensure_field_nullability<O: OffsetSizeTrait>(
792 field_nullable: bool,
793 list: GenericListArray<O>,
794 ) -> GenericListArray<O> {
795 let (field, offsets, values, nulls) = list.into_parts();
796
797 if field.is_nullable() == field_nullable {
798 return GenericListArray::new(field, offsets, values, nulls);
799 }
800 if !field_nullable {
801 assert_eq!(nulls, None);
802 }
803
804 let field = Arc::new(field.deref().clone().with_nullable(field_nullable));
805
806 GenericListArray::new(field, offsets, values, nulls)
807 }
808
809 #[test]
810 fn test_array_remove_non_nullable() {
811 let input_list = Arc::new(ensure_field_nullability(
812 false,
813 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
814 Some(([1, 2, 2, 3, 2, 1, 4]).iter().copied().map(Some)),
815 Some(([42, 2, 55, 63, 2]).iter().copied().map(Some)),
816 ]),
817 ));
818 let expected_list = ensure_field_nullability(
819 false,
820 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
821 Some(([1, 2, 3, 2, 1, 4]).iter().copied().map(Some)),
822 Some(([42, 55, 63, 2]).iter().copied().map(Some)),
823 ]),
824 );
825
826 let element_to_remove = ScalarValue::Int32(Some(2));
827
828 assert_array_remove(input_list, expected_list, element_to_remove);
829 }
830
831 #[test]
832 fn test_array_remove_nullable() {
833 let input_list = Arc::new(ensure_field_nullability(
834 true,
835 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
836 Some(vec![
837 Some(1),
838 Some(2),
839 Some(2),
840 Some(3),
841 None,
842 Some(1),
843 Some(4),
844 ]),
845 Some(vec![Some(42), Some(2), None, Some(63), Some(2)]),
846 ]),
847 ));
848 let expected_list = ensure_field_nullability(
849 true,
850 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
851 Some(vec![Some(1), Some(2), Some(3), None, Some(1), Some(4)]),
852 Some(vec![Some(42), None, Some(63), Some(2)]),
853 ]),
854 );
855
856 let element_to_remove = ScalarValue::Int32(Some(2));
857
858 assert_array_remove(input_list, expected_list, element_to_remove);
859 }
860
861 fn assert_array_remove(
862 input_list: ArrayRef,
863 expected_list: GenericListArray<i32>,
864 element_to_remove: ScalarValue,
865 ) {
866 assert_eq!(input_list.data_type(), expected_list.data_type());
867 assert_eq!(expected_list.value_type(), element_to_remove.data_type());
868 let input_list_len = input_list.len();
869 let input_list_data_type = input_list.data_type().clone();
870
871 let udf = ArrayRemove::new();
872 let args_fields = vec![
873 Arc::new(Field::new("num", input_list.data_type().clone(), false)),
874 Arc::new(Field::new(
875 "el",
876 element_to_remove.data_type(),
877 element_to_remove.is_null(),
878 )),
879 ];
880 let scalar_args = vec![None, Some(&element_to_remove)];
881
882 let return_field = udf
883 .return_field_from_args(ReturnFieldArgs {
884 arg_fields: &args_fields,
885 scalar_arguments: &scalar_args,
886 })
887 .unwrap();
888
889 let result = udf
890 .invoke_with_args(ScalarFunctionArgs {
891 args: vec![
892 ColumnarValue::Array(input_list),
893 ColumnarValue::Scalar(element_to_remove),
894 ],
895 arg_fields: args_fields,
896 number_rows: input_list_len,
897 return_field,
898 config_options: Arc::new(Default::default()),
899 })
900 .unwrap();
901
902 assert_eq!(result.data_type(), input_list_data_type);
903 match result {
904 ColumnarValue::Array(array) => {
905 let result_list = array.as_list::<i32>();
906 assert_eq!(result_list, &expected_list);
907 }
908 _ => panic!("Expected ColumnarValue::Array"),
909 }
910 }
911
912 #[test]
913 fn test_array_remove_n_non_nullable() {
914 let input_list = Arc::new(ensure_field_nullability(
915 false,
916 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
917 Some(([1, 2, 2, 3, 2, 1, 4]).iter().copied().map(Some)),
918 Some(([42, 2, 55, 63, 2]).iter().copied().map(Some)),
919 ]),
920 ));
921 let expected_list = ensure_field_nullability(
922 false,
923 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
924 Some(([1, 3, 2, 1, 4]).iter().copied().map(Some)),
925 Some(([42, 55, 63]).iter().copied().map(Some)),
926 ]),
927 );
928
929 let element_to_remove = ScalarValue::Int32(Some(2));
930
931 assert_array_remove_n(input_list, expected_list, element_to_remove, 2);
932 }
933
934 #[test]
935 fn test_array_remove_n_nullable() {
936 let input_list = Arc::new(ensure_field_nullability(
937 true,
938 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
939 Some(vec![
940 Some(1),
941 Some(2),
942 Some(2),
943 Some(3),
944 None,
945 Some(1),
946 Some(4),
947 ]),
948 Some(vec![Some(42), Some(2), None, Some(63), Some(2)]),
949 ]),
950 ));
951 let expected_list = ensure_field_nullability(
952 true,
953 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
954 Some(vec![Some(1), Some(3), None, Some(1), Some(4)]),
955 Some(vec![Some(42), None, Some(63)]),
956 ]),
957 );
958
959 let element_to_remove = ScalarValue::Int32(Some(2));
960
961 assert_array_remove_n(input_list, expected_list, element_to_remove, 2);
962 }
963
964 #[test]
965 fn test_array_remove_n_null_count_returns_null() {
966 let array: ArrayRef =
967 Arc::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
968 Some(vec![Some(1), Some(2), Some(2)]),
969 Some(vec![Some(4), Some(2)]),
970 ]));
971 let element: ArrayRef = Arc::new(Int32Array::from(vec![2, 2]));
972 let max: ArrayRef = Arc::new(Int64Array::new(
973 ScalarBuffer::from(vec![1, 1]),
974 Some(NullBuffer::from(vec![true, false])),
975 ));
976
977 let udf = ArrayRemoveN::new();
978 let args_fields = vec![
979 Arc::new(Field::new("num", array.data_type().clone(), false)),
980 Arc::new(Field::new("el", DataType::Int32, false)),
981 Arc::new(Field::new("count", DataType::Int64, true)),
982 ];
983 let scalar_args = vec![None, None, None];
984 let return_field = udf
985 .return_field_from_args(ReturnFieldArgs {
986 arg_fields: &args_fields,
987 scalar_arguments: &scalar_args,
988 })
989 .unwrap();
990 let result = udf
991 .invoke_with_args(ScalarFunctionArgs {
992 args: vec![
993 ColumnarValue::Array(array),
994 ColumnarValue::Array(element),
995 ColumnarValue::Array(max),
996 ],
997 arg_fields: args_fields,
998 number_rows: 2,
999 return_field,
1000 config_options: Arc::new(Default::default()),
1001 })
1002 .unwrap();
1003 let expected = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1004 Some(vec![Some(1), Some(2)]),
1005 None,
1006 ]);
1007
1008 match result {
1009 ColumnarValue::Array(array) => {
1010 assert_eq!(array.as_list::<i32>(), &expected);
1011 }
1012 _ => panic!("Expected ColumnarValue::Array"),
1013 }
1014 }
1015
1016 fn assert_array_remove_n(
1017 input_list: ArrayRef,
1018 expected_list: GenericListArray<i32>,
1019 element_to_remove: ScalarValue,
1020 n: i64,
1021 ) {
1022 assert_eq!(input_list.data_type(), expected_list.data_type());
1023 assert_eq!(expected_list.value_type(), element_to_remove.data_type());
1024 let input_list_len = input_list.len();
1025 let input_list_data_type = input_list.data_type().clone();
1026
1027 let count_scalar = ScalarValue::Int64(Some(n));
1028
1029 let udf = ArrayRemoveN::new();
1030 let args_fields = vec![
1031 Arc::new(Field::new("num", input_list.data_type().clone(), false)),
1032 Arc::new(Field::new(
1033 "el",
1034 element_to_remove.data_type(),
1035 element_to_remove.is_null(),
1036 )),
1037 Arc::new(Field::new("count", DataType::Int64, false)),
1038 ];
1039 let scalar_args = vec![None, Some(&element_to_remove), Some(&count_scalar)];
1040
1041 let return_field = udf
1042 .return_field_from_args(ReturnFieldArgs {
1043 arg_fields: &args_fields,
1044 scalar_arguments: &scalar_args,
1045 })
1046 .unwrap();
1047
1048 let result = udf
1049 .invoke_with_args(ScalarFunctionArgs {
1050 args: vec![
1051 ColumnarValue::Array(input_list),
1052 ColumnarValue::Scalar(element_to_remove),
1053 ColumnarValue::Scalar(count_scalar),
1054 ],
1055 arg_fields: args_fields,
1056 number_rows: input_list_len,
1057 return_field,
1058 config_options: Arc::new(Default::default()),
1059 })
1060 .unwrap();
1061
1062 assert_eq!(result.data_type(), input_list_data_type);
1063 match result {
1064 ColumnarValue::Array(array) => {
1065 let result_list = array.as_list::<i32>();
1066 assert_eq!(result_list, &expected_list);
1067 }
1068 _ => panic!("Expected ColumnarValue::Array"),
1069 }
1070 }
1071
1072 #[test]
1073 fn test_array_remove_all_non_nullable() {
1074 let input_list = Arc::new(ensure_field_nullability(
1075 false,
1076 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1077 Some(([1, 2, 2, 3, 2, 1, 4]).iter().copied().map(Some)),
1078 Some(([42, 2, 55, 63, 2]).iter().copied().map(Some)),
1079 ]),
1080 ));
1081 let expected_list = ensure_field_nullability(
1082 false,
1083 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1084 Some(([1, 3, 1, 4]).iter().copied().map(Some)),
1085 Some(([42, 55, 63]).iter().copied().map(Some)),
1086 ]),
1087 );
1088
1089 let element_to_remove = ScalarValue::Int32(Some(2));
1090
1091 assert_array_remove_all(input_list, expected_list, element_to_remove);
1092 }
1093
1094 #[test]
1095 fn test_array_remove_all_nullable() {
1096 let input_list = Arc::new(ensure_field_nullability(
1097 true,
1098 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1099 Some(vec![
1100 Some(1),
1101 Some(2),
1102 Some(2),
1103 Some(3),
1104 None,
1105 Some(1),
1106 Some(4),
1107 ]),
1108 Some(vec![Some(42), Some(2), None, Some(63), Some(2)]),
1109 ]),
1110 ));
1111 let expected_list = ensure_field_nullability(
1112 true,
1113 ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1114 Some(vec![Some(1), Some(3), None, Some(1), Some(4)]),
1115 Some(vec![Some(42), None, Some(63)]),
1116 ]),
1117 );
1118
1119 let element_to_remove = ScalarValue::Int32(Some(2));
1120
1121 assert_array_remove_all(input_list, expected_list, element_to_remove);
1122 }
1123
1124 fn assert_array_remove_all(
1125 input_list: ArrayRef,
1126 expected_list: GenericListArray<i32>,
1127 element_to_remove: ScalarValue,
1128 ) {
1129 assert_eq!(input_list.data_type(), expected_list.data_type());
1130 assert_eq!(expected_list.value_type(), element_to_remove.data_type());
1131 let input_list_len = input_list.len();
1132 let input_list_data_type = input_list.data_type().clone();
1133
1134 let udf = ArrayRemoveAll::new();
1135 let args_fields = vec![
1136 Arc::new(Field::new("num", input_list.data_type().clone(), false)),
1137 Arc::new(Field::new(
1138 "el",
1139 element_to_remove.data_type(),
1140 element_to_remove.is_null(),
1141 )),
1142 ];
1143 let scalar_args = vec![None, Some(&element_to_remove)];
1144
1145 let return_field = udf
1146 .return_field_from_args(ReturnFieldArgs {
1147 arg_fields: &args_fields,
1148 scalar_arguments: &scalar_args,
1149 })
1150 .unwrap();
1151
1152 let result = udf
1153 .invoke_with_args(ScalarFunctionArgs {
1154 args: vec![
1155 ColumnarValue::Array(input_list),
1156 ColumnarValue::Scalar(element_to_remove),
1157 ],
1158 arg_fields: args_fields,
1159 number_rows: input_list_len,
1160 return_field,
1161 config_options: Arc::new(Default::default()),
1162 })
1163 .unwrap();
1164
1165 assert_eq!(result.data_type(), input_list_data_type);
1166 match result {
1167 ColumnarValue::Array(array) => {
1168 let result_list = array.as_list::<i32>();
1169 assert_eq!(result_list, &expected_list);
1170 }
1171 _ => panic!("Expected ColumnarValue::Array"),
1172 }
1173 }
1174}