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(DataType::Utf8View)
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, StringViewArray};
112 use arrow::datatypes::DataType::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 Utf8View,
131 StringViewArray
132 );
133 test_function!(
134 RightFunc::new(),
135 vec![
136 ColumnarValue::Scalar(ScalarValue::from("abcde")),
137 ColumnarValue::Scalar(ScalarValue::from(200i64)),
138 ],
139 Ok(Some("abcde")),
140 &str,
141 Utf8View,
142 StringViewArray
143 );
144 test_function!(
145 RightFunc::new(),
146 vec![
147 ColumnarValue::Scalar(ScalarValue::from("abcde")),
148 ColumnarValue::Scalar(ScalarValue::from(-2i64)),
149 ],
150 Ok(Some("cde")),
151 &str,
152 Utf8View,
153 StringViewArray
154 );
155 test_function!(
156 RightFunc::new(),
157 vec![
158 ColumnarValue::Scalar(ScalarValue::from("abcde")),
159 ColumnarValue::Scalar(ScalarValue::from(i64::MIN)),
160 ],
161 Ok(Some("")),
162 &str,
163 Utf8View,
164 StringViewArray
165 );
166 test_function!(
167 RightFunc::new(),
168 vec![
169 ColumnarValue::Scalar(ScalarValue::from("abcde")),
170 ColumnarValue::Scalar(ScalarValue::from(-200i64)),
171 ],
172 Ok(Some("")),
173 &str,
174 Utf8View,
175 StringViewArray
176 );
177 test_function!(
178 RightFunc::new(),
179 vec![
180 ColumnarValue::Scalar(ScalarValue::from("abcde")),
181 ColumnarValue::Scalar(ScalarValue::from(0i64)),
182 ],
183 Ok(Some("")),
184 &str,
185 Utf8View,
186 StringViewArray
187 );
188 test_function!(
189 RightFunc::new(),
190 vec![
191 ColumnarValue::Scalar(ScalarValue::Utf8(None)),
192 ColumnarValue::Scalar(ScalarValue::from(2i64)),
193 ],
194 Ok(None),
195 &str,
196 Utf8View,
197 StringViewArray
198 );
199 test_function!(
200 RightFunc::new(),
201 vec![
202 ColumnarValue::Scalar(ScalarValue::from("abcde")),
203 ColumnarValue::Scalar(ScalarValue::Int64(None)),
204 ],
205 Ok(None),
206 &str,
207 Utf8View,
208 StringViewArray
209 );
210 test_function!(
211 RightFunc::new(),
212 vec![
213 ColumnarValue::Scalar(ScalarValue::from("joséérend")),
214 ColumnarValue::Scalar(ScalarValue::from(5i64)),
215 ],
216 Ok(Some("érend")),
217 &str,
218 Utf8View,
219 StringViewArray
220 );
221 test_function!(
222 RightFunc::new(),
223 vec![
224 ColumnarValue::Scalar(ScalarValue::from("joséérend")),
225 ColumnarValue::Scalar(ScalarValue::from(-3i64)),
226 ],
227 Ok(Some("éérend")),
228 &str,
229 Utf8View,
230 StringViewArray
231 );
232 #[cfg(not(feature = "unicode_expressions"))]
233 test_function!(
234 RightFunc::new(),
235 &[
236 ColumnarValue::Scalar(ScalarValue::from("abcde")),
237 ColumnarValue::Scalar(ScalarValue::from(2i64)),
238 ],
239 internal_err!(
240 "function right requires compilation with feature flag: unicode_expressions."
241 ),
242 &str,
243 Utf8View,
244 StringViewArray
245 );
246
247 test_function!(
249 RightFunc::new(),
250 vec![
251 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("abcde".to_string()))),
252 ColumnarValue::Scalar(ScalarValue::from(2i64)),
253 ],
254 Ok(Some("de")),
255 &str,
256 Utf8View,
257 StringViewArray
258 );
259 test_function!(
260 RightFunc::new(),
261 vec![
262 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("abcde".to_string()))),
263 ColumnarValue::Scalar(ScalarValue::from(200i64)),
264 ],
265 Ok(Some("abcde")),
266 &str,
267 Utf8View,
268 StringViewArray
269 );
270 test_function!(
271 RightFunc::new(),
272 vec![
273 ColumnarValue::Scalar(ScalarValue::Utf8View(Some("".to_string()))),
274 ColumnarValue::Scalar(ScalarValue::from(200i64)),
275 ],
276 Ok(Some("")),
277 &str,
278 Utf8View,
279 StringViewArray
280 );
281 test_function!(
282 RightFunc::new(),
283 vec![
284 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(
285 "joséérend".to_string()
286 ))),
287 ColumnarValue::Scalar(ScalarValue::from(-3i64)),
288 ],
289 Ok(Some("éérend")),
290 &str,
291 Utf8View,
292 StringViewArray
293 );
294
295 let input = "joé楽s𐀀so↓j";
297 for n in 1..=input.chars().count() {
298 let expected = input.chars().skip(n).collect::<String>();
299 test_function!(
300 RightFunc::new(),
301 vec![
302 ColumnarValue::Scalar(ScalarValue::from(input)),
303 ColumnarValue::Scalar(ScalarValue::from(-(n as i64))),
304 ],
305 Ok(Some(expected.as_str())),
306 &str,
307 Utf8View,
308 StringViewArray
309 );
310 }
311
312 Ok(())
313 }
314}