datafusion_functions_nested/
empty.rs1use crate::utils::make_scalar_function;
21use arrow::array::{Array, ArrayRef, BooleanArray, OffsetSizeTrait};
22use arrow::buffer::BooleanBuffer;
23use arrow::datatypes::{
24 DataType,
25 DataType::{Boolean, FixedSizeList, LargeList, List},
26};
27use datafusion_common::cast::as_generic_list_array;
28use datafusion_common::{Result, exec_err, utils::take_function_args};
29use datafusion_expr::{
30 ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
31 Volatility,
32};
33use datafusion_macros::user_doc;
34use std::sync::Arc;
35
36make_udf_expr_and_func!(
37 ArrayEmpty,
38 array_empty,
39 array,
40 "returns true for an empty array or false for a non-empty array.",
41 array_empty_udf
42);
43
44#[user_doc(
45 doc_section(label = "Array Functions"),
46 description = "Returns 1 for an empty array or 0 for a non-empty array.",
47 syntax_example = "empty(array)",
48 sql_example = r#"```sql
49> select empty([1]);
50+------------------+
51| empty(List([1])) |
52+------------------+
53| 0 |
54+------------------+
55```"#,
56 argument(
57 name = "array",
58 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
59 )
60)]
61#[derive(Debug, PartialEq, Eq, Hash)]
62pub struct ArrayEmpty {
63 signature: Signature,
64 aliases: Vec<String>,
65}
66
67impl Default for ArrayEmpty {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72impl ArrayEmpty {
73 pub fn new() -> Self {
74 Self {
75 signature: Signature::arrays(1, None, Volatility::Immutable),
76 aliases: vec!["array_empty".to_string(), "list_empty".to_string()],
77 }
78 }
79}
80
81impl ScalarUDFImpl for ArrayEmpty {
82 fn name(&self) -> &str {
83 "empty"
84 }
85
86 fn signature(&self) -> &Signature {
87 &self.signature
88 }
89
90 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
91 Ok(Boolean)
92 }
93
94 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
95 make_scalar_function(array_empty_inner)(&args.args)
96 }
97
98 fn aliases(&self) -> &[String] {
99 &self.aliases
100 }
101
102 fn documentation(&self) -> Option<&Documentation> {
103 self.doc()
104 }
105}
106
107fn array_empty_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
108 let [array] = take_function_args("array_empty", args)?;
109 match array.data_type() {
110 List(_) => general_array_empty::<i32>(array),
111 LargeList(_) => general_array_empty::<i64>(array),
112 FixedSizeList(_, size) => {
113 let values = if *size == 0 {
114 BooleanBuffer::new_set(array.len())
115 } else {
116 BooleanBuffer::new_unset(array.len())
117 };
118 Ok(Arc::new(BooleanArray::new(values, array.nulls().cloned())))
119 }
120 arg_type => exec_err!("array_empty does not support type {arg_type}"),
121 }
122}
123
124fn general_array_empty<O: OffsetSizeTrait>(array: &ArrayRef) -> Result<ArrayRef> {
125 let result = as_generic_list_array::<O>(array)?
126 .iter()
127 .map(|arr| arr.map(|arr| arr.is_empty()))
128 .collect::<BooleanArray>();
129 Ok(Arc::new(result))
130}