@@ -3695,3 +3695,38 @@ fn adjust_input_keys_ordering_no_transform_for_filter_scan() -> Result<()> {
36953695 ) ;
36963696 Ok ( ( ) )
36973697}
3698+
3699+ /// Verifies the `ensure_distribution` fast path: when no child of a node is
3700+ /// replaced (no `RepartitionExec` or `SortExec` injection is required),
3701+ /// the rule must reuse the input `Arc<dyn ExecutionPlan>` unchanged instead
3702+ /// of calling `with_new_children`. For a deep `ProjectionExec` chain over a
3703+ /// single-partition scan with `target_partitions = 1`, every node hits this
3704+ /// fast path, so the root returned by `ensure_distribution` must be the
3705+ /// same `Arc` as the input.
3706+ ///
3707+ /// Regression test for the optimization that avoids
3708+ /// `ProjectionExec::with_new_children` (which recomputes schema, equivalence
3709+ /// properties, output ordering, and partitioning) on the common point-query
3710+ /// plan shape. Cherry-pick of upstream apache/datafusion#22521.
3711+ #[ test]
3712+ fn ensure_distribution_reuses_plan_arc_when_no_redistribution_needed ( ) -> Result < ( ) > {
3713+ let scan = parquet_exec ( ) ;
3714+ let proj1 = projection_exec_with_alias (
3715+ scan,
3716+ vec ! [
3717+ ( "a" . to_string( ) , "a" . to_string( ) ) ,
3718+ ( "b" . to_string( ) , "b" . to_string( ) ) ,
3719+ ] ,
3720+ ) ;
3721+ let proj2 =
3722+ projection_exec_with_alias ( proj1, vec ! [ ( "a" . to_string( ) , "a" . to_string( ) ) ] ) ;
3723+ let plan: Arc < dyn ExecutionPlan > = proj2;
3724+
3725+ let result = ensure_distribution_helper ( Arc :: clone ( & plan) , 1 , false ) ?;
3726+
3727+ assert ! (
3728+ Arc :: ptr_eq( & result, & plan) ,
3729+ "ensure_distribution must reuse the input Arc when no children require redistribution"
3730+ ) ;
3731+ Ok ( ( ) )
3732+ }
0 commit comments