@@ -29,6 +29,8 @@ use arrow::array::StructArray;
2929use arrow_schema:: { FieldRef , Fields } ;
3030use common_telemetry:: debug;
3131use datafusion:: functions_aggregate:: all_default_aggregate_functions;
32+ use datafusion:: functions_aggregate:: count:: Count ;
33+ use datafusion:: functions_aggregate:: min_max:: { Max , Min } ;
3234use datafusion:: optimizer:: AnalyzerRule ;
3335use datafusion:: optimizer:: analyzer:: type_coercion:: TypeCoercion ;
3436use datafusion:: physical_planner:: create_aggregate_expr_and_maybe_filter;
@@ -413,6 +415,51 @@ impl AggregateUDFImpl for StateWrapper {
413415 fn coerce_types ( & self , arg_types : & [ DataType ] ) -> datafusion_common:: Result < Vec < DataType > > {
414416 self . inner . coerce_types ( arg_types)
415417 }
418+
419+ fn value_from_stats (
420+ & self ,
421+ statistics_args : & datafusion_expr:: StatisticsArgs ,
422+ ) -> Option < ScalarValue > {
423+ let inner = self . inner ( ) . inner ( ) . as_any ( ) ;
424+ // only count/min/max need special handling here, for getting result from statistics
425+ // the result of count/min/max is also the result of count_state so can return directly
426+ let can_use_stat = inner. is :: < Count > ( ) || inner. is :: < Max > ( ) || inner. is :: < Min > ( ) ;
427+ if !can_use_stat {
428+ return None ;
429+ }
430+
431+ // fix return type by extract the first field's data type from the struct type
432+ let state_type = if let DataType :: Struct ( fields) = & statistics_args. return_type {
433+ if fields. is_empty ( ) {
434+ return None ;
435+ }
436+ fields[ 0 ] . data_type ( ) . clone ( )
437+ } else {
438+ return None ;
439+ } ;
440+
441+ let fixed_args = datafusion_expr:: StatisticsArgs {
442+ statistics : statistics_args. statistics ,
443+ return_type : & state_type,
444+ is_distinct : statistics_args. is_distinct ,
445+ exprs : statistics_args. exprs ,
446+ } ;
447+
448+ let ret = self . inner ( ) . value_from_stats ( & fixed_args) ?;
449+
450+ // wrap the result into struct scalar value
451+ let fields = if let DataType :: Struct ( fields) = & statistics_args. return_type {
452+ fields
453+ } else {
454+ return None ;
455+ } ;
456+
457+ let array = ret. to_array ( ) . ok ( ) ?;
458+
459+ let struct_array = StructArray :: new ( fields. clone ( ) , vec ! [ array] , None ) ;
460+ let ret = ScalarValue :: Struct ( Arc :: new ( struct_array) ) ;
461+ Some ( ret)
462+ }
416463}
417464
418465/// The wrapper's input is the same as the original aggregate function's input,
0 commit comments