Skip to content

Commit

Permalink
builtin: add lpad built-in function (#2838)
Browse files Browse the repository at this point in the history
  • Loading branch information
hsqlu authored and zimulala committed Mar 16, 2017
1 parent a4dde03 commit 6e27871
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 2 deletions.
34 changes: 33 additions & 1 deletion expression/builtin_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -1599,5 +1599,37 @@ type builtinLpadSig struct {

// See https://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_lpad
func (b *builtinLpadSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("lpad")
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
// LPAD(str,len,padstr)
// args[0] string, args[1] int, args[2] string
str, err := args[0].ToString()
if err != nil {
return d, errors.Trace(err)
}
length, err := args[1].ToInt64(b.ctx.GetSessionVars().StmtCtx)
if err != nil {
return d, errors.Trace(err)
}
l := int(length)

padStr, err := args[2].ToString()
if err != nil {
return d, errors.Trace(err)
}

if l < 0 || (len(str) < l && padStr == "") {
return d, nil
}

tailLen := l - len(str)
if tailLen > 0 {
repeatCount := tailLen/len(padStr) + 1
str = strings.Repeat(padStr, repeatCount)[:tailLen] + str
}
d.SetString(str[:l])

return d, nil
}
34 changes: 34 additions & 0 deletions expression/builtin_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -949,3 +949,37 @@ func (s *testEvaluatorSuite) TestField(c *C) {
c.Assert(r, testutil.DatumEquals, types.NewDatum(t.ret))
}
}

func (s *testEvaluatorSuite) TestLpad(c *C) {
tests := []struct {
str string
len int64
padStr string
expect interface{}
}{
{"hi", 5, "?", "???hi"},
{"hi", 1, "?", "h"},
{"hi", 0, "?", ""},
{"hi", -1, "?", nil},
{"hi", 1, "", "h"},
{"hi", 5, "", nil},
{"hi", 5, "ab", "abahi"},
{"hi", 6, "ab", "ababhi"},
}
fc := funcs[ast.Lpad]
for _, test := range tests {
str := types.NewStringDatum(test.str)
length := types.NewIntDatum(test.len)
padStr := types.NewStringDatum(test.padStr)
f, err := fc.getFunction(datumsToConstants([]types.Datum{str, length, padStr}), s.ctx)
c.Assert(err, IsNil)
result, err := f.eval(nil)
c.Assert(err, IsNil)
if test.expect == nil {
c.Assert(result.Kind(), Equals, types.KindNull)
} else {
expect, _ := test.expect.(string)
c.Assert(result.GetString(), Equals, expect)
}
}
}
2 changes: 1 addition & 1 deletion plan/typeinferer.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) {
case "dayname", "version", "database", "user", "current_user", "schema",
"concat", "concat_ws", "left", "lcase", "lower", "repeat",
"replace", "ucase", "upper", "convert", "substring",
"substring_index", "trim", "ltrim", "rtrim", "reverse", "hex", "unhex", "date_format", "rpad", "char_func", "conv":
"substring_index", "trim", "ltrim", "rtrim", "reverse", "hex", "unhex", "date_format", "rpad", "lpad", "char_func", "conv":
tp = types.NewFieldType(mysql.TypeVarString)
chs = v.defaultCharset
case "strcmp", "isnull", "bit_length", "char_length", "character_length", "crc32", "timestampdiff", "sign":
Expand Down
1 change: 1 addition & 0 deletions plan/typeinferer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) {
{"unhex(12)", mysql.TypeVarString, "utf8"},
{"DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y')", mysql.TypeVarString, "utf8"},
{"rpad('TiDB', 12, 'go')", mysql.TypeVarString, charset.CharsetUTF8},
{"lpad('TiDB', 12, 'go')", mysql.TypeVarString, charset.CharsetUTF8},
{"bit_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"char(66)", mysql.TypeVarString, charset.CharsetUTF8},
{"char_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
Expand Down

0 comments on commit 6e27871

Please sign in to comment.