diff --git a/evaluator/builtin_string.go b/evaluator/builtin_string.go index ffa67b934d..d3656bec0d 100644 --- a/evaluator/builtin_string.go +++ b/evaluator/builtin_string.go @@ -275,12 +275,12 @@ func builtinSubstring(args []types.Datum, _ context.Context) (d types.Datum, err } pos := args[1].GetInt64() - length := int64(-1) + length, hasLen := int64(-1), false if len(args) == 3 { if args[2].Kind() != types.KindInt64 { return d, errors.Errorf("Substring invalid pos args, need int but get %T", args[2].GetValue()) } - length = args[2].GetInt64() + length, hasLen = args[2].GetInt64(), true } // The forms without a len argument return a substring from string str starting at position pos. // The forms with a len argument return a substring len characters long from string str, starting at position pos. @@ -292,17 +292,20 @@ func builtinSubstring(args []types.Datum, _ context.Context) (d types.Datum, err } else { pos-- } - if pos > int64(len(str)) || pos <= int64(0) { + if pos > int64(len(str)) || pos < int64(0) { pos = int64(len(str)) } - end := int64(len(str)) - if length != int64(-1) { - end = pos + length + if hasLen { + if end := pos + length; end < pos { + d.SetString("") + } else if end > int64(len(str)) { + d.SetString(str[pos:]) + } else { + d.SetString(str[pos:end]) + } + } else { + d.SetString(str[pos:]) } - if end > int64(len(str)) { - end = int64(len(str)) - } - d.SetString(str[pos:end]) return d, nil } diff --git a/evaluator/builtin_string_test.go b/evaluator/builtin_string_test.go index b5d598b1b6..fea7e0d829 100644 --- a/evaluator/builtin_string_test.go +++ b/evaluator/builtin_string_test.go @@ -263,6 +263,11 @@ func (s *testEvaluatorSuite) TestReplace(c *C) { func (s *testEvaluatorSuite) TestSubstring(c *C) { defer testleak.AfterTest(c)() + + d, err := builtinSubstring(types.MakeDatums([]interface{}{"hello", 2, -1}...), nil) + c.Assert(err, IsNil) + c.Assert(d.GetString(), Equals, "") + tbl := []struct { str string pos int64 @@ -271,10 +276,21 @@ func (s *testEvaluatorSuite) TestSubstring(c *C) { }{ {"Quadratically", 5, -1, "ratically"}, {"foobarbar", 4, -1, "barbar"}, - {"Quadratically", 5, 6, "ratica"}, + {"Sakila", 1, -1, "Sakila"}, + {"Sakila", 2, -1, "akila"}, {"Sakila", -3, -1, "ila"}, {"Sakila", -5, 3, "aki"}, {"Sakila", -4, 2, "ki"}, + {"Quadratically", 5, 6, "ratica"}, + {"Sakila", 1, 4, "Saki"}, + {"Sakila", -6, 4, "Saki"}, + {"Sakila", 2, 1000, "akila"}, + {"Sakila", -5, 1000, "akila"}, + {"Sakila", 2, -2, ""}, + {"Sakila", -5, -2, ""}, + {"Sakila", 2, 0, ""}, + {"Sakila", -5, -3, ""}, + {"Sakila", -1000, 3, ""}, {"Sakila", 1000, 2, ""}, {"", 2, 3, ""}, }