1use std::sync::Arc;
21
22use crate::make_array::make_array_inner;
23use crate::utils::{
24 align_array_dimensions, check_datatypes, list_inner_field, list_type_with_element,
25 make_scalar_function,
26};
27use arrow::array::{
28 Array, ArrayData, ArrayRef, Capacities, GenericListArray, MutableArrayData,
29 OffsetSizeTrait,
30};
31use arrow::buffer::{NullBuffer, OffsetBuffer};
32use arrow::datatypes::{DataType, Field, FieldRef};
33use datafusion_common::Result;
34use datafusion_common::utils::{
35 ListCoercion, base_type, coerced_type_with_base_type_only,
36};
37use datafusion_common::{
38 cast::as_generic_list_array,
39 exec_err, internal_err, plan_err,
40 utils::{list_ndims, take_function_args},
41};
42use datafusion_expr::binary::type_union_resolution;
43use datafusion_expr::{
44 ColumnarValue, Documentation, ReturnFieldArgs, ScalarFunctionArgs, ScalarUDFImpl,
45 Signature, Volatility,
46};
47use datafusion_macros::user_doc;
48use itertools::Itertools;
49
50make_udf_expr_and_func!(
51 ArrayAppend,
52 array_append,
53 array element, "appends an element to the end of an array.", array_append_udf );
57
58#[user_doc(
59 doc_section(label = "Array Functions"),
60 description = "Appends an element to the end of an array.",
61 syntax_example = "array_append(array, element)",
62 sql_example = r#"```sql
63> select array_append([1, 2, 3], 4);
64+--------------------------------------+
65| array_append(List([1,2,3]),Int64(4)) |
66+--------------------------------------+
67| [1, 2, 3, 4] |
68+--------------------------------------+
69```"#,
70 argument(
71 name = "array",
72 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
73 ),
74 argument(name = "element", description = "Element to append to the array.")
75)]
76#[derive(Debug, PartialEq, Eq, Hash)]
77pub struct ArrayAppend {
78 signature: Signature,
79 aliases: Vec<String>,
80}
81
82impl Default for ArrayAppend {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88impl ArrayAppend {
89 pub fn new() -> Self {
90 Self {
91 signature: Signature::array_and_element(Volatility::Immutable),
92 aliases: vec![
93 String::from("list_append"),
94 String::from("array_push_back"),
95 String::from("list_push_back"),
96 ],
97 }
98 }
99}
100
101impl ScalarUDFImpl for ArrayAppend {
102 fn name(&self) -> &str {
103 "array_append"
104 }
105
106 fn signature(&self) -> &Signature {
107 &self.signature
108 }
109
110 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
111 internal_err!("return_field_from_args should be used instead")
112 }
113
114 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
115 let [array_field, element_field] =
116 take_function_args(self.name(), args.arg_fields)?;
117 let data_type = append_prepend_return_type(
118 array_field.data_type(),
119 element_field.data_type(),
120 element_field.is_nullable(),
121 );
122 Ok(Arc::new(Field::new(self.name(), data_type, true)))
123 }
124
125 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
126 let return_type = args.return_field.data_type().clone();
127 make_scalar_function(|args: &[ArrayRef]| array_append_inner(args, &return_type))(
128 &args.args,
129 )
130 }
131
132 fn aliases(&self) -> &[String] {
133 &self.aliases
134 }
135
136 fn documentation(&self) -> Option<&Documentation> {
137 self.doc()
138 }
139}
140
141make_udf_expr_and_func!(
142 ArrayPrepend,
143 array_prepend,
144 element array,
145 "Prepends an element to the beginning of an array.",
146 array_prepend_udf
147);
148
149#[user_doc(
150 doc_section(label = "Array Functions"),
151 description = "Prepends an element to the beginning of an array.",
152 syntax_example = "array_prepend(element, array)",
153 sql_example = r#"```sql
154> select array_prepend(1, [2, 3, 4]);
155+---------------------------------------+
156| array_prepend(Int64(1),List([2,3,4])) |
157+---------------------------------------+
158| [1, 2, 3, 4] |
159+---------------------------------------+
160```"#,
161 argument(
162 name = "array",
163 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
164 ),
165 argument(name = "element", description = "Element to prepend to the array.")
166)]
167#[derive(Debug, PartialEq, Eq, Hash)]
168pub struct ArrayPrepend {
169 signature: Signature,
170 aliases: Vec<String>,
171}
172
173impl Default for ArrayPrepend {
174 fn default() -> Self {
175 Self::new()
176 }
177}
178
179impl ArrayPrepend {
180 pub fn new() -> Self {
181 Self {
182 signature: Signature::element_and_array(Volatility::Immutable),
183 aliases: vec![
184 String::from("list_prepend"),
185 String::from("array_push_front"),
186 String::from("list_push_front"),
187 ],
188 }
189 }
190}
191
192impl ScalarUDFImpl for ArrayPrepend {
193 fn name(&self) -> &str {
194 "array_prepend"
195 }
196
197 fn signature(&self) -> &Signature {
198 &self.signature
199 }
200
201 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
202 internal_err!("return_field_from_args should be used instead")
203 }
204
205 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
206 let [element_field, array_field] =
207 take_function_args(self.name(), args.arg_fields)?;
208 let data_type = append_prepend_return_type(
209 array_field.data_type(),
210 element_field.data_type(),
211 element_field.is_nullable(),
212 );
213 Ok(Arc::new(Field::new(self.name(), data_type, true)))
214 }
215
216 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
217 let return_type = args.return_field.data_type().clone();
218 make_scalar_function(|args: &[ArrayRef]| array_prepend_inner(args, &return_type))(
219 &args.args,
220 )
221 }
222
223 fn aliases(&self) -> &[String] {
224 &self.aliases
225 }
226
227 fn documentation(&self) -> Option<&Documentation> {
228 self.doc()
229 }
230}
231
232make_udf_expr_and_func!(
233 ArrayConcat,
234 array_concat,
235 "Concatenates arrays.",
236 array_concat_udf
237);
238
239#[user_doc(
240 doc_section(label = "Array Functions"),
241 description = "Concatenates arrays.",
242 syntax_example = "array_concat(array[, ..., array_n])",
243 sql_example = r#"```sql
244> select array_concat([1, 2], [3, 4], [5, 6]);
245+---------------------------------------------------+
246| array_concat(List([1,2]),List([3,4]),List([5,6])) |
247+---------------------------------------------------+
248| [1, 2, 3, 4, 5, 6] |
249+---------------------------------------------------+
250```"#,
251 argument(
252 name = "array",
253 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
254 ),
255 argument(
256 name = "array_n",
257 description = "Subsequent array column or literal array to concatenate."
258 )
259)]
260#[derive(Debug, PartialEq, Eq, Hash)]
261pub struct ArrayConcat {
262 signature: Signature,
263 aliases: Vec<String>,
264}
265
266impl Default for ArrayConcat {
267 fn default() -> Self {
268 Self::new()
269 }
270}
271
272impl ArrayConcat {
273 pub fn new() -> Self {
274 Self {
275 signature: Signature::user_defined(Volatility::Immutable),
276 aliases: vec![
277 String::from("array_cat"),
278 String::from("list_concat"),
279 String::from("list_cat"),
280 ],
281 }
282 }
283}
284
285impl ScalarUDFImpl for ArrayConcat {
286 fn name(&self) -> &str {
287 "array_concat"
288 }
289
290 fn signature(&self) -> &Signature {
291 &self.signature
292 }
293
294 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
295 let mut max_dims = 0;
296 let mut large_list = false;
297 let mut element_types = Vec::with_capacity(arg_types.len());
298 for arg_type in arg_types {
299 match arg_type {
300 DataType::Null | DataType::List(_) | DataType::FixedSizeList(..) => (),
301 DataType::LargeList(_) => large_list = true,
302 arg_type => {
303 return plan_err!("{} does not support type {arg_type}", self.name());
304 }
305 }
306
307 max_dims = max_dims.max(list_ndims(arg_type));
308 element_types.push(base_type(arg_type))
309 }
310
311 if max_dims == 0 {
312 Ok(DataType::Null)
313 } else if let Some(mut return_type) = type_union_resolution(&element_types) {
314 for _ in 1..max_dims {
315 return_type = DataType::new_list(return_type, true)
316 }
317
318 if large_list {
319 Ok(DataType::new_large_list(return_type, true))
320 } else {
321 Ok(DataType::new_list(return_type, true))
322 }
323 } else {
324 plan_err!(
325 "Failed to unify argument types of {}: [{}]",
326 self.name(),
327 arg_types.iter().join(", ")
328 )
329 }
330 }
331
332 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
333 make_scalar_function(array_concat_inner)(&args.args)
334 }
335
336 fn aliases(&self) -> &[String] {
337 &self.aliases
338 }
339
340 fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
341 let return_type = self.return_type(arg_types)?;
342 let base_type = base_type(&return_type);
343 let coercion = Some(&ListCoercion::FixedSizedListToList);
344 let promote_to_large_list = matches!(return_type, DataType::LargeList(_));
349 let arg_types = arg_types.iter().map(|arg_type| {
350 let coerced =
351 coerced_type_with_base_type_only(arg_type, &base_type, coercion);
352 match coerced {
353 DataType::List(field) if promote_to_large_list => {
354 DataType::LargeList(field)
355 }
356 other => other,
357 }
358 });
359
360 Ok(arg_types.collect())
361 }
362
363 fn documentation(&self) -> Option<&Documentation> {
364 self.doc()
365 }
366}
367
368pub fn array_concat_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
369 if args.is_empty() {
370 return exec_err!("array_concat expects at least one argument");
371 }
372
373 let mut all_null = true;
374 let mut large_list = false;
375 for arg in args {
376 match arg.data_type() {
377 DataType::Null => continue,
378 DataType::LargeList(_) => large_list = true,
379 _ => (),
380 }
381 if arg.null_count() < arg.len() {
382 all_null = false;
383 }
384 }
385
386 if all_null {
387 let return_type = args
389 .iter()
390 .map(|arg| arg.data_type())
391 .find_or_first(|d| !d.is_null())
392 .unwrap(); Ok(arrow::array::make_array(ArrayData::new_null(
395 return_type,
396 args[0].len(),
397 )))
398 } else if large_list {
399 concat_internal::<i64>(args, None)
400 } else {
401 concat_internal::<i32>(args, None)
402 }
403}
404
405fn append_prepend_return_type(
409 array_type: &DataType,
410 element_type: &DataType,
411 element_nullable: bool,
412) -> DataType {
413 if array_type.is_null() {
414 DataType::new_list(element_type.clone(), true)
415 } else {
416 list_type_with_element(array_type, element_nullable)
417 }
418}
419
420fn concat_internal<O: OffsetSizeTrait>(
428 args: &[ArrayRef],
429 field: Option<&FieldRef>,
430) -> Result<ArrayRef> {
431 let args = align_array_dimensions::<O>(args.to_vec())?;
432
433 let list_arrays = args
434 .iter()
435 .map(|arg| as_generic_list_array::<O>(arg))
436 .collect::<Result<Vec<_>>>()?;
437 let row_count = list_arrays[0].len();
438
439 let values_data: Vec<ArrayData> =
441 list_arrays.iter().map(|la| la.values().to_data()).collect();
442 let values_data_refs: Vec<&ArrayData> = values_data.iter().collect();
443
444 let total_capacity: usize = values_data.iter().map(|d| d.len()).sum();
446
447 let mut mutable = MutableArrayData::with_capacities(
448 values_data_refs,
449 false,
450 Capacities::Array(total_capacity),
451 );
452 let mut offsets: Vec<O> = Vec::with_capacity(row_count + 1);
453 offsets.push(O::zero());
454
455 let nulls = list_arrays
460 .iter()
461 .filter_map(|la| la.nulls())
462 .collect::<Vec<_>>();
463 let valid = if nulls.len() == list_arrays.len() {
464 nulls
465 .iter()
466 .map(|n| n.inner().clone())
467 .reduce(|a, b| &a | &b)
468 .map(NullBuffer::new)
469 } else {
470 None
471 };
472
473 for row_idx in 0..row_count {
474 for (arr_idx, list_array) in list_arrays.iter().enumerate() {
475 if list_array.is_null(row_idx) {
476 continue;
477 }
478 let start = list_array.offsets()[row_idx].to_usize().unwrap();
479 let end = list_array.offsets()[row_idx + 1].to_usize().unwrap();
480 if start < end {
481 mutable.try_extend(arr_idx, start, end)?;
482 }
483 }
484 offsets.push(O::usize_as(mutable.len()));
485 }
486
487 let field = match field {
488 Some(field) => Arc::clone(field),
489 None => Arc::new(Field::new_list_field(list_arrays[0].value_type(), true)),
490 };
491 let data = mutable.freeze();
492
493 Ok(Arc::new(GenericListArray::<O>::try_new(
494 field,
495 OffsetBuffer::new(offsets.into()),
496 arrow::array::make_array(data),
497 valid,
498 )?))
499}
500
501fn array_append_inner(args: &[ArrayRef], return_type: &DataType) -> Result<ArrayRef> {
504 let [array, values] = take_function_args("array_append", args)?;
505 match array.data_type() {
506 DataType::Null => make_array_inner(&[Arc::clone(values)]),
507 DataType::List(_) => general_append_and_prepend::<i32>(args, true, return_type),
508 DataType::LargeList(_) => {
509 general_append_and_prepend::<i64>(args, true, return_type)
510 }
511 arg_type => exec_err!("array_append does not support type {arg_type}"),
512 }
513}
514
515fn array_prepend_inner(args: &[ArrayRef], return_type: &DataType) -> Result<ArrayRef> {
516 let [values, array] = take_function_args("array_prepend", args)?;
517 match array.data_type() {
518 DataType::Null => make_array_inner(&[Arc::clone(values)]),
519 DataType::List(_) => general_append_and_prepend::<i32>(args, false, return_type),
520 DataType::LargeList(_) => {
521 general_append_and_prepend::<i64>(args, false, return_type)
522 }
523 arg_type => exec_err!("array_prepend does not support type {arg_type}"),
524 }
525}
526
527fn general_append_and_prepend<O: OffsetSizeTrait>(
528 args: &[ArrayRef],
529 is_append: bool,
530 return_type: &DataType,
531) -> Result<ArrayRef>
532where
533 i64: TryInto<O>,
534{
535 let (list_array, element_array) = if is_append {
536 let list_array = as_generic_list_array::<O>(&args[0])?;
537 let element_array = &args[1];
538 check_datatypes("array_append", &[element_array, list_array.values()])?;
539 (list_array, element_array)
540 } else {
541 let list_array = as_generic_list_array::<O>(&args[1])?;
542 let element_array = &args[0];
543 check_datatypes("array_prepend", &[list_array.values(), element_array])?;
544 (list_array, element_array)
545 };
546
547 let name = if is_append {
548 "array_append"
549 } else {
550 "array_prepend"
551 };
552 let field = list_inner_field(name, return_type)?;
553
554 let res = match list_array.value_type() {
555 DataType::List(_) | DataType::LargeList(_) => {
556 concat_internal::<O>(args, Some(&field))?
557 }
558 _ => {
559 return generic_append_and_prepend::<O>(
560 list_array,
561 element_array,
562 field,
563 is_append,
564 );
565 }
566 };
567
568 Ok(res)
569}
570
571fn generic_append_and_prepend<O: OffsetSizeTrait>(
591 list_array: &GenericListArray<O>,
592 element_array: &ArrayRef,
593 field: FieldRef,
594 is_append: bool,
595) -> Result<ArrayRef>
596where
597 i64: TryInto<O>,
598{
599 let mut offsets = vec![O::usize_as(0)];
600 let values = list_array.values();
601 let original_data = values.to_data();
602 let element_data = element_array.to_data();
603 let capacity = Capacities::Array(original_data.len() + element_data.len());
604
605 let mut mutable = MutableArrayData::with_capacities(
606 vec![&original_data, &element_data],
607 false,
608 capacity,
609 );
610
611 let values_index = 0;
612 let element_index = 1;
613
614 for (row_index, offset_window) in list_array.offsets().windows(2).enumerate() {
615 let start = offset_window[0].to_usize().unwrap();
616 let end = offset_window[1].to_usize().unwrap();
617 if is_append {
618 mutable.try_extend(values_index, start, end)?;
619 mutable.try_extend(element_index, row_index, row_index + 1)?;
620 } else {
621 mutable.try_extend(element_index, row_index, row_index + 1)?;
622 mutable.try_extend(values_index, start, end)?;
623 }
624 offsets.push(offsets[row_index] + O::usize_as(end - start + 1));
625 }
626
627 let data = mutable.freeze();
628
629 Ok(Arc::new(GenericListArray::<O>::try_new(
630 field,
631 OffsetBuffer::new(offsets.into()),
632 arrow::array::make_array(data),
633 None,
634 )?))
635}