vortex_array/scalar_fn/fns/fill_null/
kernel.rs1use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6use vortex_error::vortex_ensure;
7
8use crate::ArrayRef;
9use crate::ExecutionCtx;
10use crate::IntoArray;
11use crate::array::ArrayView;
12use crate::array::VTable;
13use crate::arrays::Constant;
14use crate::arrays::ConstantArray;
15use crate::arrays::ScalarFn;
16use crate::arrays::scalar_fn::ExactScalarFn;
17use crate::arrays::scalar_fn::ScalarFnArrayExt;
18use crate::arrays::scalar_fn::ScalarFnArrayView;
19use crate::builtins::ArrayBuiltins;
20use crate::kernel::ExecuteParentKernel;
21use crate::optimizer::rules::ArrayParentReduceRule;
22use crate::scalar::Scalar;
23use crate::scalar_fn::fns::fill_null::FillNull as FillNullExpr;
24use crate::validity::Validity;
25
26pub trait FillNullReduce: VTable {
37 fn fill_null(array: ArrayView<'_, Self>, fill_value: &Scalar)
38 -> VortexResult<Option<ArrayRef>>;
39}
40
41pub trait FillNullKernel: VTable {
51 fn fill_null(
52 array: ArrayView<'_, Self>,
53 fill_value: &Scalar,
54 ctx: &mut ExecutionCtx,
55 ) -> VortexResult<Option<ArrayRef>>;
56}
57
58pub(super) fn short_circuit(
68 array: &ArrayRef,
69 fill_value: &Scalar,
70) -> VortexResult<Option<ArrayRef>> {
71 vortex_ensure!(
72 !fill_value.is_null(),
73 "fill_null requires a non-null fill value"
74 );
75
76 if !array.dtype().is_nullable()
78 || matches!(
79 array.validity()?,
80 Validity::NonNullable | Validity::AllValid
81 )
82 {
83 return array.clone().cast(fill_value.dtype().clone()).map(Some);
84 }
85
86 if array.validity()?.definitely_all_null() {
88 return Ok(Some(
89 ConstantArray::new(fill_value.clone(), array.len()).into_array(),
90 ));
91 }
92
93 Ok(None)
94}
95
96pub(crate) fn fill_null_constant(
99 array: ArrayView<Constant>,
100 fill_value: &Scalar,
101) -> VortexResult<ArrayRef> {
102 let scalar = if array.scalar().is_null() {
103 fill_value.clone()
104 } else {
105 array.scalar().cast(fill_value.dtype())?
106 };
107 Ok(ConstantArray::new(scalar, array.len()).into_array())
108}
109
110#[derive(Default, Debug)]
112pub struct FillNullReduceAdaptor<V>(pub V);
113
114impl<V> ArrayParentReduceRule<V> for FillNullReduceAdaptor<V>
115where
116 V: FillNullReduce,
117{
118 type Parent = ExactScalarFn<FillNullExpr>;
119
120 fn reduce_parent(
121 &self,
122 array: ArrayView<'_, V>,
123 parent: ScalarFnArrayView<'_, FillNullExpr>,
124 child_idx: usize,
125 ) -> VortexResult<Option<ArrayRef>> {
126 if child_idx != 0 {
128 return Ok(None);
129 }
130 let scalar_fn_array = parent
131 .as_opt::<ScalarFn>()
132 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
133 let fill_value = scalar_fn_array
134 .get_child(1)
135 .as_constant()
136 .vortex_expect("fill_null fill_value must be constant");
137 let arr = array.array().clone();
138 if let Some(result) = short_circuit(&arr, &fill_value)? {
139 return Ok(Some(result));
140 }
141 <V as FillNullReduce>::fill_null(array, &fill_value)
142 }
143}
144
145#[derive(Default, Debug)]
147pub struct FillNullExecuteAdaptor<V>(pub V);
148
149impl<V> ExecuteParentKernel<V> for FillNullExecuteAdaptor<V>
150where
151 V: FillNullKernel,
152{
153 type Parent = ExactScalarFn<FillNullExpr>;
154
155 fn execute_parent(
156 &self,
157 array: ArrayView<'_, V>,
158 parent: ScalarFnArrayView<'_, FillNullExpr>,
159 child_idx: usize,
160 ctx: &mut ExecutionCtx,
161 ) -> VortexResult<Option<ArrayRef>> {
162 if child_idx != 0 {
164 return Ok(None);
165 }
166 let scalar_fn_array = parent
167 .as_opt::<ScalarFn>()
168 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
169 let fill_value = scalar_fn_array
170 .get_child(1)
171 .as_constant()
172 .vortex_expect("fill_null fill_value must be constant");
173 let arr = array.array().clone();
174 if let Some(result) = short_circuit(&arr, &fill_value)? {
175 return Ok(Some(result));
176 }
177 <V as FillNullKernel>::fill_null(array, &fill_value, ctx)
178 }
179}