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::{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, 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, 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 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
113fn array_empty_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
114    let [array] = take_function_args("array_empty", args)?;
115    match array.data_type() {
116        List(_) => general_array_empty::<i32>(array),
117        LargeList(_) => general_array_empty::<i64>(array),
118        FixedSizeList(_, size) => {
119            let values = if *size == 0 {
120                BooleanBuffer::new_set(array.len())
121            } else {
122                BooleanBuffer::new_unset(array.len())
123            };
124            Ok(Arc::new(BooleanArray::new(values, array.nulls().cloned())))
125        }
126        arg_type => exec_err!("array_empty does not support type {arg_type}"),
127    }
128}
129
130fn general_array_empty<O: OffsetSizeTrait>(array: &ArrayRef) -> Result<ArrayRef> {
131    let result = as_generic_list_array::<O>(array)?
132        .iter()
133        .map(|arr| arr.map(|arr| arr.is_empty()))
134        .collect::<BooleanArray>();
135    Ok(Arc::new(result))
136}