@@ -5,7 +5,9 @@ use vortex_array::ArrayRef;
55use vortex_array:: ArrayView ;
66use vortex_array:: ExecutionCtx ;
77use vortex_array:: IntoArray ;
8+ use vortex_array:: arrays:: BoolArray ;
89use vortex_array:: arrays:: ConstantArray ;
10+ use vortex_array:: arrays:: bool:: BoolArrayExt ;
911use vortex_array:: builtins:: ArrayBuiltins ;
1012use vortex_array:: dtype:: DType ;
1113use vortex_array:: dtype:: Nullability ;
@@ -16,6 +18,7 @@ use vortex_array::scalar_fn::fns::operators::CompareOperator;
1618use vortex_array:: scalar_fn:: fns:: operators:: Operator ;
1719use vortex_array:: validity:: Validity ;
1820use vortex_error:: VortexResult ;
21+ use vortex_mask:: AllOr ;
1922
2023use crate :: array:: DateTimeParts ;
2124use crate :: array:: DateTimePartsArraySlotsExt ;
@@ -87,9 +90,10 @@ fn compare_eq(
8790 nullability : Nullability ,
8891 ctx : & mut ExecutionCtx ,
8992) -> VortexResult < ArrayRef > {
90- let mut comparison = compare_dtp ( lhs. days ( ) , ts_parts. days , CompareOperator :: Eq , nullability) ?;
91- if comparison. statistics ( ) . compute_max :: < bool > ( ctx) == Some ( false ) {
92- return Ok ( comparison) ;
93+ let mut comparison = compare_dtp ( lhs. days ( ) , ts_parts. days , CompareOperator :: Eq , nullability) ?
94+ . execute :: < BoolArray > ( ctx) ?;
95+ if valid_rows_all ( & comparison, false , ctx) ? {
96+ return Ok ( comparison. into_array ( ) ) ;
9397 }
9498
9599 comparison = compare_dtp (
@@ -98,10 +102,11 @@ fn compare_eq(
98102 CompareOperator :: Eq ,
99103 nullability,
100104 ) ?
101- . binary ( comparison, Operator :: And ) ?;
105+ . binary ( comparison. into_array ( ) , Operator :: And ) ?
106+ . execute :: < BoolArray > ( ctx) ?;
102107
103- if comparison . statistics ( ) . compute_max :: < bool > ( ctx ) == Some ( false ) {
104- return Ok ( comparison) ;
108+ if valid_rows_all ( & comparison , false , ctx ) ? {
109+ return Ok ( comparison. into_array ( ) ) ;
105110 }
106111
107112 compare_dtp (
@@ -110,7 +115,7 @@ fn compare_eq(
110115 CompareOperator :: Eq ,
111116 nullability,
112117 ) ?
113- . binary ( comparison, Operator :: And )
118+ . binary ( comparison. into_array ( ) , Operator :: And )
114119}
115120
116121fn compare_ne (
@@ -124,9 +129,10 @@ fn compare_ne(
124129 ts_parts. days ,
125130 CompareOperator :: NotEq ,
126131 nullability,
127- ) ?;
128- if comparison. statistics ( ) . compute_min :: < bool > ( ctx) == Some ( true ) {
129- return Ok ( comparison) ;
132+ ) ?
133+ . execute :: < BoolArray > ( ctx) ?;
134+ if valid_rows_all ( & comparison, true , ctx) ? {
135+ return Ok ( comparison. into_array ( ) ) ;
130136 }
131137
132138 comparison = compare_dtp (
@@ -135,10 +141,11 @@ fn compare_ne(
135141 CompareOperator :: NotEq ,
136142 nullability,
137143 ) ?
138- . binary ( comparison, Operator :: Or ) ?;
144+ . binary ( comparison. into_array ( ) , Operator :: Or ) ?
145+ . execute :: < BoolArray > ( ctx) ?;
139146
140- if comparison . statistics ( ) . compute_min :: < bool > ( ctx ) == Some ( true ) {
141- return Ok ( comparison) ;
147+ if valid_rows_all ( & comparison , true , ctx ) ? {
148+ return Ok ( comparison. into_array ( ) ) ;
142149 }
143150
144151 compare_dtp (
@@ -147,7 +154,7 @@ fn compare_ne(
147154 CompareOperator :: NotEq ,
148155 nullability,
149156 ) ?
150- . binary ( comparison, Operator :: Or )
157+ . binary ( comparison. into_array ( ) , Operator :: Or )
151158}
152159
153160/// Orders timestamps by their parts.
@@ -170,14 +177,17 @@ fn compare_ordered(
170177 }
171178 } ;
172179
173- let days_strict = compare_dtp ( lhs. days ( ) , ts_parts. days , strict, nullability) ?;
174- if days_strict. statistics ( ) . compute_min :: < bool > ( ctx) == Some ( true ) {
175- return Ok ( days_strict) ;
180+ let days_strict =
181+ compare_dtp ( lhs. days ( ) , ts_parts. days , strict, nullability) ?. execute :: < BoolArray > ( ctx) ?;
182+ if valid_rows_all ( & days_strict, true , ctx) ? {
183+ return Ok ( days_strict. into_array ( ) ) ;
176184 }
177- let days_eq = compare_dtp ( lhs. days ( ) , ts_parts. days , CompareOperator :: Eq , nullability) ?;
178- if days_eq. statistics ( ) . compute_max :: < bool > ( ctx) == Some ( false ) {
179- return Ok ( days_strict) ;
185+ let days_eq = compare_dtp ( lhs. days ( ) , ts_parts. days , CompareOperator :: Eq , nullability) ?
186+ . execute :: < BoolArray > ( ctx) ?;
187+ if valid_rows_all ( & days_eq, false , ctx) ? {
188+ return Ok ( days_strict. into_array ( ) ) ;
180189 }
190+ let ( days_strict, days_eq) = ( days_strict. into_array ( ) , days_eq. into_array ( ) ) ;
181191
182192 let seconds_strict = compare_dtp ( lhs. seconds ( ) , ts_parts. seconds , strict, nullability) ?;
183193 let seconds_eq = compare_dtp (
@@ -193,6 +203,35 @@ fn compare_ordered(
193203 days_strict. binary ( days_eq. binary ( within_day, Operator :: And ) ?, Operator :: Or )
194204}
195205
206+ /// Whether every valid row of `comparison` is `value`. This is `false` when no row is valid, as the
207+ /// min and max statistics of such an array are unknown.
208+ ///
209+ /// The comparison is already evaluated, so a population count answers this, where the min and max
210+ /// statistics of a lazy comparison would evaluate it again.
211+ fn valid_rows_all (
212+ comparison : & BoolArray ,
213+ value : bool ,
214+ ctx : & mut ExecutionCtx ,
215+ ) -> VortexResult < bool > {
216+ let bits = comparison. to_bit_buffer ( ) ;
217+ let valid = comparison. validity ( ) ?. execute_mask ( comparison. len ( ) , ctx) ?;
218+ let ( valid_count, true_count) = match valid. bit_buffer ( ) {
219+ AllOr :: All => ( bits. len ( ) , bits. true_count ( ) ) ,
220+ AllOr :: None => return Ok ( false ) ,
221+ AllOr :: Some ( valid_bits) => ( valid. true_count ( ) , ( & bits & valid_bits) . true_count ( ) ) ,
222+ } ;
223+
224+ if valid_count == 0 {
225+ return Ok ( false ) ;
226+ }
227+
228+ Ok ( if value {
229+ true_count == valid_count
230+ } else {
231+ true_count == 0
232+ } )
233+ }
234+
196235fn compare_dtp (
197236 lhs : & ArrayRef ,
198237 rhs : i32 ,
0 commit comments