44use vortex_array:: ArrayRef ;
55use vortex_array:: ArrayView ;
66use vortex_array:: IntoArray ;
7- use vortex_array:: LEGACY_SESSION ;
8- use vortex_array:: VortexSessionExecute ;
97use vortex_array:: builtins:: ArrayBuiltins ;
108use vortex_array:: dtype:: DType ;
119use vortex_array:: scalar_fn:: fns:: cast:: CastReduce ;
@@ -16,38 +14,35 @@ use crate::alp_rd::ALPRD;
1614
1715impl CastReduce for ALPRD {
1816 fn cast ( array : ArrayView < ' _ , Self > , dtype : & DType ) -> VortexResult < Option < ArrayRef > > {
19- // ALPRDArray stores floating-point values, so only cast between float types
20- // or if just changing nullability
21-
2217 // Check if this is just a nullability change
23- if array. dtype ( ) . eq_ignore_nullability ( dtype) {
24- // For nullability-only changes, we need to cast the left_parts array
25- // since it carries the validity information
26- let new_left_parts = array. left_parts ( ) . cast (
27- array
28- . left_parts ( )
29- . dtype ( )
30- . with_nullability ( dtype. nullability ( ) ) ,
31- ) ?;
18+ if !array. dtype ( ) . eq_ignore_nullability ( dtype) {
19+ return Ok ( None ) ;
20+ }
21+
22+ // For nullability-only changes, we need to cast the left_parts array
23+ // since it carries the validity information
24+ let new_left_parts = array. left_parts ( ) . cast (
25+ array
26+ . left_parts ( )
27+ . dtype ( )
28+ . with_nullability ( dtype. nullability ( ) ) ,
29+ ) ?;
3230
33- // NOTE: `CastReduce::cast` has a fixed trait signature without `ExecutionCtx`, so we
34- // construct a legacy ctx locally at this trait boundary.
35- return Ok ( Some (
36- ALPRD :: try_new (
31+ // NOTE: `CastReduce::cast` has a fixed trait signature without `ExecutionCtx`, so we
32+ // construct a legacy ctx locally at this trait boundary.
33+ Ok ( Some (
34+ unsafe {
35+ ALPRD :: new_unchecked (
3736 dtype. clone ( ) ,
3837 new_left_parts,
3938 array. left_parts_dictionary ( ) . clone ( ) ,
4039 array. right_parts ( ) . clone ( ) ,
4140 array. right_bit_width ( ) ,
4241 array. left_parts_patches ( ) ,
43- & mut LEGACY_SESSION . create_execution_ctx ( ) ,
44- ) ?
45- . into_array ( ) ,
46- ) ) ;
47- }
48-
49- // For other casts (e.g., f32 to f64), decode to canonical and let PrimitiveArray handle it
50- Ok ( None )
42+ )
43+ }
44+ . into_array ( ) ,
45+ ) )
5146 }
5247}
5348
@@ -99,12 +94,17 @@ mod tests {
9994 let encoder = RDEncoder :: new ( & values) ;
10095 let alprd = encoder. encode ( arr. as_view ( ) , & mut ctx) ;
10196
102- // Cast to NonNullable should fail since we have nulls
97+ // Cast to NonNullable should fail since we have nulls. The failure surfaces during
98+ // execution since the reduce path defers when the validity stat is not cached.
10399 let result = alprd
104100 . clone ( )
105101 . into_array ( )
106- . cast ( DType :: Primitive ( PType :: F64 , Nullability :: NonNullable ) ) ;
107- assert ! ( result. is_err( ) ) ;
102+ . cast ( DType :: Primitive ( PType :: F64 , Nullability :: NonNullable ) )
103+ . and_then ( |a| {
104+ a. execute :: < PrimitiveArray > ( & mut ctx)
105+ . map ( |p| p. into_array ( ) )
106+ } ) ;
107+ assert ! ( result. is_err( ) , "Expected error, got: {result:?}" ) ;
108108
109109 // Cast to same type with Nullable should succeed
110110 let casted = alprd
0 commit comments