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.
1718#![doc(
19 html_logo_url = "https://raw.githubusercontent.com/apache/datafusion/19fe44cf2f30cbdd63d4a4f52c74055163c6cc38/docs/logos/standalone_logo/logo_original.svg",
20 html_favicon_url = "https://raw.githubusercontent.com/apache/datafusion/19fe44cf2f30cbdd63d4a4f52c74055163c6cc38/docs/logos/standalone_logo/logo_original.svg"
21)]
22#![cfg_attr(docsrs, feature(doc_auto_cfg))]
23// Make cheap clones clear: https://github.com/apache/datafusion/issues/11143
24#![deny(clippy::clone_on_ref_ptr)]
2526//! Aggregate Function packages for [DataFusion].
27//!
28//! This crate contains a collection of various aggregate function packages for DataFusion,
29//! implemented using the extension API. Users may wish to control which functions
30//! are available to control the binary size of their application as well as
31//! use dialect specific implementations of functions (e.g. Spark vs Postgres)
32//!
33//! Each package is implemented as a separate
34//! module, activated by a feature flag.
35//!
36//! [DataFusion]: https://crates.io/crates/datafusion
37//!
38//! # Available Packages
39//! See the list of [modules](#modules) in this crate for available packages.
40//!
41//! # Using A Package
42//! You can register all functions in all packages using the [`register_all`] function.
43//!
44//! Each package also exports an `expr_fn` submodule to help create [`Expr`]s that invoke
45//! functions using a fluent style. For example:
46//!
47//![`Expr`]: datafusion_expr::Expr
48//!
49//! # Implementing A New Package
50//!
51//! To add a new package to this crate, you should follow the model of existing
52//! packages. The high level steps are:
53//!
54//! 1. Create a new module with the appropriate [AggregateUDF] implementations.
55//!
56//! 2. Use the macros in [`macros`] to create standard entry points.
57//!
58//! 3. Add a new feature to `Cargo.toml`, with any optional dependencies
59//!
60//! 4. Use the `make_package!` macro to expose the module when the
61//! feature is enabled.
6263#[macro_use]
64pub mod macros;
6566pub mod approx_distinct;
67pub mod approx_median;
68pub mod approx_percentile_cont;
69pub mod approx_percentile_cont_with_weight;
70pub mod array_agg;
71pub mod average;
72pub mod bit_and_or_xor;
73pub mod bool_and_or;
74pub mod correlation;
75pub mod count;
76pub mod covariance;
77pub mod first_last;
78pub mod grouping;
79pub mod hyperloglog;
80pub mod median;
81pub mod min_max;
82pub mod nth_value;
83pub mod regr;
84pub mod stddev;
85pub mod string_agg;
86pub mod sum;
87pub mod variance;
8889pub mod planner;
9091use crate::approx_percentile_cont::approx_percentile_cont_udaf;
92use crate::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight_udaf;
93use datafusion_common::Result;
94use datafusion_execution::FunctionRegistry;
95use datafusion_expr::AggregateUDF;
96use log::debug;
97use std::sync::Arc;
9899/// Fluent-style API for creating `Expr`s
100pub mod expr_fn {
101pub use super::approx_distinct::approx_distinct;
102pub use super::approx_median::approx_median;
103pub use super::approx_percentile_cont::approx_percentile_cont;
104pub use super::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight;
105pub use super::array_agg::array_agg;
106pub use super::average::avg;
107pub use super::bit_and_or_xor::bit_and;
108pub use super::bit_and_or_xor::bit_or;
109pub use super::bit_and_or_xor::bit_xor;
110pub use super::bool_and_or::bool_and;
111pub use super::bool_and_or::bool_or;
112pub use super::correlation::corr;
113pub use super::count::count;
114pub use super::count::count_distinct;
115pub use super::covariance::covar_pop;
116pub use super::covariance::covar_samp;
117pub use super::first_last::first_value;
118pub use super::first_last::last_value;
119pub use super::grouping::grouping;
120pub use super::median::median;
121pub use super::min_max::max;
122pub use super::min_max::min;
123pub use super::nth_value::nth_value;
124pub use super::regr::regr_avgx;
125pub use super::regr::regr_avgy;
126pub use super::regr::regr_count;
127pub use super::regr::regr_intercept;
128pub use super::regr::regr_r2;
129pub use super::regr::regr_slope;
130pub use super::regr::regr_sxx;
131pub use super::regr::regr_sxy;
132pub use super::regr::regr_syy;
133pub use super::stddev::stddev;
134pub use super::stddev::stddev_pop;
135pub use super::sum::sum;
136pub use super::variance::var_pop;
137pub use super::variance::var_sample;
138}
139140/// Returns all default aggregate functions
141pub fn all_default_aggregate_functions() -> Vec<Arc<AggregateUDF>> {
142vec![
143 array_agg::array_agg_udaf(),
144 first_last::first_value_udaf(),
145 first_last::last_value_udaf(),
146 covariance::covar_samp_udaf(),
147 covariance::covar_pop_udaf(),
148 correlation::corr_udaf(),
149 sum::sum_udaf(),
150 min_max::max_udaf(),
151 min_max::min_udaf(),
152 median::median_udaf(),
153 count::count_udaf(),
154 regr::regr_slope_udaf(),
155 regr::regr_intercept_udaf(),
156 regr::regr_count_udaf(),
157 regr::regr_r2_udaf(),
158 regr::regr_avgx_udaf(),
159 regr::regr_avgy_udaf(),
160 regr::regr_sxx_udaf(),
161 regr::regr_syy_udaf(),
162 regr::regr_sxy_udaf(),
163 variance::var_samp_udaf(),
164 variance::var_pop_udaf(),
165 stddev::stddev_udaf(),
166 stddev::stddev_pop_udaf(),
167 approx_median::approx_median_udaf(),
168 approx_distinct::approx_distinct_udaf(),
169 approx_percentile_cont_udaf(),
170 approx_percentile_cont_with_weight_udaf(),
171 string_agg::string_agg_udaf(),
172 bit_and_or_xor::bit_and_udaf(),
173 bit_and_or_xor::bit_or_udaf(),
174 bit_and_or_xor::bit_xor_udaf(),
175 bool_and_or::bool_and_udaf(),
176 bool_and_or::bool_or_udaf(),
177 average::avg_udaf(),
178 grouping::grouping_udaf(),
179 nth_value::nth_value_udaf(),
180 ]
181}
182183/// Registers all enabled packages with a [`FunctionRegistry`]
184pub fn register_all(registry: &mut dyn FunctionRegistry) -> Result<()> {
185let functions: Vec<Arc<AggregateUDF>> = all_default_aggregate_functions();
186187 functions.into_iter().try_for_each(|udf| {
188let existing_udaf = registry.register_udaf(udf)?;
189if let Some(existing_udaf) = existing_udaf {
190debug!("Overwrite existing UDAF: {}", existing_udaf.name());
191 }
192Ok(()) as Result<()>
193 })?;
194195Ok(())
196}
197198#[cfg(test)]
199mod tests {
200use crate::all_default_aggregate_functions;
201use datafusion_common::Result;
202use std::collections::HashSet;
203204#[test]
205fn test_no_duplicate_name() -> Result<()> {
206let mut names = HashSet::new();
207let migrated_functions = ["array_agg", "count", "max", "min"];
208for func in all_default_aggregate_functions() {
209// TODO: remove this
210 // These functions are in intermediate migration state, skip them
211if migrated_functions.contains(&func.name().to_lowercase().as_str()) {
212continue;
213 }
214assert!(
215 names.insert(func.name().to_string().to_lowercase()),
216"duplicate function name: {}",
217 func.name()
218 );
219for alias in func.aliases() {
220assert!(
221 names.insert(alias.to_string().to_lowercase()),
222"duplicate function name: {}",
223 alias
224 );
225 }
226 }
227Ok(())
228 }
229}