@@ -368,8 +368,8 @@ impl CommonSubexprEliminate {
368
368
369
369
None => Ok ( ( new_window_expr_list, input, None ) ) ,
370
370
} ) ?
371
- // Recurse into the new input. this is similar to top-down optimizer rule's
372
- // logic.
371
+ // Recurse into the new input.
372
+ // (This is similar to what a `ApplyOrder::TopDown` optimizer rule would do.)
373
373
. transform_data ( |( new_window_expr_list, new_input, window_expr_list) | {
374
374
self . rewrite ( new_input, config) ?. map_data ( |new_input| {
375
375
Ok ( ( new_window_expr_list, new_input, window_expr_list) )
@@ -467,8 +467,8 @@ impl CommonSubexprEliminate {
467
467
None => Ok ( ( new_aggr_expr, new_group_expr, input, None ) ) ,
468
468
}
469
469
} ) ?
470
- // Recurse into the new input. this is similar to top-down optimizer rule's
471
- // logic.
470
+ // Recurse into the new input.
471
+ // (This is similar to what a `ApplyOrder::TopDown` optimizer rule would do.)
472
472
. transform_data ( |( new_aggr_expr, new_group_expr, new_input, aggr_expr) | {
473
473
self . rewrite ( new_input, config) ?. map_data ( |new_input| {
474
474
Ok ( (
@@ -636,8 +636,8 @@ impl CommonSubexprEliminate {
636
636
None => Ok ( ( new_exprs, input) ) ,
637
637
}
638
638
} ) ?
639
- // Recurse into the new input. This is similar to top-down optimizer rule's
640
- // logic.
639
+ // Recurse into the new input.
640
+ // (This is similar to what a `ApplyOrder::TopDown` optimizer rule would do.)
641
641
. transform_data ( |( new_exprs, new_input) | {
642
642
self . rewrite ( new_input, config) ?
643
643
. map_data ( |new_input| Ok ( ( new_exprs, new_input) ) )
@@ -702,7 +702,10 @@ impl OptimizerRule for CommonSubexprEliminate {
702
702
}
703
703
704
704
fn apply_order ( & self ) -> Option < ApplyOrder > {
705
- Some ( ApplyOrder :: TopDown )
705
+ // This rule handles recursion itself in a `ApplyOrder::TopDown` like manner.
706
+ // This is because in some cases adjacent nodes are collected (e.g. `Window`) and
707
+ // CSEd as a group, which can't be done in a simple `ApplyOrder::TopDown` rule.
708
+ None
706
709
}
707
710
708
711
fn rewrite (
@@ -740,8 +743,9 @@ impl OptimizerRule for CommonSubexprEliminate {
740
743
| LogicalPlan :: Unnest ( _)
741
744
| LogicalPlan :: RecursiveQuery ( _)
742
745
| LogicalPlan :: Prepare ( _) => {
743
- // ApplyOrder::TopDown handles recursion
744
- Transformed :: no ( plan)
746
+ // This rule handles recursion itself in a `ApplyOrder::TopDown` like
747
+ // manner.
748
+ plan. map_children ( |c| self . rewrite ( c, config) ) ?
745
749
}
746
750
} ;
747
751
@@ -1187,42 +1191,22 @@ mod test {
1187
1191
} ;
1188
1192
use datafusion_expr:: { lit, logical_plan:: builder:: LogicalPlanBuilder } ;
1189
1193
1194
+ use super :: * ;
1190
1195
use crate :: optimizer:: OptimizerContext ;
1191
1196
use crate :: test:: * ;
1197
+ use crate :: Optimizer ;
1192
1198
use datafusion_expr:: test:: function_stub:: { avg, sum} ;
1193
1199
1194
- use super :: * ;
1195
-
1196
- fn assert_non_optimized_plan_eq (
1197
- expected : & str ,
1198
- plan : LogicalPlan ,
1199
- config : Option < & dyn OptimizerConfig > ,
1200
- ) {
1201
- assert_eq ! ( expected, format!( "{plan}" ) , "Unexpected starting plan" ) ;
1202
- let optimizer = CommonSubexprEliminate :: new ( ) ;
1203
- let default_config = OptimizerContext :: new ( ) ;
1204
- let config = config. unwrap_or ( & default_config) ;
1205
- let optimized_plan = optimizer. rewrite ( plan, config) . unwrap ( ) ;
1206
- assert ! ( !optimized_plan. transformed, "unexpectedly optimize plan" ) ;
1207
- let optimized_plan = optimized_plan. data ;
1208
- assert_eq ! (
1209
- expected,
1210
- format!( "{optimized_plan}" ) ,
1211
- "Unexpected optimized plan"
1212
- ) ;
1213
- }
1214
-
1215
1200
fn assert_optimized_plan_eq (
1216
1201
expected : & str ,
1217
1202
plan : LogicalPlan ,
1218
1203
config : Option < & dyn OptimizerConfig > ,
1219
1204
) {
1220
- let optimizer = CommonSubexprEliminate :: new ( ) ;
1205
+ let optimizer =
1206
+ Optimizer :: with_rules ( vec ! [ Arc :: new( CommonSubexprEliminate :: new( ) ) ] ) ;
1221
1207
let default_config = OptimizerContext :: new ( ) ;
1222
1208
let config = config. unwrap_or ( & default_config) ;
1223
- let optimized_plan = optimizer. rewrite ( plan, config) . unwrap ( ) ;
1224
- assert ! ( optimized_plan. transformed, "failed to optimize plan" ) ;
1225
- let optimized_plan = optimized_plan. data ;
1209
+ let optimized_plan = optimizer. optimize ( plan, config, |_, _| ( ) ) . unwrap ( ) ;
1226
1210
let formatted_plan = format ! ( "{optimized_plan}" ) ;
1227
1211
assert_eq ! ( expected, formatted_plan) ;
1228
1212
}
@@ -1612,7 +1596,7 @@ mod test {
1612
1596
let expected = "Projection: Int32(1) + test.a, test.a + Int32(1)\
1613
1597
\n TableScan: test";
1614
1598
1615
- assert_non_optimized_plan_eq ( expected, plan, None ) ;
1599
+ assert_optimized_plan_eq ( expected, plan, None ) ;
1616
1600
1617
1601
Ok ( ( ) )
1618
1602
}
@@ -1630,7 +1614,7 @@ mod test {
1630
1614
\n Projection: Int32(1) + test.a, test.a\
1631
1615
\n TableScan: test";
1632
1616
1633
- assert_non_optimized_plan_eq ( expected, plan, None ) ;
1617
+ assert_optimized_plan_eq ( expected, plan, None ) ;
1634
1618
Ok ( ( ) )
1635
1619
}
1636
1620
0 commit comments