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