use self::DataFusionExactHostAccumulator as Accumulator;
use super::{AggregateExpr, AggregateFunction, AggregateSpec, ArrowDataType};
pub fn aggregate_spec_has_avg(spec: &AggregateSpec) -> bool {
spec.aggr_exprs.iter().any(|expr| expr.function == AggregateFunction::Avg)
}
pub fn aggregate_spec_has_floating_statistical_aggregate(spec: &AggregateSpec) -> bool {
spec.aggr_exprs.iter().any(|expr| expr.function.is_floating_statistical())
}
pub fn aggregate_spec_has_median(spec: &AggregateSpec) -> bool {
spec.aggr_exprs.iter().any(|expr| expr.function == AggregateFunction::Median)
}
pub fn aggregate_spec_requires_whole_input(spec: &AggregateSpec) -> bool {
aggregate_spec_has_floating_statistical_aggregate(spec)
|| aggregate_spec_has_distinct(spec)
|| aggregate_spec_has_median(spec)
}
pub fn aggregate_spec_has_distinct(spec: &AggregateSpec) -> bool {
spec.aggr_exprs.iter().any(aggregate_expr_is_exact_nunique)
}
pub fn aggregate_expr_is_exact_nunique(expr: &AggregateExpr) -> bool {
expr.function == AggregateFunction::NUnique || expr.distinct && expr.function == AggregateFunction::Count
}
pub fn aggregate_spec_has_filters(spec: &AggregateSpec) -> bool {
spec.aggr_exprs.iter().any(|expr| expr.filter.is_some())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataFusionExactHostAccumulator {
Count,
SignedSum,
UnsignedSum,
FloatSum,
SignedMin,
SignedMax,
UnsignedMin,
UnsignedMax,
FloatMin,
FloatMax,
Avg,
Welford,
}
pub fn datafusion_exact_host_accumulator(
expr: &AggregateExpr,
input_type: Option<&ArrowDataType>,
output_type: &ArrowDataType,
) -> Option<DataFusionExactHostAccumulator> {
if expr.distinct || aggregate_expr_is_exact_nunique(expr) {
return None;
}
if expr.function == AggregateFunction::Count {
return (*output_type == ArrowDataType::Int64).then_some(Accumulator::Count);
}
let input_type = input_type?;
let numeric_input = matches!(
input_type,
ArrowDataType::Int32 | ArrowDataType::Int64 | ArrowDataType::UInt64 | ArrowDataType::Float64
);
let same_type = input_type == output_type;
match (expr.function, output_type) {
(AggregateFunction::Sum, ArrowDataType::Int64) if same_type => Some(Accumulator::SignedSum),
(AggregateFunction::Sum, ArrowDataType::UInt64) if same_type => Some(Accumulator::UnsignedSum),
(AggregateFunction::Sum, ArrowDataType::Float64) if same_type => Some(Accumulator::FloatSum),
(AggregateFunction::Min, ArrowDataType::Int32 | ArrowDataType::Int64) if same_type => {
Some(Accumulator::SignedMin)
},
(AggregateFunction::Max, ArrowDataType::Int32 | ArrowDataType::Int64) if same_type => {
Some(Accumulator::SignedMax)
},
(AggregateFunction::Min, ArrowDataType::UInt64) if same_type => Some(Accumulator::UnsignedMin),
(AggregateFunction::Max, ArrowDataType::UInt64) if same_type => Some(Accumulator::UnsignedMax),
(AggregateFunction::Min, ArrowDataType::Float64) if same_type => Some(Accumulator::FloatMin),
(AggregateFunction::Max, ArrowDataType::Float64) if same_type => Some(Accumulator::FloatMax),
(AggregateFunction::Avg, ArrowDataType::Float64) if numeric_input => Some(Accumulator::Avg),
(function, ArrowDataType::Float64) if function.is_floating_statistical() && numeric_input => {
Some(Accumulator::Welford)
},
_ => None,
}
}
pub fn datafusion_exact_host_group_key_supported(input_type: &ArrowDataType, output_type: &ArrowDataType) -> bool {
let is_string = |data_type: &ArrowDataType| {
matches!(data_type, ArrowDataType::Utf8 | ArrowDataType::LargeUtf8 | ArrowDataType::Utf8View)
};
if is_string(input_type) {
return is_string(output_type);
}
input_type == output_type
&& matches!(
input_type,
ArrowDataType::Boolean
| ArrowDataType::Int32
| ArrowDataType::Date32
| ArrowDataType::Int64
| ArrowDataType::UInt64
| ArrowDataType::Float64
)
}