@@ -75,6 +75,13 @@ pub trait ArrayBatchDecoder: Send {
7575 batch_size : usize ,
7676 parent_present : Option < & NullBuffer > ,
7777 ) -> Result < ArrayRef > ;
78+
79+ /// Skip the next `n` values without decoding them, failing if it cannot skip the enough values.
80+ /// If parent nested type (e.g. Struct) indicates a null in it's PRESENT stream,
81+ /// then the child doesn't have a value (similar to other nullability). So we need
82+ /// to take care to insert these null values as Arrow requires the child to hold
83+ /// data in the null slot of the child.
84+ fn skip_values ( & mut self , n : usize , parent_present : Option < & NullBuffer > ) -> Result < ( ) > ;
7885}
7986
8087struct PrimitiveArrayDecoder < T : ArrowPrimitiveType > {
@@ -123,6 +130,12 @@ impl<T: ArrowPrimitiveType> ArrayBatchDecoder for PrimitiveArrayDecoder<T> {
123130 let array = Arc :: new ( array) as ArrayRef ;
124131 Ok ( array)
125132 }
133+
134+ fn skip_values ( & mut self , n : usize , parent_present : Option < & NullBuffer > ) -> Result < ( ) > {
135+ let non_null_count =
136+ skip_present_and_get_non_null_count ( & mut self . present , parent_present, n) ?;
137+ self . iter . skip ( non_null_count)
138+ }
126139}
127140
128141type Int64ArrayDecoder = PrimitiveArrayDecoder < Int64Type > ;
@@ -168,6 +181,12 @@ impl ArrayBatchDecoder for BooleanArrayDecoder {
168181 } ;
169182 Ok ( Arc :: new ( array) )
170183 }
184+
185+ fn skip_values ( & mut self , n : usize , parent_present : Option < & NullBuffer > ) -> Result < ( ) > {
186+ let non_null_count =
187+ skip_present_and_get_non_null_count ( & mut self . present , parent_present, n) ?;
188+ self . iter . skip ( non_null_count)
189+ }
171190}
172191
173192struct PresentDecoder {
@@ -232,6 +251,42 @@ fn derive_present_vec(
232251 }
233252}
234253
254+ /// Skip n values and return the non-null count for the data stream
255+ fn skip_present_and_get_non_null_count (
256+ present : & mut Option < PresentDecoder > ,
257+ parent_present : Option < & NullBuffer > ,
258+ n : usize ,
259+ ) -> Result < usize > {
260+ match ( present, parent_present) {
261+ ( Some ( present) , Some ( parent_present) ) => {
262+ // Parent has nulls, so we need to decode parent present to know how many
263+ // of our present values to skip
264+ let non_null_in_parent = parent_present. len ( ) - parent_present. null_count ( ) ;
265+
266+ // Skip our present values for non-null parents and count non-nulls
267+ let mut our_present = vec ! [ false ; non_null_in_parent] ;
268+ present. inner . decode ( & mut our_present) ?;
269+ let our_non_null_count = our_present. iter ( ) . filter ( |& & v| v) . count ( ) ;
270+
271+ Ok ( our_non_null_count)
272+ }
273+ ( Some ( present) , None ) => {
274+ // No parent present, skip n values and count non-nulls
275+ let mut present_values = vec ! [ false ; n] ;
276+ present. inner . decode ( & mut present_values) ?;
277+ Ok ( present_values. iter ( ) . filter ( |& & v| v) . count ( ) )
278+ }
279+ ( None , Some ( parent_present) ) => {
280+ // No our present stream, all non-null parents have data
281+ Ok ( parent_present. len ( ) - parent_present. null_count ( ) )
282+ }
283+ ( None , None ) => {
284+ // No nulls at all, all n values have data
285+ Ok ( n)
286+ }
287+ }
288+ }
289+
235290pub struct NaiveStripeDecoder {
236291 stripe : Stripe ,
237292 schema_ref : SchemaRef ,
@@ -243,56 +298,81 @@ pub struct NaiveStripeDecoder {
243298 selection_index : usize ,
244299}
245300
301+ impl NaiveStripeDecoder {
302+ /// Advance according to the configured row selection and return the next batch, if any.
303+ ///
304+ /// Behavior:
305+ /// - Iterates `RowSelection` segments (skip/select) starting at `selection_index`.
306+ /// - For skip segments: clamp to remaining rows in this stripe, advance decoders via
307+ /// `skip_rows(actual_skip)`, and advance `index`. If the segment is fully consumed,
308+ /// increment `selection_index`.
309+ /// - For select segments: decode up to `min(row_count, batch_size, remaining_in_stripe)`,
310+ /// advance `index`, update `selection_index` if fully consumed, and return the batch.
311+ /// - If a segment requests rows beyond the end of the stripe, it is skipped (advancing
312+ /// `selection_index`) without touching decoders.
313+ fn next_with_row_selection ( & mut self ) -> Option < Result < RecordBatch > > {
314+ // Process selectors until we produce a batch or exhaust selection
315+ loop {
316+ let ( is_skip, row_count) = {
317+ let selectors = self . row_selection . as_ref ( ) . unwrap ( ) . selectors ( ) ;
318+ if self . selection_index >= selectors. len ( ) {
319+ return None ;
320+ }
321+ let selector = selectors[ self . selection_index ] ;
322+ ( selector. skip , selector. row_count )
323+ } ;
324+
325+ if is_skip {
326+ let remaining = self . number_of_rows - self . index ;
327+ let actual_skip = row_count. min ( remaining) ;
328+
329+ if actual_skip == 0 {
330+ // Nothing to skip in this stripe; try next selector
331+ self . selection_index += 1 ;
332+ continue ;
333+ }
334+
335+ // Keep decoders in sync by skipping values per column
336+ if let Err ( e) = self . skip_rows ( actual_skip) {
337+ return Some ( Err ( e) ) ;
338+ }
339+ self . index += actual_skip;
340+
341+ if actual_skip >= row_count {
342+ self . selection_index += 1 ;
343+ }
344+ } else {
345+ let rows_to_read = row_count. min ( self . batch_size ) ;
346+ let remaining = self . number_of_rows - self . index ;
347+ let actual_rows = rows_to_read. min ( remaining) ;
348+
349+ if actual_rows == 0 {
350+ // Nothing to read from this selector in this stripe; advance selector
351+ self . selection_index += 1 ;
352+ continue ;
353+ }
354+
355+ let record = self . decode_next_batch ( actual_rows) . transpose ( ) ?;
356+ self . index += actual_rows;
357+
358+ if actual_rows >= row_count {
359+ self . selection_index += 1 ;
360+ }
361+ return Some ( record) ;
362+ }
363+ }
364+ }
365+ }
366+
246367impl Iterator for NaiveStripeDecoder {
247368 type Item = Result < RecordBatch > ;
248369
370+ // TODO: check if we can make this more efficient
249371 fn next ( & mut self ) -> Option < Self :: Item > {
250372 if self . index < self . number_of_rows {
251373 // Handle row selection if present
252374 if self . row_selection . is_some ( ) {
253- // Process selectors until we find rows to select or exhaust the selection
254- loop {
255- let ( is_skip, row_count) = {
256- // Safety: this has been checked above
257- let selectors = self . row_selection . as_ref ( ) . unwrap ( ) . selectors ( ) ;
258- if self . selection_index >= selectors. len ( ) {
259- return None ;
260- }
261- let selector = selectors[ self . selection_index ] ;
262- ( selector. skip , selector. row_count )
263- } ;
264-
265- if is_skip {
266- // Skip these rows by advancing the index
267- self . index += row_count;
268- self . selection_index += 1 ;
269-
270- // Decode and discard the skipped rows to advance the internal decoders
271- if let Err ( e) = self . skip_rows ( row_count) {
272- return Some ( Err ( e) ) ;
273- }
274- } else {
275- // Select these rows
276- let rows_to_read = row_count. min ( self . batch_size ) ;
277- let remaining = self . number_of_rows - self . index ;
278- let actual_rows = rows_to_read. min ( remaining) ;
279-
280- if actual_rows == 0 {
281- self . selection_index += 1 ;
282- continue ;
283- }
284-
285- let record = self . decode_next_batch ( actual_rows) . transpose ( ) ?;
286- self . index += actual_rows;
287-
288- // Update selector to track progress
289- if actual_rows >= row_count {
290- self . selection_index += 1 ;
291- }
292-
293- return Some ( record) ;
294- }
295- }
375+ self . next_with_row_selection ( )
296376 } else {
297377 // No row selection - decode normally
298378 let record = self
@@ -513,14 +593,12 @@ impl NaiveStripeDecoder {
513593 } )
514594 }
515595
516- /// Skip the specified number of rows by decoding and discarding them
596+ /// Skip the specified number of rows by calling skip_values on each decoder
517597 fn skip_rows ( & mut self , count : usize ) -> Result < ( ) > {
518- // Decode in batches to avoid large memory allocations
519- let mut remaining = count;
520- while remaining > 0 {
521- let chunk = self . batch_size . min ( remaining) ;
522- let _ = self . inner_decode_next_batch ( chunk) ?;
523- remaining -= chunk;
598+ // Call skip_values on each decoder to efficiently skip rows
599+ // Top-level decoders don't have parent_present
600+ for decoder in & mut self . decoders {
601+ decoder. skip_values ( count, None ) ?;
524602 }
525603 Ok ( ( ) )
526604 }
0 commit comments