From 935cc8bd5261060d408385ea6e531190c41e325e Mon Sep 17 00:00:00 2001 From: xia Date: Wed, 28 Oct 2015 17:51:18 +0800 Subject: [PATCH 1/5] parser: add replace func --- parser/parser.y | 13 +++++++++++++ parser/parser_test.go | 2 ++ parser/scanner.l | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/parser/parser.y b/parser/parser.y index 94cf454e95..9a2c38a9d6 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -2429,6 +2429,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)} diff --git a/parser/parser_test.go b/parser/parser_test.go index f276e07ed9..bb22afb434 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -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}, diff --git a/parser/scanner.l b/parser/scanner.l index bc4a35790f..2c780419ac 100644 --- a/parser/scanner.l +++ b/parser/scanner.l @@ -803,7 +803,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) From ab735686f0f9b31661df9982d7d92f560d950fb0 Mon Sep 17 00:00:00 2001 From: xia Date: Wed, 28 Oct 2015 17:52:02 +0800 Subject: [PATCH 2/5] expression: add replace function --- expression/builtin/builtin.go | 1 + expression/builtin/string.go | 24 ++++++++++++++++++++++++ expression/builtin/string_test.go | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/expression/builtin/builtin.go b/expression/builtin/builtin.go index bcf3126090..162d5f0931 100644 --- a/expression/builtin/builtin.go +++ b/expression/builtin/builtin.go @@ -101,6 +101,7 @@ var Funcs = map[string]Func{ "lower": {builtinLower, 1, 1, true, false}, "repeat": {builtinRepeat, 2, 2, true, false}, "upper": {builtinUpper, 1, 1, true, false}, + "replace": {builtinReplace, 3, 3, true, false}, // information functions "current_user": {builtinCurrentUser, 0, 0, false, false}, diff --git a/expression/builtin/string.go b/expression/builtin/string.go index 1db1de397c..33d3ba8c5c 100644 --- a/expression/builtin/string.go +++ b/expression/builtin/string.go @@ -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.0/en/string-functions.html#function_replace +func builtinReplace(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) { + for _, arg := range args { + if arg == nil { + 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 +} diff --git a/expression/builtin/string_test.go b/expression/builtin/string_test.go index 5c128a47d9..de5b1651a2 100644 --- a/expression/builtin/string_test.go +++ b/expression/builtin/string_test.go @@ -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) + } +} From a39d9daf86d7417bdd6dc3eba27bbaea64caee9b Mon Sep 17 00:00:00 2001 From: xia Date: Wed, 28 Oct 2015 17:52:30 +0800 Subject: [PATCH 3/5] expression: rename Val to val --- expression/call.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/expression/call.go b/expression/call.go index 0125bd7358..4804b034e3 100644 --- a/expression/call.go +++ b/expression/call.go @@ -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 From 784a6773176bf32fa2e0c898b9939c5c549b8639 Mon Sep 17 00:00:00 2001 From: zimulala Date: Wed, 28 Oct 2015 21:08:38 +0800 Subject: [PATCH 4/5] expression: handle DataItem nil --- expression/builtin/string.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expression/builtin/string.go b/expression/builtin/string.go index 42f93debbc..21129d2819 100644 --- a/expression/builtin/string.go +++ b/expression/builtin/string.go @@ -147,10 +147,10 @@ func builtinUpper(args []interface{}, ctx map[interface{}]interface{}) (interfac } } -// See: https://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_replace +// 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 arg == nil { + if types.IsNil(arg) { return nil, nil } } From ad94d351e522dc41b7b1f604ac48d5d965a7a358 Mon Sep 17 00:00:00 2001 From: xia Date: Thu, 29 Oct 2015 09:29:57 +0800 Subject: [PATCH 5/5] expression: keep replace in order in builtin --- expression/builtin/builtin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/builtin/builtin.go b/expression/builtin/builtin.go index 162d5f0931..fc7fcdf26b 100644 --- a/expression/builtin/builtin.go +++ b/expression/builtin/builtin.go @@ -100,8 +100,8 @@ var Funcs = map[string]Func{ "length": {builtinLength, 1, 1, true, false}, "lower": {builtinLower, 1, 1, true, false}, "repeat": {builtinRepeat, 2, 2, true, false}, - "upper": {builtinUpper, 1, 1, true, false}, "replace": {builtinReplace, 3, 3, true, false}, + "upper": {builtinUpper, 1, 1, true, false}, // information functions "current_user": {builtinCurrentUser, 0, 0, false, false},