Skip to main content

datafusion_functions_aggregate/
count.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 arrow::{
19    array::{Array, ArrayRef, AsArray, BooleanArray, Int64Array, PrimitiveArray},
20    buffer::BooleanBuffer,
21    compute,
22    datatypes::{
23        DataType, Date32Type, Date64Type, Decimal128Type, Decimal256Type, Field,
24        FieldRef, Float16Type, Float32Type, Float64Type, Int8Type, Int16Type, Int32Type,
25        Int64Type, Time32MillisecondType, Time32SecondType, Time64MicrosecondType,
26        Time64NanosecondType, TimeUnit, TimestampMicrosecondType,
27        TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType,
28        UInt8Type, UInt16Type, UInt32Type, UInt64Type,
29    },
30};
31use datafusion_common::hash_utils::RandomState;
32use datafusion_common::heap_size::{DFHeapSize, DFHeapSizeCtx};
33use datafusion_common::{
34    HashMap, Result, ScalarValue, downcast_value, exec_err, internal_err, not_impl_err,
35    stats::Precision, utils::expr::COUNT_STAR_EXPANSION,
36};
37use datafusion_expr::{
38    Accumulator, AggregateUDFImpl, Documentation, EmitTo, Expr, GroupsAccumulator,
39    ReversedUDAF, SetMonotonicity, Signature, StatisticsArgs, TypeSignature, Volatility,
40    WindowFunctionDefinition,
41    expr::WindowFunction,
42    function::{AccumulatorArgs, StateFieldsArgs},
43    utils::format_state_name,
44};
45use datafusion_functions_aggregate_common::aggregate::count_distinct::PrimitiveDistinctCountGroupsAccumulator;
46use datafusion_functions_aggregate_common::aggregate::{
47    count_distinct::Bitmap65536DistinctCountAccumulator,
48    count_distinct::Bitmap65536DistinctCountAccumulatorI16,
49    count_distinct::BoolArray256DistinctCountAccumulator,
50    count_distinct::BoolArray256DistinctCountAccumulatorI8,
51    count_distinct::BytesDistinctCountAccumulator,
52    count_distinct::BytesViewDistinctCountAccumulator,
53    count_distinct::DictionaryCountAccumulator,
54    count_distinct::FloatDistinctCountAccumulator,
55    count_distinct::PrimitiveDistinctCountAccumulator,
56    groups_accumulator::accumulate::accumulate_indices,
57};
58use datafusion_macros::user_doc;
59use datafusion_physical_expr::expressions;
60use datafusion_physical_expr_common::binary_map::OutputType;
61use std::{
62    collections::HashSet,
63    fmt::Debug,
64    mem::{size_of, size_of_val},
65    ops::BitAnd,
66    sync::Arc,
67};
68
69make_udaf_expr_and_func!(
70    Count,
71    count,
72    expr,
73    "Count the number of non-null values in the column",
74    count_udaf
75);
76
77pub fn count_distinct(expr: Expr) -> Expr {
78    Expr::AggregateFunction(datafusion_expr::expr::AggregateFunction::new_udf(
79        count_udaf(),
80        vec![expr],
81        true,
82        None,
83        vec![],
84        None,
85    ))
86}
87
88/// Creates aggregation to count all rows.
89///
90/// In SQL this is `SELECT COUNT(*) ... `
91///
92/// The expression is equivalent to `COUNT(*)`, `COUNT()`, `COUNT(1)`, and is
93/// aliased to a column named `"count(*)"` for backward compatibility.
94///
95/// Example
96/// ```
97/// # use datafusion_functions_aggregate::count::count_all;
98/// # use datafusion_expr::col;
99/// // create `count(*)` expression
100/// let expr = count_all();
101/// assert_eq!(expr.schema_name().to_string(), "count(*)");
102/// // if you need to refer to this column, use the `schema_name` function
103/// let expr = col(expr.schema_name().to_string());
104/// ```
105pub fn count_all() -> Expr {
106    count(Expr::Literal(COUNT_STAR_EXPANSION, None)).alias("count(*)")
107}
108
109/// Creates window aggregation to count all rows.
110///
111/// In SQL this is `SELECT COUNT(*) OVER (..) ... `
112///
113/// The expression is equivalent to `COUNT(*)`, `COUNT()`, `COUNT(1)`
114///
115/// Example
116/// ```
117/// # use datafusion_functions_aggregate::count::count_all_window;
118/// # use datafusion_expr::col;
119/// // create `count(*)` OVER ... window function expression
120/// let expr = count_all_window();
121/// assert_eq!(
122///     expr.schema_name().to_string(),
123///     "count(Int64(1)) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
124/// );
125/// // if you need to refer to this column, use the `schema_name` function
126/// let expr = col(expr.schema_name().to_string());
127/// ```
128pub fn count_all_window() -> Expr {
129    Expr::from(WindowFunction::new(
130        WindowFunctionDefinition::AggregateUDF(count_udaf()),
131        vec![Expr::Literal(COUNT_STAR_EXPANSION, None)],
132    ))
133}
134
135#[user_doc(
136    doc_section(label = "General Functions"),
137    description = "Returns the number of non-null values in the specified column. To include null values in the total count, use `count(*)`.",
138    syntax_example = "count(expression)",
139    sql_example = r#"```sql
140> SELECT count(column_name) FROM table_name;
141+-----------------------+
142| count(column_name)     |
143+-----------------------+
144| 100                   |
145+-----------------------+
146
147> SELECT count(*) FROM table_name;
148+------------------+
149| count(*)         |
150+------------------+
151| 120              |
152+------------------+
153```"#,
154    standard_argument(name = "expression",)
155)]
156#[derive(PartialEq, Eq, Hash, Debug)]
157pub struct Count {
158    signature: Signature,
159}
160
161impl Default for Count {
162    fn default() -> Self {
163        Self::new()
164    }
165}
166
167impl Count {
168    pub fn new() -> Self {
169        Self {
170            signature: Signature::one_of(
171                vec![TypeSignature::VariadicAny, TypeSignature::Nullary],
172                Volatility::Immutable,
173            ),
174        }
175    }
176}
177fn get_count_accumulator(data_type: &DataType) -> Box<dyn Accumulator> {
178    match data_type {
179        // HashSet-based accumulator for larger integer types
180        DataType::Int32 => Box::new(PrimitiveDistinctCountAccumulator::<Int32Type>::new(
181            data_type,
182        )),
183        DataType::Int64 => Box::new(PrimitiveDistinctCountAccumulator::<Int64Type>::new(
184            data_type,
185        )),
186        DataType::UInt32 => Box::new(
187            PrimitiveDistinctCountAccumulator::<UInt32Type>::new(data_type),
188        ),
189        DataType::UInt64 => Box::new(
190            PrimitiveDistinctCountAccumulator::<UInt64Type>::new(data_type),
191        ),
192        // Small int types - cold path
193        DataType::UInt8 | DataType::Int8 | DataType::UInt16 | DataType::Int16 => {
194            get_small_int_accumulator(data_type).unwrap()
195        }
196        DataType::Decimal128(_, _) => Box::new(PrimitiveDistinctCountAccumulator::<
197            Decimal128Type,
198        >::new(data_type)),
199        DataType::Decimal256(_, _) => Box::new(PrimitiveDistinctCountAccumulator::<
200            Decimal256Type,
201        >::new(data_type)),
202
203        DataType::Date32 => Box::new(
204            PrimitiveDistinctCountAccumulator::<Date32Type>::new(data_type),
205        ),
206        DataType::Date64 => Box::new(
207            PrimitiveDistinctCountAccumulator::<Date64Type>::new(data_type),
208        ),
209        DataType::Time32(TimeUnit::Millisecond) => Box::new(
210            PrimitiveDistinctCountAccumulator::<Time32MillisecondType>::new(data_type),
211        ),
212        DataType::Time32(TimeUnit::Second) => Box::new(
213            PrimitiveDistinctCountAccumulator::<Time32SecondType>::new(data_type),
214        ),
215        DataType::Time64(TimeUnit::Microsecond) => Box::new(
216            PrimitiveDistinctCountAccumulator::<Time64MicrosecondType>::new(data_type),
217        ),
218        DataType::Time64(TimeUnit::Nanosecond) => Box::new(
219            PrimitiveDistinctCountAccumulator::<Time64NanosecondType>::new(data_type),
220        ),
221        DataType::Timestamp(TimeUnit::Microsecond, _) => Box::new(
222            PrimitiveDistinctCountAccumulator::<TimestampMicrosecondType>::new(data_type),
223        ),
224        DataType::Timestamp(TimeUnit::Millisecond, _) => Box::new(
225            PrimitiveDistinctCountAccumulator::<TimestampMillisecondType>::new(data_type),
226        ),
227        DataType::Timestamp(TimeUnit::Nanosecond, _) => Box::new(
228            PrimitiveDistinctCountAccumulator::<TimestampNanosecondType>::new(data_type),
229        ),
230        DataType::Timestamp(TimeUnit::Second, _) => Box::new(
231            PrimitiveDistinctCountAccumulator::<TimestampSecondType>::new(data_type),
232        ),
233
234        DataType::Float16 => {
235            Box::new(FloatDistinctCountAccumulator::<Float16Type>::new())
236        }
237        DataType::Float32 => {
238            Box::new(FloatDistinctCountAccumulator::<Float32Type>::new())
239        }
240        DataType::Float64 => {
241            Box::new(FloatDistinctCountAccumulator::<Float64Type>::new())
242        }
243
244        DataType::Utf8 => {
245            Box::new(BytesDistinctCountAccumulator::<i32>::new(OutputType::Utf8))
246        }
247        DataType::Utf8View => {
248            Box::new(BytesViewDistinctCountAccumulator::new(OutputType::Utf8View))
249        }
250        DataType::LargeUtf8 => {
251            Box::new(BytesDistinctCountAccumulator::<i64>::new(OutputType::Utf8))
252        }
253        DataType::Binary => Box::new(BytesDistinctCountAccumulator::<i32>::new(
254            OutputType::Binary,
255        )),
256        DataType::BinaryView => Box::new(BytesViewDistinctCountAccumulator::new(
257            OutputType::BinaryView,
258        )),
259        DataType::LargeBinary => Box::new(BytesDistinctCountAccumulator::<i64>::new(
260            OutputType::Binary,
261        )),
262
263        // Use the generic accumulator based on `ScalarValue` for all other types
264        _ => Box::new(DistinctCountAccumulator {
265            values: HashSet::default(),
266            state_data_type: data_type.clone(),
267        }),
268    }
269}
270
271/// Uses optimized bitmap accumulators but separated to keep hot path small
272#[cold]
273fn get_small_int_accumulator(data_type: &DataType) -> Result<Box<dyn Accumulator>> {
274    match data_type {
275        DataType::UInt8 => Ok(Box::new(BoolArray256DistinctCountAccumulator::new())),
276        DataType::Int8 => Ok(Box::new(BoolArray256DistinctCountAccumulatorI8::new())),
277        DataType::UInt16 => Ok(Box::new(Bitmap65536DistinctCountAccumulator::new())),
278        DataType::Int16 => Ok(Box::new(Bitmap65536DistinctCountAccumulatorI16::new())),
279        _ => exec_err!("unsupported accumulator for datatype: {}", data_type),
280    }
281}
282
283impl AggregateUDFImpl for Count {
284    fn name(&self) -> &str {
285        "count"
286    }
287
288    fn signature(&self) -> &Signature {
289        &self.signature
290    }
291
292    fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
293        Ok(DataType::Int64)
294    }
295
296    fn is_nullable(&self) -> bool {
297        false
298    }
299
300    fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
301        if args.is_distinct {
302            let dtype: DataType = match &args.input_fields[0].data_type() {
303                DataType::Dictionary(_, values_type) => (**values_type).clone(),
304                &dtype => dtype.clone(),
305            };
306
307            Ok(vec![
308                Field::new_list(
309                    format_state_name(args.name, "count distinct"),
310                    // See COMMENTS.md to understand why nullable is set to true
311                    Field::new_list_field(dtype, true),
312                    false,
313                )
314                .into(),
315            ])
316        } else {
317            Ok(vec![
318                Field::new(
319                    format_state_name(args.name, "count"),
320                    DataType::Int64,
321                    false,
322                )
323                .into(),
324            ])
325        }
326    }
327
328    fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
329        if !acc_args.is_distinct {
330            return Ok(Box::new(CountAccumulator::new()));
331        }
332
333        if acc_args.exprs.len() > 1 {
334            return not_impl_err!("COUNT DISTINCT with multiple arguments");
335        }
336
337        let data_type = acc_args.expr_fields[0].data_type();
338
339        Ok(match data_type {
340            DataType::Dictionary(_, values_type) => {
341                let inner = get_count_accumulator(values_type);
342                Box::new(DictionaryCountAccumulator::new(inner))
343            }
344            _ => get_count_accumulator(data_type),
345        })
346    }
347
348    fn groups_accumulator_supported(&self, args: AccumulatorArgs) -> bool {
349        if args.exprs.len() != 1 {
350            return false;
351        }
352        if !args.is_distinct {
353            return true;
354        }
355        matches!(
356            args.expr_fields[0].data_type(),
357            DataType::Int8
358                | DataType::Int16
359                | DataType::Int32
360                | DataType::Int64
361                | DataType::UInt8
362                | DataType::UInt16
363                | DataType::UInt32
364                | DataType::UInt64
365        )
366    }
367
368    fn create_groups_accumulator(
369        &self,
370        args: AccumulatorArgs,
371    ) -> Result<Box<dyn GroupsAccumulator>> {
372        if !args.is_distinct {
373            return Ok(Box::new(CountGroupsAccumulator::new()));
374        }
375        create_distinct_count_groups_accumulator(&args)
376    }
377
378    fn reverse_expr(&self) -> ReversedUDAF {
379        ReversedUDAF::Identical
380    }
381
382    fn default_value(&self, _data_type: &DataType) -> Result<ScalarValue> {
383        Ok(ScalarValue::Int64(Some(0)))
384    }
385
386    fn value_from_stats(&self, statistics_args: &StatisticsArgs) -> Option<ScalarValue> {
387        let [expr] = statistics_args.exprs else {
388            return None;
389        };
390        let col_stats = &statistics_args.statistics.column_statistics;
391
392        if statistics_args.is_distinct {
393            // Only column references can be resolved from statistics;
394            // expressions like casts or literals are not supported.
395            let col_expr = expr.downcast_ref::<expressions::Column>()?;
396            if let Precision::Exact(dc) = col_stats[col_expr.index()].distinct_count {
397                let dc = i64::try_from(dc).ok()?;
398                return Some(ScalarValue::Int64(Some(dc)));
399            }
400            return None;
401        }
402
403        let Precision::Exact(num_rows) = statistics_args.statistics.num_rows else {
404            return None;
405        };
406
407        // TODO optimize with exprs other than Column
408        if let Some(col_expr) = expr.downcast_ref::<expressions::Column>() {
409            if let Precision::Exact(val) = col_stats[col_expr.index()].null_count {
410                let count = i64::try_from(num_rows - val).ok()?;
411                return Some(ScalarValue::Int64(Some(count)));
412            }
413        } else if let Some(lit_expr) = expr.downcast_ref::<expressions::Literal>()
414            && lit_expr.value() == &COUNT_STAR_EXPANSION
415        {
416            let num_rows = i64::try_from(num_rows).ok()?;
417            return Some(ScalarValue::Int64(Some(num_rows)));
418        }
419
420        None
421    }
422
423    fn documentation(&self) -> Option<&Documentation> {
424        self.doc()
425    }
426
427    fn set_monotonicity(&self, _data_type: &DataType) -> SetMonotonicity {
428        // `COUNT` is monotonically increasing as it always increases or stays
429        // the same as new values are seen.
430        SetMonotonicity::Increasing
431    }
432
433    fn create_sliding_accumulator(
434        &self,
435        args: AccumulatorArgs,
436    ) -> Result<Box<dyn Accumulator>> {
437        if args.is_distinct {
438            let acc =
439                SlidingDistinctCountAccumulator::try_new(args.return_field.data_type())?;
440            Ok(Box::new(acc))
441        } else {
442            let acc = CountAccumulator::new();
443            Ok(Box::new(acc))
444        }
445    }
446}
447
448#[cold]
449fn create_distinct_count_groups_accumulator(
450    args: &AccumulatorArgs,
451) -> Result<Box<dyn GroupsAccumulator>> {
452    let data_type = args.expr_fields[0].data_type();
453    match data_type {
454        DataType::Int8 => Ok(Box::new(
455            PrimitiveDistinctCountGroupsAccumulator::<Int8Type>::new(),
456        )),
457        DataType::Int16 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
458            Int16Type,
459        >::new())),
460        DataType::Int32 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
461            Int32Type,
462        >::new())),
463        DataType::Int64 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
464            Int64Type,
465        >::new())),
466        DataType::UInt8 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
467            UInt8Type,
468        >::new())),
469        DataType::UInt16 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
470            UInt16Type,
471        >::new())),
472        DataType::UInt32 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
473            UInt32Type,
474        >::new())),
475        DataType::UInt64 => Ok(Box::new(PrimitiveDistinctCountGroupsAccumulator::<
476            UInt64Type,
477        >::new())),
478        _ => not_impl_err!(
479            "GroupsAccumulator not supported for COUNT(DISTINCT) with {}",
480            data_type
481        ),
482    }
483}
484
485// DistinctCountAccumulator does not support retract_batch and sliding window
486// this is a specialized accumulator for distinct count that supports retract_batch
487// and sliding window.
488#[derive(Debug)]
489pub struct SlidingDistinctCountAccumulator {
490    counts: HashMap<ScalarValue, usize, RandomState>,
491    data_type: DataType,
492}
493
494impl SlidingDistinctCountAccumulator {
495    pub fn try_new(data_type: &DataType) -> Result<Self> {
496        Ok(Self {
497            counts: HashMap::default(),
498            data_type: data_type.clone(),
499        })
500    }
501}
502
503impl Accumulator for SlidingDistinctCountAccumulator {
504    fn state(&mut self) -> Result<Vec<ScalarValue>> {
505        let keys = self.counts.keys().cloned().collect::<Vec<_>>();
506        Ok(vec![ScalarValue::List(ScalarValue::new_list_nullable(
507            keys.as_slice(),
508            &self.data_type,
509        ))])
510    }
511
512    fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
513        let arr = &values[0];
514        for i in 0..arr.len() {
515            let v = ScalarValue::try_from_array(arr, i)?;
516            if !v.is_null() {
517                *self.counts.entry(v).or_default() += 1;
518            }
519        }
520        Ok(())
521    }
522
523    fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
524        let arr = &values[0];
525        for i in 0..arr.len() {
526            let v = ScalarValue::try_from_array(arr, i)?;
527            if !v.is_null()
528                && let Some(cnt) = self.counts.get_mut(&v)
529            {
530                *cnt -= 1;
531                if *cnt == 0 {
532                    self.counts.remove(&v);
533                }
534            }
535        }
536        Ok(())
537    }
538
539    fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
540        let list_arr = states[0].as_list::<i32>();
541        for inner in list_arr.iter().flatten() {
542            for j in 0..inner.len() {
543                let v = ScalarValue::try_from_array(&*inner, j)?;
544                *self.counts.entry(v).or_default() += 1;
545            }
546        }
547        Ok(())
548    }
549
550    fn evaluate(&mut self) -> Result<ScalarValue> {
551        Ok(ScalarValue::Int64(Some(self.counts.len() as i64)))
552    }
553
554    fn supports_retract_batch(&self) -> bool {
555        true
556    }
557
558    fn size(&self) -> usize {
559        // Mirrors `DistinctCountAccumulator::full_size`: self + HashMap
560        // bucket array + per-key inner heap + DataType inner heap.
561        size_of_val(self)
562            + (size_of::<ScalarValue>() + size_of::<usize>()) * self.counts.capacity()
563            + self
564                .counts
565                .keys()
566                .map(|k| k.size() - size_of_val(k))
567                .sum::<usize>()
568            + self.data_type.size()
569            - size_of_val(&self.data_type)
570    }
571}
572
573#[derive(Debug)]
574struct CountAccumulator {
575    count: i64,
576}
577
578impl CountAccumulator {
579    /// new count accumulator
580    pub fn new() -> Self {
581        Self { count: 0 }
582    }
583}
584
585impl Accumulator for CountAccumulator {
586    fn state(&mut self) -> Result<Vec<ScalarValue>> {
587        Ok(vec![ScalarValue::Int64(Some(self.count))])
588    }
589
590    fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
591        let array = &values[0];
592        self.count += (array.len() - null_count_for_multiple_cols(values)) as i64;
593        Ok(())
594    }
595
596    fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
597        let array = &values[0];
598        self.count -= (array.len() - null_count_for_multiple_cols(values)) as i64;
599        Ok(())
600    }
601
602    fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
603        let counts = downcast_value!(states[0], Int64Array);
604        let delta = &compute::sum(counts);
605        if let Some(d) = delta {
606            self.count += *d;
607        }
608        Ok(())
609    }
610
611    fn evaluate(&mut self) -> Result<ScalarValue> {
612        Ok(ScalarValue::Int64(Some(self.count)))
613    }
614
615    fn supports_retract_batch(&self) -> bool {
616        true
617    }
618
619    fn size(&self) -> usize {
620        size_of_val(self)
621    }
622}
623
624/// An accumulator to compute the counts of [`PrimitiveArray<T>`].
625/// Stores values as native types, and does overflow checking
626///
627/// Unlike most other accumulators, COUNT never produces NULLs. If no
628/// non-null values are seen in any group the output is 0. Thus, this
629/// accumulator has no additional null or seen filter tracking.
630#[derive(Debug)]
631struct CountGroupsAccumulator {
632    /// Count per group.
633    ///
634    /// Note this is an i64 and not a u64 (or usize) because the
635    /// output type of count is `DataType::Int64`. Thus by using `i64`
636    /// for the counts, the output [`Int64Array`] can be created
637    /// without copy.
638    counts: Vec<i64>,
639}
640
641impl CountGroupsAccumulator {
642    pub fn new() -> Self {
643        Self { counts: vec![] }
644    }
645}
646
647impl GroupsAccumulator for CountGroupsAccumulator {
648    fn update_batch(
649        &mut self,
650        values: &[ArrayRef],
651        group_indices: &[usize],
652        opt_filter: Option<&BooleanArray>,
653        total_num_groups: usize,
654    ) -> Result<()> {
655        assert_eq!(values.len(), 1, "single argument to update_batch");
656        let values = &values[0];
657
658        // Add one to each group's counter for each non null, non
659        // filtered value
660        self.counts.resize(total_num_groups, 0);
661        accumulate_indices(
662            group_indices,
663            values.logical_nulls().as_ref(),
664            opt_filter,
665            |group_index| {
666                // SAFETY: group_index is guaranteed to be in bounds
667                let count = unsafe { self.counts.get_unchecked_mut(group_index) };
668                *count += 1;
669            },
670        );
671
672        Ok(())
673    }
674
675    fn merge_batch(
676        &mut self,
677        values: &[ArrayRef],
678        group_indices: &[usize],
679        total_num_groups: usize,
680    ) -> Result<()> {
681        assert_eq!(values.len(), 1, "one argument to merge_batch");
682        // first batch is counts, second is partial sums
683        let partial_counts = values[0].as_primitive::<Int64Type>();
684
685        // intermediate counts are always created as non null
686        assert_eq!(partial_counts.null_count(), 0);
687        let partial_counts = partial_counts.values();
688
689        // Adds the counts with the partial counts
690        self.counts.resize(total_num_groups, 0);
691        group_indices.iter().zip(partial_counts.iter()).for_each(
692            |(&group_index, partial_count)| {
693                self.counts[group_index] += partial_count;
694            },
695        );
696
697        Ok(())
698    }
699
700    fn evaluate(&mut self, emit_to: EmitTo) -> Result<ArrayRef> {
701        let counts = emit_to.take_needed(&mut self.counts);
702
703        // Count is always non null (null inputs just don't contribute to the overall values)
704        let nulls = None;
705        let array = PrimitiveArray::<Int64Type>::new(counts.into(), nulls);
706
707        Ok(Arc::new(array))
708    }
709
710    // return arrays for counts
711    fn state(&mut self, emit_to: EmitTo) -> Result<Vec<ArrayRef>> {
712        let counts = emit_to.take_needed(&mut self.counts);
713        let counts: PrimitiveArray<Int64Type> = Int64Array::from(counts); // zero copy, no nulls
714        Ok(vec![Arc::new(counts) as ArrayRef])
715    }
716
717    /// Converts an input batch directly to a state batch
718    ///
719    /// The state of `COUNT` is always a single Int64Array:
720    /// * `1` (for non-null, non filtered values)
721    /// * `0` (for null values)
722    fn convert_to_state(
723        &self,
724        values: &[ArrayRef],
725        opt_filter: Option<&BooleanArray>,
726    ) -> Result<Vec<ArrayRef>> {
727        let values = &values[0];
728
729        let state_array = match (values.logical_nulls(), opt_filter) {
730            (None, None) => {
731                // In case there is no nulls in input and no filter, returning array of 1
732                Arc::new(Int64Array::from_value(1, values.len()))
733            }
734            (Some(nulls), None) => {
735                // If there are any nulls in input values -- casting `nulls` (true for values, false for nulls)
736                // of input array to Int64
737                let nulls = BooleanArray::new(nulls.into_inner(), None);
738                compute::cast(&nulls, &DataType::Int64)?
739            }
740            (None, Some(filter)) => {
741                // If there is only filter
742                // - applying filter null mask to filter values by bitand filter values and nulls buffers
743                //   (using buffers guarantees absence of nulls in result)
744                // - casting result of bitand to Int64 array
745                let (filter_values, filter_nulls) = filter.clone().into_parts();
746
747                let state_buf = match filter_nulls {
748                    Some(filter_nulls) => &filter_values & filter_nulls.inner(),
749                    None => filter_values,
750                };
751
752                let boolean_state = BooleanArray::new(state_buf, None);
753                compute::cast(&boolean_state, &DataType::Int64)?
754            }
755            (Some(nulls), Some(filter)) => {
756                // For both input nulls and filter
757                // - applying filter null mask to filter values by bitand filter values and nulls buffers
758                //   (using buffers guarantees absence of nulls in result)
759                // - applying values null mask to filter buffer by another bitand on filter result and
760                //   nulls from input values
761                // - casting result to Int64 array
762                let (filter_values, filter_nulls) = filter.clone().into_parts();
763
764                let filter_buf = match filter_nulls {
765                    Some(filter_nulls) => &filter_values & filter_nulls.inner(),
766                    None => filter_values,
767                };
768                let state_buf = &filter_buf & nulls.inner();
769
770                let boolean_state = BooleanArray::new(state_buf, None);
771                compute::cast(&boolean_state, &DataType::Int64)?
772            }
773        };
774
775        Ok(vec![state_array])
776    }
777    fn size(&self) -> usize {
778        self.counts.heap_size(&mut DFHeapSizeCtx::default())
779    }
780}
781
782/// count null values for multiple columns
783/// for each row if one column value is null, then null_count + 1
784fn null_count_for_multiple_cols(values: &[ArrayRef]) -> usize {
785    if values.len() > 1 {
786        let result_bool_buf: Option<BooleanBuffer> = values
787            .iter()
788            .map(|a| a.logical_nulls())
789            .fold(None, |acc, b| match (acc, b) {
790                (Some(acc), Some(b)) => Some(acc.bitand(b.inner())),
791                (Some(acc), None) => Some(acc),
792                (None, Some(b)) => Some(b.into_inner()),
793                _ => None,
794            });
795        result_bool_buf.map_or(0, |b| values[0].len() - b.count_set_bits())
796    } else {
797        values[0]
798            .logical_nulls()
799            .map_or(0, |nulls| nulls.null_count())
800    }
801}
802
803/// General purpose distinct accumulator that works for any DataType by using
804/// [`ScalarValue`].
805///
806/// It stores intermediate results as a `ListArray`
807///
808/// Note that many types have specialized accumulators that are (much)
809/// more efficient such as [`PrimitiveDistinctCountAccumulator`] and
810/// [`BytesDistinctCountAccumulator`]
811#[derive(Debug)]
812struct DistinctCountAccumulator {
813    values: HashSet<ScalarValue, RandomState>,
814    state_data_type: DataType,
815}
816
817impl DistinctCountAccumulator {
818    // calculating the size for fixed length values, taking first batch size *
819    // number of batches This method is faster than .full_size(), however it is
820    // not suitable for variable length values like strings or complex types
821    fn fixed_size(&self) -> usize {
822        size_of_val(self)
823            + (size_of::<ScalarValue>() * self.values.capacity())
824            + self
825                .values
826                .iter()
827                .next()
828                .map(|vals| ScalarValue::size(vals) - size_of_val(vals))
829                .unwrap_or(0)
830            + size_of::<DataType>()
831    }
832
833    // calculates the size as accurately as possible. Note that calling this
834    // method is expensive
835    fn full_size(&self) -> usize {
836        size_of_val(self)
837            + (size_of::<ScalarValue>() * self.values.capacity())
838            + self
839                .values
840                .iter()
841                .map(|vals| ScalarValue::size(vals) - size_of_val(vals))
842                .sum::<usize>()
843            + size_of::<DataType>()
844    }
845}
846
847impl Accumulator for DistinctCountAccumulator {
848    /// Returns the distinct values seen so far as (one element) ListArray.
849    fn state(&mut self) -> Result<Vec<ScalarValue>> {
850        let scalars = self.values.iter().cloned().collect::<Vec<_>>();
851        let arr =
852            ScalarValue::new_list_nullable(scalars.as_slice(), &self.state_data_type);
853        Ok(vec![ScalarValue::List(arr)])
854    }
855
856    fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
857        if values.is_empty() {
858            return Ok(());
859        }
860
861        let arr = &values[0];
862        if arr.data_type() == &DataType::Null {
863            return Ok(());
864        }
865
866        (0..arr.len()).try_for_each(|index| {
867            let scalar = ScalarValue::try_from_array(arr, index)?;
868            if !scalar.is_null() {
869                self.values.insert(scalar);
870            }
871            Ok(())
872        })
873    }
874
875    /// Merges multiple sets of distinct values into the current set.
876    ///
877    /// The input to this function is a `ListArray` with **multiple** rows,
878    /// where each row contains the values from a partial aggregate's phase (e.g.
879    /// the result of calling `Self::state` on multiple accumulators).
880    fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
881        if states.is_empty() {
882            return Ok(());
883        }
884        assert_eq!(states.len(), 1, "array_agg states must be singleton!");
885        let array = &states[0];
886        let list_array = array.as_list::<i32>();
887        for inner_array in list_array.iter() {
888            let Some(inner_array) = inner_array else {
889                return internal_err!(
890                    "Intermediate results of COUNT DISTINCT should always be non null"
891                );
892            };
893            self.update_batch(&[inner_array])?;
894        }
895        Ok(())
896    }
897
898    fn evaluate(&mut self) -> Result<ScalarValue> {
899        Ok(ScalarValue::Int64(Some(self.values.len() as i64)))
900    }
901
902    fn size(&self) -> usize {
903        match &self.state_data_type {
904            DataType::Boolean | DataType::Null => self.fixed_size(),
905            d if d.is_primitive() => self.fixed_size(),
906            _ => self.full_size(),
907        }
908    }
909}
910
911#[cfg(test)]
912mod tests {
913
914    use super::*;
915    use arrow::{
916        array::{DictionaryArray, Int32Array, NullArray, StringArray},
917        datatypes::{DataType, Field, Int32Type, Schema},
918    };
919    use datafusion_expr::function::AccumulatorArgs;
920    use datafusion_physical_expr::{PhysicalExpr, expressions::Column};
921    use std::sync::Arc;
922    /// Helper function to create a dictionary array with non-null keys but some null values
923    /// Returns a dictionary array where:
924    /// - keys are [0, 1, 2, 0, 1] (all non-null)
925    /// - values are ["a", null, "c"]
926    /// - so the keys reference: "a", null, "c", "a", null
927    fn create_dictionary_with_null_values() -> Result<DictionaryArray<Int32Type>> {
928        let values = StringArray::from(vec![Some("a"), None, Some("c")]);
929        let keys = Int32Array::from(vec![0, 1, 2, 0, 1]); // references "a", null, "c", "a", null
930        Ok(DictionaryArray::<Int32Type>::try_new(
931            keys,
932            Arc::new(values),
933        )?)
934    }
935
936    #[test]
937    fn count_groups_size_includes_vec_capacity() -> Result<()> {
938        let mut acc = CountGroupsAccumulator::new();
939        let empty_size = acc.size();
940        assert_eq!(empty_size, 0);
941        let values: ArrayRef = Arc::new(Int64Array::from(vec![1, 2, 3]));
942        acc.update_batch(&[values], &[0, 1, 2], None, 3)?;
943
944        assert!(acc.counts.capacity() > 0);
945        let allocated_size = acc.counts.heap_size(&mut DFHeapSizeCtx::default());
946        assert_eq!(allocated_size, acc.counts.capacity() * size_of::<i64>());
947        assert_eq!(acc.size(), allocated_size);
948        assert!(acc.size() > empty_size);
949
950        Ok(())
951    }
952
953    #[test]
954    fn count_accumulator_nulls() -> Result<()> {
955        let mut accumulator = CountAccumulator::new();
956        accumulator.update_batch(&[Arc::new(NullArray::new(10))])?;
957        assert_eq!(accumulator.evaluate()?, ScalarValue::Int64(Some(0)));
958        Ok(())
959    }
960
961    #[test]
962    fn test_nested_dictionary() -> Result<()> {
963        let schema = Arc::new(Schema::new(vec![Field::new(
964            "dict_col",
965            DataType::Dictionary(
966                Box::new(DataType::Int32),
967                Box::new(DataType::Dictionary(
968                    Box::new(DataType::Int32),
969                    Box::new(DataType::Utf8),
970                )),
971            ),
972            true,
973        )]));
974
975        // Using Count UDAF's accumulator
976        let count = Count::new();
977        let expr = Arc::new(Column::new("dict_col", 0));
978        let expr_field = expr.return_field(&schema)?;
979        let args = AccumulatorArgs {
980            schema: &schema,
981            expr_fields: &[expr_field],
982            exprs: &[expr],
983            is_distinct: true,
984            name: "count",
985            ignore_nulls: false,
986            is_reversed: false,
987            return_field: Arc::new(Field::new_list_field(DataType::Int64, true)),
988            order_bys: &[],
989        };
990
991        let inner_dict =
992            DictionaryArray::<Int32Type>::from_iter(["a", "b", "c", "d", "a", "b"]);
993
994        let keys = Int32Array::from(vec![0, 1, 2, 0, 3, 1]);
995        let dict_of_dict =
996            DictionaryArray::<Int32Type>::try_new(keys, Arc::new(inner_dict))?;
997
998        let mut acc = count.accumulator(args)?;
999        acc.update_batch(&[Arc::new(dict_of_dict)])?;
1000        assert_eq!(acc.evaluate()?, ScalarValue::Int64(Some(4)));
1001
1002        Ok(())
1003    }
1004
1005    #[test]
1006    fn count_distinct_accumulator_dictionary_with_null_values() -> Result<()> {
1007        let dict_array = create_dictionary_with_null_values()?;
1008
1009        // The expected behavior is that count_distinct should count only non-null values
1010        // which in this case are "a" and "c" (appearing as 0 and 2 in keys)
1011        let mut accumulator = DistinctCountAccumulator {
1012            values: HashSet::default(),
1013            state_data_type: dict_array.data_type().clone(),
1014        };
1015
1016        accumulator.update_batch(&[Arc::new(dict_array)])?;
1017
1018        // Should have 2 distinct non-null values ("a" and "c")
1019        assert_eq!(accumulator.evaluate()?, ScalarValue::Int64(Some(2)));
1020        Ok(())
1021    }
1022
1023    #[test]
1024    fn count_accumulator_dictionary_with_null_values() -> Result<()> {
1025        let dict_array = create_dictionary_with_null_values()?;
1026
1027        // The expected behavior is that count should only count non-null values
1028        let mut accumulator = CountAccumulator::new();
1029
1030        accumulator.update_batch(&[Arc::new(dict_array)])?;
1031
1032        // 5 elements in the array, of which 2 reference null values (the two 1s in the keys)
1033        // So we should count 3 non-null values
1034        assert_eq!(accumulator.evaluate()?, ScalarValue::Int64(Some(3)));
1035        Ok(())
1036    }
1037
1038    #[test]
1039    fn count_distinct_accumulator_dictionary_all_null_values() -> Result<()> {
1040        // Create a dictionary array that only contains null values
1041        let dict_values = StringArray::from(vec![None, Some("abc")]);
1042        let dict_indices = Int32Array::from(vec![0; 5]);
1043        let dict_array =
1044            DictionaryArray::<Int32Type>::try_new(dict_indices, Arc::new(dict_values))?;
1045
1046        let mut accumulator = DistinctCountAccumulator {
1047            values: HashSet::default(),
1048            state_data_type: dict_array.data_type().clone(),
1049        };
1050
1051        accumulator.update_batch(&[Arc::new(dict_array)])?;
1052
1053        // All referenced values are null so count(distinct) should be 0
1054        assert_eq!(accumulator.evaluate()?, ScalarValue::Int64(Some(0)));
1055        Ok(())
1056    }
1057
1058    #[test]
1059    fn sliding_distinct_count_accumulator_basic() -> Result<()> {
1060        // Basic update_batch + evaluate functionality
1061        let mut acc = SlidingDistinctCountAccumulator::try_new(&DataType::Int32)?;
1062        // Create an Int32Array: [1, 2, 2, 3, null]
1063        let values: ArrayRef = Arc::new(Int32Array::from(vec![
1064            Some(1),
1065            Some(2),
1066            Some(2),
1067            Some(3),
1068            None,
1069        ]));
1070        acc.update_batch(&[values])?;
1071        // Expect distinct values {1,2,3} → count = 3
1072        assert_eq!(acc.evaluate()?, ScalarValue::Int64(Some(3)));
1073        Ok(())
1074    }
1075
1076    #[test]
1077    fn sliding_distinct_count_accumulator_retract() -> Result<()> {
1078        // Test that retract_batch properly decrements counts
1079        let mut acc = SlidingDistinctCountAccumulator::try_new(&DataType::Utf8)?;
1080        // Initial batch: ["a", "b", "a"]
1081        let arr1 = Arc::new(StringArray::from(vec![Some("a"), Some("b"), Some("a")]))
1082            as ArrayRef;
1083        acc.update_batch(&[arr1])?;
1084        assert_eq!(acc.evaluate()?, ScalarValue::Int64(Some(2))); // {"a","b"}
1085
1086        // Retract batch: ["a", null, "b"]
1087        let arr2 =
1088            Arc::new(StringArray::from(vec![Some("a"), None, Some("b")])) as ArrayRef;
1089        acc.retract_batch(&[arr2])?;
1090        // Before: a→2, b→1; after retract a→1, b→0 → b removed; remaining {"a"}
1091        assert_eq!(acc.evaluate()?, ScalarValue::Int64(Some(1)));
1092        Ok(())
1093    }
1094
1095    #[test]
1096    fn sliding_distinct_count_accumulator_merge_states() -> Result<()> {
1097        // Test merging multiple accumulator states with merge_batch
1098        let mut acc1 = SlidingDistinctCountAccumulator::try_new(&DataType::Int32)?;
1099        let mut acc2 = SlidingDistinctCountAccumulator::try_new(&DataType::Int32)?;
1100        // acc1 sees [1, 2]
1101        acc1.update_batch(&[Arc::new(Int32Array::from(vec![Some(1), Some(2)]))])?;
1102        // acc2 sees [2, 3]
1103        acc2.update_batch(&[Arc::new(Int32Array::from(vec![Some(2), Some(3)]))])?;
1104        // Extract their states as Vec<ScalarValue>
1105        let state_sv1 = acc1.state()?;
1106        let state_sv2 = acc2.state()?;
1107        // Convert ScalarValue states into Vec<ArrayRef>, propagating errors
1108        // NOTE we pass `1` because each ScalarValue.to_array produces a 1‑row ListArray
1109        let state_arr1: Vec<ArrayRef> = state_sv1
1110            .into_iter()
1111            .map(|sv| sv.to_array())
1112            .collect::<Result<_>>()?;
1113        let state_arr2: Vec<ArrayRef> = state_sv2
1114            .into_iter()
1115            .map(|sv| sv.to_array())
1116            .collect::<Result<_>>()?;
1117        // Merge both states into a fresh accumulator
1118        let mut merged = SlidingDistinctCountAccumulator::try_new(&DataType::Int32)?;
1119        merged.merge_batch(&state_arr1)?;
1120        merged.merge_batch(&state_arr2)?;
1121        // Expect distinct {1,2,3} → count = 3
1122        assert_eq!(merged.evaluate()?, ScalarValue::Int64(Some(3)));
1123        Ok(())
1124    }
1125}