1818//! [`FileScanConfig`] to configure scanning of possibly partitioned
1919//! file sources.
2020
21+ use crate :: file:: ProjectionPushdownResult ;
2122use crate :: file_groups:: FileGroup ;
2223#[ allow( unused_imports) ]
2324use crate :: schema_adapter:: SchemaAdapterFactory ;
@@ -44,16 +45,14 @@ use datafusion_execution::{
4445 object_store:: ObjectStoreUrl , SendableRecordBatchStream , TaskContext ,
4546} ;
4647use datafusion_expr:: Operator ;
47- use datafusion_physical_expr:: expressions:: { BinaryExpr , Column } ;
48+ use datafusion_physical_expr:: expressions:: BinaryExpr ;
4849use datafusion_physical_expr:: projection:: ProjectionExprs ;
4950use datafusion_physical_expr:: utils:: reassign_expr_columns;
5051use datafusion_physical_expr:: { split_conjunction, EquivalenceProperties , Partitioning } ;
5152use datafusion_physical_expr_adapter:: PhysicalExprAdapterFactory ;
5253use datafusion_physical_expr_common:: physical_expr:: PhysicalExpr ;
5354use datafusion_physical_expr_common:: sort_expr:: LexOrdering ;
54- use datafusion_physical_plan:: projection:: {
55- all_alias_free_columns, new_projections_for_columns, ProjectionExpr ,
56- } ;
55+ use datafusion_physical_plan:: projection:: ProjectionExpr ;
5756use datafusion_physical_plan:: {
5857 display:: { display_orderings, ProjectSchemaDisplay } ,
5958 filter_pushdown:: FilterPushdownPropagation ,
@@ -679,42 +678,42 @@ impl DataSource for FileScanConfig {
679678 fn try_swapping_with_projection (
680679 & self ,
681680 projection : & [ ProjectionExpr ] ,
682- ) -> Result < Option < Arc < dyn DataSource > > > {
683- // This process can be moved into CsvExec, but it would be an overlap of their responsibility.
684-
685- // Must be all column references, with no table partition columns (which can not be projected)
686- let partitioned_columns_in_proj = projection. iter ( ) . any ( |proj_expr| {
687- proj_expr
688- . expr
689- . as_any ( )
690- . downcast_ref :: < Column > ( )
691- . map ( |expr| expr. index ( ) >= self . file_schema ( ) . fields ( ) . len ( ) )
692- . unwrap_or ( false )
693- } ) ;
681+ ) -> Result < crate :: source:: ProjectionPushdownResult > {
682+ let new_projection_exprs = ProjectionExprs :: from ( projection) ;
683+
684+ // get current projection indices if they exist
685+ let current_projection = self
686+ . projection_exprs
687+ . as_ref ( )
688+ . map ( |p| p. ordered_column_indices ( ) ) ;
689+
690+ // pass the new projections to the file source, along wiht the current projection
691+ // the file source will merge them if possible
692+ let res = self . file_source ( ) . try_pushdown_projections (
693+ & new_projection_exprs,
694+ self . file_schema ( ) ,
695+ current_projection. as_deref ( ) ,
696+ ) ?;
694697
695- // If there is any non-column or alias-carrier expression, Projection should not be removed.
696- let no_aliases = all_alias_free_columns ( projection ) ;
697-
698- Ok ( ( no_aliases && !partitioned_columns_in_proj ) . then ( || {
699- let file_scan = self . clone ( ) ;
700- let source = Arc :: clone ( & file_scan . file_source ) ;
701- let new_projections = new_projections_for_columns (
702- projection ,
703- & file_scan
704- . projection_exprs
705- . as_ref ( )
706- . map ( |p| p . ordered_column_indices ( ) )
707- . unwrap_or_else ( || ( 0 .. self . file_schema ( ) . fields ( ) . len ( ) ) . collect ( ) ) ,
708- ) ;
698+ match res {
699+ ProjectionPushdownResult :: None => Ok ( None ) ,
700+ ProjectionPushdownResult :: Partial {
701+ new_file_source ,
702+ remaining_projections ,
703+ new_projection_indices ,
704+ } => {
705+ let mut builder = FileScanConfigBuilder :: from ( self . clone ( ) ) ;
706+
707+ if let Some ( new_source ) = new_file_source {
708+ builder = builder . with_source ( new_source ) ;
709+ }
710+
711+ builder = builder . with_projection_indices ( new_projection_indices ) ;
709712
710- Arc :: new (
711- FileScanConfigBuilder :: from ( file_scan)
712- // Assign projected statistics to source
713- . with_projection_indices ( Some ( new_projections) )
714- . with_source ( source)
715- . build ( ) ,
716- ) as _
717- } ) )
713+ let new_config = Arc :: new ( builder. build ( ) ) as Arc < dyn DataSource > ;
714+ Ok ( Some ( ( new_config, remaining_projections) ) )
715+ }
716+ }
718717 }
719718
720719 fn try_pushdown_filters (
@@ -2300,7 +2299,7 @@ mod tests {
23002299
23012300 // Simulate projection being updated. Since the filter has already been pushed down,
23022301 // the new projection won't include the filtered column.
2303- let data_source = config
2302+ let ( data_source, _remaining_projections ) = config
23042303 . try_swapping_with_projection ( & [ ProjectionExpr :: new (
23052304 col ( "c3" , & file_schema) . unwrap ( ) ,
23062305 "c3" . to_string ( ) ,
0 commit comments