Skip to content

Commit a0a635a

Browse files
authored
Adds WindowUDFImpl::reverse_exprtrait method + Support for IGNORE NULLS (#12662)
* Adds method for reversing a user-defined window function * Adds support for `IGNORE NULLS` * Adds doc comments for `reverse_expr` * Minor: copy edit for doc comment * Adds doc comments for `WindowUDFExpr` fields
1 parent c4b48d7 commit a0a635a

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

datafusion/expr/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub use sqlparser;
9292
pub use table_source::{TableProviderFilterPushDown, TableSource, TableType};
9393
pub use udaf::{AggregateUDF, AggregateUDFImpl, ReversedUDAF};
9494
pub use udf::{ScalarUDF, ScalarUDFImpl};
95-
pub use udwf::{WindowUDF, WindowUDFImpl};
95+
pub use udwf::{ReversedUDWF, WindowUDF, WindowUDFImpl};
9696
pub use window_frame::{WindowFrame, WindowFrameBound, WindowFrameUnits};
9797

9898
#[cfg(test)]

datafusion/expr/src/udwf.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ impl WindowUDF {
172172
pub fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
173173
self.inner.coerce_types(arg_types)
174174
}
175+
176+
/// Returns the reversed user-defined window function when the
177+
/// order of evaluation is reversed.
178+
///
179+
/// See [`WindowUDFImpl::reverse_expr`] for more details.
180+
pub fn reverse_expr(&self) -> ReversedUDWF {
181+
self.inner.reverse_expr()
182+
}
175183
}
176184

177185
impl<F> From<F> for WindowUDF
@@ -351,6 +359,24 @@ pub trait WindowUDFImpl: Debug + Send + Sync {
351359
fn coerce_types(&self, _arg_types: &[DataType]) -> Result<Vec<DataType>> {
352360
not_impl_err!("Function {} does not implement coerce_types", self.name())
353361
}
362+
363+
/// Allows customizing the behavior of the user-defined window
364+
/// function when it is evaluated in reverse order.
365+
fn reverse_expr(&self) -> ReversedUDWF {
366+
ReversedUDWF::NotSupported
367+
}
368+
}
369+
370+
pub enum ReversedUDWF {
371+
/// The result of evaluating the user-defined window function
372+
/// remains identical when reversed.
373+
Identical,
374+
/// A window function which does not support evaluating the result
375+
/// in reverse order.
376+
NotSupported,
377+
/// Customize the user-defined window function for evaluating the
378+
/// result in reverse order.
379+
Reversed(Arc<WindowUDF>),
354380
}
355381

356382
impl PartialEq for dyn WindowUDFImpl {

datafusion/physical-plan/src/windows/mod.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use datafusion_common::{
3434
exec_datafusion_err, exec_err, DataFusionError, Result, ScalarValue,
3535
};
3636
use datafusion_expr::{
37-
BuiltInWindowFunction, PartitionEvaluator, WindowFrame, WindowFunctionDefinition,
38-
WindowUDF,
37+
BuiltInWindowFunction, PartitionEvaluator, ReversedUDWF, WindowFrame,
38+
WindowFunctionDefinition, WindowUDF,
3939
};
4040
use datafusion_physical_expr::aggregate::{AggregateExprBuilder, AggregateFunctionExpr};
4141
use datafusion_physical_expr::equivalence::collapse_lex_req;
@@ -130,7 +130,7 @@ pub fn create_window_expr(
130130
}
131131
// TODO: Ordering not supported for Window UDFs yet
132132
WindowFunctionDefinition::WindowUDF(fun) => Arc::new(BuiltInWindowExpr::new(
133-
create_udwf_window_expr(fun, args, input_schema, name)?,
133+
create_udwf_window_expr(fun, args, input_schema, name, ignore_nulls)?,
134134
partition_by,
135135
order_by,
136136
window_frame,
@@ -329,6 +329,7 @@ fn create_udwf_window_expr(
329329
args: &[Arc<dyn PhysicalExpr>],
330330
input_schema: &Schema,
331331
name: String,
332+
ignore_nulls: bool,
332333
) -> Result<Arc<dyn BuiltInWindowFunctionExpr>> {
333334
// need to get the types into an owned vec for some reason
334335
let input_types: Vec<_> = args
@@ -341,6 +342,8 @@ fn create_udwf_window_expr(
341342
args: args.to_vec(),
342343
input_types,
343344
name,
345+
is_reversed: false,
346+
ignore_nulls,
344347
}))
345348
}
346349

@@ -353,6 +356,12 @@ struct WindowUDFExpr {
353356
name: String,
354357
/// Types of input expressions
355358
input_types: Vec<DataType>,
359+
/// This is set to `true` only if the user-defined window function
360+
/// expression supports evaluation in reverse order, and the
361+
/// evaluation order is reversed.
362+
is_reversed: bool,
363+
/// Set to `true` if `IGNORE NULLS` is defined, `false` otherwise.
364+
ignore_nulls: bool,
356365
}
357366

358367
impl BuiltInWindowFunctionExpr for WindowUDFExpr {
@@ -378,7 +387,18 @@ impl BuiltInWindowFunctionExpr for WindowUDFExpr {
378387
}
379388

380389
fn reverse_expr(&self) -> Option<Arc<dyn BuiltInWindowFunctionExpr>> {
381-
None
390+
match self.fun.reverse_expr() {
391+
ReversedUDWF::Identical => Some(Arc::new(self.clone())),
392+
ReversedUDWF::NotSupported => None,
393+
ReversedUDWF::Reversed(fun) => Some(Arc::new(WindowUDFExpr {
394+
fun,
395+
args: self.args.clone(),
396+
name: self.name.clone(),
397+
input_types: self.input_types.clone(),
398+
is_reversed: !self.is_reversed,
399+
ignore_nulls: self.ignore_nulls,
400+
})),
401+
}
382402
}
383403

384404
fn get_result_ordering(&self, schema: &SchemaRef) -> Option<PhysicalSortExpr> {

0 commit comments

Comments
 (0)