22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
44use vortex_error:: VortexResult ;
5+ use vortex_mask:: Mask ;
56
67use crate :: ArrayRef ;
7- use crate :: DynArray ;
88use crate :: ExecutionCtx ;
99use crate :: aggregate_fn:: AggregateFnRef ;
1010use crate :: aggregate_fn:: fns:: is_constant:: IsConstant ;
@@ -16,7 +16,8 @@ use crate::scalar::Scalar;
1616/// Dict-specific is_constant kernel.
1717///
1818/// If codes are constant, the whole array is constant.
19- /// Otherwise, check the values array.
19+ /// When all dictionary values are referenced, is_constant can be computed directly on the values
20+ /// array. Otherwise, unreferenced values are filtered out first.
2021#[ derive( Debug ) ]
2122pub ( crate ) struct DictIsConstantKernel ;
2223
@@ -35,37 +36,21 @@ impl DynAggregateKernel for DictIsConstantKernel {
3536 return Ok ( None ) ;
3637 } ;
3738
38- let result = if is_constant ( dict. codes ( ) , ctx) ? {
39- true
40- } else {
39+ // If codes are constant, only one dictionary value is referenced → constant.
40+ if is_constant ( dict. codes ( ) , ctx) ? {
41+ return Ok ( Some ( IsConstant :: make_partial ( batch, true ) ?) ) ;
42+ }
43+
44+ // Otherwise, check the values array. Filter to only referenced values if needed.
45+ let result = if dict. has_all_values_referenced ( ) {
4146 is_constant ( dict. values ( ) , ctx) ?
47+ } else {
48+ let referenced_mask = dict. compute_referenced_values_mask ( true ) ?;
49+ let mask = Mask :: from ( referenced_mask) ;
50+ let filtered_values = dict. values ( ) . filter ( mask) ?;
51+ is_constant ( & filtered_values, ctx) ?
4252 } ;
4353
44- // Return in the partial dtype format: struct {is_constant, value}
45- // We use the first scalar as the representative value.
46- let partial_dtype =
47- crate :: aggregate_fn:: fns:: is_constant:: make_is_constant_partial_dtype ( batch. dtype ( ) ) ;
48- if result {
49- let first_value = if batch. is_empty ( ) {
50- return Ok ( Some ( Scalar :: null ( partial_dtype) ) ) ;
51- } else {
52- batch. scalar_at ( 0 ) ?. into_nullable ( )
53- } ;
54- Ok ( Some ( Scalar :: struct_ (
55- partial_dtype,
56- vec ! [
57- Scalar :: bool ( true , crate :: dtype:: Nullability :: NonNullable ) ,
58- first_value,
59- ] ,
60- ) ) )
61- } else {
62- Ok ( Some ( Scalar :: struct_ (
63- partial_dtype,
64- vec ! [
65- Scalar :: bool ( false , crate :: dtype:: Nullability :: NonNullable ) ,
66- Scalar :: null( batch. dtype( ) . as_nullable( ) ) ,
67- ] ,
68- ) ) )
69- }
54+ Ok ( Some ( IsConstant :: make_partial ( batch, result) ?) )
7055 }
7156}
0 commit comments