@ -100,6 +100,7 @@ var Funcs = map[string]Func{
|
||||
"length": {builtinLength, 1, 1, true, false},
|
||||
"lower": {builtinLower, 1, 1, true, false},
|
||||
"repeat": {builtinRepeat, 2, 2, true, false},
|
||||
"replace": {builtinReplace, 3, 3, true, false},
|
||||
"upper": {builtinUpper, 1, 1, true, false},
|
||||
|
||||
// information functions
|
||||
|
||||
@ -146,3 +146,27 @@ func builtinUpper(args []interface{}, ctx map[interface{}]interface{}) (interfac
|
||||
return strings.ToUpper(s), nil
|
||||
}
|
||||
}
|
||||
|
||||
// See: https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace
|
||||
func builtinReplace(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) {
|
||||
for _, arg := range args {
|
||||
if types.IsNil(arg) {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
str, err := types.ToString(args[0])
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
oldStr, err := types.ToString(args[1])
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
newStr, err := types.ToString(args[2])
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
|
||||
return strings.Replace(str, oldStr, newStr, -1), nil
|
||||
}
|
||||
|
||||
@ -166,3 +166,23 @@ func (s *testBuiltinSuite) TestLowerAndUpper(c *C) {
|
||||
c.Assert(v, Equals, strings.ToUpper(t.Expect))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testBuiltinSuite) TestReplace(c *C) {
|
||||
tbl := []struct {
|
||||
Input []interface{}
|
||||
Expect interface{}
|
||||
}{
|
||||
{[]interface{}{nil, nil, nil}, nil},
|
||||
{[]interface{}{1, nil, 2}, nil},
|
||||
{[]interface{}{1, 1, nil}, nil},
|
||||
{[]interface{}{"12345", 2, 222}, "1222345"},
|
||||
{[]interface{}{"12325", 2, "a"}, "1a3a5"},
|
||||
{[]interface{}{12345, 2, "aa"}, "1aa345"},
|
||||
}
|
||||
|
||||
for _, t := range tbl {
|
||||
v, err := builtinReplace(t.Input, nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(v, Equals, t.Expect)
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,18 +63,18 @@ func NewCall(f string, args []Expression, distinct bool) (v Expression, err erro
|
||||
}
|
||||
|
||||
c := Call{F: f, Distinct: distinct, distinctKey: new(int)}
|
||||
for _, Val := range args {
|
||||
if !Val.IsStatic() {
|
||||
c.Args = append(c.Args, Val)
|
||||
for _, val := range args {
|
||||
if !val.IsStatic() {
|
||||
c.Args = append(c.Args, val)
|
||||
continue
|
||||
}
|
||||
|
||||
eVal, err := Val.Eval(nil, nil)
|
||||
v, err := val.Eval(nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Args = append(c.Args, Value{eVal})
|
||||
c.Args = append(c.Args, Value{v})
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
|
||||
@ -2439,6 +2439,19 @@ FunctionCallNonKeyword:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "REPLACE" '(' Expression ',' Expression ',' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression),
|
||||
$5.(expression.Expression),
|
||||
$7.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expression.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err(err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "SECOND" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
|
||||
@ -349,6 +349,8 @@ func (s *testParserSuite) TestBuiltin(c *C) {
|
||||
|
||||
{`SELECT LOWER("A"), UPPER("a")`, true},
|
||||
|
||||
{`SELECT REPLACE('www.mysql.com', 'w', 'Ww')`, true},
|
||||
|
||||
{`SELECT LOCATE('bar', 'foobarbar');`, true},
|
||||
{`SELECT LOCATE('bar', 'foobarbar', 5);`, true},
|
||||
|
||||
|
||||
@ -816,7 +816,8 @@ year_month {y}{e}{a}{r}_{m}{o}{n}{t}{h}
|
||||
return repeat
|
||||
{regexp} return regexp
|
||||
{references} return references
|
||||
{replace} return replace
|
||||
{replace} lval.item = string(l.val)
|
||||
return replace
|
||||
{rlike} return rlike
|
||||
|
||||
{sys_var} lval.item = string(l.val)
|
||||
|
||||
Reference in New Issue
Block a user