@@ -360,7 +360,7 @@ impl Optimizer {
360
360
plan. check_invariants ( InvariantLevel :: Executable )
361
361
. map_err ( |e| {
362
362
DataFusionError :: Context (
363
- "check_plan_before_optimizers " . to_string ( ) ,
363
+ "check_plan_is_executable before optimizers " . to_string ( ) ,
364
364
Box :: new ( e) ,
365
365
)
366
366
} ) ?;
@@ -372,6 +372,9 @@ impl Optimizer {
372
372
let mut previous_plans = HashSet :: with_capacity ( 16 ) ;
373
373
previous_plans. insert ( LogicalPlanSignature :: new ( & new_plan) ) ;
374
374
375
+ #[ cfg( debug_assertions) ]
376
+ let starting_schema = Arc :: clone ( new_plan. schema ( ) ) ;
377
+
375
378
let mut i = 0 ;
376
379
while i < options. optimizer . max_passes {
377
380
log_plan ( & format ! ( "Optimizer input (pass {i})" ) , & new_plan) ;
@@ -395,14 +398,23 @@ impl Optimizer {
395
398
None => optimize_plan_node ( new_plan, rule. as_ref ( ) , config) ,
396
399
}
397
400
. and_then ( |tnr| {
398
- // verify after each optimizer pass.
399
- assert_valid_optimization ( rule. name ( ) , & tnr. data , & starting_schema)
401
+ // in debug mode, run checks are each optimer pass
402
+ #[ cfg( debug_assertions) ]
403
+ assert_valid_optimization ( & tnr. data , & starting_schema)
404
+ . map_err ( |e| {
405
+ DataFusionError :: Context (
406
+ format ! ( "check_optimizer_specific_invariants after optimizer pass: {}" , rule. name( ) ) ,
407
+ Box :: new ( e) ,
408
+ )
409
+ } ) ?;
410
+ #[ cfg( debug_assertions) ]
411
+ tnr. data . check_invariants ( InvariantLevel :: Executable )
400
412
. map_err ( |e| {
401
- DataFusionError :: Context (
402
- "check_optimized_plan" . to_string ( ) ,
403
- Box :: new ( e) ,
404
- )
405
- } ) ?;
413
+ DataFusionError :: Context (
414
+ format ! ( "check_plan_is_executable after optimizer pass: {}" , rule . name ( ) ) ,
415
+ Box :: new ( e) ,
416
+ )
417
+ } ) ?;
406
418
407
419
Ok ( tnr)
408
420
} ) ;
@@ -463,12 +475,20 @@ impl Optimizer {
463
475
i += 1 ;
464
476
}
465
477
478
+ // verify that the optimizer passes only mutated what was permitted.
479
+ assert_valid_optimization ( & new_plan, & starting_schema) . map_err ( |e| {
480
+ DataFusionError :: Context (
481
+ "check_optimizer_specific_invariants after all passes" . to_string ( ) ,
482
+ Box :: new ( e) ,
483
+ )
484
+ } ) ?;
485
+
466
486
// verify LP is valid, after the last optimizer pass.
467
487
new_plan
468
488
. check_invariants ( InvariantLevel :: Executable )
469
489
. map_err ( |e| {
470
490
DataFusionError :: Context (
471
- "check_plan_after_optimizers " . to_string ( ) ,
491
+ "check_plan_is_executable after optimizers " . to_string ( ) ,
472
492
Box :: new ( e) ,
473
493
)
474
494
} ) ?;
@@ -479,19 +499,17 @@ impl Optimizer {
479
499
}
480
500
}
481
501
482
- /// These are invariants which should hold true before and after each optimization.
502
+ /// These are invariants which should hold true before and after [`LogicalPlan`] optimization.
483
503
///
484
504
/// This differs from [`LogicalPlan::check_invariants`], which addresses if a singular
485
- /// LogicalPlan is valid. Instead this address if the optimization (before and after)
486
- /// is valid based upon permitted changes.
505
+ /// LogicalPlan is valid. Instead this address if the optimization was valid based upon permitted changes.
487
506
fn assert_valid_optimization (
488
- rule_name : & str ,
489
507
plan : & LogicalPlan ,
490
508
prev_schema : & Arc < DFSchema > ,
491
509
) -> Result < ( ) > {
492
- // verify invariant: optimizer rule didn't change the schema
510
+ // verify invariant: optimizer passes should not change the schema
493
511
// Refer to <https://datafusion.apache.org/contributor-guide/specification/invariants.html#logical-schema-is-invariant-under-logical-optimization>
494
- assert_expected_schema ( rule_name , prev_schema, plan) ?;
512
+ assert_expected_schema ( prev_schema, plan) ?;
495
513
496
514
Ok ( ( ) )
497
515
}
@@ -549,8 +567,8 @@ mod tests {
549
567
let err = opt. optimize ( plan, & config, & observe) . unwrap_err ( ) ;
550
568
assert_eq ! (
551
569
"Optimizer rule 'get table_scan rule' failed\n \
552
- caused by\n check_optimized_plan \ n\
553
- caused by \n get table_scan rule\n \
570
+ caused by\n \
571
+ check_optimizer_specific_invariants after optimizer pass: get table_scan rule\n \
554
572
caused by\n \
555
573
Internal error: Failed due to a difference in schemas, \
556
574
original schema: DFSchema { inner: Schema { \
0 commit comments