(
&self,
array: Array<'a, T>,
indices: Variadic<i64>,
)
| 355 | } |
| 356 | #[sqlfunc(ArrayIndex, sqlname = "array_index", introduces_nulls = true)] |
| 357 | fn array_index<'a, T: FromDatum<'a>>( |
| 358 | &self, |
| 359 | array: Array<'a, T>, |
| 360 | indices: Variadic<i64>, |
| 361 | ) -> Option<T> { |
| 362 | mz_ore::soft_assert_no_log!( |
| 363 | self.offset == 0 || self.offset == 1, |
| 364 | "offset must be either 0 or 1" |
| 365 | ); |
| 366 | |
| 367 | let dims = array.dims(); |
| 368 | if dims.len() != indices.len() { |
| 369 | // You missed the datums "layer" |
| 370 | return None; |
| 371 | } |
| 372 | |
| 373 | let mut final_idx = 0; |
| 374 | |
| 375 | for (d, idx) in dims.into_iter().zip_eq(indices.iter()) { |
| 376 | // Lower bound is written in terms of 1-based indexing, which offset accounts for. |
| 377 | let idx = isize::cast_from(*idx + self.offset); |
| 378 | |
| 379 | let (lower, upper) = d.dimension_bounds(); |
| 380 | |
| 381 | // This index missed all of the data at this layer. The dimension bounds are inclusive, |
| 382 | // while range checks are exclusive, so adjust. |
| 383 | if !(lower..upper + 1).contains(&idx) { |
| 384 | return None; |
| 385 | } |
| 386 | |
| 387 | // We discover how many indices our last index represents physically. |
| 388 | final_idx *= d.length; |
| 389 | |
| 390 | // Because both index and lower bound are handled in 1-based indexing, taking their |
| 391 | // difference moves us back into 0-based indexing. Similarly, if the lower bound is |
| 392 | // negative, subtracting a negative value >= to itself ensures its non-negativity. |
| 393 | final_idx += usize::try_from(idx - d.lower_bound) |
| 394 | .expect("previous bounds check ensures physical index is at least 0"); |
| 395 | } |
| 396 | |
| 397 | array.elements().typed_iter().nth(final_idx) |
| 398 | } |
| 399 | |
| 400 | #[sqlfunc] |
| 401 | fn array_position<'a>( |
nothing calls this directly
no test coverage detected