| 102 | #[async_trait] |
| 103 | impl FormatFileReader for VortexFormatReader { |
| 104 | async fn read_batch_stream( |
| 105 | &self, |
| 106 | reader: Box<dyn FileRead>, |
| 107 | file_size: u64, |
| 108 | read_fields: &[DataField], |
| 109 | predicates: Option<&FilePredicates>, |
| 110 | _batch_size: Option<usize>, |
| 111 | row_selection: Option<Vec<RowRange>>, |
| 112 | ) -> crate::Result<ArrowRecordBatchStream> { |
| 113 | let session = VortexSession::default(); |
| 114 | |
| 115 | let source = Arc::new(PaimonVortexReadAt { |
| 116 | file_size, |
| 117 | reader: Arc::from(reader), |
| 118 | }); |
| 119 | |
| 120 | let vortex_file = session |
| 121 | .open_options() |
| 122 | .with_file_size(file_size) |
| 123 | .open(source) |
| 124 | .await |
| 125 | .map_err(|e| Error::DataInvalid { |
| 126 | message: format!("Failed to open Vortex file: {e}"), |
| 127 | source: None, |
| 128 | })?; |
| 129 | |
| 130 | // Build the target Arrow schema for the projected fields. |
| 131 | let target_schema = crate::arrow::build_target_arrow_schema(read_fields)?; |
| 132 | |
| 133 | if read_fields.is_empty() { |
| 134 | let row_count = match &row_selection { |
| 135 | Some(ranges) => ranges.iter().map(|r| r.count() as usize).sum(), |
| 136 | None => vortex_file.row_count() as usize, |
| 137 | }; |
| 138 | let batch = RecordBatch::try_new_with_options( |
| 139 | target_schema, |
| 140 | vec![], |
| 141 | &arrow_array::RecordBatchOptions::new().with_row_count(Some(row_count)), |
| 142 | ) |
| 143 | .map_err(|e| Error::DataInvalid { |
| 144 | message: format!("Failed to build empty RecordBatch: {e}"), |
| 145 | source: None, |
| 146 | })?; |
| 147 | return Ok(Box::pin(futures::stream::once(async { Ok(batch) }))); |
| 148 | } |
| 149 | |
| 150 | // Build projection expression for requested fields. |
| 151 | let projected_names: Vec<&str> = read_fields.iter().map(|f| f.name()).collect(); |
| 152 | |
| 153 | let mut scan_builder = vortex_file.scan().map_err(|e| Error::DataInvalid { |
| 154 | message: format!("Failed to create Vortex scan: {e}"), |
| 155 | source: None, |
| 156 | })?; |
| 157 | |
| 158 | // Apply column projection. |
| 159 | { |
| 160 | use vortex::array::expr::{root, select}; |
| 161 | scan_builder = scan_builder.with_projection(select(projected_names, root())); |