datafusion_functions/unicode/
right.rs1use crate::unicode::common::{RightSlicer, general_left_right};
19use crate::utils::make_scalar_function;
20use arrow::datatypes::DataType;
21use datafusion_common::Result;
22use datafusion_common::exec_err;
23use datafusion_expr::TypeSignature::Exact;
24use datafusion_expr::{
25 ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
26 Volatility,
27};
28use datafusion_macros::user_doc;
29
30#[user_doc(
31 doc_section(label = "String Functions"),
32 description = "Returns a specified number of characters from the right side of a string.",
33 syntax_example = "right(str, n)",
34 sql_example = r#"```sql
35> select right('datafusion', 6);
36+------------------------------------+
37| right(Utf8("datafusion"),Int64(6)) |
38+------------------------------------+
39| fusion |
40+------------------------------------+
41```"#,
42 standard_argument(name = "str", prefix = "String"),
43 argument(name = "n", description = "Number of characters to return."),
44 related_udf(name = "left")
45)]
46#[derive(Debug, PartialEq, Eq, Hash)]
47pub struct RightFunc {
48 signature: Signature,
49}
50
51impl Default for RightFunc {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57impl RightFunc {
58 pub fn new() -> Self {
59 use DataType::*;
60 Self {
61 signature: Signature::one_of(
62 vec![
63 Exact(vec![Utf8View, Int64]),
64 Exact(vec![Utf8, Int64]),
65 Exact(vec![LargeUtf8, Int64]),
66 ],
67 Volatility::Immutable,
68 ),
69 }
70 }
71}
72
73impl ScalarUDFImpl for RightFunc {
74 fn name(&self) -> &str {
75 "right"
76 }
77
78 fn signature(&self) -> &Signature {
79 &self.signature
80 }
81
82 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
83 Ok(arg_types[0].clone())
84 }
85
86 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
91 let args = &args.args;
92 match args[0].data_type() {
93 DataType::Utf8 | DataType::Utf8View | DataType::LargeUtf8 => {
94 make_scalar_function(general_left_right::<RightSlicer>, vec![])(args)
95 }
96 other => exec_err!(
97 "Unsupported data type {other:?} for function {},\
98 expected Utf8View, Utf8 or LargeUtf8.",
99 self.name()
100 ),
101 }
102 }
103
104 fn documentation(&self) -> Option<&Documentation> {
105 self.doc()
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use arrow::array::{Array, LargeStringArray, StringArray, StringViewArray};
112 use arrow::datatypes::DataType::{LargeUtf8, Utf8, Utf8View};
113
114 use datafusion_common::{Result, ScalarValue};
115 use datafusion_expr::{ColumnarValue, ScalarUDFImpl};
116
117 use crate::unicode::right::RightFunc;
118 use crate::utils::test::test_function;
119
120 #[test]
121 fn test_functions() -> Result<()> {
122 test_function!(
123 RightFunc::new(),
124 vec![
125 ColumnarValue::Scalar(ScalarValue::from("abcde")),
126 ColumnarValue::Scalar(ScalarValue::from(2i64)),
127 ],
128 Ok(Some("de")),
129 &str,
130 Utf8,
131 StringArray
132 );
133 test_function!(
134 RightFunc::new(),
135 vec![
136 ColumnarValue::Scalar(ScalarValue::LargeUtf8(Some("abcde".to_string()))),
137 ColumnarValue::Scalar(ScalarValue::from(2i64)),
138 ],
139 Ok(Some("de")),
140 &str,
141 LargeUtf8,
142 LargeStringArray
143 );
144 test_function!(
145 RightFunc::new(),
146 vec![
147 ColumnarValue::Scalar(ScalarValue::from("abcde")),
148 ColumnarValue::Scalar(ScalarValue::from(200i64)),
149 ],
150 Ok(Some("abcde")),
151 &str,
152 Utf8,
153 StringArray
154 );
155 test_function!(
156 RightFunc::new(),
157 vec![
158 ColumnarValue::Scalar(ScalarValue::from("abcde")),
159 ColumnarValue::Scalar(ScalarValue::from(-2i64)),
160 ],
161 Ok(Some("cde")),
162 &str,
163 Utf8,
164 StringArray
165 );
166 test_function!(
167 RightFunc::new(),
168 vec![
169 ColumnarValue::Scalar(ScalarValue::from("abcde")),
170 ColumnarValue::Scalar(ScalarValue::from(i64::MIN)),
171 ],
172 Ok(Some("")),
173 &str,
174 Utf8,
175 StringArray
176 );
177 test_function!(
178 RightFunc::new(),
179 vec![
180 ColumnarValue::Scalar(ScalarValue::from("abcde")),
181 ColumnarValue::Scalar(ScalarValue::from(-200i64)),
182 ],
183 Ok(Some("")),
184 &str,
185 Utf8,
186 StringArray
187 );
188 test_function!(
189 RightFunc::new(),
190 vec![
191 ColumnarValue::Scalar(ScalarValue::from("abcde")),
192 ColumnarValue::Scalar(ScalarValue::from(0i64)),
193 ],
194 Ok(Some("")),
195 &str,
196 Utf8,
197 StringArray
198 );
199 test_function!(
200 RightFunc::new(),
201 vec![
202 ColumnarValue::Scalar(ScalarValue::Utf8(None)),
203 ColumnarValue::Scalar(ScalarValue::from(2i64)),
204 ],
205 Ok(None),
206 &str,
207 Utf8,
208 StringArray
209 );
210 test_function!(
211 RightFunc::new(),
212 vec![
213 ColumnarValue::Scalar(ScalarValue::from("abcde")),
214 ColumnarValue::Scalar(ScalarValue::Int64(None)),
215 ],
216 Ok(None),
217 &str,
218 Utf8,
219 StringArray
220 );
221 test_function!(
222 RightFunc::new(),
223 vec![
224 ColumnarValue::Scalar(ScalarValue::from("joséérend")),
225 ColumnarValue::Scalar(ScalarValue::from(5i64)),
226 ],
227 Ok(Some("érend")),
228 &str,
229 Utf8,
230 StringArray
231 );
232 test_function!(
233 RightFunc::new(),
234 vec![
235 ColumnarValue::Scalar(ScalarValue::from("joséérend")),
236 ColumnarValue::Scalar(ScalarValue::from(-3i64)),
237 ],
238 Ok(Some("éérend")),
239 &str,
240 Utf8,
241 StringArray
242 );
243 #[cfg(not(feature = "unicode_expressions"))]
244 test_function!(
245 RightFunc::new(),
246 &[
247 ColumnarValue::Scalar(ScalarValue::from("abcde")),
248 ColumnarValue::Scalar(ScalarValue::from(2i64)),
249 ],
250 internal_err!(
251 "function right requires compilation with feature flag: unicode_expressions."
252 ),
253 &str,
254 Utf8,
255 StringArray
256 );
257
258 test_function!(
260 RightFunc::new(),
261 vec![
262 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("abcde".to_string()))),
263 ColumnarValue::Scalar(ScalarValue::from(2i64)),
264 ],
265 Ok(Some("de")),
266 &str,
267 Utf8View,
268 StringViewArray
269 );
270 test_function!(
271 RightFunc::new(),
272 vec![
273 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("abcde".to_string()))),
274 ColumnarValue::Scalar(ScalarValue::from(200i64)),
275 ],
276 Ok(Some("abcde")),
277 &str,
278 Utf8View,
279 StringViewArray
280 );
281 test_function!(
282 RightFunc::new(),
283 vec![
284 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("".to_string()))),
285 ColumnarValue::Scalar(ScalarValue::from(200i64)),
286 ],
287 Ok(Some("")),
288 &str,
289 Utf8View,
290 StringViewArray
291 );
292 test_function!(
293 RightFunc::new(),
294 vec![
295 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(
296 "joséérend".to_string()
297 ))),
298 ColumnarValue::Scalar(ScalarValue::from(-3i64)),
299 ],
300 Ok(Some("éérend")),
301 &str,
302 Utf8View,
303 StringViewArray
304 );
305
306 let input = "joé楽s𐀀so↓j";
308 for n in 1..=input.chars().count() {
309 let expected = input.chars().skip(n).collect::<String>();
310 test_function!(
311 RightFunc::new(),
312 vec![
313 ColumnarValue::Scalar(ScalarValue::from(input)),
314 ColumnarValue::Scalar(ScalarValue::from(-(n as i64))),
315 ],
316 Ok(Some(expected.as_str())),
317 &str,
318 Utf8,
319 StringArray
320 );
321 }
322
323 Ok(())
324 }
325}