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