1pub(crate) mod groups_accumulator {
19 #[expect(unused_imports)]
20 pub(crate) mod accumulate {
21 pub use datafusion_functions_aggregate_common::aggregate::groups_accumulator::accumulate::NullState;
22 }
23 pub use datafusion_functions_aggregate_common::aggregate::groups_accumulator::{
24 GroupsAccumulatorAdapter, accumulate::NullState,
25 };
26}
27pub(crate) mod stats {
28 pub use datafusion_functions_aggregate_common::stats::StatsType;
29}
30pub mod utils {
31 pub use datafusion_functions_aggregate_common::utils::{
32 DecimalAverager, Hashable, get_accum_scalar_values_as_arrays, get_sort_options,
33 ordering_fields,
34 };
35}
36
37use std::fmt::Debug;
38use std::sync::Arc;
39
40use crate::expressions::Column;
41use crate::physical_expr::create_physical_sort_exprs;
42use crate::planner::{create_physical_expr, create_physical_exprs};
43
44use arrow::compute::SortOptions;
45use arrow::datatypes::{DataType, FieldRef, Schema, SchemaRef};
46use datafusion_common::metadata::FieldMetadata;
47use datafusion_common::{
48 DFSchema, Result, ScalarValue, assert_or_internal_err, internal_err, not_impl_err,
49};
50use datafusion_expr::execution_props::ExecutionProps;
51use datafusion_expr::expr::{
52 AggregateFunction, AggregateFunctionParams, NullTreatment, physical_name,
53};
54use datafusion_expr::physical_planning_context::PhysicalPlanningContext;
55use datafusion_expr::{AggregateUDF, Expr, ReversedUDAF, SetMonotonicity};
56use datafusion_expr_common::accumulator::Accumulator;
57use datafusion_expr_common::groups_accumulator::GroupsAccumulator;
58use datafusion_expr_common::type_coercion::aggregates::check_arg_count;
59use datafusion_functions_aggregate_common::accumulator::{
60 AccumulatorArgs, StateFieldsArgs,
61};
62use datafusion_functions_aggregate_common::order::AggregateOrderSensitivity;
63use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
64use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
65
66#[derive(Debug, Clone)]
67struct AggregateHumanDisplay {
68 expression: String,
69 alias: Option<String>,
70}
71
72impl AggregateHumanDisplay {
73 fn try_new(
74 expression: Option<String>,
75 alias: Option<String>,
76 name: &str,
77 ) -> Result<Option<Self>> {
78 let alias = alias.filter(|alias| !alias.is_empty());
79 let Some(expression) = expression else {
80 if alias.is_some() {
81 return internal_err!(
82 "AggregateExprBuilder::human_display must be provided when human_display_alias is set"
83 );
84 }
85 return Ok(None);
86 };
87
88 if expression.is_empty() {
89 if alias.is_some() {
90 return internal_err!(
91 "AggregateExprBuilder::human_display must be non-empty when human_display_alias is set"
92 );
93 }
94 return Ok(None);
95 }
96
97 if let Some(alias) = alias.as_deref()
98 && alias != name
99 {
100 return internal_err!(
101 "aggregate human_display_alias must match aggregate name `{name}`: {alias}"
102 );
103 }
104
105 Ok(Some(Self { expression, alias }))
106 }
107
108 fn expression(&self) -> &str {
109 &self.expression
110 }
111
112 fn alias(&self) -> Option<&str> {
113 self.alias.as_deref()
114 }
115}
116
117#[derive(Debug, Clone)]
122pub struct AggregateExprBuilder {
123 fun: Arc<AggregateUDF>,
124 args: Vec<Arc<dyn PhysicalExpr>>,
126 alias: Option<String>,
127 output_metadata: Option<FieldMetadata>,
128 human_display: Option<String>,
130 human_display_alias: Option<String>,
132 schema: SchemaRef,
134 order_bys: Vec<PhysicalSortExpr>,
136 ignore_nulls: bool,
138 is_distinct: bool,
140 is_reversed: bool,
142}
143
144impl AggregateExprBuilder {
145 pub fn new(fun: Arc<AggregateUDF>, args: Vec<Arc<dyn PhysicalExpr>>) -> Self {
146 Self {
147 fun,
148 args,
149 alias: None,
150 output_metadata: None,
151 human_display: None,
152 human_display_alias: None,
153 schema: Arc::new(Schema::empty()),
154 order_bys: vec![],
155 ignore_nulls: false,
156 is_distinct: false,
157 is_reversed: false,
158 }
159 }
160
161 pub fn build(self) -> Result<AggregateFunctionExpr> {
252 let Self {
253 fun,
254 args,
255 alias,
256 output_metadata,
257 human_display,
258 human_display_alias,
259 schema,
260 order_bys,
261 ignore_nulls,
262 is_distinct,
263 is_reversed,
264 } = self;
265 assert_or_internal_err!(!args.is_empty(), "args should not be empty");
266
267 let ordering_types = order_bys
268 .iter()
269 .map(|e| e.expr.data_type(&schema))
270 .collect::<Result<Vec<_>>>()?;
271
272 let ordering_fields = utils::ordering_fields(&order_bys, &ordering_types);
273
274 let input_exprs_fields = args
275 .iter()
276 .map(|arg| arg.return_field(&schema))
277 .collect::<Result<Vec<_>>>()?;
278
279 check_arg_count(
280 fun.name(),
281 &input_exprs_fields,
282 &fun.signature().type_signature,
283 )?;
284
285 let mut return_field = fun.return_field(&input_exprs_fields)?;
286 if let Some(output_metadata) = output_metadata {
287 return_field = output_metadata.add_to_field_ref(return_field);
288 }
289 let is_nullable = fun.is_nullable();
290 let name = match alias {
291 None => {
292 return internal_err!(
293 "AggregateExprBuilder::alias must be provided prior to calling build"
294 );
295 }
296 Some(alias) => alias,
297 };
298
299 let human_display =
300 AggregateHumanDisplay::try_new(human_display, human_display_alias, &name)?;
301
302 let arg_fields = args
303 .iter()
304 .map(|e| e.return_field(schema.as_ref()))
305 .collect::<Result<Vec<_>>>()?;
306
307 Ok(AggregateFunctionExpr {
308 fun: Arc::unwrap_or_clone(fun),
309 args,
310 arg_fields,
311 return_field,
312 name,
313 human_display,
314 schema: Arc::unwrap_or_clone(schema),
315 order_bys,
316 ignore_nulls,
317 ordering_fields,
318 is_distinct,
319 input_fields: input_exprs_fields,
320 is_reversed,
321 is_nullable,
322 })
323 }
324
325 pub fn alias(mut self, alias: impl Into<String>) -> Self {
326 self.alias = Some(alias.into());
327 self
328 }
329
330 fn output_metadata(mut self, metadata: Option<FieldMetadata>) -> Self {
331 self.output_metadata = metadata;
332 self
333 }
334
335 pub fn human_display(mut self, name: impl Into<String>) -> Self {
336 let name = name.into();
337 self.human_display = (!name.is_empty()).then_some(name);
338 if self.human_display.is_none() {
339 self.human_display_alias = None;
340 }
341 self
342 }
343
344 #[doc(hidden)]
345 pub fn human_display_alias(mut self, alias: impl Into<String>) -> Self {
346 let alias = alias.into();
347 self.human_display_alias = (!alias.is_empty()).then_some(alias);
348 self
349 }
350
351 pub fn schema(mut self, schema: SchemaRef) -> Self {
352 self.schema = schema;
353 self
354 }
355
356 pub fn order_by(mut self, order_bys: Vec<PhysicalSortExpr>) -> Self {
357 self.order_bys = order_bys;
358 self
359 }
360
361 pub fn reversed(mut self) -> Self {
362 self.is_reversed = true;
363 self
364 }
365
366 pub fn with_reversed(mut self, is_reversed: bool) -> Self {
367 self.is_reversed = is_reversed;
368 self
369 }
370
371 pub fn distinct(mut self) -> Self {
372 self.is_distinct = true;
373 self
374 }
375
376 pub fn with_distinct(mut self, is_distinct: bool) -> Self {
377 self.is_distinct = is_distinct;
378 self
379 }
380
381 pub fn ignore_nulls(mut self) -> Self {
382 self.ignore_nulls = true;
383 self
384 }
385
386 pub fn with_ignore_nulls(mut self, ignore_nulls: bool) -> Self {
387 self.ignore_nulls = ignore_nulls;
388 self
389 }
390}
391
392#[derive(Debug, Clone)]
393struct LoweredAggregateHumanDisplay {
394 expression: String,
395 alias: Option<String>,
396}
397
398#[derive(Debug, Clone)]
401pub struct LoweredAggregate {
402 pub aggregate: Arc<AggregateFunctionExpr>,
405 pub filter: Option<Arc<dyn PhysicalExpr>>,
407 pub order_bys: Vec<PhysicalSortExpr>,
409}
410
411pub struct LoweredAggregateBuilder<'a> {
419 expr: &'a Expr,
420 name: Option<String>,
421 human_display: Option<LoweredAggregateHumanDisplay>,
422 output_metadata: Option<FieldMetadata>,
423 preserve_alias_metadata: bool,
424 logical_input_schema: &'a DFSchema,
425 physical_input_schema: &'a Schema,
426 execution_props: &'a ExecutionProps,
427 planning_ctx: &'a PhysicalPlanningContext,
428}
429
430impl<'a> LoweredAggregateBuilder<'a> {
431 pub fn new(
441 expr: &'a Expr,
442 logical_input_schema: &'a DFSchema,
443 physical_input_schema: &'a Schema,
444 execution_props: &'a ExecutionProps,
445 planning_ctx: &'a PhysicalPlanningContext,
446 ) -> Self {
447 Self {
448 expr,
449 name: None,
450 human_display: None,
451 output_metadata: None,
452 preserve_alias_metadata: true,
453 logical_input_schema,
454 physical_input_schema,
455 execution_props,
456 planning_ctx,
457 }
458 }
459
460 pub fn with_name(mut self, name: impl Into<String>) -> Self {
465 self.name = Some(name.into());
466 self
467 }
468
469 pub fn with_human_display(mut self, human_display: impl Into<String>) -> Self {
476 self.human_display = Some(LoweredAggregateHumanDisplay {
477 expression: human_display.into(),
478 alias: None,
479 });
480 self.preserve_alias_metadata = false;
481 self
482 }
483
484 pub fn build(self) -> Result<LoweredAggregate> {
486 let Self {
487 expr,
488 name,
489 human_display,
490 output_metadata,
491 preserve_alias_metadata,
492 logical_input_schema,
493 physical_input_schema,
494 execution_props,
495 planning_ctx,
496 } = self;
497
498 let (name, human_display, output_metadata, expr) = lower_aggregate_display(
499 expr,
500 name,
501 human_display,
502 output_metadata,
503 preserve_alias_metadata,
504 );
505
506 let Expr::AggregateFunction(AggregateFunction {
507 func,
508 params:
509 AggregateFunctionParams {
510 args,
511 distinct,
512 filter,
513 order_by,
514 null_treatment,
515 },
516 }) = &expr
517 else {
518 return internal_err!("Invalid aggregate expression '{expr:?}'");
519 };
520
521 let name = if let Some(name) = name {
522 name
523 } else {
524 physical_name(&expr)?
525 };
526
527 let physical_args = create_physical_exprs(
528 args,
529 logical_input_schema,
530 execution_props,
531 planning_ctx,
532 )?;
533 let filter = filter
534 .as_ref()
535 .map(|filter| {
536 create_physical_expr(
537 filter,
538 logical_input_schema,
539 execution_props,
540 planning_ctx,
541 )
542 })
543 .transpose()?;
544 let order_bys = create_physical_sort_exprs(
545 order_by,
546 logical_input_schema,
547 execution_props,
548 planning_ctx,
549 )?;
550 let ignore_nulls = null_treatment.unwrap_or(NullTreatment::RespectNulls)
551 == NullTreatment::IgnoreNulls;
552
553 let mut builder = AggregateExprBuilder::new(func.to_owned(), physical_args)
554 .order_by(order_bys.clone())
555 .schema(Arc::new(physical_input_schema.to_owned()))
556 .alias(name)
557 .output_metadata(output_metadata)
558 .with_ignore_nulls(ignore_nulls)
559 .with_distinct(*distinct);
560
561 if let Some(human_display) = human_display {
562 builder = builder.human_display(human_display.expression);
563 if let Some(alias) = human_display.alias {
564 builder = builder.human_display_alias(alias);
565 }
566 }
567
568 Ok(LoweredAggregate {
569 aggregate: Arc::new(builder.build()?),
570 filter,
571 order_bys,
572 })
573 }
574}
575
576fn lower_aggregate_display(
577 expr: &Expr,
578 name: Option<String>,
579 human_display: Option<LoweredAggregateHumanDisplay>,
580 output_metadata: Option<FieldMetadata>,
581 preserve_alias_metadata: bool,
582) -> (
583 Option<String>,
584 Option<LoweredAggregateHumanDisplay>,
585 Option<FieldMetadata>,
586 Expr,
587) {
588 let mut expr = expr.clone();
589 let mut alias_name = None;
590 let mut alias_metadata = None;
591 while let Expr::Alias(alias) = expr {
592 if alias_name.is_none() {
593 alias_name = Some(alias.name);
594 alias_metadata = alias.metadata;
595 }
596 expr = *alias.expr;
597 }
598
599 let output_metadata = if preserve_alias_metadata {
600 output_metadata.or(alias_metadata)
601 } else {
602 output_metadata
603 };
604
605 if human_display.is_some() {
606 return (name.or(alias_name), human_display, output_metadata, expr);
607 }
608
609 match &expr {
610 Expr::AggregateFunction(_) => {
611 if let Some(alias_name) = alias_name {
612 let name = name.unwrap_or(alias_name);
613 let expression = expr.human_display().to_string();
614 let human_display = if expression.is_empty() || expression == name {
615 LoweredAggregateHumanDisplay {
616 expression: name.clone(),
617 alias: None,
618 }
619 } else {
620 LoweredAggregateHumanDisplay {
621 expression,
622 alias: Some(name.clone()),
623 }
624 };
625
626 return (Some(name), Some(human_display), output_metadata, expr);
627 }
628
629 let name = name.unwrap_or_else(|| expr.schema_name().to_string());
630 let human_display = LoweredAggregateHumanDisplay {
631 expression: expr.human_display().to_string(),
632 alias: None,
633 };
634
635 (Some(name), Some(human_display), output_metadata, expr)
636 }
637 _ => (name.or(alias_name), None, output_metadata, expr),
638 }
639}
640
641#[derive(Debug, Clone)]
645pub struct AggregateFunctionExpr {
646 fun: AggregateUDF,
647 args: Vec<Arc<dyn PhysicalExpr>>,
648 arg_fields: Vec<FieldRef>,
650 return_field: FieldRef,
652 name: String,
654 human_display: Option<AggregateHumanDisplay>,
656 schema: Schema,
657 order_bys: Vec<PhysicalSortExpr>,
659 ignore_nulls: bool,
661 ordering_fields: Vec<FieldRef>,
663 is_distinct: bool,
664 is_reversed: bool,
665 input_fields: Vec<FieldRef>,
666 is_nullable: bool,
667}
668
669impl AggregateFunctionExpr {
670 pub fn fun(&self) -> &AggregateUDF {
672 &self.fun
673 }
674
675 pub fn expressions(&self) -> Vec<Arc<dyn PhysicalExpr>> {
678 self.args.clone()
679 }
680
681 pub fn name(&self) -> &str {
683 &self.name
684 }
685
686 pub fn human_display(&self) -> Option<&str> {
688 self.human_display
689 .as_ref()
690 .map(AggregateHumanDisplay::expression)
691 }
692
693 #[doc(hidden)]
694 pub fn human_display_alias(&self) -> Option<&str> {
695 self.human_display
696 .as_ref()
697 .and_then(AggregateHumanDisplay::alias)
698 }
699
700 fn return_field_metadata(&self) -> Option<FieldMetadata> {
701 let metadata = FieldMetadata::from(self.return_field.as_ref());
702 (!metadata.is_empty()).then_some(metadata)
703 }
704
705 pub fn is_distinct(&self) -> bool {
707 self.is_distinct
708 }
709
710 pub fn ignore_nulls(&self) -> bool {
712 self.ignore_nulls
713 }
714
715 pub fn is_reversed(&self) -> bool {
717 self.is_reversed
718 }
719
720 pub fn is_nullable(&self) -> bool {
722 self.is_nullable
723 }
724
725 pub fn field(&self) -> FieldRef {
727 self.return_field
728 .as_ref()
729 .clone()
730 .with_name(&self.name)
731 .into()
732 }
733
734 pub fn create_accumulator(&self) -> Result<Box<dyn Accumulator>> {
738 let acc_args = AccumulatorArgs {
739 return_field: Arc::clone(&self.return_field),
740 schema: &self.schema,
741 expr_fields: &self.arg_fields,
742 ignore_nulls: self.ignore_nulls,
743 order_bys: self.order_bys.as_ref(),
744 is_distinct: self.is_distinct,
745 name: &self.name,
746 is_reversed: self.is_reversed,
747 exprs: &self.args,
748 };
749
750 self.fun.accumulator(acc_args)
751 }
752
753 pub fn state_fields(&self) -> Result<Vec<FieldRef>> {
755 let args = StateFieldsArgs {
756 name: &self.name,
757 input_fields: &self.input_fields,
758 return_field: Arc::clone(&self.return_field),
759 ordering_fields: &self.ordering_fields,
760 is_distinct: self.is_distinct,
761 };
762
763 self.fun.state_fields(args)
764 }
765
766 pub fn order_bys(&self) -> &[PhysicalSortExpr] {
768 if self.order_sensitivity().is_insensitive() {
769 &[]
770 } else {
771 &self.order_bys
772 }
773 }
774
775 pub fn order_sensitivity(&self) -> AggregateOrderSensitivity {
779 if self.order_bys.is_empty() {
780 AggregateOrderSensitivity::Insensitive
781 } else {
782 self.fun.order_sensitivity()
784 }
785 }
786
787 pub fn with_beneficial_ordering(
799 self: Arc<Self>,
800 beneficial_ordering: bool,
801 ) -> Result<Option<AggregateFunctionExpr>> {
802 let Some(updated_fn) = self
803 .fun
804 .clone()
805 .with_beneficial_ordering(beneficial_ordering)?
806 else {
807 return Ok(None);
808 };
809
810 let mut builder =
811 AggregateExprBuilder::new(Arc::new(updated_fn), self.args.to_vec())
812 .order_by(self.order_bys.clone())
813 .schema(Arc::new(self.schema.clone()))
814 .alias(self.name().to_string())
815 .output_metadata(self.return_field_metadata())
816 .with_ignore_nulls(self.ignore_nulls)
817 .with_distinct(self.is_distinct)
818 .with_reversed(self.is_reversed);
819 if let Some(human_display) = self.human_display() {
820 builder = builder.human_display(human_display);
821 }
822 if let Some(alias) = self.human_display_alias() {
823 builder = builder.human_display_alias(alias);
824 }
825 builder.build().map(Some)
826 }
827
828 pub fn create_sliding_accumulator(&self) -> Result<Box<dyn Accumulator>> {
830 let args = AccumulatorArgs {
831 return_field: Arc::clone(&self.return_field),
832 schema: &self.schema,
833 expr_fields: &self.arg_fields,
834 ignore_nulls: self.ignore_nulls,
835 order_bys: self.order_bys.as_ref(),
836 is_distinct: self.is_distinct,
837 name: &self.name,
838 is_reversed: self.is_reversed,
839 exprs: &self.args,
840 };
841
842 let accumulator = self.fun.create_sliding_accumulator(args)?;
843
844 if !accumulator.supports_retract_batch() {
887 return not_impl_err!(
888 "Aggregate can not be used as a sliding accumulator because \
889 `retract_batch` is not implemented: {}",
890 self.name
891 );
892 }
893 Ok(accumulator)
894 }
895
896 pub fn groups_accumulator_supported(&self) -> bool {
900 let args = AccumulatorArgs {
901 return_field: Arc::clone(&self.return_field),
902 schema: &self.schema,
903 expr_fields: &self.arg_fields,
904 ignore_nulls: self.ignore_nulls,
905 order_bys: self.order_bys.as_ref(),
906 is_distinct: self.is_distinct,
907 name: &self.name,
908 is_reversed: self.is_reversed,
909 exprs: &self.args,
910 };
911 self.fun.groups_accumulator_supported(args)
912 }
913
914 pub fn create_groups_accumulator(&self) -> Result<Box<dyn GroupsAccumulator>> {
920 let args = AccumulatorArgs {
921 return_field: Arc::clone(&self.return_field),
922 schema: &self.schema,
923 expr_fields: &self.arg_fields,
924 ignore_nulls: self.ignore_nulls,
925 order_bys: self.order_bys.as_ref(),
926 is_distinct: self.is_distinct,
927 name: &self.name,
928 is_reversed: self.is_reversed,
929 exprs: &self.args,
930 };
931 self.fun.create_groups_accumulator(args)
932 }
933
934 pub fn reverse_expr(&self) -> Option<AggregateFunctionExpr> {
939 match self.fun.reverse_udf() {
940 ReversedUDAF::NotSupported => None,
941 ReversedUDAF::Identical => Some(self.clone()),
942 ReversedUDAF::Reversed(reverse_udf) => {
943 let was_aliased = self.human_display_alias().is_some();
944 let mut name = self.name().to_string();
945 let mut human_display = self.human_display.clone();
946 if !was_aliased && self.fun().name() != reverse_udf.name() {
954 replace_order_by_clause(&mut name);
955 }
956 if !was_aliased {
957 replace_fn_name_clause(
958 &mut name,
959 self.fun.name(),
960 reverse_udf.name(),
961 );
962 }
963
964 if let Some(human_display) = human_display.as_mut() {
965 if self.fun().name() != reverse_udf.name() {
966 replace_order_by_clause(&mut human_display.expression);
967 }
968 replace_fn_name_clause(
969 &mut human_display.expression,
970 self.fun.name(),
971 reverse_udf.name(),
972 );
973 }
974
975 let mut builder =
976 AggregateExprBuilder::new(reverse_udf, self.args.to_vec())
977 .order_by(self.order_bys.iter().map(|e| e.reverse()).collect())
978 .schema(Arc::new(self.schema.clone()))
979 .alias(name)
980 .output_metadata(self.return_field_metadata())
981 .with_ignore_nulls(self.ignore_nulls)
982 .with_distinct(self.is_distinct)
983 .with_reversed(!self.is_reversed);
984 if let Some(human_display) = human_display {
985 builder = builder.human_display(human_display.expression);
986 if let Some(alias) = human_display.alias {
987 builder = builder.human_display_alias(alias);
988 }
989 }
990 builder.build().ok()
991 }
992 }
993 }
994
995 pub fn all_expressions(&self) -> AggregatePhysicalExpressions {
998 let args = self.expressions();
999 let order_by_exprs = self
1000 .order_bys()
1001 .iter()
1002 .map(|sort_expr| Arc::clone(&sort_expr.expr))
1003 .collect();
1004 AggregatePhysicalExpressions {
1005 args,
1006 order_by_exprs,
1007 }
1008 }
1009
1010 pub fn with_new_expressions(
1014 &self,
1015 args: Vec<Arc<dyn PhysicalExpr>>,
1016 order_by_exprs: Vec<Arc<dyn PhysicalExpr>>,
1017 ) -> Option<AggregateFunctionExpr> {
1018 if args.len() != self.args.len()
1019 || (self.order_sensitivity() != AggregateOrderSensitivity::Insensitive
1020 && order_by_exprs.len() != self.order_bys.len())
1021 {
1022 return None;
1023 }
1024
1025 let new_order_bys = self
1026 .order_bys
1027 .iter()
1028 .zip(order_by_exprs)
1029 .map(|(req, new_expr)| PhysicalSortExpr {
1030 expr: new_expr,
1031 options: req.options,
1032 })
1033 .collect();
1034
1035 Some(AggregateFunctionExpr {
1036 fun: self.fun.clone(),
1037 args,
1038 arg_fields: self.arg_fields.clone(),
1041 return_field: Arc::clone(&self.return_field),
1042 name: self.name.clone(),
1043 human_display: self.human_display.clone(),
1045 schema: self.schema.clone(),
1046 order_bys: new_order_bys,
1047 ignore_nulls: self.ignore_nulls,
1048 ordering_fields: self.ordering_fields.clone(),
1049 is_distinct: self.is_distinct,
1050 is_reversed: false,
1051 input_fields: self.input_fields.clone(),
1052 is_nullable: self.is_nullable,
1053 })
1054 }
1055
1056 pub fn get_minmax_desc(&self) -> Option<(FieldRef, bool)> {
1064 self.fun.is_descending().map(|flag| (self.field(), flag))
1065 }
1066
1067 pub fn default_value(&self, data_type: &DataType) -> Result<ScalarValue> {
1071 self.fun.default_value(data_type)
1072 }
1073
1074 pub fn set_monotonicity(&self) -> SetMonotonicity {
1077 let field = self.field();
1078 let data_type = field.data_type();
1079 self.fun.inner().set_monotonicity(data_type)
1080 }
1081
1082 pub fn get_result_ordering(&self, aggr_func_idx: usize) -> Option<PhysicalSortExpr> {
1084 let monotonicity = self.set_monotonicity();
1087 if monotonicity == SetMonotonicity::NotMonotonic {
1088 return None;
1089 }
1090 let expr = Arc::new(Column::new(self.name(), aggr_func_idx));
1091 let options =
1092 SortOptions::new(monotonicity == SetMonotonicity::Decreasing, false);
1093 Some(PhysicalSortExpr { expr, options })
1094 }
1095}
1096
1097pub struct AggregatePhysicalExpressions {
1099 pub args: Vec<Arc<dyn PhysicalExpr>>,
1101 pub order_by_exprs: Vec<Arc<dyn PhysicalExpr>>,
1103}
1104
1105impl PartialEq for AggregateFunctionExpr {
1106 fn eq(&self, other: &Self) -> bool {
1107 self.name == other.name
1108 && self.return_field == other.return_field
1109 && self.fun == other.fun
1110 && self.args.len() == other.args.len()
1111 && self
1112 .args
1113 .iter()
1114 .zip(other.args.iter())
1115 .all(|(this_arg, other_arg)| this_arg.eq(other_arg))
1116 }
1117}
1118
1119fn replace_order_by_clause(order_by: &mut String) {
1120 let suffixes = [
1121 (" DESC NULLS FIRST]", " ASC NULLS LAST]"),
1122 (" ASC NULLS FIRST]", " DESC NULLS LAST]"),
1123 (" DESC NULLS LAST]", " ASC NULLS FIRST]"),
1124 (" ASC NULLS LAST]", " DESC NULLS FIRST]"),
1125 ];
1126
1127 if let Some(start) = order_by.find("ORDER BY [")
1128 && let Some(end) = order_by[start..].find(']')
1129 {
1130 let order_by_start = start + 9;
1131 let order_by_end = start + end;
1132
1133 let column_order = &order_by[order_by_start..=order_by_end];
1134 for (suffix, replacement) in suffixes {
1135 if column_order.ends_with(suffix) {
1136 let new_order = column_order.replace(suffix, replacement);
1137 order_by.replace_range(order_by_start..=order_by_end, &new_order);
1138 break;
1139 }
1140 }
1141 }
1142}
1143
1144fn replace_fn_name_clause(aggr_name: &mut String, fn_name_old: &str, fn_name_new: &str) {
1145 if let Some(rest) = aggr_name.strip_prefix(fn_name_old) {
1146 *aggr_name = format!("{fn_name_new}{rest}");
1147 }
1148}
1149
1150#[cfg(test)]
1151mod tests {
1152 use super::*;
1153
1154 use std::collections::HashMap;
1155
1156 use arrow::datatypes::Field;
1157 use datafusion_common::metadata::FieldMetadata;
1158 use datafusion_expr::{col, test::function_stub::sum};
1159
1160 fn aggregate_test_schema() -> Result<(Schema, DFSchema)> {
1161 let schema = Schema::new(vec![Field::new("column1", DataType::Int64, true)]);
1162 let logical_schema = DFSchema::try_from(schema.clone())?;
1163 Ok((schema, logical_schema))
1164 }
1165
1166 fn test_metadata() -> FieldMetadata {
1167 FieldMetadata::from(HashMap::from([(
1168 "some_key".to_string(),
1169 "some_value".to_string(),
1170 )]))
1171 }
1172
1173 fn aggregate_alias_with_metadata() -> Expr {
1174 sum(col("column1")).alias_with_metadata("agg", Some(test_metadata()))
1175 }
1176
1177 #[test]
1178 fn lowered_aggregate_builder_unwraps_alias_with_metadata() -> Result<()> {
1179 let (schema, logical_schema) = aggregate_test_schema()?;
1180 let expr = aggregate_alias_with_metadata();
1181
1182 let lowered = LoweredAggregateBuilder::new(
1183 &expr,
1184 &logical_schema,
1185 &schema,
1186 &ExecutionProps::new(),
1187 &PhysicalPlanningContext::default(),
1188 )
1189 .build()?;
1190
1191 assert_eq!(lowered.aggregate.name(), "agg");
1192 assert_eq!(lowered.aggregate.human_display_alias(), Some("agg"));
1193 assert_eq!(
1194 lowered.aggregate.field().metadata().get("some_key"),
1195 Some(&"some_value".to_string())
1196 );
1197
1198 Ok(())
1199 }
1200
1201 #[test]
1202 fn lowered_aggregate_builder_display_override_skips_alias_metadata() -> Result<()> {
1203 let (schema, logical_schema) = aggregate_test_schema()?;
1204 let expr = aggregate_alias_with_metadata();
1205
1206 let lowered = LoweredAggregateBuilder::new(
1207 &expr,
1208 &logical_schema,
1209 &schema,
1210 &ExecutionProps::new(),
1211 &PhysicalPlanningContext::default(),
1212 )
1213 .with_human_display(expr.human_display().to_string())
1214 .build()?;
1215
1216 assert_eq!(lowered.aggregate.name(), "agg");
1217 assert_eq!(lowered.aggregate.human_display_alias(), None);
1218 assert!(
1219 lowered
1220 .aggregate
1221 .field()
1222 .metadata()
1223 .get("some_key")
1224 .is_none()
1225 );
1226
1227 Ok(())
1228 }
1229}