diff --git a/src/coprocessor/dag/expr/builtin_string.rs b/src/coprocessor/dag/expr/builtin_string.rs index 3d4dbd1349a..31c0a7fe0e2 100644 --- a/src/coprocessor/dag/expr/builtin_string.rs +++ b/src/coprocessor/dag/expr/builtin_string.rs @@ -903,6 +903,28 @@ impl ScalarFunc { Ok(Some(Cow::Borrowed(b""))) } } + + #[inline] + pub fn instr_binary<'a, 'b: 'a>( + &'b self, + ctx: &mut EvalContext, + row: &'a [Datum], + ) -> Result> { + let s = try_opt!(self.children[0].eval_string_and_decode(ctx, row)); + let substr = try_opt!(self.children[1].eval_string_and_decode(ctx, row)); + if s.is_empty() { + return Ok(Some(0)); + } + if substr.is_empty() { + return Ok(Some(0)); + } + let s = String::from(s); + let substr = String::from(substr); + match s.find(&substr) { + Some(x) => Ok(Some(1 + s[..x].chars().count() as i64)), + None => Ok(Some(0)), + } + } } // when target_len is 0, return Some(0), means the pad function should return empty string @@ -1850,7 +1872,7 @@ mod tests { Datum::Bytes("CAFÉ".as_bytes().to_vec()), Datum::Bytes("数据库".as_bytes().to_vec()), Datum::Bytes("قاعدة البيانات".as_bytes().to_vec()), - Datum::Bytes( "НОЧЬ НА ОКРАИНЕ МОСКВЫ".as_bytes().to_vec()), + Datum::Bytes("НОЧЬ НА ОКРАИНЕ МОСКВЫ".as_bytes().to_vec()), ], Datum::Bytes( "忠犬ハチ公CAFÉ数据库قاعدة البياناتНОЧЬ НА ОКРАИНЕ МОСКВЫ" @@ -1885,6 +1907,7 @@ mod tests { assert_eq!(res, exp); } } + #[test] fn test_concat_ws() { let cases = vec![ @@ -1903,7 +1926,7 @@ mod tests { Datum::Bytes("CAFÉ".as_bytes().to_vec()), Datum::Bytes("数据库".as_bytes().to_vec()), Datum::Bytes("قاعدة البيانات".as_bytes().to_vec()), - Datum::Bytes( "НОЧЬ НА ОКРАИНЕ МОСКВЫ".as_bytes().to_vec()), + Datum::Bytes("НОЧЬ НА ОКРАИНЕ МОСКВЫ".as_bytes().to_vec()), ], Datum::Bytes( "忠犬ハチ公,CAFÉ,数据库,قاعدة البيانات,НОЧЬ НА ОКРАИНЕ МОСКВЫ" @@ -2373,6 +2396,7 @@ mod tests { assert_eq!(got, exp); } } + #[test] fn test_trim_3_args() { let tests = vec![ @@ -3259,4 +3283,43 @@ mod tests { assert_eq!(got, exp); } } + + #[test] + fn test_instr_binary() { + let cases: Vec<(&str, &str, i64)> = vec![ + ("a", "abcdefg", 1), + ("0", "abcdefg", 0), + ("c", "abcdefg", 3), + ("F", "abcdefg", 0), + ("cd", "abcdefg", 3), + (" ", "abcdefg", 0), + ("", "", 0), + ("eFg", "abcdefg", 0), + ("deF", "abcdefg", 0), + ("字节", "a多字节", 3), + ("a", "a多字节", 1), + ("bar", "foobarbar", 4), + ("bAr", "foobarbar", 0), + ("好世", "你好世界", 2), + ]; + + for (substr, s, exp) in cases { + let substr = Datum::Bytes(substr.as_bytes().to_vec()); + let s = Datum::Bytes(s.as_bytes().to_vec()); + let got = eval_func(ScalarFuncSig::InstrBinary, &[s, substr]).unwrap(); + assert_eq!(got, Datum::I64(exp)) + } + + let null_cases = vec![ + (Datum::Null, Datum::Bytes(b"".to_vec()), Datum::Null), + (Datum::Null, Datum::Bytes(b"foobar".to_vec()), Datum::Null), + (Datum::Bytes(b"".to_vec()), Datum::Null, Datum::Null), + (Datum::Bytes(b"bar".to_vec()), Datum::Null, Datum::Null), + (Datum::Null, Datum::Null, Datum::Null), + ]; + for (substr, s, exp) in null_cases { + let got = eval_func(ScalarFuncSig::InstrBinary, &[substr, s]).unwrap(); + assert_eq!(got, exp); + } + } } diff --git a/src/coprocessor/dag/expr/scalar_function.rs b/src/coprocessor/dag/expr/scalar_function.rs index 8c4fe49959d..5623b4327be 100644 --- a/src/coprocessor/dag/expr/scalar_function.rs +++ b/src/coprocessor/dag/expr/scalar_function.rs @@ -138,6 +138,7 @@ impl ScalarFunc { | ScalarFuncSig::SubDatetimeAndString | ScalarFuncSig::SubDurationAndDuration | ScalarFuncSig::Strcmp + | ScalarFuncSig::InstrBinary | ScalarFuncSig::Locate2Args | ScalarFuncSig::LocateBinary2Args => (2, 2), @@ -416,7 +417,6 @@ impl ScalarFunc { | ScalarFuncSig::Insert | ScalarFuncSig::InsertBinary | ScalarFuncSig::Instr - | ScalarFuncSig::InstrBinary | ScalarFuncSig::IntAnyValue | ScalarFuncSig::IsIPv4Compat | ScalarFuncSig::IsIPv4Mapped @@ -837,6 +837,7 @@ dispatch_call! { UncompressedLength => uncompressed_length, Strcmp => strcmp, + InstrBinary => instr_binary, } REAL_CALLS { CastIntAsReal => cast_int_as_real, @@ -1180,6 +1181,7 @@ mod tests { ScalarFuncSig::SubDurationAndDuration, ScalarFuncSig::Locate2Args, ScalarFuncSig::LocateBinary2Args, + ScalarFuncSig::InstrBinary, ], 2, 2, @@ -1501,7 +1503,6 @@ mod tests { ScalarFuncSig::Insert, ScalarFuncSig::InsertBinary, ScalarFuncSig::Instr, - ScalarFuncSig::InstrBinary, ScalarFuncSig::IntAnyValue, ScalarFuncSig::IsIPv4Compat, ScalarFuncSig::IsIPv4Mapped,