datafusion_functions/math/
iszero.rs1use 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 sql_example = r#"```sql
40> SELECT iszero(0);
41+------------+
42| iszero(0) |
43+------------+
44| true |
45+------------+
46```"#,
47 standard_argument(name = "numeric_expression", prefix = "Numeric")
48)]
49#[derive(Debug, PartialEq, Eq, Hash)]
50pub struct IsZeroFunc {
51 signature: Signature,
52}
53
54impl Default for IsZeroFunc {
55 fn default() -> Self {
56 IsZeroFunc::new()
57 }
58}
59
60impl IsZeroFunc {
61 pub fn new() -> Self {
62 use DataType::*;
63 Self {
64 signature: Signature::one_of(
65 vec![Exact(vec![Float32]), Exact(vec![Float64])],
66 Volatility::Immutable,
67 ),
68 }
69 }
70}
71
72impl ScalarUDFImpl for IsZeroFunc {
73 fn as_any(&self) -> &dyn Any {
74 self
75 }
76
77 fn name(&self) -> &str {
78 "iszero"
79 }
80
81 fn signature(&self) -> &Signature {
82 &self.signature
83 }
84
85 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
86 Ok(Boolean)
87 }
88
89 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
90 make_scalar_function(iszero, vec![])(&args.args)
91 }
92
93 fn documentation(&self) -> Option<&Documentation> {
94 self.doc()
95 }
96}
97
98pub fn iszero(args: &[ArrayRef]) -> Result<ArrayRef> {
100 match args[0].data_type() {
101 Float64 => Ok(Arc::new(BooleanArray::from_unary(
102 args[0].as_primitive::<Float64Type>(),
103 |x| x == 0.0,
104 )) as ArrayRef),
105
106 Float32 => Ok(Arc::new(BooleanArray::from_unary(
107 args[0].as_primitive::<Float32Type>(),
108 |x| x == 0.0,
109 )) as ArrayRef),
110
111 other => exec_err!("Unsupported data type {other:?} for function iszero"),
112 }
113}
114
115#[cfg(test)]
116mod test {
117 use std::sync::Arc;
118
119 use arrow::array::{ArrayRef, Float32Array, Float64Array};
120
121 use datafusion_common::cast::as_boolean_array;
122
123 use crate::math::iszero::iszero;
124
125 #[test]
126 fn test_iszero_f64() {
127 let args: Vec<ArrayRef> =
128 vec![Arc::new(Float64Array::from(vec![1.0, 0.0, 3.0, -0.0]))];
129
130 let result = iszero(&args).expect("failed to initialize function iszero");
131 let booleans =
132 as_boolean_array(&result).expect("failed to initialize function iszero");
133
134 assert_eq!(booleans.len(), 4);
135 assert!(!booleans.value(0));
136 assert!(booleans.value(1));
137 assert!(!booleans.value(2));
138 assert!(booleans.value(3));
139 }
140
141 #[test]
142 fn test_iszero_f32() {
143 let args: Vec<ArrayRef> =
144 vec![Arc::new(Float32Array::from(vec![1.0, 0.0, 3.0, -0.0]))];
145
146 let result = iszero(&args).expect("failed to initialize function iszero");
147 let booleans =
148 as_boolean_array(&result).expect("failed to initialize function iszero");
149
150 assert_eq!(booleans.len(), 4);
151 assert!(!booleans.value(0));
152 assert!(booleans.value(1));
153 assert!(!booleans.value(2));
154 assert!(booleans.value(3));
155 }
156}