datafusion_functions_aggregate/
bool_and_or.rs1use std::mem::size_of_val;
21
22use arrow::array::ArrayRef;
23use arrow::array::BooleanArray;
24use arrow::compute::bool_and as compute_bool_and;
25use arrow::compute::bool_or as compute_bool_or;
26use arrow::datatypes::Field;
27use arrow::datatypes::{DataType, FieldRef};
28
29use datafusion_common::internal_err;
30use datafusion_common::{Result, ScalarValue};
31use datafusion_common::{downcast_value, not_impl_err};
32use datafusion_expr::function::{AccumulatorArgs, StateFieldsArgs};
33use datafusion_expr::utils::{AggregateOrderSensitivity, format_state_name};
34use datafusion_expr::{
35 Accumulator, AggregateUDFImpl, Documentation, GroupsAccumulator, ReversedUDAF,
36 Signature, Volatility,
37};
38
39use datafusion_functions_aggregate_common::aggregate::groups_accumulator::bool_op::BooleanGroupsAccumulator;
40use datafusion_macros::user_doc;
41
42macro_rules! typed_bool_and_or_batch {
44 ($VALUES:expr, $ARRAYTYPE:ident, $SCALAR:ident, $OP:ident) => {{
45 let array = downcast_value!($VALUES, $ARRAYTYPE);
46 let delta = $OP(array);
47 Ok(ScalarValue::$SCALAR(delta))
48 }};
49}
50
51macro_rules! bool_and_or_batch {
53 ($VALUES:expr, $OP:ident) => {{
54 match $VALUES.data_type() {
55 DataType::Boolean => {
56 typed_bool_and_or_batch!($VALUES, BooleanArray, Boolean, $OP)
57 }
58 e => {
59 return internal_err!(
60 "Bool and/Bool or is not expected to receive the type {e:?}"
61 );
62 }
63 }
64 }};
65}
66
67fn bool_and_batch(values: &ArrayRef) -> Result<ScalarValue> {
69 bool_and_or_batch!(values, compute_bool_and)
70}
71
72fn bool_or_batch(values: &ArrayRef) -> Result<ScalarValue> {
74 bool_and_or_batch!(values, compute_bool_or)
75}
76
77make_udaf_expr_and_func!(
78 BoolAnd,
79 bool_and,
80 expression,
81 "The values to combine with `AND`",
82 bool_and_udaf
83);
84
85make_udaf_expr_and_func!(
86 BoolOr,
87 bool_or,
88 expression,
89 "The values to combine with `OR`",
90 bool_or_udaf
91);
92
93#[user_doc(
94 doc_section(label = "General Functions"),
95 description = "Returns true if all non-null input values are true, otherwise false.",
96 syntax_example = "bool_and(expression)",
97 sql_example = r#"```sql
98> SELECT bool_and(column_name) FROM table_name;
99+----------------------------+
100| bool_and(column_name) |
101+----------------------------+
102| true |
103+----------------------------+
104```"#,
105 standard_argument(name = "expression", prefix = "The")
106)]
107#[derive(Debug, PartialEq, Eq, Hash)]
109pub struct BoolAnd {
110 signature: Signature,
111}
112
113impl BoolAnd {
114 fn new() -> Self {
115 Self {
116 signature: Signature::exact(vec![DataType::Boolean], Volatility::Immutable),
117 }
118 }
119}
120
121impl Default for BoolAnd {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl AggregateUDFImpl for BoolAnd {
128 fn name(&self) -> &str {
129 "bool_and"
130 }
131
132 fn signature(&self) -> &Signature {
133 &self.signature
134 }
135
136 fn return_type(&self, _: &[DataType]) -> Result<DataType> {
137 Ok(DataType::Boolean)
138 }
139
140 fn accumulator(&self, _: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
141 Ok(Box::<BoolAndAccumulator>::default())
142 }
143
144 fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
145 Ok(vec![
146 Field::new(
147 format_state_name(args.name, self.name()),
148 DataType::Boolean,
149 true,
150 )
151 .into(),
152 ])
153 }
154
155 fn groups_accumulator_supported(&self, _args: AccumulatorArgs) -> bool {
156 true
157 }
158
159 fn create_groups_accumulator(
160 &self,
161 args: AccumulatorArgs,
162 ) -> Result<Box<dyn GroupsAccumulator>> {
163 match args.return_field.data_type() {
164 DataType::Boolean => {
165 Ok(Box::new(BooleanGroupsAccumulator::new(|x, y| x && y, true)))
166 }
167 _ => not_impl_err!(
168 "GroupsAccumulator not supported for {} with {}",
169 args.name,
170 args.return_field.data_type()
171 ),
172 }
173 }
174
175 fn order_sensitivity(&self) -> AggregateOrderSensitivity {
176 AggregateOrderSensitivity::Insensitive
177 }
178
179 fn reverse_expr(&self) -> ReversedUDAF {
180 ReversedUDAF::Identical
181 }
182
183 fn documentation(&self) -> Option<&Documentation> {
184 self.doc()
185 }
186}
187
188#[derive(Debug, Default)]
189struct BoolAndAccumulator {
190 acc: Option<bool>,
191}
192
193impl Accumulator for BoolAndAccumulator {
194 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
195 let values = &values[0];
196 self.acc = match (self.acc, bool_and_batch(values)?) {
197 (None, ScalarValue::Boolean(v)) => v,
198 (Some(v), ScalarValue::Boolean(None)) => Some(v),
199 (Some(a), ScalarValue::Boolean(Some(b))) => Some(a && b),
200 _ => unreachable!(),
201 };
202 Ok(())
203 }
204
205 fn evaluate(&mut self) -> Result<ScalarValue> {
206 Ok(ScalarValue::Boolean(self.acc))
207 }
208
209 fn size(&self) -> usize {
210 size_of_val(self)
211 }
212
213 fn state(&mut self) -> Result<Vec<ScalarValue>> {
214 Ok(vec![ScalarValue::Boolean(self.acc)])
215 }
216
217 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
218 self.update_batch(states)
219 }
220}
221
222#[user_doc(
223 doc_section(label = "General Functions"),
224 description = "Returns true if all non-null input values are true, otherwise false.",
225 syntax_example = "bool_and(expression)",
226 sql_example = r#"```sql
227> SELECT bool_and(column_name) FROM table_name;
228+----------------------------+
229| bool_and(column_name) |
230+----------------------------+
231| true |
232+----------------------------+
233```"#,
234 standard_argument(name = "expression", prefix = "The")
235)]
236#[derive(Debug, Clone, PartialEq, Eq, Hash)]
238pub struct BoolOr {
239 signature: Signature,
240}
241
242impl BoolOr {
243 fn new() -> Self {
244 Self {
245 signature: Signature::exact(vec![DataType::Boolean], Volatility::Immutable),
246 }
247 }
248}
249
250impl Default for BoolOr {
251 fn default() -> Self {
252 Self::new()
253 }
254}
255
256impl AggregateUDFImpl for BoolOr {
257 fn name(&self) -> &str {
258 "bool_or"
259 }
260
261 fn signature(&self) -> &Signature {
262 &self.signature
263 }
264
265 fn return_type(&self, _: &[DataType]) -> Result<DataType> {
266 Ok(DataType::Boolean)
267 }
268
269 fn accumulator(&self, _: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
270 Ok(Box::<BoolOrAccumulator>::default())
271 }
272
273 fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
274 Ok(vec![
275 Field::new(
276 format_state_name(args.name, self.name()),
277 DataType::Boolean,
278 true,
279 )
280 .into(),
281 ])
282 }
283
284 fn groups_accumulator_supported(&self, _args: AccumulatorArgs) -> bool {
285 true
286 }
287
288 fn create_groups_accumulator(
289 &self,
290 args: AccumulatorArgs,
291 ) -> Result<Box<dyn GroupsAccumulator>> {
292 match args.return_field.data_type() {
293 DataType::Boolean => Ok(Box::new(BooleanGroupsAccumulator::new(
294 |x, y| x || y,
295 false,
296 ))),
297 _ => not_impl_err!(
298 "GroupsAccumulator not supported for {} with {}",
299 args.name,
300 args.return_field.data_type()
301 ),
302 }
303 }
304
305 fn order_sensitivity(&self) -> AggregateOrderSensitivity {
306 AggregateOrderSensitivity::Insensitive
307 }
308
309 fn reverse_expr(&self) -> ReversedUDAF {
310 ReversedUDAF::Identical
311 }
312
313 fn documentation(&self) -> Option<&Documentation> {
314 self.doc()
315 }
316}
317
318#[derive(Debug, Default)]
319struct BoolOrAccumulator {
320 acc: Option<bool>,
321}
322
323impl Accumulator for BoolOrAccumulator {
324 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
325 let values = &values[0];
326 self.acc = match (self.acc, bool_or_batch(values)?) {
327 (None, ScalarValue::Boolean(v)) => v,
328 (Some(v), ScalarValue::Boolean(None)) => Some(v),
329 (Some(a), ScalarValue::Boolean(Some(b))) => Some(a || b),
330 _ => unreachable!(),
331 };
332 Ok(())
333 }
334
335 fn evaluate(&mut self) -> Result<ScalarValue> {
336 Ok(ScalarValue::Boolean(self.acc))
337 }
338
339 fn size(&self) -> usize {
340 size_of_val(self)
341 }
342
343 fn state(&mut self) -> Result<Vec<ScalarValue>> {
344 Ok(vec![ScalarValue::Boolean(self.acc)])
345 }
346
347 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
348 self.update_batch(states)
349 }
350}