22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
44use std:: borrow:: Cow ;
5+ use std:: future;
6+ use std:: ops:: Range ;
57use std:: sync:: Arc ;
68
9+ use futures:: FutureExt ;
10+ use futures:: TryStreamExt ;
11+ use futures:: stream:: FuturesOrdered ;
12+ use vortex_array:: Canonical ;
713use vortex_array:: EmptyMetadata ;
14+ use vortex_array:: IntoArray ;
15+ use vortex_array:: MaskFuture ;
16+ use vortex_array:: arrays:: ChunkedArray ;
817use vortex_array:: dtype:: DType ;
9- use vortex_array:: expr:: ExactBoundExpr ;
10- use vortex_array:: expr:: label_bound_tree;
18+ use vortex_error:: VortexExpect ;
1119use vortex_error:: VortexResult ;
1220use vortex_error:: vortex_bail;
21+ use vortex_error:: vortex_ensure;
22+ use vortex_error:: vortex_err;
1323use vortex_session:: registry:: CachedId ;
1424
15- use crate :: layouts:: row_idx:: RowIdx as RowIdxFn ;
1625use crate :: plan:: Eval ;
1726use crate :: plan:: EvalPlan ;
1827use crate :: plan:: Plan ;
28+ use crate :: plan:: PlanArrayFuture ;
1929use crate :: plan:: PlanChildren ;
30+ use crate :: plan:: PlanExecutionContext ;
2031use crate :: plan:: PlanId ;
2132use crate :: plan:: PlanParts ;
2233use crate :: plan:: PlanRef ;
@@ -142,6 +153,57 @@ impl PlanVTable for Concat {
142153 Ok ( ( ) )
143154 }
144155
156+ fn execute (
157+ plan : & Plan < Self > ,
158+ ctx : & PlanExecutionContext ,
159+ row_range : & Range < u64 > ,
160+ mask : MaskFuture ,
161+ ) -> VortexResult < PlanArrayFuture > {
162+ vortex_ensure ! (
163+ row_range. start <= row_range. end && row_range. end <= plan. row_count( ) ,
164+ "Concat row range {:?} is outside 0..{}" ,
165+ row_range,
166+ plan. row_count( )
167+ ) ;
168+ vortex_ensure ! (
169+ mask. len( ) == usize :: try_from( row_range. end - row_range. start) ?,
170+ "Concat mask length mismatch"
171+ ) ;
172+ if row_range. is_empty ( ) {
173+ let empty = Canonical :: empty ( plan. dtype ( ) ) . into_array ( ) ;
174+ return Ok ( future:: ready ( Ok ( empty) ) . boxed ( ) ) ;
175+ }
176+
177+ let mut chunk_futures = Vec :: new ( ) ;
178+ for ( chunk, & chunk_offset) in plan. children ( ) . iter ( ) . zip ( plan. row_offsets ( ) ) {
179+ let chunk = chunk?;
180+ let chunk_end = chunk_offset
181+ . checked_add ( chunk. row_count ( ) )
182+ . ok_or_else ( || vortex_err ! ( "Chunk row offset overflow" ) ) ?;
183+ let start = row_range. start . max ( chunk_offset) ;
184+ let end = row_range. end . min ( chunk_end) ;
185+ if start < end {
186+ let child_range = start - chunk_offset..end - chunk_offset;
187+ let mask_range = usize:: try_from ( start - row_range. start ) ?
188+ ..usize:: try_from ( end - row_range. start ) ?;
189+ chunk_futures. push ( chunk. execute ( ctx, & child_range, mask. slice ( mask_range) ) ?) ;
190+ }
191+ }
192+
193+ Ok ( async move {
194+ let chunks: Vec < _ > = FuturesOrdered :: from_iter ( chunk_futures)
195+ . try_collect ( )
196+ . await ?;
197+ vortex_ensure ! ( !chunks. is_empty( ) , "Non-empty row range selected no chunks" ) ;
198+ if chunks. len ( ) == 1 {
199+ return Ok ( chunks. into_iter ( ) . next ( ) . vortex_expect ( "one chunk" ) ) ;
200+ }
201+ let dtype = chunks[ 0 ] . dtype ( ) . clone ( ) ;
202+ Ok ( ChunkedArray :: try_new ( chunks, dtype) ?. into_array ( ) )
203+ }
204+ . boxed ( ) )
205+ }
206+
145207 fn child_name ( _plan : & Plan < Self > , index : usize ) -> Cow < ' _ , str > {
146208 Cow :: Owned ( format ! ( "chunks[{index}]" ) )
147209 }
@@ -161,23 +223,6 @@ impl PlanParentReduceRule<Concat> for ExpressionConcatRule {
161223 _child_idx : usize ,
162224 ) -> VortexResult < Option < PlanRef > > {
163225 let expression = parent. expression ( ) ;
164- // Row-index expressions are relative to the whole row domain, so they cannot be evaluated
165- // chunk by chunk.
166- let references_row_idx = label_bound_tree (
167- expression,
168- |node| {
169- node. as_scalar ( )
170- . is_some_and ( |scalar_fn| scalar_fn. is :: < RowIdxFn > ( ) )
171- } ,
172- |acc, & child| acc | child,
173- )
174- . get ( & ExactBoundExpr ( expression. clone ( ) ) )
175- . copied ( )
176- . unwrap_or ( false ) ;
177- if references_row_idx {
178- return Ok ( None ) ;
179- }
180-
181226 let chunks = child
182227 . children ( )
183228 . iter ( )
0 commit comments