(
a: Option<Array<'a>>,
b: Option<Array<'a>>,
temp_storage: &'a RowArena,
)
| 2844 | introduces_nulls = false |
| 2845 | )] |
| 2846 | fn array_array_concat<'a>( |
| 2847 | a: Option<Array<'a>>, |
| 2848 | b: Option<Array<'a>>, |
| 2849 | temp_storage: &'a RowArena, |
| 2850 | ) -> Result<Option<Array<'a>>, EvalError> { |
| 2851 | let Some(a_array) = a else { |
| 2852 | return Ok(b); |
| 2853 | }; |
| 2854 | let Some(b_array) = b else { |
| 2855 | return Ok(a); |
| 2856 | }; |
| 2857 | |
| 2858 | let a_dims: Vec<ArrayDimension> = a_array.dims().into_iter().collect(); |
| 2859 | let b_dims: Vec<ArrayDimension> = b_array.dims().into_iter().collect(); |
| 2860 | |
| 2861 | let a_ndims = a_dims.len(); |
| 2862 | let b_ndims = b_dims.len(); |
| 2863 | |
| 2864 | // Per PostgreSQL, if either of the input arrays is zero dimensional, |
| 2865 | // the output is the other array, no matter their dimensions. |
| 2866 | if a_ndims == 0 { |
| 2867 | return Ok(b); |
| 2868 | } else if b_ndims == 0 { |
| 2869 | return Ok(a); |
| 2870 | } |
| 2871 | |
| 2872 | // Postgres supports concatenating arrays of different dimensions, |
| 2873 | // as long as one of the arrays has the same type as an element of |
| 2874 | // the other array, i.e. `int[2][4] || int[4]` (or `int[4] || int[2][4]`) |
| 2875 | // works, because each element of `int[2][4]` is an `int[4]`. |
| 2876 | // This check is separate from the one below because Postgres gives a |
| 2877 | // specific error message if the number of dimensions differs by more |
| 2878 | // than one. |
| 2879 | // This cast is safe since MAX_ARRAY_DIMENSIONS is 6 |
| 2880 | // Can be replaced by .abs_diff once it is stabilized |
| 2881 | // TODO(benesch): remove potentially dangerous usage of `as`. |
| 2882 | #[allow(clippy::as_conversions)] |
| 2883 | if (a_ndims as isize - b_ndims as isize).abs() > 1 { |
| 2884 | return Err(EvalError::IncompatibleArrayDimensions { |
| 2885 | dims: Some((a_ndims, b_ndims)), |
| 2886 | }); |
| 2887 | } |
| 2888 | |
| 2889 | let mut dims; |
| 2890 | |
| 2891 | // After the checks above, we are certain that: |
| 2892 | // - neither array is zero dimensional nor empty |
| 2893 | // - both arrays have the same number of dimensions, or differ |
| 2894 | // at most by one. |
| 2895 | match a_ndims.cmp(&b_ndims) { |
| 2896 | // If both arrays have the same number of dimensions, validate |
| 2897 | // that their inner dimensions are the same and concatenate the |
| 2898 | // arrays. |
| 2899 | Ordering::Equal => { |
| 2900 | if &a_dims[1..] != &b_dims[1..] { |
| 2901 | return Err(EvalError::IncompatibleArrayDimensions { dims: None }); |
| 2902 | } |
| 2903 | dims = vec![ArrayDimension { |
nothing calls this directly
no test coverage detected