(&self, args: HigherOrderFunctionArgs)
| 181 | } |
| 182 | |
| 183 | fn invoke_with_args(&self, args: HigherOrderFunctionArgs) -> Result<ColumnarValue> { |
| 184 | let [ValueOrLambda::Value(list), ValueOrLambda::Lambda(lambda)] = |
| 185 | take_function_args(self.name(), &args.args)? |
| 186 | else { |
| 187 | return exec_err!("{} expects a value followed by a lambda", self.name()); |
| 188 | }; |
| 189 | |
| 190 | let list_array = list.to_array(args.number_rows)?; |
| 191 | |
| 192 | // fast path: fully null input — also required for FixedSizeList which can't be |
| 193 | // handled by clear_null_values when fully null |
| 194 | if list_array.null_count() == list_array.len() { |
| 195 | return Ok(ColumnarValue::Array(new_null_array( |
| 196 | args.return_type(), |
| 197 | list_array.len(), |
| 198 | ))); |
| 199 | } |
| 200 | |
| 201 | let list_values = list_values(&list_array)?; |
| 202 | |
| 203 | let values_param = || Ok(Arc::clone(&list_values)); |
| 204 | |
| 205 | let predicate_results = lambda |
| 206 | .evaluate(&[&values_param], |arrays| { |
| 207 | let indices = list_values_row_number(&list_array)?; |
| 208 | Ok(take_arrays(arrays, &indices, None)?) |
| 209 | })? |
| 210 | .into_array(list_values.len())?; |
| 211 | |
| 212 | let predicate_bool = predicate_results |
| 213 | .as_any() |
| 214 | .downcast_ref::<BooleanArray>() |
| 215 | .ok_or_else(|| { |
| 216 | exec_datafusion_err!( |
| 217 | "{} predicate must return boolean array", |
| 218 | self.name() |
| 219 | ) |
| 220 | })?; |
| 221 | |
| 222 | let mut values = BooleanBuilder::with_capacity(list_array.len()); |
| 223 | |
| 224 | // Maps predicate results (flat over all elements) back to one Boolean per row. |
| 225 | // Uses adjusted offsets so sliced lists index correctly into the predicate array. |
| 226 | macro_rules! process_list { |
| 227 | ($list_typed:expr) => {{ |
| 228 | let offsets = adjust_offsets_for_slice($list_typed); |
| 229 | for i in 0..$list_typed.len() { |
| 230 | let start = offsets[i].as_usize(); |
| 231 | let end = offsets[i + 1].as_usize(); |
| 232 | // any_match_for_range returns None when nulls poison the result; |
| 233 | // null rows produce an empty range and return Some(false), but their |
| 234 | // null bit is preserved by attaching the original null bitmap below. |
| 235 | values.append_option(any_match_for_range(predicate_bool, start, end)); |
| 236 | } |
| 237 | }}; |
| 238 | } |
| 239 | |
| 240 | match list_array.data_type() { |
nothing calls this directly
no test coverage detected