Jefffrey commented on code in PR #9023: URL: https://github.com/apache/arrow-datafusion/pull/9023#discussion_r1468666687
########## docs/source/user-guide/sql/scalar_functions.md: ########## @@ -2457,6 +2458,34 @@ array_replace_all(array, from, to) - list_replace_all +### `array_reverse` + +Returns the array with the order of the elements reversed. + +``` +array_reverse(array) +``` + +#### Arguments + +- **array**: Array expression. + Can be a constant, column, or function, and any combination of array operators. + +#### Example + +``` +❯ select array_reverse([1, 2, 3, 4]); ++------------------------------------------------------------+ +| array_reverse(List([1, 2, 3, 4])) | ++------------------------------------------------------------+ +| [4, 3, 2, 1] | ++------------------------------------------------------------+ +``` + +#### Aliases + +- list_reverse Review Comment: I think also need to add doc stub for list_reverse? e.g. https://github.com/apache/arrow-datafusion/blob/7a5f2054305fd92852b589473afbc9bb034379d7/docs/source/user-guide/sql/scalar_functions.md?plain=1#L2718-L2720 ########## datafusion/physical-expr/src/array_expressions.rs: ########## @@ -2766,6 +2766,72 @@ where )?)) } +/// array_reverse SQL function +pub fn array_reverse(arg: &[ArrayRef]) -> Result<ArrayRef> { + if arg.len() != 1 { + return exec_err!("array_reverse needs one argument"); + } + + match &arg[0].data_type() { + DataType::List(field) => { + let array = as_list_array(&arg[0])?; + general_array_reverse::<i32>(array, &field) + } + DataType::LargeList(field) => { + let array = as_large_list_array(&arg[0])?; + general_array_reverse::<i64>(array, &field) + } + DataType::Null => Ok(arg[0].clone()), + array_type => exec_err!("array_reverse does not support type '{array_type:?}'."), + } +} + +fn general_array_reverse<O: OffsetSizeTrait>( + array: &GenericListArray<O>, + field: &FieldRef, +) -> Result<ArrayRef> +where + O: TryFrom<i64>, +{ + let values = array.values(); + let original_data = values.to_data(); + let capacity = Capacities::Array(original_data.len()); + let mut offsets = vec![O::usize_as(0)]; + let mut nulls = vec![]; + let mut mutable = + MutableArrayData::with_capacities(vec![&original_data], false, capacity); + + for (row_index, offset_window) in array.offsets().windows(2).enumerate() { + let start = offset_window[0]; + let end = offset_window[1]; + + let mut index = end - O::one(); + let mut cnt = 0; + let stride: O = (-1 as i64).try_into().map_err(|_| { + internal_datafusion_err!("array_reverse: failed to convert size to i64") + })?; + while index >= start { + mutable.extend(0, index.to_usize().unwrap(), index.to_usize().unwrap() + 1); + index += stride; + cnt += 1; + } + offsets.push(offsets[row_index] + O::usize_as(cnt)); + if cnt == 0 { + nulls.push(false); + } else { + nulls.push(true); + } Review Comment: I'm not sure we can rely on `cnt` being zero to indicate a null? According to arrow-rs doc for GenericListArray: https://github.com/apache/arrow-rs/blob/5117b38d99f23498f6b87e23efbe06a841c63b0b/arrow-array/src/array/list_array.rs#L99-L123 Nulls could take up a non-zero slot if offsets. Please let me know if my understanding is incorrect on this account :sweat_smile: ########## datafusion/physical-expr/src/array_expressions.rs: ########## @@ -2766,6 +2766,72 @@ where )?)) } +/// array_reverse SQL function +pub fn array_reverse(arg: &[ArrayRef]) -> Result<ArrayRef> { + if arg.len() != 1 { + return exec_err!("array_reverse needs one argument"); + } + + match &arg[0].data_type() { + DataType::List(field) => { + let array = as_list_array(&arg[0])?; + general_array_reverse::<i32>(array, &field) + } + DataType::LargeList(field) => { + let array = as_large_list_array(&arg[0])?; + general_array_reverse::<i64>(array, &field) + } + DataType::Null => Ok(arg[0].clone()), Review Comment: Leave a TODO item/create new issue for support for reversing FixedSizeList too? Unless you feel you can add in support for that in this PR, even though they aren't a GenericListArray underneath ########## datafusion/sqllogictest/test_files/array.slt: ########## @@ -5009,6 +5009,34 @@ select array_resize(arrow_cast([[1], [2], [3]], 'LargeList(List(Int64))'), 10, [ ---- [[1], [2], [3], [5], [5], [5], [5], [5], [5], [5]] +## array_reverse +query ?? +select array_reverse(make_array(1, 2, 3)), array_reverse(make_array(1)); +---- +[3, 2, 1] [1] + +query ?? +select array_reverse(arrow_cast(make_array(1, 2, 3), 'LargeList(Int64)')), array_reverse(arrow_cast(make_array(1), 'LargeList(Int64)')); +---- +[3, 2, 1] [1] + +query ? +select array_reverse(NULL); +---- +NULL + +query ?? +select array_reverse(column1), column1 from arrays_values; +---- +[10, 9, 8, 7, 6, 5, 4, 3, 2, ] [, 2, 3, 4, 5, 6, 7, 8, 9, 10] +[20, , 18, 17, 16, 15, 14, 13, 12, 11] [11, 12, 13, 14, 15, 16, 17, 18, , 20] +[30, 29, 28, 27, 26, 25, , 23, 22, 21] [21, 22, 23, , 25, 26, 27, 28, 29, 30] +[40, 39, 38, 37, , 35, 34, 33, 32, 31] [31, 32, 33, 34, 35, , 37, 38, 39, 40] +NULL NULL +[50, 49, 48, 47, 46, 45, 44, 43, 42, 41] [41, 42, 43, 44, 45, 46, 47, 48, 49, 50] +[60, 59, 58, 57, 56, 55, 54, , 52, 51] [51, 52, , 54, 55, 56, 57, 58, 59, 60] +[70, 69, 68, 67, 66, 65, 64, 63, 62, 61] [61, 62, 63, 64, 65, 66, 67, 68, 69, 70] Review Comment: Can we add a test for when the list is empty? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
