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
27 changes: 12 additions & 15 deletions datafusion/proto/src/physical_plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,15 +1179,11 @@ pub trait PhysicalPlanNodeExt: Sized {
})?;
let schema: SchemaRef = SchemaRef::new(proto_schema.try_into()?);

let projection = if !scan.projection.is_empty() {
Some(
scan.projection
.iter()
.map(|i| *i as usize)
.collect::<Vec<_>>(),
)
} else {
None
// Preserve the empty-projection sentinel written by `try_from_data_source_exec`.
let projection = match scan.projection.as_slice() {
[] => None,
[u32::MAX] => Some(Vec::new()),
indices => Some(indices.iter().map(|i| *i as usize).collect()),
};

let mut sort_information = vec![];
Expand Down Expand Up @@ -2364,12 +2360,13 @@ pub trait PhysicalPlanNodeExt: Sized {
let proto_schema: protobuf::Schema =
source_conf.original_schema().as_ref().try_into()?;

let proto_projection = source_conf
.projection()
.as_ref()
.map_or_else(Vec::new, |v| {
v.iter().map(|x| *x as u32).collect::<Vec<u32>>()
});
// Proto3 can't tell `None` from `Some(vec![])`; encode the latter
// as the `[u32::MAX]` sentinel, matching the join/filter nodes.
let proto_projection = match source_conf.projection().as_ref() {
None => Vec::new(),
Some(v) if v.is_empty() => vec![u32::MAX],
Some(v) => v.iter().map(|x| *x as u32).collect(),
};
Comment on lines +2363 to +2369

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this is a wire format change but it only impacts the already broken empty projection case, so it seems justified.


let proto_sort_information = source_conf
.sort_information()
Expand Down
19 changes: 19 additions & 0 deletions datafusion/proto/tests/cases/roundtrip_physical_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,25 @@ async fn roundtrip_empty_projection() -> Result<()> {
roundtrip_test_sql_with_context(sql, &ctx).await
}

#[tokio::test]
async fn roundtrip_memory_source_empty_projection() -> Result<()> {
// Memory scan: `Some(vec![])` must not decode back as `None`
let ctx = SessionContext::new();
let batch = RecordBatch::try_new(
Arc::new(Schema::new(vec![
Field::new("a", DataType::Utf8, false),
Field::new("b", DataType::Int64, false),
])),
vec![
Arc::new(arrow::array::StringArray::from(vec!["Tom"])),
Arc::new(arrow::array::Int64Array::from(vec![18i64])),
],
)?;
ctx.register_batch("tmem", batch)?;
let sql = "select 1 from tmem";
roundtrip_test_sql_with_context(sql, &ctx).await
}

#[tokio::test]
async fn roundtrip_physical_plan_node() {
use datafusion::prelude::*;
Expand Down
Loading