This is an automated email from the ASF dual-hosted git repository.

Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 2cc31af529 GH-10676: Fix IPC StreamReader projected schema (#10677)
2cc31af529 is described below

commit 2cc31af5297492b41ddf4b8f9f0d33ff15d9a400
Author: anchor <[email protected]>
AuthorDate: Sat Aug 15 22:21:34 2026 +0800

    GH-10676: Fix IPC StreamReader projected schema (#10677)
    
    # Which issue does this PR close?
    
    - Closes #10676.
    
    # Rationale for this change
    
    With a projection set, `StreamReader` yields batches with the projected
    schema, but `StreamReader::schema()` and its
    `RecordBatchReader::schema()` impl return the full stream schema. Same
    as #10382 (csv) and #10613 (ipc file reader); #10627 fixed `FileReader`,
    `StreamReader` was the remaining case.
    
    # What changes are included in this PR?
    
    - Keep the projected schema `StreamReader::try_new` already computes as
    a `SchemaRef` and return it from `StreamReader::schema()`; the
    `RecordBatchReader` impl delegates to it, as `FileReader` does.
    - Decoding is untouched: batch and dictionary decoding still use the
    full stream schema, and with no projection the reported schema is
    unchanged.
    - Add a regression test mirroring
    `test_file_reader_projected_schema_matches_batch_schema`.
    
    # Are these changes tested?
    
    Yes, the new test fails before this change (14 column stream schema vs 3
    column batch schema) and passes after. I ran:
    
    - `cargo test -p arrow-ipc` (143 passed) and `--all-features` (148
    passed)
    - `cargo clippy -p arrow-ipc --all-targets --all-features -- -D
    warnings`
    - `cargo fmt --all -- --check`
    
    I did not run the full workspace suite; outside `arrow-ipc` every
    `StreamReader::try_new` call site passes `None`, which is unaffected.
    
    # Are there any user-facing changes?
    
    Yes. A projected IPC `StreamReader` now reports the same schema as the
    batches it produces. No public API signature changes.
    
    AI assistance: an AI agent found this by auditing the remaining
    `RecordBatchReader` impls after #10613 and drafted the fix and its test;
    I reviewed every line and ran the reproduction and the checks above
    locally.
    
    Co-authored-by: codeAnqiang-ma 
<[email protected]>
---
 arrow-ipc/src/reader.rs | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/arrow-ipc/src/reader.rs b/arrow-ipc/src/reader.rs
index 99e7c89c9c..c0d99c370e 100644
--- a/arrow-ipc/src/reader.rs
+++ b/arrow-ipc/src/reader.rs
@@ -1541,8 +1541,8 @@ pub struct StreamReader<R> {
     /// This value is set to `true` the first time the reader's `next()` 
returns `None`.
     finished: bool,
 
-    /// Optional projection
-    projection: Option<(Vec<usize>, Schema)>,
+    /// Optional projection: column indices and the resulting projected schema
+    projection: Option<(Vec<usize>, SchemaRef)>,
 
     /// Should validation be skipped when reading data? Defaults to false.
     ///
@@ -1612,7 +1612,7 @@ impl<R: Read> StreamReader<R> {
 
         let projection = match projection {
             Some(projection_indices) => {
-                let schema = schema.project(&projection_indices)?;
+                let schema = Arc::new(schema.project(&projection_indices)?);
                 Some((projection_indices, schema))
             }
             _ => None,
@@ -1628,9 +1628,12 @@ impl<R: Read> StreamReader<R> {
         })
     }
 
-    /// Return the schema of the stream
+    /// Return the schema of the record batches produced by this reader
     pub fn schema(&self) -> SchemaRef {
-        self.schema.clone()
+        match &self.projection {
+            Some((_, projected_schema)) => projected_schema.clone(),
+            None => self.schema.clone(),
+        }
     }
 
     /// Check if the stream is finished
@@ -1786,7 +1789,7 @@ impl<R: Read> Iterator for StreamReader<R> {
 
 impl<R: Read> RecordBatchReader for StreamReader<R> {
     fn schema(&self) -> SchemaRef {
-        self.schema.clone()
+        self.schema()
     }
 }
 
@@ -2378,6 +2381,26 @@ mod tests {
         assert_eq!(reader_schema, read_batch.schema());
     }
 
+    #[test]
+    fn test_stream_reader_projected_schema_matches_batch_schema() {
+        let schema = create_test_projection_schema();
+        let batch = create_test_projection_batch_data(&schema);
+
+        let mut buf = Vec::new();
+        {
+            let mut writer = crate::writer::StreamWriter::try_new(&mut buf, 
&schema).unwrap();
+            writer.write(&batch).unwrap();
+            writer.finish().unwrap();
+        }
+
+        let projection = vec![3, 2, 1];
+        let mut reader = StreamReader::try_new(Cursor::new(buf), 
Some(projection)).unwrap();
+        let reader_schema = RecordBatchReader::schema(&reader);
+        let read_batch = reader.next().unwrap().unwrap();
+
+        assert_eq!(reader_schema, read_batch.schema());
+    }
+
     #[test]
     fn test_file_reader_rejects_invalid_projection() {
         let schema = create_test_projection_schema();

Reply via email to