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