Jefffrey commented on code in PR #17255: URL: https://github.com/apache/datafusion/pull/17255#discussion_r2295094013
########## datafusion/functions-aggregate/src/average.rs: ########## @@ -114,72 +115,88 @@ impl AggregateUDFImpl for Avg { } fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> { - if acc_args.is_distinct { - return exec_err!("avg(DISTINCT) aggregations are not available"); - } + let data_type = acc_args.exprs[0].data_type(acc_args.schema)?; use DataType::*; - let data_type = acc_args.exprs[0].data_type(acc_args.schema)?; // instantiate specialized accumulator based for the type - match (&data_type, acc_args.return_field.data_type()) { - (Float64, Float64) => Ok(Box::<AvgAccumulator>::default()), - ( - Decimal128(sum_precision, sum_scale), - Decimal128(target_precision, target_scale), - ) => Ok(Box::new(DecimalAvgAccumulator::<Decimal128Type> { - sum: None, - count: 0, - sum_scale: *sum_scale, - sum_precision: *sum_precision, - target_precision: *target_precision, - target_scale: *target_scale, - })), - - ( - Decimal256(sum_precision, sum_scale), - Decimal256(target_precision, target_scale), - ) => Ok(Box::new(DecimalAvgAccumulator::<Decimal256Type> { - sum: None, - count: 0, - sum_scale: *sum_scale, - sum_precision: *sum_precision, - target_precision: *target_precision, - target_scale: *target_scale, - })), - - (Duration(time_unit), Duration(result_unit)) => { - Ok(Box::new(DurationAvgAccumulator { + if acc_args.is_distinct { + match &data_type { + // Numeric types are converted to Float64 via `coerce_avg_type` during logical plan creation + Float64 => Ok(Box::new(Float64DistinctAvgAccumulator::default())), + _ => exec_err!("AVG(DISTINCT) for {} not supported", data_type), + } + } else { + match (&data_type, acc_args.return_field.data_type()) { + (Float64, Float64) => Ok(Box::<AvgAccumulator>::default()), + ( + Decimal128(sum_precision, sum_scale), + Decimal128(target_precision, target_scale), + ) => Ok(Box::new(DecimalAvgAccumulator::<Decimal128Type> { sum: None, count: 0, - time_unit: *time_unit, - result_unit: *result_unit, - })) - } + sum_scale: *sum_scale, + sum_precision: *sum_precision, + target_precision: *target_precision, + target_scale: *target_scale, + })), + + ( + Decimal256(sum_precision, sum_scale), + Decimal256(target_precision, target_scale), + ) => Ok(Box::new(DecimalAvgAccumulator::<Decimal256Type> { + sum: None, + count: 0, + sum_scale: *sum_scale, + sum_precision: *sum_precision, + target_precision: *target_precision, + target_scale: *target_scale, + })), + + (Duration(time_unit), Duration(result_unit)) => { + Ok(Box::new(DurationAvgAccumulator { + sum: None, + count: 0, + time_unit: *time_unit, + result_unit: *result_unit, + })) + } - _ => exec_err!( - "AvgAccumulator for ({} --> {})", - &data_type, - acc_args.return_field.data_type() - ), + _ => exec_err!( + "AvgAccumulator for ({} --> {})", + &data_type, + acc_args.return_field.data_type() + ), + } } } fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> { - Ok(vec![ - Field::new( - format_state_name(args.name, "count"), - DataType::UInt64, - true, - ), - Field::new( - format_state_name(args.name, "sum"), - args.input_fields[0].data_type().clone(), - true, - ), - ] - .into_iter() - .map(Arc::new) - .collect()) + if args.is_distinct { + // Copied from datafusion_functions_aggregate::sum::Sum::state_fields + // since the accumulator uses DistinctSumAccumulator internally. + Ok(vec![Field::new_list( + format_state_name(args.name, "sum distinct"), + Field::new_list_field(args.return_type().clone(), true), + false, + ) + .into()]) + } else { + Ok(vec![ + Field::new( + format_state_name(args.name, "count"), + DataType::UInt64, + true, + ), + Field::new( + format_state_name(args.name, "sum"), + args.input_fields[0].data_type().clone(), + true, + ), + ] + .into_iter() + .map(Arc::new) + .collect()) + } Review Comment: Sorry, what I meant was that in accumulators we can return the `state()` like so: https://github.com/apache/datafusion/blob/be3842b55d61095d77aae54426726ddd1eed5f2c/datafusion/functions-aggregate/src/sum.rs#L432-L450 However this must align with `state_fields()` of the parent aggregate UDF: https://github.com/apache/datafusion/blob/be3842b55d61095d77aae54426726ddd1eed5f2c/datafusion/functions-aggregate/src/sum.rs#L204-L221 But this isn't clearly obvious at compile time, and during runtime we only hit this issue for certain test cases (for this distinct avg PR). So I was wondering if there was a better way to enforce this at compile time. Hope that clears it up. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org For additional commands, e-mail: github-h...@datafusion.apache.org