@@ -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,8 @@ impl Optimizer {
372
372
let mut previous_plans = HashSet :: with_capacity ( 16 ) ;
373
373
previous_plans. insert ( LogicalPlanSignature :: new ( & new_plan) ) ;
374
374
375
+ let starting_schema = Arc :: clone ( new_plan. schema ( ) ) ;
376
+
375
377
let mut i = 0 ;
376
378
while i < options. optimizer . max_passes {
377
379
log_plan ( & format ! ( "Optimizer input (pass {i})" ) , & new_plan) ;
@@ -395,14 +397,23 @@ impl Optimizer {
395
397
None => optimize_plan_node ( new_plan, rule. as_ref ( ) , config) ,
396
398
}
397
399
. and_then ( |tnr| {
398
- // verify after each optimizer pass.
399
- assert_valid_optimization ( rule. name ( ) , & tnr. data , & starting_schema)
400
+ // in debug mode, run checks are each optimer pass
401
+ #[ cfg( debug_assertions) ]
402
+ assert_valid_optimization ( & tnr. data , & starting_schema)
403
+ . map_err ( |e| {
404
+ DataFusionError :: Context (
405
+ format ! ( "check_optimizer_specific_invariants after optimizer pass: {}" , rule. name( ) ) ,
406
+ Box :: new ( e) ,
407
+ )
408
+ } ) ?;
409
+ #[ cfg( debug_assertions) ]
410
+ tnr. data . check_invariants ( InvariantLevel :: Executable )
400
411
. map_err ( |e| {
401
- DataFusionError :: Context (
402
- "check_optimized_plan" . to_string ( ) ,
403
- Box :: new ( e) ,
404
- )
405
- } ) ?;
412
+ DataFusionError :: Context (
413
+ format ! ( "check_plan_is_executable after optimizer pass: {}" , rule . name ( ) ) ,
414
+ Box :: new ( e) ,
415
+ )
416
+ } ) ?;
406
417
407
418
Ok ( tnr)
408
419
} ) ;
@@ -463,12 +474,20 @@ impl Optimizer {
463
474
i += 1 ;
464
475
}
465
476
477
+ // verify that the optimizer passes only mutated what was permitted.
478
+ assert_valid_optimization ( & new_plan, & starting_schema) . map_err ( |e| {
479
+ DataFusionError :: Context (
480
+ "check_optimizer_specific_invariants after all passes" . to_string ( ) ,
481
+ Box :: new ( e) ,
482
+ )
483
+ } ) ?;
484
+
466
485
// verify LP is valid, after the last optimizer pass.
467
486
new_plan
468
487
. check_invariants ( InvariantLevel :: Executable )
469
488
. map_err ( |e| {
470
489
DataFusionError :: Context (
471
- "check_plan_after_optimizers " . to_string ( ) ,
490
+ "check_plan_is_executable after optimizers " . to_string ( ) ,
472
491
Box :: new ( e) ,
473
492
)
474
493
} ) ?;
@@ -479,19 +498,18 @@ impl Optimizer {
479
498
}
480
499
}
481
500
482
- /// These are invariants which should hold true before and after each optimization.
501
+ /// These are invariants which should hold true before and after [`LogicalPlan`] optimization.
483
502
///
484
503
/// This differs from [`LogicalPlan::check_invariants`], which addresses if a singular
485
504
/// LogicalPlan is valid. Instead this address if the optimization (before and after)
486
505
/// is 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