1use crate::utils::make_scalar_function;
21use arrow::array::{
22 Array, ArrayRef, GenericListArray, OffsetSizeTrait, UInt32Array, UInt64Array,
23 new_empty_array, new_null_array,
24};
25use arrow::buffer::{NullBuffer, OffsetBuffer};
26use arrow::compute::{concat, take};
27use arrow::datatypes::DataType::{LargeList, List, Null};
28use arrow::datatypes::{DataType, Field, FieldRef};
29use arrow::row::{RowConverter, SortField};
30use datafusion_common::cast::{as_large_list_array, as_list_array};
31use datafusion_common::utils::{ListCoercion, normalize_float_zero};
32use datafusion_common::{
33 Result, assert_eq_or_internal_err, exec_err, internal_err, utils::take_function_args,
34};
35use datafusion_expr::{
36 ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
37 Volatility,
38};
39use datafusion_macros::user_doc;
40use hashbrown::HashSet;
41use std::fmt::{Display, Formatter};
42use std::sync::Arc;
43
44make_udf_expr_and_func!(
46 ArrayUnion,
47 array_union,
48 array1 array2,
49 "returns an array of the elements in the union of array1 and array2 without duplicates.",
50 array_union_udf
51);
52
53make_udf_expr_and_func!(
54 ArrayIntersect,
55 array_intersect,
56 first_array second_array,
57 "returns an array of the elements in the intersection of array1 and array2.",
58 array_intersect_udf
59);
60
61make_udf_expr_and_func!(
62 ArrayDistinct,
63 array_distinct,
64 array,
65 "returns distinct values from the array after removing duplicates.",
66 array_distinct_udf
67);
68
69#[user_doc(
70 doc_section(label = "Array Functions"),
71 description = "Returns an array of elements that are present in both arrays (all elements from both arrays) without duplicates.",
72 syntax_example = "array_union(array1, array2)",
73 sql_example = r#"```sql
74> select array_union([1, 2, 3, 4], [5, 6, 3, 4]);
75+----------------------------------------------------+
76| array_union([1, 2, 3, 4], [5, 6, 3, 4]); |
77+----------------------------------------------------+
78| [1, 2, 3, 4, 5, 6] |
79+----------------------------------------------------+
80> select array_union([1, 2, 3, 4], [5, 6, 7, 8]);
81+----------------------------------------------------+
82| array_union([1, 2, 3, 4], [5, 6, 7, 8]); |
83+----------------------------------------------------+
84| [1, 2, 3, 4, 5, 6, 7, 8] |
85+----------------------------------------------------+
86```"#,
87 argument(
88 name = "array1",
89 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
90 ),
91 argument(
92 name = "array2",
93 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
94 )
95)]
96#[derive(Debug, PartialEq, Eq, Hash)]
97pub struct ArrayUnion {
98 signature: Signature,
99 aliases: Vec<String>,
100}
101
102impl Default for ArrayUnion {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108impl ArrayUnion {
109 pub fn new() -> Self {
110 Self {
111 signature: Signature::arrays(
112 2,
113 Some(ListCoercion::FixedSizedListToList),
114 Volatility::Immutable,
115 ),
116 aliases: vec![String::from("list_union")],
117 }
118 }
119}
120
121impl ScalarUDFImpl for ArrayUnion {
122 fn name(&self) -> &str {
123 "array_union"
124 }
125
126 fn signature(&self) -> &Signature {
127 &self.signature
128 }
129
130 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
131 let [array1, array2] = take_function_args(self.name(), arg_types)?;
132 match (array1, array2) {
133 (Null, Null) => Ok(DataType::new_list(Null, true)),
134 (Null, dt) | (dt, Null) => Ok(dt.clone()),
135 (dt, _) => Ok(dt.clone()),
136 }
137 }
138
139 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
140 make_scalar_function(array_union_inner)(&args.args)
141 }
142
143 fn aliases(&self) -> &[String] {
144 &self.aliases
145 }
146
147 fn documentation(&self) -> Option<&Documentation> {
148 self.doc()
149 }
150}
151
152#[user_doc(
153 doc_section(label = "Array Functions"),
154 description = "Returns an array of elements in the intersection of array1 and array2.",
155 syntax_example = "array_intersect(array1, array2)",
156 sql_example = r#"```sql
157> select array_intersect([1, 2, 3, 4], [5, 6, 3, 4]);
158+----------------------------------------------------+
159| array_intersect([1, 2, 3, 4], [5, 6, 3, 4]); |
160+----------------------------------------------------+
161| [3, 4] |
162+----------------------------------------------------+
163> select array_intersect([1, 2, 3, 4], [5, 6, 7, 8]);
164+----------------------------------------------------+
165| array_intersect([1, 2, 3, 4], [5, 6, 7, 8]); |
166+----------------------------------------------------+
167| [] |
168+----------------------------------------------------+
169```"#,
170 argument(
171 name = "array1",
172 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
173 ),
174 argument(
175 name = "array2",
176 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
177 )
178)]
179#[derive(Debug, PartialEq, Eq, Hash)]
180pub struct ArrayIntersect {
181 signature: Signature,
182 aliases: Vec<String>,
183}
184
185impl Default for ArrayIntersect {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191impl ArrayIntersect {
192 pub fn new() -> Self {
193 Self {
194 signature: Signature::arrays(
195 2,
196 Some(ListCoercion::FixedSizedListToList),
197 Volatility::Immutable,
198 ),
199 aliases: vec![String::from("list_intersect")],
200 }
201 }
202}
203
204impl ScalarUDFImpl for ArrayIntersect {
205 fn name(&self) -> &str {
206 "array_intersect"
207 }
208
209 fn signature(&self) -> &Signature {
210 &self.signature
211 }
212
213 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
214 let [array1, array2] = take_function_args(self.name(), arg_types)?;
215 match (array1, array2) {
216 (Null, Null) => Ok(DataType::new_list(Null, true)),
217 (Null, dt) | (dt, Null) => Ok(dt.clone()),
218 (dt, _) => Ok(dt.clone()),
219 }
220 }
221
222 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
223 make_scalar_function(array_intersect_inner)(&args.args)
224 }
225
226 fn aliases(&self) -> &[String] {
227 &self.aliases
228 }
229
230 fn documentation(&self) -> Option<&Documentation> {
231 self.doc()
232 }
233}
234
235#[user_doc(
236 doc_section(label = "Array Functions"),
237 description = "Returns distinct values from the array after removing duplicates.",
238 syntax_example = "array_distinct(array)",
239 sql_example = r#"```sql
240> select array_distinct([1, 3, 2, 3, 1, 2, 4]);
241+---------------------------------+
242| array_distinct(List([1,2,3,4])) |
243+---------------------------------+
244| [1, 2, 3, 4] |
245+---------------------------------+
246```"#,
247 argument(
248 name = "array",
249 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
250 )
251)]
252#[derive(Debug, PartialEq, Eq, Hash)]
253pub struct ArrayDistinct {
254 signature: Signature,
255 aliases: Vec<String>,
256}
257
258impl ArrayDistinct {
259 pub fn new() -> Self {
260 Self {
261 signature: Signature::array(Volatility::Immutable),
262 aliases: vec!["list_distinct".to_string()],
263 }
264 }
265}
266
267impl Default for ArrayDistinct {
268 fn default() -> Self {
269 Self::new()
270 }
271}
272
273impl ScalarUDFImpl for ArrayDistinct {
274 fn name(&self) -> &str {
275 "array_distinct"
276 }
277
278 fn signature(&self) -> &Signature {
279 &self.signature
280 }
281
282 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
283 Ok(arg_types[0].clone())
284 }
285
286 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
287 make_scalar_function(array_distinct_inner)(&args.args)
288 }
289
290 fn aliases(&self) -> &[String] {
291 &self.aliases
292 }
293
294 fn documentation(&self) -> Option<&Documentation> {
295 self.doc()
296 }
297}
298
299fn array_distinct_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
302 let [array] = take_function_args("array_distinct", args)?;
303 match array.data_type() {
304 Null => Ok(Arc::clone(array)),
305 List(field) => {
306 let array = as_list_array(&array)?;
307 general_array_distinct(array, field)
308 }
309 LargeList(field) => {
310 let array = as_large_list_array(&array)?;
311 general_array_distinct(array, field)
312 }
313 arg_type => exec_err!("array_distinct does not support type {arg_type}"),
314 }
315}
316
317#[derive(Debug, PartialEq, Copy, Clone)]
318enum SetOp {
319 Union,
320 Intersect,
321}
322
323impl Display for SetOp {
324 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
325 match self {
326 SetOp::Union => write!(f, "array_union"),
327 SetOp::Intersect => write!(f, "array_intersect"),
328 }
329 }
330}
331
332fn generic_set_lists<OffsetSize: OffsetSizeTrait>(
333 l: &GenericListArray<OffsetSize>,
334 r: &GenericListArray<OffsetSize>,
335 field: Arc<Field>,
336 set_op: SetOp,
337) -> Result<ArrayRef> {
338 if l.is_empty() || l.value_type().is_null() {
339 let field = Arc::new(Field::new_list_field(r.value_type(), true));
340 return general_array_distinct::<OffsetSize>(r, &field);
341 } else if r.is_empty() || r.value_type().is_null() {
342 let field = Arc::new(Field::new_list_field(l.value_type(), true));
343 return general_array_distinct::<OffsetSize>(l, &field);
344 }
345
346 assert_eq_or_internal_err!(
347 l.value_type(),
348 r.value_type(),
349 "{set_op:?} is not implemented for '{l:?}' and '{r:?}'"
350 );
351
352 let converter = RowConverter::new(vec![SortField::new(l.value_type())])?;
353
354 let l_values_norm = normalize_float_zero(l.values());
358 let r_values_norm = normalize_float_zero(r.values());
359
360 let l_first = l.offsets()[0].as_usize();
364 let l_len = l.offsets()[l.len()].as_usize() - l_first;
365 let l_values = l_values_norm.slice(l_first, l_len);
366 let rows_l = converter.convert_columns(&[Arc::clone(&l_values)])?;
367
368 let r_first = r.offsets()[0].as_usize();
369 let r_len = r.offsets()[r.len()].as_usize() - r_first;
370 let r_values = r_values_norm.slice(r_first, r_len);
371 let rows_r = converter.convert_columns(&[Arc::clone(&r_values)])?;
372
373 let combined_values = concat(&[l_values.as_ref(), r_values.as_ref()])?;
377 let r_offset = l_len;
378
379 match set_op {
380 SetOp::Union => generic_set_loop::<OffsetSize, true>(
381 l,
382 r,
383 &rows_l,
384 &rows_r,
385 field,
386 &combined_values,
387 r_offset,
388 ),
389 SetOp::Intersect => generic_set_loop::<OffsetSize, false>(
390 l,
391 r,
392 &rows_l,
393 &rows_r,
394 field,
395 &combined_values,
396 r_offset,
397 ),
398 }
399}
400
401fn generic_set_loop<OffsetSize: OffsetSizeTrait, const IS_UNION: bool>(
404 l: &GenericListArray<OffsetSize>,
405 r: &GenericListArray<OffsetSize>,
406 rows_l: &arrow::row::Rows,
407 rows_r: &arrow::row::Rows,
408 field: Arc<Field>,
409 combined_values: &ArrayRef,
410 r_offset: usize,
411) -> Result<ArrayRef> {
412 let l_offsets = l.value_offsets();
413 let r_offsets = r.value_offsets();
414 let l_first = l.offsets()[0].as_usize();
415 let r_first = r.offsets()[0].as_usize();
416
417 let mut result_offsets = Vec::with_capacity(l.len() + 1);
418 result_offsets.push(OffsetSize::usize_as(0));
419 let initial_capacity = if IS_UNION {
420 rows_l.num_rows()
422 } else {
423 rows_l.num_rows().min(rows_r.num_rows())
425 };
426
427 let mut indices: Vec<usize> = Vec::with_capacity(initial_capacity);
428
429 let mut seen = HashSet::new();
431 let mut lookup_set = HashSet::new();
432 for i in 0..l.len() {
433 let last_offset = *result_offsets.last().unwrap();
434
435 if l.is_null(i) || r.is_null(i) {
436 result_offsets.push(last_offset);
437 continue;
438 }
439
440 let l_start = l_offsets[i].as_usize() - l_first;
441 let l_end = l_offsets[i + 1].as_usize() - l_first;
442 let r_start = r_offsets[i].as_usize() - r_first;
443 let r_end = r_offsets[i + 1].as_usize() - r_first;
444
445 seen.clear();
446
447 if IS_UNION {
448 for idx in l_start..l_end {
449 let row = rows_l.row(idx);
450 if seen.insert(row) {
451 indices.push(idx);
452 }
453 }
454 for idx in r_start..r_end {
455 let row = rows_r.row(idx);
456 if seen.insert(row) {
457 indices.push(idx + r_offset);
458 }
459 }
460 } else {
461 let l_len = l_end - l_start;
462 let r_len = r_end - r_start;
463
464 let (lookup_rows, lookup_range, probe_rows, probe_range, probe_offset) =
467 if l_len < r_len {
468 (rows_l, l_start..l_end, rows_r, r_start..r_end, r_offset)
469 } else {
470 (rows_r, r_start..r_end, rows_l, l_start..l_end, 0)
471 };
472 lookup_set.clear();
473 lookup_set.reserve(lookup_range.len());
474
475 for idx in lookup_range {
477 lookup_set.insert(lookup_rows.row(idx));
478 }
479
480 for idx in probe_range {
482 let row = probe_rows.row(idx);
483 if lookup_set.contains(&row) && seen.insert(row) {
484 indices.push(idx + probe_offset);
485 }
486 }
487 }
488 result_offsets.push(last_offset + OffsetSize::usize_as(seen.len()));
489 }
490
491 let final_values = if indices.is_empty() {
494 new_empty_array(&l.value_type())
495 } else if OffsetSize::IS_LARGE {
496 let indices =
497 UInt64Array::from(indices.into_iter().map(|i| i as u64).collect::<Vec<_>>());
498 take(combined_values.as_ref(), &indices, None)?
499 } else {
500 let indices =
501 UInt32Array::from(indices.into_iter().map(|i| i as u32).collect::<Vec<_>>());
502 take(combined_values.as_ref(), &indices, None)?
503 };
504
505 let arr = GenericListArray::<OffsetSize>::try_new(
506 field,
507 OffsetBuffer::new(result_offsets.into()),
508 final_values,
509 NullBuffer::union(l.nulls(), r.nulls()),
510 )?;
511 Ok(Arc::new(arr))
512}
513
514fn general_set_op(
515 array1: &ArrayRef,
516 array2: &ArrayRef,
517 set_op: SetOp,
518) -> Result<ArrayRef> {
519 let len = array1.len();
520 match (array1.data_type(), array2.data_type()) {
521 (Null, Null) => Ok(new_null_array(&DataType::new_list(Null, true), len)),
522 (Null, dt @ List(_))
523 | (Null, dt @ LargeList(_))
524 | (dt @ List(_), Null)
525 | (dt @ LargeList(_), Null) => Ok(new_null_array(dt, len)),
526 (List(field), List(_)) => {
527 let array1 = as_list_array(&array1)?;
528 let array2 = as_list_array(&array2)?;
529 generic_set_lists::<i32>(array1, array2, Arc::clone(field), set_op)
530 }
531 (LargeList(field), LargeList(_)) => {
532 let array1 = as_large_list_array(&array1)?;
533 let array2 = as_large_list_array(&array2)?;
534 generic_set_lists::<i64>(array1, array2, Arc::clone(field), set_op)
535 }
536 (data_type1, data_type2) => {
537 internal_err!(
538 "{set_op} does not support types '{data_type1:?}' and '{data_type2:?}'"
539 )
540 }
541 }
542}
543
544fn array_union_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
545 let [array1, array2] = take_function_args("array_union", args)?;
546 general_set_op(array1, array2, SetOp::Union)
547}
548
549fn array_intersect_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
550 let [array1, array2] = take_function_args("array_intersect", args)?;
551 general_set_op(array1, array2, SetOp::Intersect)
552}
553
554fn general_array_distinct<OffsetSize: OffsetSizeTrait>(
555 array: &GenericListArray<OffsetSize>,
556 field: &FieldRef,
557) -> Result<ArrayRef> {
558 if array.is_empty() {
559 return Ok(Arc::new(array.clone()) as ArrayRef);
560 }
561 let value_offsets = array.value_offsets();
562 let dt = array.value_type();
563 let mut offsets = Vec::with_capacity(array.len() + 1);
564 offsets.push(OffsetSize::usize_as(0));
565
566 let converter = RowConverter::new(vec![SortField::new(dt.clone())])?;
567
568 let values_norm = normalize_float_zero(array.values());
572
573 let first_offset = value_offsets[0].as_usize();
577 let visible_len = value_offsets[array.len()].as_usize() - first_offset;
578 let rows =
579 converter.convert_columns(&[values_norm.slice(first_offset, visible_len)])?;
580
581 let mut indices: Vec<usize> = Vec::with_capacity(rows.num_rows());
582 let mut seen = HashSet::new();
583 for i in 0..array.len() {
584 let last_offset = *offsets.last().unwrap();
585
586 if array.is_null(i) {
588 offsets.push(last_offset);
589 continue;
590 }
591
592 let start = value_offsets[i].as_usize() - first_offset;
593 let end = value_offsets[i + 1].as_usize() - first_offset;
594 seen.clear();
595 seen.reserve(end - start);
596
597 for idx in start..end {
599 let row = rows.row(idx);
600 if seen.insert(row) {
601 indices.push(idx + first_offset);
602 }
603 }
604 offsets.push(last_offset + OffsetSize::usize_as(seen.len()));
605 }
606
607 let final_values = if indices.is_empty() {
612 new_empty_array(&dt)
613 } else if OffsetSize::IS_LARGE {
614 let indices =
615 UInt64Array::from(indices.into_iter().map(|i| i as u64).collect::<Vec<_>>());
616 take(values_norm.as_ref(), &indices, None)?
617 } else {
618 let indices =
619 UInt32Array::from(indices.into_iter().map(|i| i as u32).collect::<Vec<_>>());
620 take(values_norm.as_ref(), &indices, None)?
621 };
622
623 Ok(Arc::new(GenericListArray::<OffsetSize>::try_new(
624 Arc::clone(field),
625 OffsetBuffer::new(offsets.into()),
626 final_values,
627 array.nulls().cloned(),
629 )?))
630}
631
632#[cfg(test)]
633mod tests {
634 use std::sync::Arc;
635
636 use arrow::{
637 array::{Array, AsArray, Int32Array, ListArray},
638 buffer::OffsetBuffer,
639 datatypes::{DataType, Field, Int32Type},
640 };
641 use datafusion_common::{DataFusionError, Result, config::ConfigOptions};
642 use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl};
643
644 use crate::set_ops::{ArrayDistinct, ArrayIntersect, ArrayUnion, array_distinct_udf};
645
646 fn make_sliced_pair() -> (ListArray, ListArray, Arc<Field>) {
652 let l = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
653 Some(vec![Some(1), Some(2)]),
654 Some(vec![Some(3), Some(4)]),
655 Some(vec![Some(5), Some(6)]),
656 Some(vec![Some(7), Some(8)]),
657 ]);
658 let r = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
659 Some(vec![Some(1), Some(3)]),
660 Some(vec![Some(3), Some(5)]),
661 Some(vec![Some(5), Some(7)]),
662 Some(vec![Some(7), Some(1)]),
663 ]);
664 let field = Arc::new(Field::new("item", l.data_type().clone(), true));
665 (l.slice(1, 2), r.slice(1, 2), field)
666 }
667
668 fn collect_i32_list(list: &ListArray) -> Vec<Vec<i32>> {
669 (0..list.len())
670 .map(|i| {
671 let arr = list.value(i);
672 arr.as_any()
673 .downcast_ref::<Int32Array>()
674 .unwrap()
675 .values()
676 .to_vec()
677 })
678 .collect()
679 }
680
681 #[test]
682 fn test_array_union_sliced_lists() -> Result<()> {
683 let (l, r, field) = make_sliced_pair();
684
685 let result = ArrayUnion::new().invoke_with_args(ScalarFunctionArgs {
686 args: vec![
687 ColumnarValue::Array(Arc::new(l)),
688 ColumnarValue::Array(Arc::new(r)),
689 ],
690 arg_fields: vec![Arc::clone(&field), Arc::clone(&field)],
691 number_rows: 2,
692 return_field: Arc::clone(&field),
693 config_options: Arc::new(ConfigOptions::default()),
694 })?;
695
696 let output = result.into_array(2)?;
697 let output = output.as_list::<i32>();
698 let rows = collect_i32_list(output);
699
700 assert_eq!(rows[0], vec![3, 4, 5]);
702 assert_eq!(rows[1], vec![5, 6, 7]);
704 Ok(())
705 }
706
707 #[test]
708 fn test_array_intersect_sliced_lists() -> Result<()> {
709 let (l, r, field) = make_sliced_pair();
710
711 let result = ArrayIntersect::new().invoke_with_args(ScalarFunctionArgs {
712 args: vec![
713 ColumnarValue::Array(Arc::new(l)),
714 ColumnarValue::Array(Arc::new(r)),
715 ],
716 arg_fields: vec![Arc::clone(&field), Arc::clone(&field)],
717 number_rows: 2,
718 return_field: Arc::clone(&field),
719 config_options: Arc::new(ConfigOptions::default()),
720 })?;
721
722 let output = result.into_array(2)?;
723 let output = output.as_list::<i32>();
724 let rows = collect_i32_list(output);
725
726 assert_eq!(rows[0], vec![3]);
728 assert_eq!(rows[1], vec![5]);
730 Ok(())
731 }
732
733 #[test]
734 fn test_array_distinct_sliced_list() -> Result<()> {
735 let list = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
737 Some(vec![Some(1), Some(1)]),
738 Some(vec![Some(3), Some(3), Some(4)]),
739 Some(vec![Some(5), Some(5), Some(6)]),
740 Some(vec![Some(7), Some(7)]),
741 ]);
742 let sliced = list.slice(1, 2);
743 let field = Arc::new(Field::new("item", sliced.data_type().clone(), true));
744
745 let result = ArrayDistinct::new().invoke_with_args(ScalarFunctionArgs {
746 args: vec![ColumnarValue::Array(Arc::new(sliced))],
747 arg_fields: vec![Arc::clone(&field)],
748 number_rows: 2,
749 return_field: field,
750 config_options: Arc::new(ConfigOptions::default()),
751 })?;
752
753 let output = result.into_array(2)?;
754 let output = output.as_list::<i32>();
755 let rows = collect_i32_list(output);
756
757 assert_eq!(rows[0], vec![3, 4]);
759 assert_eq!(rows[1], vec![5, 6]);
761 Ok(())
762 }
763
764 #[test]
765 fn test_array_distinct_inner_nullability_result_type_match_return_type()
766 -> Result<(), DataFusionError> {
767 let udf = array_distinct_udf();
768
769 for inner_nullable in [true, false] {
770 let inner_field = Field::new_list_field(DataType::Int32, inner_nullable);
771 let input_field =
772 Field::new_list("input", Arc::new(inner_field.clone()), true);
773
774 let input_array = ListArray::new(
776 inner_field.into(),
777 OffsetBuffer::new(vec![0, 3].into()),
778 Arc::new(Int32Array::new(vec![1, 1, 2].into(), None)),
779 None,
780 );
781
782 let input_array = ColumnarValue::Array(Arc::new(input_array));
783
784 let result = udf.invoke_with_args(ScalarFunctionArgs {
785 args: vec![input_array],
786 arg_fields: vec![input_field.clone().into()],
787 number_rows: 1,
788 return_field: input_field.clone().into(),
789 config_options: Arc::new(ConfigOptions::default()),
790 })?;
791
792 assert_eq!(
793 result.data_type(),
794 udf.return_type(&[input_field.data_type().clone()])?
795 );
796 }
797 Ok(())
798 }
799}