@@ -9,18 +9,17 @@ use vortex_dtype::DType;
99use vortex_dtype:: FieldName ;
1010use vortex_dtype:: FieldPath ;
1111use vortex_dtype:: Nullability ;
12- use vortex_error:: vortex_err;
1312use vortex_error:: VortexExpect ;
1413use vortex_error:: VortexResult ;
15- use vortex_mask :: Mask ;
14+ use vortex_error :: vortex_err ;
1615use vortex_proto:: expr as pb;
1716use vortex_vector:: Datum ;
1817use vortex_vector:: ScalarOps ;
1918use vortex_vector:: VectorOps ;
2019
20+ use crate :: ArrayRef ;
21+ use crate :: ToCanonical ;
2122use crate :: compute:: mask;
22- use crate :: expr:: exprs:: root:: root;
23- use crate :: expr:: stats:: Stat ;
2423use crate :: expr:: Arity ;
2524use crate :: expr:: ChildName ;
2625use crate :: expr:: ExecutionArgs ;
@@ -31,9 +30,10 @@ use crate::expr::SimplifyCtx;
3130use crate :: expr:: StatsCatalog ;
3231use crate :: expr:: VTable ;
3332use crate :: expr:: VTableExt ;
33+ use crate :: expr:: exprs:: root:: root;
34+ use crate :: expr:: lit;
35+ use crate :: expr:: stats:: Stat ;
3436use crate :: scalar_fns:: ExprBuiltins ;
35- use crate :: ArrayRef ;
36- use crate :: ToCanonical ;
3737
3838pub struct GetItem ;
3939
@@ -173,6 +173,44 @@ impl VTable for GetItem {
173173 Ok ( None )
174174 }
175175
176+ fn simplify_untyped (
177+ & self ,
178+ field_name : & FieldName ,
179+ expr : & Expression ,
180+ ) -> VortexResult < Option < Expression > > {
181+ let child = expr. child ( 0 ) ;
182+
183+ // If the child is a Pack expression, we can directly return the corresponding child.
184+ if let Some ( pack) = child. as_opt :: < Pack > ( ) {
185+ let idx = pack
186+ . names
187+ . iter ( )
188+ . position ( |name| name == field_name)
189+ . ok_or_else ( || {
190+ vortex_err ! (
191+ "Cannot find field {} in pack fields {:?}" ,
192+ field_name,
193+ pack. names
194+ )
195+ } ) ?;
196+
197+ let mut field = child. child ( idx) . clone ( ) ;
198+
199+ // It's useful to simplify this node without type info, but we need to make sure
200+ // the nullability is correct. We cannot cast since we don't have the dtype info here,
201+ // so instead we insert a Mask expression that we know converts a child's dtype to
202+ // nullable.
203+ if pack. nullability . is_nullable ( ) {
204+ // Mask with an all-true array to ensure the field DType is nullable.
205+ field = field. mask ( lit ( true ) ) ?;
206+ }
207+
208+ return Ok ( Some ( field) ) ;
209+ }
210+
211+ Ok ( None )
212+ }
213+
176214 fn stat_expression (
177215 & self ,
178216 field_name : & FieldName ,
@@ -200,11 +238,6 @@ impl VTable for GetItem {
200238 // If this type-checks its infallible.
201239 false
202240 }
203-
204- fn cost_estimate ( & self , _options : & Self :: Options , _selection : & Mask ) -> f64 {
205- // This is largely a metadata-only operation.
206- 0.0
207- }
208241}
209242
210243/// Creates an expression that accesses a field from the root array.
@@ -242,15 +275,15 @@ mod tests {
242275 use vortex_dtype:: StructFields ;
243276 use vortex_scalar:: Scalar ;
244277
278+ use crate :: Array ;
279+ use crate :: IntoArray ;
245280 use crate :: arrays:: StructArray ;
246281 use crate :: expr:: exprs:: binary:: checked_add;
247282 use crate :: expr:: exprs:: get_item:: get_item;
248283 use crate :: expr:: exprs:: literal:: lit;
249284 use crate :: expr:: exprs:: pack:: pack;
250285 use crate :: expr:: exprs:: root:: root;
251286 use crate :: validity:: Validity ;
252- use crate :: Array ;
253- use crate :: IntoArray ;
254287
255288 fn test_array ( ) -> StructArray {
256289 StructArray :: from_fields ( & [
0 commit comments