datafusion_functions/math/
iszero.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
18use std::any::Any;
19use std::sync::Arc;
20
21use arrow::array::{ArrayRef, AsArray, BooleanArray};
22use arrow::datatypes::DataType::{Boolean, Float32, Float64};
23use arrow::datatypes::{DataType, Float32Type, Float64Type};
24
25use datafusion_common::{exec_err, Result};
26use datafusion_expr::TypeSignature::Exact;
27use datafusion_expr::{
28    ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
29    Volatility,
30};
31use datafusion_macros::user_doc;
32
33use crate::utils::make_scalar_function;
34
35#[user_doc(
36    doc_section(label = "Math Functions"),
37    description = "Returns true if a given number is +0.0 or -0.0 otherwise returns false.",
38    syntax_example = "iszero(numeric_expression)",
39    standard_argument(name = "numeric_expression", prefix = "Numeric")
40)]
41#[derive(Debug)]
42pub struct IsZeroFunc {
43    signature: Signature,
44}
45
46impl Default for IsZeroFunc {
47    fn default() -> Self {
48        IsZeroFunc::new()
49    }
50}
51
52impl IsZeroFunc {
53    pub fn new() -> Self {
54        use DataType::*;
55        Self {
56            signature: Signature::one_of(
57                vec![Exact(vec![Float32]), Exact(vec![Float64])],
58                Volatility::Immutable,
59            ),
60        }
61    }
62}
63
64impl ScalarUDFImpl for IsZeroFunc {
65    fn as_any(&self) -> &dyn Any {
66        self
67    }
68
69    fn name(&self) -> &str {
70        "iszero"
71    }
72
73    fn signature(&self) -> &Signature {
74        &self.signature
75    }
76
77    fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
78        Ok(Boolean)
79    }
80
81    fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
82        make_scalar_function(iszero, vec![])(&args.args)
83    }
84
85    fn documentation(&self) -> Option<&Documentation> {
86        self.doc()
87    }
88}
89
90/// Iszero SQL function
91pub fn iszero(args: &[ArrayRef]) -> Result<ArrayRef> {
92    match args[0].data_type() {
93        Float64 => Ok(Arc::new(BooleanArray::from_unary(
94            args[0].as_primitive::<Float64Type>(),
95            |x| x == 0.0,
96        )) as ArrayRef),
97
98        Float32 => Ok(Arc::new(BooleanArray::from_unary(
99            args[0].as_primitive::<Float32Type>(),
100            |x| x == 0.0,
101        )) as ArrayRef),
102
103        other => exec_err!("Unsupported data type {other:?} for function iszero"),
104    }
105}
106
107#[cfg(test)]
108mod test {
109    use std::sync::Arc;
110
111    use arrow::array::{ArrayRef, Float32Array, Float64Array};
112
113    use datafusion_common::cast::as_boolean_array;
114
115    use crate::math::iszero::iszero;
116
117    #[test]
118    fn test_iszero_f64() {
119        let args: Vec<ArrayRef> =
120            vec![Arc::new(Float64Array::from(vec![1.0, 0.0, 3.0, -0.0]))];
121
122        let result = iszero(&args).expect("failed to initialize function iszero");
123        let booleans =
124            as_boolean_array(&result).expect("failed to initialize function iszero");
125
126        assert_eq!(booleans.len(), 4);
127        assert!(!booleans.value(0));
128        assert!(booleans.value(1));
129        assert!(!booleans.value(2));
130        assert!(booleans.value(3));
131    }
132
133    #[test]
134    fn test_iszero_f32() {
135        let args: Vec<ArrayRef> =
136            vec![Arc::new(Float32Array::from(vec![1.0, 0.0, 3.0, -0.0]))];
137
138        let result = iszero(&args).expect("failed to initialize function iszero");
139        let booleans =
140            as_boolean_array(&result).expect("failed to initialize function iszero");
141
142        assert_eq!(booleans.len(), 4);
143        assert!(!booleans.value(0));
144        assert!(booleans.value(1));
145        assert!(!booleans.value(2));
146        assert!(booleans.value(3));
147    }
148}