vortex_array/scalar_fn/fns/fill_null/
kernel.rs1use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6
7use crate::ArrayRef;
8use crate::ExecutionCtx;
9use crate::IntoArray;
10use crate::arrays::ConstantArray;
11use crate::arrays::ExactScalarFn;
12use crate::arrays::ScalarFnArrayView;
13use crate::arrays::ScalarFnVTable;
14use crate::builtins::ArrayBuiltins;
15use crate::kernel::ExecuteParentKernel;
16use crate::optimizer::rules::ArrayParentReduceRule;
17use crate::scalar::Scalar;
18use crate::scalar_fn::fns::fill_null::FillNull as FillNullExpr;
19use crate::vtable::VTable;
20
21pub trait FillNullReduce: VTable {
32 fn fill_null(array: &Self::Array, fill_value: &Scalar) -> VortexResult<Option<ArrayRef>>;
33}
34
35pub trait FillNullKernel: VTable {
45 fn fill_null(
46 array: &Self::Array,
47 fill_value: &Scalar,
48 ctx: &mut ExecutionCtx,
49 ) -> VortexResult<Option<ArrayRef>>;
50}
51
52pub(super) fn precondition(
57 array: &ArrayRef,
58 fill_value: &Scalar,
59) -> VortexResult<Option<ArrayRef>> {
60 if !array.dtype().is_nullable() || array.all_valid()? {
62 return array.to_array().cast(fill_value.dtype().clone()).map(Some);
63 }
64
65 if array.all_invalid()? {
67 return Ok(Some(
68 ConstantArray::new(fill_value.clone(), array.len()).into_array(),
69 ));
70 }
71
72 Ok(None)
73}
74
75pub(crate) fn fill_null_constant(
78 array: &ConstantArray,
79 fill_value: &Scalar,
80) -> VortexResult<ArrayRef> {
81 let scalar = if array.scalar().is_null() {
82 fill_value.clone()
83 } else {
84 array.scalar().cast(fill_value.dtype())?
85 };
86 Ok(ConstantArray::new(scalar, array.len()).into_array())
87}
88
89#[derive(Default, Debug)]
91pub struct FillNullReduceAdaptor<V>(pub V);
92
93impl<V> ArrayParentReduceRule<V> for FillNullReduceAdaptor<V>
94where
95 V: FillNullReduce,
96{
97 type Parent = ExactScalarFn<FillNullExpr>;
98
99 fn reduce_parent(
100 &self,
101 array: &V::Array,
102 parent: ScalarFnArrayView<'_, FillNullExpr>,
103 child_idx: usize,
104 ) -> VortexResult<Option<ArrayRef>> {
105 if child_idx != 0 {
107 return Ok(None);
108 }
109 let scalar_fn_array = parent
110 .as_opt::<ScalarFnVTable>()
111 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
112 let fill_value = scalar_fn_array.children()[1]
113 .as_constant()
114 .vortex_expect("fill_null fill_value must be constant");
115 let arr = array.to_array();
116 if let Some(result) = precondition(&arr, &fill_value)? {
117 return Ok(Some(result));
118 }
119 <V as FillNullReduce>::fill_null(array, &fill_value)
120 }
121}
122
123#[derive(Default, Debug)]
125pub struct FillNullExecuteAdaptor<V>(pub V);
126
127impl<V> ExecuteParentKernel<V> for FillNullExecuteAdaptor<V>
128where
129 V: FillNullKernel,
130{
131 type Parent = ExactScalarFn<FillNullExpr>;
132
133 fn execute_parent(
134 &self,
135 array: &V::Array,
136 parent: ScalarFnArrayView<'_, FillNullExpr>,
137 child_idx: usize,
138 ctx: &mut ExecutionCtx,
139 ) -> VortexResult<Option<ArrayRef>> {
140 if child_idx != 0 {
142 return Ok(None);
143 }
144 let scalar_fn_array = parent
145 .as_opt::<ScalarFnVTable>()
146 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
147 let fill_value = scalar_fn_array.children()[1]
148 .as_constant()
149 .vortex_expect("fill_null fill_value must be constant");
150 let arr = array.to_array();
151 if let Some(result) = precondition(&arr, &fill_value)? {
152 return Ok(Some(result));
153 }
154 <V as FillNullKernel>::fill_null(array, &fill_value, ctx)
155 }
156}