@@ -968,6 +968,7 @@ fn is_projection_removable(projection: &ProjectionExec) -> bool {
968968 } ;
969969 col. name ( ) == proj_expr. alias && col. index ( ) == idx
970970 } ) && exprs. len ( ) == projection. input ( ) . schema ( ) . fields ( ) . len ( )
971+ && projection. schema ( ) == projection. input ( ) . schema ( )
971972}
972973
973974/// Given the expression set of a projection, checks if the projection causes
@@ -1006,8 +1007,12 @@ pub fn make_with_child(
10061007 projection : & ProjectionExec ,
10071008 child : & Arc < dyn ExecutionPlan > ,
10081009) -> Result < Arc < dyn ExecutionPlan > > {
1009- ProjectionExec :: try_new ( projection. expr ( ) . to_vec ( ) , Arc :: clone ( child) )
1010- . map ( |e| Arc :: new ( e) as _ )
1010+ ProjectionExec :: try_new_with_schema_metadata (
1011+ projection. expr ( ) . to_vec ( ) ,
1012+ Arc :: clone ( child) ,
1013+ projection. schema ( ) . as_ref ( ) ,
1014+ )
1015+ . map ( |e| Arc :: new ( e) as _ )
10111016}
10121017
10131018/// Returns `true` if all the expressions in the argument are `Column`s.
@@ -1441,6 +1446,7 @@ mod tests {
14411446 use crate :: statistics:: { StatisticsArgs , StatisticsContext } ;
14421447 use crate :: test;
14431448 use crate :: test:: exec:: StatisticsExec ;
1449+ use crate :: union:: UnionExec ;
14441450
14451451 use arrow:: datatypes:: { DataType , Field , Schema } ;
14461452 use datafusion_common:: ScalarValue ;
@@ -1491,6 +1497,38 @@ mod tests {
14911497 Ok ( ( ) )
14921498 }
14931499
1500+ #[ test]
1501+ fn test_projection_pushdown_preserves_output_metadata ( ) -> Result < ( ) > {
1502+ let input_schema = Arc :: new ( Schema :: new ( vec ! [
1503+ Field :: new( "input" , DataType :: Int32 , false ) . with_metadata( HashMap :: from( [ (
1504+ "source" . to_string( ) ,
1505+ "input" . to_string( ) ,
1506+ ) ] ) ) ,
1507+ Field :: new( "unused" , DataType :: Int32 , false ) ,
1508+ ] ) ) ;
1509+ let input: Arc < dyn ExecutionPlan > = UnionExec :: try_new ( vec ! [
1510+ Arc :: new( EmptyExec :: new( Arc :: clone( & input_schema) ) ) ,
1511+ Arc :: new( EmptyExec :: new( input_schema) ) ,
1512+ ] ) ?;
1513+ let projected_schema =
1514+ Schema :: new ( vec ! [ Field :: new( "input" , DataType :: Int32 , false ) ] ) ;
1515+ let projection = ProjectionExec :: try_new_with_schema_metadata (
1516+ [ ProjectionExpr {
1517+ expr : Arc :: new ( Column :: new ( "input" , 0 ) ) ,
1518+ alias : "input" . to_string ( ) ,
1519+ } ] ,
1520+ input,
1521+ & projected_schema,
1522+ ) ?;
1523+
1524+ assert ! ( !is_projection_removable( & projection) ) ;
1525+ let plan: Arc < dyn ExecutionPlan > = Arc :: new ( projection) ;
1526+ let optimized = remove_unnecessary_projections ( Arc :: clone ( & plan) ) ?;
1527+ assert ! ( optimized. transformed) ;
1528+ assert_eq ! ( optimized. data. schema( ) , plan. schema( ) ) ;
1529+ Ok ( ( ) )
1530+ }
1531+
14941532 #[ test]
14951533 fn test_collect_column_indices ( ) -> Result < ( ) > {
14961534 let expr = Arc :: new ( BinaryExpr :: new (
0 commit comments