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::{exec_err, utils::take_function_args, Result};
29use datafusion_expr::{
30 ColumnarValue, Documentation, ScalarUDFImpl, Signature, Volatility,
31};
32use datafusion_macros::user_doc;
33use std::any::Any;
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)]
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 as_any(&self) -> &dyn Any {
83 self
84 }
85 fn name(&self) -> &str {
86 "empty"
87 }
88
89 fn signature(&self) -> &Signature {
90 &self.signature
91 }
92
93 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
94 Ok(Boolean)
95 }
96
97 fn invoke_with_args(
98 &self,
99 args: datafusion_expr::ScalarFunctionArgs,
100 ) -> Result<ColumnarValue> {
101 make_scalar_function(array_empty_inner)(&args.args)
102 }
103
104 fn aliases(&self) -> &[String] {
105 &self.aliases
106 }
107
108 fn documentation(&self) -> Option<&Documentation> {
109 self.doc()
110 }
111}
112
113pub fn array_empty_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
115 let [array] = take_function_args("array_empty", args)?;
116 match array.data_type() {
117 List(_) => general_array_empty::<i32>(array),
118 LargeList(_) => general_array_empty::<i64>(array),
119 FixedSizeList(_, size) => {
120 let values = if *size == 0 {
121 BooleanBuffer::new_set(array.len())
122 } else {
123 BooleanBuffer::new_unset(array.len())
124 };
125 Ok(Arc::new(BooleanArray::new(values, array.nulls().cloned())))
126 }
127 arg_type => exec_err!("array_empty does not support type {arg_type}"),
128 }
129}
130
131fn general_array_empty<O: OffsetSizeTrait>(array: &ArrayRef) -> Result<ArrayRef> {
132 let result = as_generic_list_array::<O>(array)?
133 .iter()
134 .map(|arr| arr.map(|arr| arr.is_empty()))
135 .collect::<BooleanArray>();
136 Ok(Arc::new(result))
137}