datafusion_functions_nested/
empty.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! [`ScalarUDFImpl`] definitions for array_empty function.
19
20use 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
117/// Array_empty SQL function
118pub 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}