@@ -34,7 +34,7 @@ use arrow::array::ArrayRef;
34
34
use arrow:: datatypes:: FieldRef ;
35
35
use arrow:: record_batch:: RecordBatch ;
36
36
use datafusion_common:: { DataFusionError , Result , ScalarValue } ;
37
- use datafusion_expr:: { Accumulator , WindowFrame } ;
37
+ use datafusion_expr:: { Accumulator , WindowFrame , WindowFrameBound , WindowFrameUnits } ;
38
38
use datafusion_physical_expr_common:: sort_expr:: LexOrdering ;
39
39
40
40
/// A window expr that takes the form of an aggregate function.
@@ -46,6 +46,7 @@ pub struct PlainAggregateWindowExpr {
46
46
partition_by : Vec < Arc < dyn PhysicalExpr > > ,
47
47
order_by : LexOrdering ,
48
48
window_frame : Arc < WindowFrame > ,
49
+ is_constant_in_partition : bool ,
49
50
}
50
51
51
52
impl PlainAggregateWindowExpr {
@@ -56,11 +57,14 @@ impl PlainAggregateWindowExpr {
56
57
order_by : & LexOrdering ,
57
58
window_frame : Arc < WindowFrame > ,
58
59
) -> Self {
60
+ let is_constant_in_partition =
61
+ Self :: is_window_constant_in_partition ( order_by, & window_frame) ;
59
62
Self {
60
63
aggregate,
61
64
partition_by : partition_by. to_vec ( ) ,
62
65
order_by : order_by. clone ( ) ,
63
66
window_frame,
67
+ is_constant_in_partition,
64
68
}
65
69
}
66
70
@@ -85,6 +89,30 @@ impl PlainAggregateWindowExpr {
85
89
) ;
86
90
}
87
91
}
92
+
93
+ // Returns true if every row in the partition has the same window frame. This allows
94
+ // for preventing bound + function calculation for every row due to the values being the
95
+ // same.
96
+ //
97
+ // This occurs when both bounds fall under either condition below:
98
+ // 1. Bound is unbounded (`Preceding` or `Following`)
99
+ // 2. Bound is `CurrentRow` while using `Range` units with no order by clause
100
+ // This results in an invalid range specification. Following PostgreSQL’s convention,
101
+ // we interpret this as the entire partition being used for the current window frame.
102
+ fn is_window_constant_in_partition (
103
+ order_by : & LexOrdering ,
104
+ window_frame : & WindowFrame ,
105
+ ) -> bool {
106
+ let is_constant_bound = |bound : & WindowFrameBound | match bound {
107
+ WindowFrameBound :: CurrentRow => {
108
+ window_frame. units == WindowFrameUnits :: Range && order_by. is_empty ( )
109
+ }
110
+ _ => bound. is_unbounded ( ) ,
111
+ } ;
112
+
113
+ is_constant_bound ( & window_frame. start_bound )
114
+ && is_constant_bound ( & window_frame. end_bound )
115
+ }
88
116
}
89
117
90
118
/// peer based evaluation based on the fact that batch is pre-sorted given the sort columns
@@ -213,4 +241,8 @@ impl AggregateWindowExpr for PlainAggregateWindowExpr {
213
241
accumulator. evaluate ( )
214
242
}
215
243
}
244
+
245
+ fn is_constant_in_partition ( & self ) -> bool {
246
+ self . is_constant_in_partition
247
+ }
216
248
}
0 commit comments