@@ -47,7 +47,7 @@ use crate::stream::RecordBatchStreamAdapter;
4747use  arrow:: array:: { Array ,  RecordBatch } ; 
4848use  arrow:: datatypes:: SchemaRef ; 
4949use  datafusion_common:: config:: ConfigOptions ; 
50- use  datafusion_common:: { exec_err,  Constraints ,  Result } ; 
50+ use  datafusion_common:: { exec_err,  Constraints ,  DataFusionError ,   Result } ; 
5151use  datafusion_common_runtime:: JoinSet ; 
5252use  datafusion_execution:: TaskContext ; 
5353use  datafusion_physical_expr:: EquivalenceProperties ; 
@@ -117,10 +117,11 @@ pub trait ExecutionPlan: Debug + DisplayAs + Send + Sync {
117117    /// Returns an error if this individual node does not conform to its invariants. 
118118     /// These invariants are typically only checked in debug mode. 
119119     /// 
120-      /// A default set of invariants is provided in the default implementation. 
120+      /// A default set of invariants is provided in the [check_default_invariants] function. 
121+      /// The default implementation of `check_invariants` calls this function. 
121122     /// Extension nodes can provide their own invariants. 
122-      fn  check_invariants ( & self ,  _check :  InvariantLevel )  -> Result < ( ) >  { 
123-         Ok ( ( ) ) 
123+      fn  check_invariants ( & self ,  check :  InvariantLevel )  -> Result < ( ) >  { 
124+         check_default_invariants ( self ,  check ) 
124125    } 
125126
126127    /// Specifies the data distribution requirements for all the 
@@ -1035,6 +1036,37 @@ impl PlanProperties {
10351036    } 
10361037} 
10371038
1039+ macro_rules!  check_len { 
1040+     ( $target: expr,  $func_name: ident,  $expected_len: expr)  => { 
1041+         let  actual_len = $target. $func_name( ) . len( ) ; 
1042+         if  actual_len != $expected_len { 
1043+             return  internal_err!( 
1044+                 "{}::{} returned Vec with incorrect size: {} != {}" , 
1045+                 $target. name( ) , 
1046+                 stringify!( $func_name) , 
1047+                 actual_len, 
1048+                 $expected_len
1049+             ) ; 
1050+         } 
1051+     } ; 
1052+ } 
1053+ 
1054+ /// Checks a set of invariants that apply to all ExecutionPlan implementations. 
1055+ /// Returns an error if the given node does not conform. 
1056+ pub  fn  check_default_invariants < P :  ExecutionPlan  + ?Sized > ( 
1057+     plan :  & P , 
1058+     _check :  InvariantLevel , 
1059+ )  -> Result < ( ) ,  DataFusionError >  { 
1060+     let  children_len = plan. children ( ) . len ( ) ; 
1061+ 
1062+     check_len ! ( plan,  maintains_input_order,  children_len) ; 
1063+     check_len ! ( plan,  required_input_ordering,  children_len) ; 
1064+     check_len ! ( plan,  required_input_distribution,  children_len) ; 
1065+     check_len ! ( plan,  benefits_from_input_partitioning,  children_len) ; 
1066+ 
1067+     Ok ( ( ) ) 
1068+ } 
1069+ 
10381070/// Indicate whether a data exchange is needed for the input of `plan`, which will be very helpful 
10391071/// especially for the distributed engine to judge whether need to deal with shuffling. 
10401072/// Currently, there are 3 kinds of execution plan which needs data exchange 
0 commit comments