44use vortex_array:: dtype:: DType ;
55use vortex_array:: dtype:: Nullability ;
66use vortex_array:: expr:: BoundExpression ;
7- #[ cfg( test) ]
8- use vortex_array:: expr:: Expression ;
9- #[ cfg( test) ]
10- use vortex_array:: expr:: is_root;
117use vortex_array:: scalar_fn:: EmptyOptions ;
128use vortex_array:: scalar_fn:: ScalarFnVTableExt ;
139use vortex_array:: scalar_fn:: fns:: is_not_null:: IsNotNull ;
@@ -32,30 +28,6 @@ pub(super) enum ListChildrenNeeded {
3228 All ,
3329}
3430
35- /// The minimal set of list children needed to evaluate `expr`, where `root()` is a field with list dtype.
36- #[ cfg( test) ]
37- pub ( super ) fn get_necessary_list_children ( expr : & Expression ) -> ListChildrenNeeded {
38- if is_null_root ( expr) {
39- return ListChildrenNeeded :: Validity ;
40- }
41-
42- if is_list_length_root ( expr) {
43- return ListChildrenNeeded :: OffsetsAndValidity ;
44- }
45-
46- if is_root ( expr) {
47- return ListChildrenNeeded :: All ;
48- }
49-
50- // Otherwise the requirement is the max over the operands. Childless expressions that never
51- // touch the list, such as literals, fall back to the cheapest usable child.
52- expr. children ( )
53- . iter ( )
54- . map ( get_necessary_list_children)
55- . max ( )
56- . unwrap_or ( ListChildrenNeeded :: Validity )
57- }
58-
5931/// The minimal set of list children needed to evaluate a bound expression.
6032pub ( super ) fn get_necessary_bound_list_children ( expr : & BoundExpression ) -> ListChildrenNeeded {
6133 if is_bound_null_root ( expr) {
@@ -90,18 +62,6 @@ fn is_bound_list_length_root(expr: &BoundExpression) -> bool {
9062 && expr. children ( ) [ 0 ] . is_root ( )
9163}
9264
93- #[ cfg( test) ]
94- fn is_null_root ( expr : & Expression ) -> bool {
95- ( expr. is :: < IsNull > ( ) || expr. is :: < IsNotNull > ( ) )
96- && expr. children ( ) . len ( ) == 1
97- && is_root ( expr. child ( 0 ) )
98- }
99-
100- #[ cfg( test) ]
101- fn is_list_length_root ( expr : & Expression ) -> bool {
102- expr. is :: < ListLength > ( ) && expr. children ( ) . len ( ) == 1 && is_root ( expr. child ( 0 ) )
103- }
104-
10565/// Rewrite a validity-class expression so it can be evaluated against the list's validity bool
10666/// array (`true` == valid row): `is_not_null(root())` becomes `root()` and `is_null(root())`
10767/// becomes `not(root())`. All other nodes are rebuilt with rewritten children.
@@ -160,58 +120,3 @@ pub(super) fn rewrite_offsets_expr(
160120 . collect :: < VortexResult < Vec < _ > > > ( ) ?;
161121 expr. clone ( ) . with_children ( children)
162122}
163-
164- #[ cfg( test) ]
165- mod tests {
166- use rstest:: rstest;
167- use vortex_array:: dtype:: DType ;
168- use vortex_array:: dtype:: Nullability ;
169- use vortex_array:: dtype:: PType ;
170- use vortex_array:: expr:: cast;
171- use vortex_array:: expr:: eq;
172- use vortex_array:: expr:: gt;
173- use vortex_array:: expr:: is_not_null;
174- use vortex_array:: expr:: is_null;
175- use vortex_array:: expr:: list_length;
176- use vortex_array:: expr:: lit;
177- use vortex_array:: expr:: not;
178- use vortex_array:: expr:: root;
179-
180- use super :: * ;
181-
182- /// `get_necessary_list_children` keys off the deepest list child an expression touches; `All`
183- /// is the always-correct default for anything not specifically recognized.
184- #[ rstest]
185- // `is_null` / `is_not_null` of the list itself need only validity.
186- #[ case:: is_null( is_null( root( ) ) , ListChildrenNeeded :: Validity ) ]
187- #[ case:: is_not_null( is_not_null( root( ) ) , ListChildrenNeeded :: Validity ) ]
188- // Compound over validity-only operands stays validity.
189- #[ case:: not_is_null( not( is_null( root( ) ) ) , ListChildrenNeeded :: Validity ) ]
190- // A list-independent (constant) expression falls to the cheapest usable child.
191- #[ case:: constant( lit( 5 ) , ListChildrenNeeded :: Validity ) ]
192- // `list_length(root())` needs offsets and validity, but not elements.
193- #[ case:: list_length( list_length( root( ) ) , ListChildrenNeeded :: OffsetsAndValidity ) ]
194- // Compound over offsets-only operands stays offsets.
195- #[ case:: list_length_filter(
196- gt( list_length( root( ) ) , lit( 1u64 ) ) ,
197- ListChildrenNeeded :: OffsetsAndValidity
198- ) ]
199- #[ case:: cast_list_length(
200- cast(
201- list_length( root( ) ) ,
202- DType :: Primitive ( PType :: I64 , Nullability :: Nullable ) ,
203- ) ,
204- ListChildrenNeeded :: OffsetsAndValidity
205- ) ]
206- // A bare list reference needs the elements.
207- #[ case:: bare_root( root( ) , ListChildrenNeeded :: All ) ]
208- // Any other fn over the list needs the elements.
209- #[ case:: not_root( not( root( ) ) , ListChildrenNeeded :: All ) ]
210- // `is_null` only short-circuits to validity when its argument is the list itself.
211- #[ case:: is_null_of_derived( is_null( not( root( ) ) ) , ListChildrenNeeded :: All ) ]
212- // Max over operands: validity + elements => elements.
213- #[ case:: validity_and_elements( eq( is_null( root( ) ) , root( ) ) , ListChildrenNeeded :: All ) ]
214- fn classify_expr_class ( #[ case] expr : Expression , #[ case] expected : ListChildrenNeeded ) {
215- assert_eq ! ( get_necessary_list_children( & expr) , expected) ;
216- }
217- }
0 commit comments