datafusion_functions_nested/
reverse.rs1use crate::utils::make_scalar_function;
21use arrow::array::{
22 Array, ArrayRef, Capacities, FixedSizeListArray, GenericListArray, MutableArrayData,
23 OffsetSizeTrait,
24};
25use arrow::buffer::OffsetBuffer;
26use arrow::datatypes::DataType::{FixedSizeList, LargeList, List, Null};
27use arrow::datatypes::{DataType, FieldRef};
28use datafusion_common::cast::{
29 as_fixed_size_list_array, as_large_list_array, as_list_array,
30};
31use datafusion_common::{exec_err, utils::take_function_args, Result};
32use datafusion_expr::{
33 ColumnarValue, Documentation, ScalarUDFImpl, Signature, Volatility,
34};
35use datafusion_macros::user_doc;
36use std::any::Any;
37use std::sync::Arc;
38
39make_udf_expr_and_func!(
40 ArrayReverse,
41 array_reverse,
42 array,
43 "reverses the order of elements in the array.",
44 array_reverse_udf
45);
46
47#[user_doc(
48 doc_section(label = "Array Functions"),
49 description = "Returns the array with the order of the elements reversed.",
50 syntax_example = "array_reverse(array)",
51 sql_example = r#"```sql
52> select array_reverse([1, 2, 3, 4]);
53+------------------------------------------------------------+
54| array_reverse(List([1, 2, 3, 4])) |
55+------------------------------------------------------------+
56| [4, 3, 2, 1] |
57+------------------------------------------------------------+
58```"#,
59 argument(
60 name = "array",
61 description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
62 )
63)]
64#[derive(Debug)]
65pub struct ArrayReverse {
66 signature: Signature,
67 aliases: Vec<String>,
68}
69
70impl Default for ArrayReverse {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76impl ArrayReverse {
77 pub fn new() -> Self {
78 Self {
79 signature: Signature::any(1, Volatility::Immutable),
80 aliases: vec!["list_reverse".to_string()],
81 }
82 }
83}
84
85impl ScalarUDFImpl for ArrayReverse {
86 fn as_any(&self) -> &dyn Any {
87 self
88 }
89
90 fn name(&self) -> &str {
91 "array_reverse"
92 }
93
94 fn signature(&self) -> &Signature {
95 &self.signature
96 }
97
98 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
99 Ok(arg_types[0].clone())
100 }
101
102 fn invoke_with_args(
103 &self,
104 args: datafusion_expr::ScalarFunctionArgs,
105 ) -> Result<ColumnarValue> {
106 make_scalar_function(array_reverse_inner)(&args.args)
107 }
108
109 fn aliases(&self) -> &[String] {
110 &self.aliases
111 }
112
113 fn documentation(&self) -> Option<&Documentation> {
114 self.doc()
115 }
116}
117
118pub fn array_reverse_inner(arg: &[ArrayRef]) -> Result<ArrayRef> {
120 let [input_array] = take_function_args("array_reverse", arg)?;
121
122 match &input_array.data_type() {
123 List(field) => {
124 let array = as_list_array(input_array)?;
125 general_array_reverse::<i32>(array, field)
126 }
127 LargeList(field) => {
128 let array = as_large_list_array(input_array)?;
129 general_array_reverse::<i64>(array, field)
130 }
131 FixedSizeList(field, _) => {
132 let array = as_fixed_size_list_array(input_array)?;
133 fixed_size_array_reverse(array, field)
134 }
135 Null => Ok(Arc::clone(input_array)),
136 array_type => exec_err!("array_reverse does not support type '{array_type:?}'."),
137 }
138}
139
140fn general_array_reverse<O: OffsetSizeTrait + TryFrom<i64>>(
141 array: &GenericListArray<O>,
142 field: &FieldRef,
143) -> Result<ArrayRef> {
144 let values = array.values();
145 let original_data = values.to_data();
146 let capacity = Capacities::Array(original_data.len());
147 let mut offsets = vec![O::usize_as(0)];
148 let mut nulls = vec![];
149 let mut mutable =
150 MutableArrayData::with_capacities(vec![&original_data], false, capacity);
151
152 for (row_index, offset_window) in array.offsets().windows(2).enumerate() {
153 if array.is_null(row_index) {
155 nulls.push(false);
156 offsets.push(offsets[row_index] + O::one());
157 mutable.extend(0, 0, 1);
158 continue;
159 } else {
160 nulls.push(true);
161 }
162
163 let start = offset_window[0];
164 let end = offset_window[1];
165
166 let mut index = end - O::one();
167 let mut cnt = 0;
168
169 while index >= start {
170 mutable.extend(0, index.to_usize().unwrap(), index.to_usize().unwrap() + 1);
171 index = index - O::one();
172 cnt += 1;
173 }
174 offsets.push(offsets[row_index] + O::usize_as(cnt));
175 }
176
177 let data = mutable.freeze();
178 Ok(Arc::new(GenericListArray::<O>::try_new(
179 Arc::clone(field),
180 OffsetBuffer::<O>::new(offsets.into()),
181 arrow::array::make_array(data),
182 Some(nulls.into()),
183 )?))
184}
185
186fn fixed_size_array_reverse(
187 array: &FixedSizeListArray,
188 field: &FieldRef,
189) -> Result<ArrayRef> {
190 let values = array.values();
191 let original_data = values.to_data();
192 let capacity = Capacities::Array(original_data.len());
193 let mut nulls = vec![];
194 let mut mutable =
195 MutableArrayData::with_capacities(vec![&original_data], false, capacity);
196 let value_length = array.value_length() as usize;
197
198 for row_index in 0..array.len() {
199 if array.is_null(row_index) {
201 nulls.push(false);
202 mutable.extend(0, 0, 1);
203 continue;
204 } else {
205 nulls.push(true);
206 }
207 let start = row_index * value_length;
208 let end = start + value_length;
209 for idx in (start..end).rev() {
210 mutable.extend(0, idx, idx + 1);
211 }
212 }
213
214 let data = mutable.freeze();
215 Ok(Arc::new(FixedSizeListArray::try_new(
216 Arc::clone(field),
217 array.value_length(),
218 arrow::array::make_array(data),
219 Some(nulls.into()),
220 )?))
221}