11// SPDX-License-Identifier: Apache-2.0
22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
4+ use std:: collections:: BTreeSet ;
45use std:: ops:: Range ;
56
67use itertools:: Itertools ;
78use vortex_array:: dtype:: DType ;
89use vortex_array:: dtype:: Field ;
910use vortex_array:: dtype:: FieldMask ;
11+ use vortex_array:: dtype:: FieldName ;
1012use vortex_array:: dtype:: FieldNames ;
1113use vortex_array:: dtype:: FieldPath ;
1214use vortex_array:: expr:: Expression ;
@@ -52,6 +54,7 @@ impl MaterializationPlan {
5254 dtype : & DType ,
5355 filter_present : bool ,
5456 projection_field_mask : & [ FieldMask ] ,
57+ filter_field_names : & BTreeSet < FieldName > ,
5558 ) -> Self {
5659 let projected_row_bytes = estimate_field_mask_row_bytes ( dtype, projection_field_mask) ;
5760 if !filter_present {
@@ -103,6 +106,14 @@ impl MaterializationPlan {
103106 } ;
104107
105108 let carry_cost_bytes_per_row = estimate_dtype_row_bytes ( & field_dtype) ;
109+ // Fields shared with the filter are already fetched during filter evaluation,
110+ // so keep them immediate to avoid double IO.
111+ if filter_field_names. contains ( name) {
112+ immediate_carry_cost =
113+ immediate_carry_cost. saturating_add ( carry_cost_bytes_per_row) ;
114+ immediate. push ( name. clone ( ) ) ;
115+ continue ;
116+ }
106117 if should_defer_field ( & field_dtype, carry_cost_bytes_per_row) {
107118 deferred_carry_cost = deferred_carry_cost. saturating_add ( carry_cost_bytes_per_row) ;
108119 deferred_groups. push ( DeferredFieldGroup {
@@ -283,6 +294,8 @@ fn estimate_dtype_row_bytes(dtype: &DType) -> usize {
283294
284295#[ cfg( test) ]
285296mod tests {
297+ use std:: collections:: BTreeSet ;
298+
286299 use vortex_array:: dtype:: DType ;
287300 use vortex_array:: dtype:: Field ;
288301 use vortex_array:: dtype:: FieldMask ;
@@ -323,7 +336,7 @@ mod tests {
323336 fn deferred_plan_activates_for_narrow_filtered_projection ( ) {
324337 let projection = select ( [ "id" , "payload" ] , root ( ) ) ;
325338 let mask = vec ! [ FieldMask :: Prefix ( FieldPath :: from( Field :: Name ( "id" . into( ) ) ) ) ] ;
326- let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , true , & mask) ;
339+ let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , true , & mask, & BTreeSet :: new ( ) ) ;
327340 let deferred = plan. deferred ( ) . expect ( "deferred plan" ) ;
328341 assert_eq ! (
329342 deferred. final_fields( ) ,
@@ -337,22 +350,22 @@ mod tests {
337350 fn deferred_plan_stays_off_for_unfiltered_projection ( ) {
338351 let projection = select ( [ "id" , "payload" ] , root ( ) ) ;
339352 let mask = vec ! [ FieldMask :: Prefix ( FieldPath :: from( Field :: Name ( "id" . into( ) ) ) ) ] ;
340- let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , false , & mask) ;
353+ let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , false , & mask, & BTreeSet :: new ( ) ) ;
341354 assert ! ( plan. deferred( ) . is_none( ) ) ;
342355 }
343356
344357 #[ test]
345358 fn deferred_plan_stays_off_for_root_projection ( ) {
346359 let mask = vec ! [ FieldMask :: Prefix ( FieldPath :: from( Field :: Name ( "id" . into( ) ) ) ) ] ;
347- let plan = MaterializationPlan :: from_projection ( & root ( ) , & scan_dtype ( ) , true , & mask) ;
360+ let plan = MaterializationPlan :: from_projection ( & root ( ) , & scan_dtype ( ) , true , & mask, & BTreeSet :: new ( ) ) ;
348361 assert ! ( plan. deferred( ) . is_none( ) ) ;
349362 }
350363
351364 #[ test]
352365 fn deferred_plan_stays_off_for_wide_projection ( ) {
353366 let projection = select ( [ "id" , "score" , "payload" , "nested" ] , root ( ) ) ;
354367 let mask = vec ! [ FieldMask :: Prefix ( FieldPath :: from( Field :: Name ( "id" . into( ) ) ) ) ] ;
355- let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , true , & mask) ;
368+ let plan = MaterializationPlan :: from_projection ( & projection, & scan_dtype ( ) , true , & mask, & BTreeSet :: new ( ) ) ;
356369 assert ! ( plan. deferred( ) . is_none( ) ) ;
357370 }
358371
0 commit comments