datafusion_physical_expr/window/
standard.rs1use std::any::Any;
21use std::ops::Range;
22use std::sync::Arc;
23
24use super::{StandardWindowFunctionExpr, WindowExpr};
25use crate::window::window_expr::{WindowEvalContext, WindowFn, get_orderby_values};
26use crate::window::{PartitionBatches, PartitionWindowAggStates, WindowState};
27use crate::{EquivalenceProperties, PhysicalExpr};
28
29use arrow::array::{ArrayRef, new_empty_array};
30use arrow::datatypes::FieldRef;
31use arrow::record_batch::RecordBatch;
32use datafusion_common::utils::evaluate_partition_ranges;
33use datafusion_common::{Result, ScalarValue};
34use datafusion_expr::WindowFrame;
35use datafusion_expr::window_state::{WindowAggState, WindowFrameContext};
36use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
37
38#[derive(Debug)]
40pub struct StandardWindowExpr {
41 expr: Arc<dyn StandardWindowFunctionExpr>,
42 partition_by: Vec<Arc<dyn PhysicalExpr>>,
43 order_by: Vec<PhysicalSortExpr>,
44 window_frame: Arc<WindowFrame>,
45}
46
47impl StandardWindowExpr {
48 pub fn new(
50 expr: Arc<dyn StandardWindowFunctionExpr>,
51 partition_by: &[Arc<dyn PhysicalExpr>],
52 order_by: &[PhysicalSortExpr],
53 window_frame: Arc<WindowFrame>,
54 ) -> Self {
55 Self {
56 expr,
57 partition_by: partition_by.to_vec(),
58 order_by: order_by.to_vec(),
59 window_frame,
60 }
61 }
62
63 pub fn get_standard_func_expr(&self) -> &Arc<dyn StandardWindowFunctionExpr> {
65 &self.expr
66 }
67
68 pub fn add_equal_orderings(
74 &self,
75 eq_properties: &mut EquivalenceProperties,
76 ) -> Result<()> {
77 let schema = eq_properties.schema();
78 if let Some(fn_res_ordering) = self.expr.get_result_ordering(schema) {
79 add_new_ordering_expr_with_partition_by(
80 eq_properties,
81 fn_res_ordering,
82 &self.partition_by,
83 )?;
84 }
85 Ok(())
86 }
87}
88
89impl WindowExpr for StandardWindowExpr {
90 fn as_any(&self) -> &dyn Any {
92 self
93 }
94
95 fn name(&self) -> &str {
96 self.expr.name()
97 }
98
99 fn field(&self) -> Result<FieldRef> {
100 self.expr.field()
101 }
102
103 fn expressions(&self) -> Vec<Arc<dyn PhysicalExpr>> {
104 self.expr.expressions()
105 }
106
107 fn partition_by(&self) -> &[Arc<dyn PhysicalExpr>] {
108 &self.partition_by
109 }
110
111 fn order_by(&self) -> &[PhysicalSortExpr] {
112 &self.order_by
113 }
114
115 fn evaluate(&self, batch: &RecordBatch) -> Result<ArrayRef> {
116 let mut evaluator = self.expr.create_evaluator()?;
117 let num_rows = batch.num_rows();
118 if evaluator.uses_window_frame() {
119 let sort_options = self.order_by.iter().map(|o| o.options).collect();
120 let mut row_wise_results = vec![];
121
122 let mut values = self.evaluate_args(batch)?;
123 let order_bys = get_orderby_values(self.order_by_columns(batch)?);
124 let n_args = values.len();
125 values.extend(order_bys);
126 let order_bys_ref = &values[n_args..];
127
128 let mut window_frame_ctx =
129 WindowFrameContext::new(Arc::clone(&self.window_frame), sort_options);
130 let mut last_range = Range { start: 0, end: 0 };
131 for idx in 0..num_rows {
133 let range = window_frame_ctx.calculate_range(
134 order_bys_ref,
135 &last_range,
136 num_rows,
137 idx,
138 )?;
139 let value = evaluator.evaluate(&values, &range)?;
140 row_wise_results.push(value);
141 last_range = range;
142 }
143 ScalarValue::iter_to_array(row_wise_results)
144 } else if evaluator.include_rank() {
145 let columns = self.order_by_columns(batch)?;
146 let sort_partition_points = evaluate_partition_ranges(num_rows, &columns)?;
147 evaluator.evaluate_all_with_rank(num_rows, &sort_partition_points)
148 } else {
149 let values = self.evaluate_args(batch)?;
150 evaluator.evaluate_all(&values, num_rows)
151 }
152 }
153
154 fn evaluate_stateful(
157 &self,
158 partition_batches: &PartitionBatches,
159 window_agg_state: &mut PartitionWindowAggStates,
160 _eval_ctx: &WindowEvalContext<'_>,
161 ) -> Result<()> {
162 let field = self.expr.field()?;
163 let out_type = field.data_type();
164 let sort_options = self.order_by.iter().map(|o| o.options).collect::<Vec<_>>();
165 let new_state = WindowAggState::new(out_type)?;
168 for (partition_row, partition_batch_state) in partition_batches.iter() {
169 let window_state =
170 if let Some(window_state) = window_agg_state.get_mut(partition_row) {
171 window_state
172 } else {
173 let evaluator = self.expr.create_evaluator()?;
174 window_agg_state
175 .entry(partition_row.clone())
176 .or_insert(WindowState {
177 state: new_state.clone(),
178 window_fn: WindowFn::Builtin(evaluator),
179 published: false,
180 })
181 };
182 let evaluator = match &mut window_state.window_fn {
183 WindowFn::Builtin(evaluator) => evaluator,
184 _ => unreachable!(),
185 };
186 let state = &mut window_state.state;
187
188 let batch_ref = &partition_batch_state.record_batch;
189 let mut values = self.evaluate_args(batch_ref)?;
190 let order_bys = if evaluator.uses_window_frame() || evaluator.include_rank() {
191 get_orderby_values(self.order_by_columns(batch_ref)?)
192 } else {
193 vec![]
194 };
195 let n_args = values.len();
196 values.extend(order_bys);
197 let order_bys_ref = &values[n_args..];
198
199 let record_batch = &partition_batch_state.record_batch;
201 let num_rows = record_batch.num_rows();
202 let mut row_wise_results: Vec<ScalarValue> = vec![];
203 let is_causal = if evaluator.uses_window_frame() {
204 self.window_frame.is_causal()
205 } else {
206 evaluator.is_causal()
207 };
208 for idx in state.last_calculated_index..num_rows {
209 let frame_range = if evaluator.uses_window_frame() {
210 state
211 .window_frame_ctx
212 .get_or_insert_with(|| {
213 WindowFrameContext::new(
214 Arc::clone(&self.window_frame),
215 sort_options.clone(),
216 )
217 })
218 .calculate_range(
219 order_bys_ref,
220 &state.window_frame_range,
222 num_rows,
223 idx,
224 )
225 } else {
226 evaluator.get_range(idx, num_rows)
227 }?;
228
229 if frame_range.end == num_rows
231 && !is_causal
232 && !partition_batch_state.is_end
233 {
234 break;
235 }
236 state.window_frame_range = frame_range;
238 row_wise_results
239 .push(evaluator.evaluate(&values, &state.window_frame_range)?);
240 }
241 let out_col = if row_wise_results.is_empty() {
242 new_empty_array(out_type)
243 } else if row_wise_results.len() == 1 {
244 row_wise_results[0].to_array()?
246 } else {
247 ScalarValue::iter_to_array(row_wise_results)?
248 };
249
250 state.update(&out_col, partition_batch_state)?;
251 if self.window_frame.start_bound.is_unbounded() {
252 evaluator.memoize(state)?;
253 }
254 }
255 Ok(())
256 }
257
258 fn get_window_frame(&self) -> &Arc<WindowFrame> {
259 &self.window_frame
260 }
261
262 fn get_reverse_expr(&self) -> Option<Arc<dyn WindowExpr>> {
263 self.expr.reverse_expr().map(|reverse_expr| {
264 Arc::new(StandardWindowExpr::new(
265 reverse_expr,
266 &self.partition_by.clone(),
267 &self
268 .order_by
269 .iter()
270 .map(|e| e.reverse())
271 .collect::<Vec<_>>(),
272 Arc::new(self.window_frame.reverse()),
273 )) as _
274 })
275 }
276
277 fn uses_bounded_memory(&self) -> bool {
278 if let Ok(evaluator) = self.expr.create_evaluator() {
279 evaluator.supports_bounded_execution()
280 && (!evaluator.uses_window_frame()
281 || !self.window_frame.end_bound.is_unbounded())
282 } else {
283 false
284 }
285 }
286
287 fn create_window_fn(&self) -> Result<WindowFn> {
288 Ok(WindowFn::Builtin(self.expr.create_evaluator()?))
289 }
290}
291
292pub(crate) fn add_new_ordering_expr_with_partition_by(
295 eqp: &mut EquivalenceProperties,
296 expr: PhysicalSortExpr,
297 partition_by: &[Arc<dyn PhysicalExpr>],
298) -> Result<()> {
299 if partition_by.is_empty() {
300 eqp.add_ordering([expr]);
302 } else {
303 let (mut ordering, _) = eqp.find_longest_permutation(partition_by)?;
310 if ordering.len() == partition_by.len() {
311 ordering.push(expr);
312 eqp.add_ordering(ordering);
313 }
314 }
315 Ok(())
316}