vortex_array/expr/exprs/fill_null/
kernel.rs1use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6
7use crate::Array;
8use crate::ArrayRef;
9use crate::ExecutionCtx;
10use crate::IntoArray;
11use crate::arrays::ConstantArray;
12use crate::arrays::ExactScalarFn;
13use crate::arrays::ScalarFnArrayView;
14use crate::arrays::ScalarFnVTable;
15use crate::builtins::ArrayBuiltins;
16use crate::expr::FillNull as FillNullExpr;
17use crate::kernel::ExecuteParentKernel;
18use crate::optimizer::rules::ArrayParentReduceRule;
19use crate::scalar::Scalar;
20use crate::vtable::VTable;
21
22pub trait FillNullReduce: VTable {
33 fn fill_null(array: &Self::Array, fill_value: &Scalar) -> VortexResult<Option<ArrayRef>>;
34}
35
36pub trait FillNullKernel: VTable {
46 fn fill_null(
47 array: &Self::Array,
48 fill_value: &Scalar,
49 ctx: &mut ExecutionCtx,
50 ) -> VortexResult<Option<ArrayRef>>;
51}
52
53pub(super) fn precondition(
58 array: &dyn Array,
59 fill_value: &Scalar,
60) -> VortexResult<Option<ArrayRef>> {
61 if !array.dtype().is_nullable() || array.all_valid()? {
63 return array.to_array().cast(fill_value.dtype().clone()).map(Some);
64 }
65
66 if array.all_invalid()? {
68 return Ok(Some(
69 ConstantArray::new(fill_value.clone(), array.len()).into_array(),
70 ));
71 }
72
73 Ok(None)
74}
75
76pub(crate) fn fill_null_constant(
79 array: &ConstantArray,
80 fill_value: &Scalar,
81) -> VortexResult<ArrayRef> {
82 let scalar = if array.scalar().is_null() {
83 fill_value.clone()
84 } else {
85 array.scalar().cast(fill_value.dtype())?
86 };
87 Ok(ConstantArray::new(scalar, array.len()).into_array())
88}
89
90#[derive(Default, Debug)]
92pub struct FillNullReduceAdaptor<V>(pub V);
93
94impl<V> ArrayParentReduceRule<V> for FillNullReduceAdaptor<V>
95where
96 V: FillNullReduce,
97{
98 type Parent = ExactScalarFn<FillNullExpr>;
99
100 fn reduce_parent(
101 &self,
102 array: &V::Array,
103 parent: ScalarFnArrayView<'_, FillNullExpr>,
104 child_idx: usize,
105 ) -> VortexResult<Option<ArrayRef>> {
106 if child_idx != 0 {
108 return Ok(None);
109 }
110 let scalar_fn_array = parent
111 .as_opt::<ScalarFnVTable>()
112 .vortex_expect("ExactScalarFn matcher confirmed ScalarFnArray");
113 let fill_value = scalar_fn_array.children()[1]
114 .as_constant()
115 .vortex_expect("fill_null fill_value must be constant");
116 if let Some(result) = precondition(&**array, &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 if let Some(result) = precondition(&**array, &fill_value)? {
151 return Ok(Some(result));
152 }
153 <V as FillNullKernel>::fill_null(array, &fill_value, ctx)
154 }
155}