Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions datafusion/physical-plan/src/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,20 +652,33 @@ impl ExecutionPlan for ProjectionExec {
metrics: _,
// Derived plan properties, recomputed on decode.
cache: _,
// Derived metadata comparison, recomputed with the projector.
overrides_metadata: _,
overrides_metadata,
} = self;
let projection_exprs = projector.projection().as_ref();
let input = ctx.encode_child(input)?;
let expr = ctx.encode_expressions(projection_exprs.iter().map(|p| &p.expr))?;
let expr_name = projection_exprs.iter().map(|p| p.alias.clone()).collect();
let output_schema = projector.output_schema();
// Preserve explicit overrides and field metadata that cannot be
// reconstructed from the child. Inherited schema metadata can be.
let schema = if *overrides_metadata
|| output_schema
.fields()
.iter()
.any(|field| !field.metadata().is_empty())
{
Some(output_schema.as_ref().try_into()?)
} else {
None
};
Ok(Some(protobuf::PhysicalPlanNode {
physical_plan_type: Some(
protobuf::physical_plan_node::PhysicalPlanType::Projection(Box::new(
protobuf::ProjectionExecNode {
input: Some(Box::new(input)),
expr,
expr_name,
schema,
},
)),
),
Expand Down Expand Up @@ -701,6 +714,7 @@ impl ProjectionExec {
input,
expr,
expr_name,
schema,
} = &**projection;
let input =
ctx.decode_required_child(input.as_deref(), "ProjectionExec", "input")?;
Expand All @@ -715,7 +729,15 @@ impl ProjectionExec {
})
})
.collect::<Result<Vec<ProjectionExpr>>>()?;
Ok(Arc::new(ProjectionExec::try_new(exprs, input)?))
let projection = match schema {
Some(schema) => ProjectionExec::try_new_with_schema_metadata(
exprs,
input,
&Schema::try_from(schema)?,
)?,
None => ProjectionExec::try_new(exprs, input)?,
};
Ok(Arc::new(projection))
}
}

Expand Down
5 changes: 5 additions & 0 deletions datafusion/proto-models/proto/datafusion.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,11 @@ message ProjectionExecNode {
PhysicalPlanNode input = 1;
repeated PhysicalExprNode expr = 2;
repeated string expr_name = 3;
// Only field and schema metadata are used; output types are derived from expr.
// Present when the projection output has metadata or explicitly overrides
// inherited metadata, including an explicit clear. Absent for older plans
// and metadata-free projections.
datafusion_common.Schema schema = 4;
}

enum AggregateMode {
Expand Down
17 changes: 17 additions & 0 deletions datafusion/proto-models/src/generated/pbjson.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24658,6 +24658,9 @@ impl serde::Serialize for ProjectionExecNode {
if !self.expr_name.is_empty() {
len += 1;
}
if self.schema.is_some() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("datafusion.ProjectionExecNode", len)?;
if let Some(v) = self.input.as_ref() {
struct_ser.serialize_field("input", v)?;
Expand All @@ -24668,6 +24671,9 @@ impl serde::Serialize for ProjectionExecNode {
if !self.expr_name.is_empty() {
struct_ser.serialize_field("exprName", &self.expr_name)?;
}
if let Some(v) = self.schema.as_ref() {
struct_ser.serialize_field("schema", v)?;
}
struct_ser.end()
}
}
Expand All @@ -24682,13 +24688,15 @@ impl<'de> serde::Deserialize<'de> for ProjectionExecNode {
"expr",
"expr_name",
"exprName",
"schema",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
Input,
Expr,
ExprName,
Schema,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
Expand All @@ -24713,6 +24721,7 @@ impl<'de> serde::Deserialize<'de> for ProjectionExecNode {
"input" => Ok(GeneratedField::Input),
"expr" => Ok(GeneratedField::Expr),
"exprName" | "expr_name" => Ok(GeneratedField::ExprName),
"schema" => Ok(GeneratedField::Schema),
_ => Err(serde::de::Error::unknown_field(value, FIELDS)),
}
}
Expand All @@ -24735,6 +24744,7 @@ impl<'de> serde::Deserialize<'de> for ProjectionExecNode {
let mut input__ = None;
let mut expr__ = None;
let mut expr_name__ = None;
let mut schema__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Input => {
Expand All @@ -24755,12 +24765,19 @@ impl<'de> serde::Deserialize<'de> for ProjectionExecNode {
}
expr_name__ = Some(map_.next_value()?);
}
GeneratedField::Schema => {
if schema__.is_some() {
return Err(serde::de::Error::duplicate_field("schema"));
}
schema__ = map_.next_value()?;
}
}
}
Ok(ProjectionExecNode {
input: input__,
expr: expr__.unwrap_or_default(),
expr_name: expr_name__.unwrap_or_default(),
schema: schema__,
})
}
}
Expand Down
6 changes: 6 additions & 0 deletions datafusion/proto-models/src/generated/prost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2302,6 +2302,12 @@ pub struct ProjectionExecNode {
pub expr: ::prost::alloc::vec::Vec<PhysicalExprNode>,
#[prost(string, repeated, tag = "3")]
pub expr_name: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
/// Only field and schema metadata are used; output types are derived from expr.
/// Present when the projection output has metadata or explicitly overrides
/// inherited metadata, including an explicit clear. Absent for older plans
/// and metadata-free projections.
#[prost(message, optional, tag = "4")]
pub schema: ::core::option::Option<super::datafusion_common::Schema>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct PartiallySortedInputOrderMode {
Expand Down
Loading
Loading