Skip to content

Commit b1657a1

Browse files
committed
Preserve metadata-changing projections
1 parent d9f1b2a commit b1657a1

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

datafusion/physical-plan/src/projection.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)