33
44mod bool;
55mod decimal;
6+ mod extension;
7+ mod fixed_size_list;
8+ mod list;
69pub mod primitive;
10+ mod struct_;
711mod varbin;
812
913use vortex_error:: VortexResult ;
14+ use vortex_mask:: Mask ;
1015
1116use self :: bool:: check_bool_constant;
1217use self :: decimal:: check_decimal_constant;
18+ use self :: extension:: check_extension_constant;
19+ use self :: fixed_size_list:: check_fixed_size_list_constant;
20+ use self :: list:: check_listview_constant;
1321use self :: primitive:: check_primitive_constant;
22+ use self :: struct_:: check_struct_constant;
1423use self :: varbin:: check_varbinview_constant;
1524use crate :: ArrayRef ;
1625use crate :: Canonical ;
1726use crate :: Columnar ;
1827use crate :: DynArray ;
1928use crate :: ExecutionCtx ;
2029use crate :: IntoArray ;
30+ use crate :: ToCanonical ;
2131use crate :: aggregate_fn:: Accumulator ;
2232use crate :: aggregate_fn:: AggregateFnId ;
2333use crate :: aggregate_fn:: AggregateFnVTable ;
2434use crate :: aggregate_fn:: DynAccumulator ;
2535use crate :: aggregate_fn:: EmptyOptions ;
36+ use crate :: arrays:: BoolArray ;
2637use crate :: arrays:: Constant ;
2738use crate :: arrays:: Null ;
39+ use crate :: builtins:: ArrayBuiltins ;
2840use crate :: dtype:: DType ;
2941use crate :: dtype:: FieldNames ;
3042use crate :: dtype:: Nullability ;
@@ -34,6 +46,37 @@ use crate::expr::stats::Stat;
3446use crate :: expr:: stats:: StatsProvider ;
3547use crate :: expr:: stats:: StatsProviderExt ;
3648use crate :: scalar:: Scalar ;
49+ use crate :: scalar_fn:: fns:: operators:: Operator ;
50+
51+ /// Check if two arrays of the same length have equal values at every position (null-safe).
52+ ///
53+ /// Two positions are considered equal if they are both null, or both non-null with the same value.
54+ fn arrays_value_equal ( a : & ArrayRef , b : & ArrayRef , ctx : & mut ExecutionCtx ) -> VortexResult < bool > {
55+ debug_assert_eq ! ( a. len( ) , b. len( ) ) ;
56+ if a. is_empty ( ) {
57+ return Ok ( true ) ;
58+ }
59+
60+ // Check validity masks match (null positions must be identical).
61+ let a_mask = a. validity_mask ( ) ?;
62+ let b_mask = b. validity_mask ( ) ?;
63+ if a_mask != b_mask {
64+ return Ok ( false ) ;
65+ }
66+
67+ let valid_count = a_mask. true_count ( ) ;
68+ if valid_count == 0 {
69+ // Both all-null → equal.
70+ return Ok ( true ) ;
71+ }
72+
73+ // Compare values element-wise. Result is null where both inputs are null,
74+ // true/false where both are valid.
75+ let eq_result = a. binary ( b. clone ( ) , Operator :: Eq ) ?;
76+ let eq_result = eq_result. execute :: < Mask > ( ctx) ?;
77+
78+ Ok ( eq_result. true_count ( ) == valid_count)
79+ }
3780
3881/// Compute whether an array has constant values.
3982///
@@ -275,7 +318,7 @@ impl AggregateFnVTable for IsConstant {
275318 & self ,
276319 partial : & mut Self :: Partial ,
277320 batch : & Columnar ,
278- _ctx : & mut ExecutionCtx ,
321+ ctx : & mut ExecutionCtx ,
279322 ) -> VortexResult < ( ) > {
280323 if !partial. is_constant {
281324 return Ok ( ( ) ) ;
@@ -318,57 +361,10 @@ impl AggregateFnVTable for IsConstant {
318361 Canonical :: Bool ( b) => check_bool_constant ( b) ,
319362 Canonical :: VarBinView ( v) => check_varbinview_constant ( v) ,
320363 Canonical :: Decimal ( d) => check_decimal_constant ( d) ,
321- Canonical :: Struct ( s) => {
322- let children = s. children ( ) ;
323- if children. is_empty ( ) {
324- true
325- } else {
326- // For struct, check each child recursively.
327- let first_scalar = s. scalar_at ( 0 ) ?;
328- let mut is_const = true ;
329- for i in 1 ..s. len ( ) {
330- if s. scalar_at ( i) ? != first_scalar {
331- is_const = false ;
332- break ;
333- }
334- }
335- is_const
336- }
337- }
338- Canonical :: Extension ( e) => {
339- // Extension arrays delegate to their storage.
340- let first_scalar = e. scalar_at ( 0 ) ?;
341- let mut is_const = true ;
342- for i in 1 ..e. len ( ) {
343- if e. scalar_at ( i) ? != first_scalar {
344- is_const = false ;
345- break ;
346- }
347- }
348- is_const
349- }
350- Canonical :: List ( l) => {
351- let first_scalar = l. scalar_at ( 0 ) ?;
352- let mut is_const = true ;
353- for i in 1 ..l. len ( ) {
354- if l. scalar_at ( i) ? != first_scalar {
355- is_const = false ;
356- break ;
357- }
358- }
359- is_const
360- }
361- Canonical :: FixedSizeList ( f) => {
362- let first_scalar = f. scalar_at ( 0 ) ?;
363- let mut is_const = true ;
364- for i in 1 ..f. len ( ) {
365- if f. scalar_at ( i) ? != first_scalar {
366- is_const = false ;
367- break ;
368- }
369- }
370- is_const
371- }
364+ Canonical :: Struct ( s) => check_struct_constant ( s, ctx) ?,
365+ Canonical :: Extension ( e) => check_extension_constant ( e, ctx) ?,
366+ Canonical :: List ( l) => check_listview_constant ( l, ctx) ?,
367+ Canonical :: FixedSizeList ( f) => check_fixed_size_list_constant ( f, ctx) ?,
372368 Canonical :: Null ( _) => true ,
373369 } ;
374370
0 commit comments