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::ScalarFnVTable;
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;
24
25pub trait FillNullReduce: VTable {
36 fn fill_null(array: ArrayView<'_, Self>, fill_value: &Scalar)
37 -> VortexResult<Option<ArrayRef>>;
38}
39
40pub trait FillNullKernel: VTable {
50 fn fill_null(
51 array: ArrayView<'_, Self>,
52 fill_value: &Scalar,
53 ctx: &mut ExecutionCtx,
54 ) -> VortexResult<Option<ArrayRef>>;
55}
56
57pub(super) fn precondition(
62 array: &ArrayRef,
63 fill_value: &Scalar,
64) -> VortexResult<Option<ArrayRef>> {
65 vortex_ensure!(
66 !fill_value.is_null(),
67 "fill_null requires a non-null fill value"
68 );
69
70 if !array.dtype().is_nullable() || array.all_valid()? {
72 return array.clone().cast(fill_value.dtype().clone()).map(Some);
73 }
74
75 if array.all_invalid()? {
77 return Ok(Some(
78 ConstantArray::new(fill_value.clone(), array.len()).into_array(),
79 ));
80 }
81
82 Ok(None)
83}
84
85pub(crate) fn fill_null_constant(
88 array: ArrayView<Constant>,
89 fill_value: &Scalar,
90) -> VortexResult<ArrayRef> {
91 let scalar = if array.scalar().is_null() {
92 fill_value.clone()
93 } else {
94 array.scalar().cast(fill_value.dtype())?
95 };
96 Ok(ConstantArray::new(scalar, array.len()).into_array())
97}
98
99#[derive(Default, Debug)]
101pub struct FillNullReduceAdaptor<V>(pub V);
102
103impl<V> ArrayParentReduceRule<V> for FillNullReduceAdaptor<V>
104where
105 V: FillNullReduce,
106{
107 type Parent = ExactScalarFn<FillNullExpr>;
108
109 fn reduce_parent(
110 &self,
111 array: ArrayView<'_, V>,
112 parent: ScalarFnArrayView<'_, FillNullExpr>,
113 child_idx: usize,
114 ) -> VortexResult<Option<ArrayRef>> {
115 if child_idx != 0 {
117 return Ok(None);
118 }
119 let scalar_fn_array = parent
120 .as_opt::<ScalarFnVTable>()
121 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
122 let fill_value = scalar_fn_array
123 .get_child(1)
124 .as_constant()
125 .vortex_expect("fill_null fill_value must be constant");
126 let arr = array.array().clone();
127 if let Some(result) = precondition(&arr, &fill_value)? {
128 return Ok(Some(result));
129 }
130 <V as FillNullReduce>::fill_null(array, &fill_value)
131 }
132}
133
134#[derive(Default, Debug)]
136pub struct FillNullExecuteAdaptor<V>(pub V);
137
138impl<V> ExecuteParentKernel<V> for FillNullExecuteAdaptor<V>
139where
140 V: FillNullKernel,
141{
142 type Parent = ExactScalarFn<FillNullExpr>;
143
144 fn execute_parent(
145 &self,
146 array: ArrayView<'_, V>,
147 parent: ScalarFnArrayView<'_, FillNullExpr>,
148 child_idx: usize,
149 ctx: &mut ExecutionCtx,
150 ) -> VortexResult<Option<ArrayRef>> {
151 if child_idx != 0 {
153 return Ok(None);
154 }
155 let scalar_fn_array = parent
156 .as_opt::<ScalarFnVTable>()
157 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
158 let fill_value = scalar_fn_array
159 .get_child(1)
160 .as_constant()
161 .vortex_expect("fill_null fill_value must be constant");
162 let arr = array.array().clone();
163 if let Some(result) = precondition(&arr, &fill_value)? {
164 return Ok(Some(result));
165 }
166 <V as FillNullKernel>::fill_null(array, &fill_value, ctx)
167 }
168}