Skip to content

Commit

Permalink
builtin: add instr built-in function (#2857)
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmtrek authored and zimulala committed Mar 22, 2017
1 parent ef7923c commit 2c3e731
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 3 deletions.
42 changes: 41 additions & 1 deletion expression/builtin_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -1695,7 +1695,47 @@ type builtinInstrSig struct {

// See https://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_instr
func (b *builtinInstrSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("instr")
args, err := b.evalArgs(row)
if err != nil {
return d, errors.Trace(err)
}
// INSTR(str, substr)
if args[0].IsNull() || args[1].IsNull() {
return d, nil
}

var str, substr string
if str, err = args[0].ToString(); err != nil {
return d, errors.Trace(err)
}
if substr, err = args[1].ToString(); err != nil {
return d, errors.Trace(err)
}

// INSTR performs case **insensitive** search by default, while at least one argument is binary string
// we do case sensitive search.
var caseSensitive bool
if args[0].Kind() == types.KindBytes || args[1].Kind() == types.KindBytes {
caseSensitive = true
}

var pos, idx int
if caseSensitive {
idx = strings.Index(str, substr)
} else {
idx = strings.Index(strings.ToLower(str), strings.ToLower(substr))
}
if idx == -1 {
pos = 0
} else {
if caseSensitive {
pos = idx + 1
} else {
pos = utf8.RuneCountInString(str[:idx]) + 1
}
}
d.SetInt64(int64(pos))
return d, nil
}

type loadFileFunctionClass struct {
Expand Down
44 changes: 44 additions & 0 deletions expression/builtin_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,50 @@ func (s *testEvaluatorSuite) TestLpad(c *C) {
}
}

func (s *testEvaluatorSuite) TestInstr(c *C) {
defer testleak.AfterTest(c)()
tbl := []struct {
Args []interface{}
Want interface{}
}{
{[]interface{}{"foobarbar", "bar"}, 4},
{[]interface{}{"xbar", "foobar"}, 0},

{[]interface{}{123456234, 234}, 2},
{[]interface{}{123456, 567}, 0},
{[]interface{}{1e10, 1e2}, 1},
{[]interface{}{1.234, ".234"}, 2},
{[]interface{}{1.234, ""}, 1},
{[]interface{}{"", 123}, 0},
{[]interface{}{"", ""}, 1},

{[]interface{}{"中文美好", "美好"}, 3},
{[]interface{}{"中文美好", "世界"}, 0},
{[]interface{}{"中文abc", "a"}, 3},

{[]interface{}{"live LONG and prosper", "long"}, 6},

{[]interface{}{"not BINARY string", "binary"}, 5},
{[]interface{}{[]byte("BINARY string"), []byte("binary")}, 0},
{[]interface{}{[]byte("BINARY string"), []byte("BINARY")}, 1},
{[]interface{}{[]byte("中文abc"), []byte("abc")}, 7},

{[]interface{}{"foobar", nil}, nil},
{[]interface{}{nil, "foobar"}, nil},
{[]interface{}{nil, nil}, nil},
}

Dtbl := tblToDtbl(tbl)
instr := funcs[ast.Instr]
for i, t := range Dtbl {
f, err := instr.getFunction(datumsToConstants(t["Args"]), s.ctx)
c.Assert(err, IsNil)
got, err := f.eval(nil)
c.Assert(err, IsNil)
c.Assert(got, DeepEquals, t["Want"][0], Commentf("[%d]: args: %v", i, t["Args"]))
}
}

func (s *testEvaluatorSuite) TestMakeSet(c *C) {
defer testleak.AfterTest(c)()

Expand Down
4 changes: 2 additions & 2 deletions plan/typeinferer.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) {
"date_format", "rpad", "lpad", "char_func", "conv", "make_set", "oct", "uuid":
tp = types.NewFieldType(mysql.TypeVarString)
chs = v.defaultCharset
case "strcmp", "isnull", "bit_length", "char_length", "character_length", "crc32", "timestampdiff", "sign",
"is_ipv6", "ord":
case "strcmp", "isnull", "bit_length", "char_length", "character_length", "crc32", "timestampdiff",
"sign", "is_ipv6", "ord", "instr":
tp = types.NewFieldType(mysql.TypeLonglong)
case "connection_id":
tp = types.NewFieldType(mysql.TypeLonglong)
Expand Down
1 change: 1 addition & 0 deletions plan/typeinferer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) {
{"char_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"character_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"crc32('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"instr('foobarbar', 'bar')", mysql.TypeLonglong, charset.CharsetBin},
{"timestampdiff(MINUTE,'2003-02-01','2003-05-01 12:05:55')", mysql.TypeLonglong, charset.CharsetBin},
{"sign(0)", mysql.TypeLonglong, charset.CharsetBin},
{"sign(null)", mysql.TypeLonglong, charset.CharsetBin},
Expand Down

0 comments on commit 2c3e731

Please sign in to comment.