This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new c6be00d501 Add Utf8View support to STRPOS function (#12087)
c6be00d501 is described below

commit c6be00d5012e89ea29611f02b9edf15c806db6c5
Author: Dmitry Bugakov <[email protected]>
AuthorDate: Wed Aug 21 21:05:03 2024 +0200

    Add Utf8View support to STRPOS function (#12087)
    
    * Add Utf8View support to STRPOS function
    
    * fix type inconsistency
    
    * fix type inconsistency
    
    * refactor tests
---
 datafusion/functions/src/unicode/strpos.rs         | 175 ++++++++++++++-------
 datafusion/sqllogictest/test_files/string_view.slt |   5 +-
 2 files changed, 121 insertions(+), 59 deletions(-)

diff --git a/datafusion/functions/src/unicode/strpos.rs 
b/datafusion/functions/src/unicode/strpos.rs
index 702baf6e8f..cf10b18ae3 100644
--- a/datafusion/functions/src/unicode/strpos.rs
+++ b/datafusion/functions/src/unicode/strpos.rs
@@ -19,11 +19,10 @@ use std::any::Any;
 use std::sync::Arc;
 
 use arrow::array::{
-    ArrayRef, ArrowPrimitiveType, GenericStringArray, OffsetSizeTrait, 
PrimitiveArray,
+    ArrayAccessor, ArrayIter, ArrayRef, ArrowPrimitiveType, AsArray, 
PrimitiveArray,
 };
 use arrow::datatypes::{ArrowNativeType, DataType, Int32Type, Int64Type};
 
-use datafusion_common::cast::as_generic_string_array;
 use datafusion_common::{exec_err, Result};
 use datafusion_expr::TypeSignature::Exact;
 use datafusion_expr::{ColumnarValue, ScalarUDFImpl, Signature, Volatility};
@@ -52,6 +51,9 @@ impl StrposFunc {
                     Exact(vec![Utf8, LargeUtf8]),
                     Exact(vec![LargeUtf8, Utf8]),
                     Exact(vec![LargeUtf8, LargeUtf8]),
+                    Exact(vec![Utf8View, Utf8View]),
+                    Exact(vec![Utf8View, Utf8]),
+                    Exact(vec![Utf8View, LargeUtf8]),
                 ],
                 Volatility::Immutable,
             ),
@@ -78,21 +80,7 @@ impl ScalarUDFImpl for StrposFunc {
     }
 
     fn invoke(&self, args: &[ColumnarValue]) -> Result<ColumnarValue> {
-        match (args[0].data_type(), args[1].data_type()) {
-            (DataType::Utf8, DataType::Utf8) => {
-                make_scalar_function(strpos::<Int32Type, Int32Type>, 
vec![])(args)
-            }
-            (DataType::Utf8, DataType::LargeUtf8) => {
-                make_scalar_function(strpos::<Int32Type, Int64Type>, 
vec![])(args)
-            }
-            (DataType::LargeUtf8, DataType::Utf8) => {
-                make_scalar_function(strpos::<Int64Type, Int32Type>, 
vec![])(args)
-            }
-            (DataType::LargeUtf8, DataType::LargeUtf8) => {
-                make_scalar_function(strpos::<Int64Type, Int64Type>, 
vec![])(args)
-            }
-            other => exec_err!("Unsupported data type {other:?} for function 
strpos"),
-        }
+        make_scalar_function(strpos, vec![])(args)
     }
 
     fn aliases(&self) -> &[String] {
@@ -100,30 +88,71 @@ impl ScalarUDFImpl for StrposFunc {
     }
 }
 
+fn strpos(args: &[ArrayRef]) -> Result<ArrayRef> {
+    match (args[0].data_type(), args[1].data_type()) {
+        (DataType::Utf8, DataType::Utf8) => {
+            let string_array = args[0].as_string::<i32>();
+            let substring_array = args[1].as_string::<i32>();
+            calculate_strpos::<_, _, Int32Type>(string_array, substring_array)
+        }
+        (DataType::Utf8, DataType::LargeUtf8) => {
+            let string_array = args[0].as_string::<i32>();
+            let substring_array = args[1].as_string::<i64>();
+            calculate_strpos::<_, _, Int32Type>(string_array, substring_array)
+        }
+        (DataType::LargeUtf8, DataType::Utf8) => {
+            let string_array = args[0].as_string::<i64>();
+            let substring_array = args[1].as_string::<i32>();
+            calculate_strpos::<_, _, Int64Type>(string_array, substring_array)
+        }
+        (DataType::LargeUtf8, DataType::LargeUtf8) => {
+            let string_array = args[0].as_string::<i64>();
+            let substring_array = args[1].as_string::<i64>();
+            calculate_strpos::<_, _, Int64Type>(string_array, substring_array)
+        }
+        (DataType::Utf8View, DataType::Utf8View) => {
+            let string_array = args[0].as_string_view();
+            let substring_array = args[1].as_string_view();
+            calculate_strpos::<_, _, Int32Type>(string_array, substring_array)
+        }
+        (DataType::Utf8View, DataType::Utf8) => {
+            let string_array = args[0].as_string_view();
+            let substring_array = args[1].as_string::<i32>();
+            calculate_strpos::<_, _, Int32Type>(string_array, substring_array)
+        }
+        (DataType::Utf8View, DataType::LargeUtf8) => {
+            let string_array = args[0].as_string_view();
+            let substring_array = args[1].as_string::<i64>();
+            calculate_strpos::<_, _, Int32Type>(string_array, substring_array)
+        }
+
+        other => {
+            exec_err!("Unsupported data type combination {other:?} for 
function strpos")
+        }
+    }
+}
+
 /// Returns starting index of specified substring within string, or zero if 
it's not present. (Same as position(substring in string), but note the reversed 
argument order.)
 /// strpos('high', 'ig') = 2
 /// The implementation uses UTF-8 code points as characters
-fn strpos<T0: ArrowPrimitiveType, T1: ArrowPrimitiveType>(
-    args: &[ArrayRef],
+fn calculate_strpos<'a, V1, V2, T: ArrowPrimitiveType>(
+    string_array: V1,
+    substring_array: V2,
 ) -> Result<ArrayRef>
 where
-    T0::Native: OffsetSizeTrait,
-    T1::Native: OffsetSizeTrait,
+    V1: ArrayAccessor<Item = &'a str>,
+    V2: ArrayAccessor<Item = &'a str>,
 {
-    let string_array: &GenericStringArray<T0::Native> =
-        as_generic_string_array::<T0::Native>(&args[0])?;
-
-    let substring_array: &GenericStringArray<T1::Native> =
-        as_generic_string_array::<T1::Native>(&args[1])?;
+    let string_iter = ArrayIter::new(string_array);
+    let substring_iter = ArrayIter::new(substring_array);
 
-    let result = string_array
-        .iter()
-        .zip(substring_array.iter())
+    let result = string_iter
+        .zip(substring_iter)
         .map(|(string, substring)| match (string, substring) {
             (Some(string), Some(substring)) => {
-                // the find method returns the byte index of the substring
-                // Next, we count the number of the chars until that byte
-                T0::Native::from_usize(
+                // The `find` method returns the byte index of the substring.
+                // We count the number of chars up to that byte index.
+                T::Native::from_usize(
                     string
                         .find(substring)
                         .map(|x| string[..x].chars().count() + 1)
@@ -132,20 +161,21 @@ where
             }
             _ => None,
         })
-        .collect::<PrimitiveArray<T0>>();
+        .collect::<PrimitiveArray<T>>();
 
     Ok(Arc::new(result) as ArrayRef)
 }
 
 #[cfg(test)]
-mod test {
-    use super::*;
+mod tests {
+    use arrow::array::{Array, Int32Array, Int64Array};
+    use arrow::datatypes::DataType::{Int32, Int64};
+
+    use datafusion_common::{Result, ScalarValue};
+    use datafusion_expr::{ColumnarValue, ScalarUDFImpl};
+
+    use crate::unicode::strpos::StrposFunc;
     use crate::utils::test::test_function;
-    use arrow::{
-        array::{Array as _, Int32Array, Int64Array},
-        datatypes::DataType::{Int32, Int64},
-    };
-    use datafusion_common::ScalarValue;
 
     macro_rules! test_strpos {
         ($lhs:literal, $rhs:literal -> $result:literal; $t1:ident $t2:ident 
$t3:ident $t4:ident $t5:ident) => {
@@ -164,21 +194,54 @@ mod test {
     }
 
     #[test]
-    fn strpos() {
-        test_strpos!("foo", "bar" -> 0; Utf8 Utf8 i32 Int32 Int32Array);
-        test_strpos!("foobar", "foo" -> 1; Utf8 Utf8 i32 Int32 Int32Array);
-        test_strpos!("foobar", "bar" -> 4; Utf8 Utf8 i32 Int32 Int32Array);
-
-        test_strpos!("foo", "bar" -> 0; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
-        test_strpos!("foobar", "foo" -> 1; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
-        test_strpos!("foobar", "bar" -> 4; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
-
-        test_strpos!("foo", "bar" -> 0; Utf8 LargeUtf8 i32 Int32 Int32Array);
-        test_strpos!("foobar", "foo" -> 1; Utf8 LargeUtf8 i32 Int32 
Int32Array);
-        test_strpos!("foobar", "bar" -> 4; Utf8 LargeUtf8 i32 Int32 
Int32Array);
-
-        test_strpos!("foo", "bar" -> 0; LargeUtf8 Utf8 i64 Int64 Int64Array);
-        test_strpos!("foobar", "foo" -> 1; LargeUtf8 Utf8 i64 Int64 
Int64Array);
-        test_strpos!("foobar", "bar" -> 4; LargeUtf8 Utf8 i64 Int64 
Int64Array);
+    fn test_strpos_functions() {
+        // Utf8 and Utf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; Utf8 Utf8 i32 Int32 Int32Array);
+        test_strpos!("alphabet", "a" -> 1; Utf8 Utf8 i32 Int32 Int32Array);
+        test_strpos!("alphabet", "z" -> 0; Utf8 Utf8 i32 Int32 Int32Array);
+        test_strpos!("alphabet", "" -> 1; Utf8 Utf8 i32 Int32 Int32Array);
+        test_strpos!("", "a" -> 0; Utf8 Utf8 i32 Int32 Int32Array);
+
+        // LargeUtf8 and LargeUtf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "a" -> 1; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "z" -> 0; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "" -> 1; LargeUtf8 LargeUtf8 i64 Int64 
Int64Array);
+        test_strpos!("", "a" -> 0; LargeUtf8 LargeUtf8 i64 Int64 Int64Array);
+
+        // Utf8 and LargeUtf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; Utf8 LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "a" -> 1; Utf8 LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "z" -> 0; Utf8 LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "" -> 1; Utf8 LargeUtf8 i32 Int32 Int32Array);
+        test_strpos!("", "a" -> 0; Utf8 LargeUtf8 i32 Int32 Int32Array);
+
+        // LargeUtf8 and Utf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; LargeUtf8 Utf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "a" -> 1; LargeUtf8 Utf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "z" -> 0; LargeUtf8 Utf8 i64 Int64 
Int64Array);
+        test_strpos!("alphabet", "" -> 1; LargeUtf8 Utf8 i64 Int64 Int64Array);
+        test_strpos!("", "a" -> 0; LargeUtf8 Utf8 i64 Int64 Int64Array);
+
+        // Utf8View and Utf8View combinations
+        test_strpos!("alphabet", "ph" -> 3; Utf8View Utf8View i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "a" -> 1; Utf8View Utf8View i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "z" -> 0; Utf8View Utf8View i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "" -> 1; Utf8View Utf8View i32 Int32 
Int32Array);
+        test_strpos!("", "a" -> 0; Utf8View Utf8View i32 Int32 Int32Array);
+
+        // Utf8View and Utf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; Utf8View Utf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "a" -> 1; Utf8View Utf8 i32 Int32 Int32Array);
+        test_strpos!("alphabet", "z" -> 0; Utf8View Utf8 i32 Int32 Int32Array);
+        test_strpos!("alphabet", "" -> 1; Utf8View Utf8 i32 Int32 Int32Array);
+        test_strpos!("", "a" -> 0; Utf8View Utf8 i32 Int32 Int32Array);
+
+        // Utf8View and LargeUtf8 combinations
+        test_strpos!("alphabet", "ph" -> 3; Utf8View LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "a" -> 1; Utf8View LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "z" -> 0; Utf8View LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("alphabet", "" -> 1; Utf8View LargeUtf8 i32 Int32 
Int32Array);
+        test_strpos!("", "a" -> 0; Utf8View LargeUtf8 i32 Int32 Int32Array);
     }
 }
diff --git a/datafusion/sqllogictest/test_files/string_view.slt 
b/datafusion/sqllogictest/test_files/string_view.slt
index 0b441bcbeb..4b4eba0522 100644
--- a/datafusion/sqllogictest/test_files/string_view.slt
+++ b/datafusion/sqllogictest/test_files/string_view.slt
@@ -1066,9 +1066,8 @@ EXPLAIN SELECT
 FROM test;
 ----
 logical_plan
-01)Projection: strpos(__common_expr_1, Utf8("f")) AS c, 
strpos(__common_expr_1, CAST(test.column2_utf8view AS Utf8)) AS c2
-02)--Projection: CAST(test.column1_utf8view AS Utf8) AS __common_expr_1, 
test.column2_utf8view
-03)----TableScan: test projection=[column1_utf8view, column2_utf8view]
+01)Projection: strpos(test.column1_utf8view, Utf8("f")) AS c, 
strpos(test.column1_utf8view, test.column2_utf8view) AS c2
+02)--TableScan: test projection=[column1_utf8view, column2_utf8view]
 
 ## Ensure no casts for SUBSTR
 ## TODO file ticket


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to