diff --git a/expression/builtin_string_vec.go b/expression/builtin_string_vec.go index 8146f9485d9cd..efa1e1f4f9bfa 100644 --- a/expression/builtin_string_vec.go +++ b/expression/builtin_string_vec.go @@ -733,11 +733,55 @@ func (b *builtinLengthSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) } func (b *builtinLocate2ArgsSig) vectorized() bool { - return false + return true } +// vecEvalInt evals LOCATE(substr,str), non case-sensitive. +// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_locate func (b *builtinLocate2ArgsSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") + n := input.NumRows() + buf, err := b.bufAllocator.get(types.ETString, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + if err := b.args[0].VecEvalString(b.ctx, input, buf); err != nil { + return err + } + buf1, err := b.bufAllocator.get(types.ETString, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + if err := b.args[1].VecEvalString(b.ctx, input, buf1); err != nil { + return err + } + + result.ResizeInt64(n, false) + result.MergeNulls(buf, buf1) + i64s := result.Int64s() + for i := 0; i < n; i++ { + if result.IsNull(i) { + continue + } + subStr := buf.GetString(i) + str := buf1.GetString(i) + subStrLen := int64(len([]rune(subStr))) + if subStrLen == 0 { + i64s[i] = 1 + continue + } + slice := string([]rune(str)) + slice = strings.ToLower(slice) + subStr = strings.ToLower(subStr) + idx := strings.Index(slice, subStr) + if idx != -1 { + i64s[i] = int64(utf8.RuneCountInString(slice[:idx])) + 1 + continue + } + i64s[i] = 0 + } + return nil } func (b *builtinBitLengthSig) vectorized() bool { diff --git a/expression/builtin_string_vec_test.go b/expression/builtin_string_vec_test.go index 73d1b0c123a83..5654cbe65f7ed 100644 --- a/expression/builtin_string_vec_test.go +++ b/expression/builtin_string_vec_test.go @@ -29,8 +29,19 @@ var vecBuiltinStringCases = map[string][]vecExprBenchCase{ ast.Convert: {}, ast.Substring: {}, ast.SubstringIndex: {}, - ast.Locate: {}, - ast.Hex: {}, + ast.Locate: { + { + retEvalType: types.ETInt, + childrenTypes: []types.EvalType{types.ETString, types.ETString}, + geners: []dataGenerator{&randLenStrGener{0, 10}, &randLenStrGener{0, 20}}, + }, + { + retEvalType: types.ETInt, + childrenTypes: []types.EvalType{types.ETString, types.ETString}, + geners: []dataGenerator{&randLenStrGener{1, 2}, &randLenStrGener{0, 20}}, + }, + }, + ast.Hex: {}, ast.Unhex: { {retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&randHexStrGener{10, 100}}}, },