@@ -11,7 +11,10 @@ use object_store::registry::ObjectStoreRegistry;
1111use url:: Url ;
1212use vortex:: array:: ArrayRef ;
1313use vortex:: array:: VortexSessionExecute as _;
14+ use vortex:: array:: arrays:: Chunked ;
15+ use vortex:: array:: arrays:: chunked:: ChunkedArrayExt as _;
1416use vortex:: array:: arrays:: struct_:: StructArrayExt as _;
17+ use vortex:: array:: scalar_fn:: fns:: dynamic:: DynamicExprUpdates ;
1518use vortex:: dtype:: FieldPath ;
1619use vortex:: error:: VortexExpect ;
1720use vortex:: error:: VortexResult ;
@@ -221,7 +224,16 @@ pub fn reader_initialize(file: &mut OpenFileReader, global: &GlobalState) -> Vor
221224 // global lock.
222225 if global. scan_v2 {
223226 let state = file. scan_state ( ) ;
224- let scan = FileScan :: try_new ( v2_builder ( state, global) ) ?;
227+ let splits = ScanBuilder :: new ( SESSION . clone ( ) , Arc :: clone ( & state. reader ) )
228+ . with_projection ( global. projection . clone ( ) )
229+ . with_some_filter ( global. filter . filter . clone ( ) )
230+ . full_file_splits ( ) ?;
231+ let dynamic = global
232+ . filter
233+ . filter
234+ . as_ref ( )
235+ . is_some_and ( |filter| DynamicExprUpdates :: new ( filter) . is_some ( ) ) ;
236+ let scan = FileScan :: try_new ( v2_builder ( state, global) , & splits, dynamic) ?;
225237 if state. v2 . set ( scan) . is_err ( ) {
226238 vortex_panic ! ( "file initialized twice" ) ;
227239 }
@@ -284,8 +296,23 @@ fn next_split_item(local: &mut LocalState) -> VortexResult<SplitItem> {
284296 . v2
285297 . get ( )
286298 . vortex_expect ( "V2 split of a file without a V2 scan" ) ;
287- let Some ( array) = scan. next_array ( & mut local. run ) ? else {
288- return Ok ( SplitItem :: Done ) ;
299+ let array = match local. pending . pop ( ) {
300+ Some ( array) => array,
301+ None => {
302+ let Some ( array) = scan. next_array ( & mut local. run ) ? else {
303+ return Ok ( SplitItem :: Done ) ;
304+ } ;
305+ // A V2 batch can join chunks of several layout chunks. Canonicalizing it
306+ // would decode their dictionaries, so export each chunk on its own, as a V1
307+ // scan yields them.
308+ match array. as_opt :: < Chunked > ( ) {
309+ Some ( chunked) => {
310+ local. pending . extend ( chunked. chunks ( ) . into_iter ( ) . rev ( ) ) ;
311+ local. pending . pop ( ) . unwrap_or ( array)
312+ }
313+ None => array,
314+ }
315+ }
289316 } ;
290317 local. split = Some ( Split :: V2 ) ;
291318 Ok ( if array. is_empty ( ) {
0 commit comments