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::{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
113/// Array_empty SQL function
114pub 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}