Skip to main content

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, 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}