@@ -35,6 +35,7 @@ use crate::arrow::util::pretty;
3535use crate :: physical_plan:: {
3636 execute_stream, execute_stream_partitioned, ExecutionPlan , SendableRecordBatchStream ,
3737} ;
38+ use crate :: sql:: utils:: { find_window_exprs, group_window_expr_by_sort_keys} ;
3839use async_trait:: async_trait;
3940
4041/// Implementation of DataFrame API
@@ -75,10 +76,27 @@ impl DataFrame for DataFrameImpl {
7576
7677 /// Create a projection based on arbitrary expressions
7778 fn select ( & self , expr_list : Vec < Expr > ) -> Result < Arc < dyn DataFrame > > {
78- let plan = LogicalPlanBuilder :: from ( self . to_logical_plan ( ) )
79- . project ( expr_list) ?
80- . build ( ) ?;
81- Ok ( Arc :: new ( DataFrameImpl :: new ( self . ctx_state . clone ( ) , & plan) ) )
79+ let window_func_exprs = find_window_exprs ( & expr_list) ;
80+ let plan = if window_func_exprs. is_empty ( ) {
81+ self . to_logical_plan ( )
82+ } else {
83+ let mut logical_plan = self . to_logical_plan ( ) ;
84+ let mut groups = group_window_expr_by_sort_keys ( & window_func_exprs) ?;
85+ groups. sort_by ( |( key1, _) , ( key2, _) | key1. len ( ) . cmp ( & key2. len ( ) ) ) ;
86+ groups. reverse ( ) ;
87+ for ( _, exprs) in groups {
88+ let window_exprs = exprs. into_iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
89+ logical_plan = LogicalPlanBuilder :: from ( logical_plan)
90+ . window ( window_exprs) ?
91+ . build ( ) ?;
92+ }
93+ logical_plan
94+ } ;
95+ let project_plan = LogicalPlanBuilder :: from ( plan) . project ( expr_list) ?. build ( ) ?;
96+ Ok ( Arc :: new ( DataFrameImpl :: new (
97+ self . ctx_state . clone ( ) ,
98+ & project_plan,
99+ ) ) )
82100 }
83101
84102 /// Create a filter based on a predicate expression
@@ -233,7 +251,7 @@ mod tests {
233251 use crate :: execution:: options:: CsvReadOptions ;
234252 use crate :: logical_plan:: * ;
235253 use crate :: physical_plan:: functions:: Volatility ;
236- use crate :: physical_plan:: ColumnarValue ;
254+ use crate :: physical_plan:: { window_functions , ColumnarValue } ;
237255 use crate :: { assert_batches_sorted_eq, execution:: context:: ExecutionContext } ;
238256 use crate :: { physical_plan:: functions:: ScalarFunctionImplementation , test} ;
239257 use arrow:: datatypes:: DataType ;
@@ -270,6 +288,31 @@ mod tests {
270288 Ok ( ( ) )
271289 }
272290
291+ #[ tokio:: test]
292+ async fn select_with_window_exprs ( ) -> Result < ( ) > {
293+ // build plan using Table API
294+ let t = test_table ( ) . await ?;
295+ let first_row = Expr :: WindowFunction {
296+ fun : window_functions:: WindowFunction :: BuiltInWindowFunction (
297+ window_functions:: BuiltInWindowFunction :: FirstValue ,
298+ ) ,
299+ args : vec ! [ col( "aggregate_test_100.c1" ) ] ,
300+ partition_by : vec ! [ col( "aggregate_test_100.c2" ) ] ,
301+ order_by : vec ! [ ] ,
302+ window_frame : None ,
303+ } ;
304+ let t2 = t. select ( vec ! [ col( "c1" ) , first_row] ) ?;
305+ let plan = t2. to_logical_plan ( ) ;
306+
307+ let sql_plan = create_plan (
308+ "select c1, first_value(c1) over (partition by c2) from aggregate_test_100" ,
309+ )
310+ . await ?;
311+
312+ assert_same_plan ( & plan, & sql_plan) ;
313+ Ok ( ( ) )
314+ }
315+
273316 #[ tokio:: test]
274317 async fn aggregate ( ) -> Result < ( ) > {
275318 // build plan using DataFrame API
0 commit comments