From d2521c5246e5cacbd7596e0cf93de133fdd9de29 Mon Sep 17 00:00:00 2001 From: shinytang6 <1074461480@qq.com> Date: Thu, 3 Jan 2019 21:35:03 +0800 Subject: [PATCH 1/4] expression:add support for JSON_MERGE_PRESERVE --- expression/builtin_json.go | 39 ++++++++++++++++++++++++++++++++- expression/builtin_json_test.go | 29 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/expression/builtin_json.go b/expression/builtin_json.go index 4f5486e9b1af3..1cc975991cf54 100644 --- a/expression/builtin_json.go +++ b/expression/builtin_json.go @@ -403,6 +403,9 @@ func (b *builtinJSONMergeSig) evalJSON(row chunk.Row) (res json.BinaryJSON, isNu values = append(values, value) } res = json.MergeBinary(values) + // function "JSON_MERGE" is deprecated since MySQL 5.7.22. Synonym for function "JSON_MERGE_PRESERVE". + // See https://dev.mysql.com/doc/refman/5.7/en/json-modification-functions.html#function_json-merge + b.ctx.GetSessionVars().StmtCtx.AppendWarning(errDeprecatedSyntaxNoReplacement.GenWithStackByArgs("JSON_MERGE")) return res, false, nil } @@ -719,8 +722,42 @@ type jsonMergePreserveFunctionClass struct { baseFunctionClass } +type builtinJSONMergePreserveSig struct { + baseBuiltinFunc +} + +func (b *builtinJSONMergePreserveSig) Clone() builtinFunc { + newSig := &builtinJSONMergePreserveSig{} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + func (c *jsonMergePreserveFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) { - return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "JSON_MERGE_PRESERVE") + if err := c.verifyArgs(args); err != nil { + return nil, err + } + argTps := make([]types.EvalType, 0, len(args)) + for range args { + argTps = append(argTps, types.ETJson) + } + bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETJson, argTps...) + sig := &builtinJSONMergePreserveSig{bf} + sig.setPbCode(tipb.ScalarFuncSig_JsonMergePreserveSig) + return sig, nil +} + +func (b *builtinJSONMergePreserveSig) evalJSON(row chunk.Row) (res json.BinaryJSON, isNull bool, err error) { + values := make([]json.BinaryJSON, 0, len(b.args)) + for _, arg := range b.args { + var value json.BinaryJSON + value, isNull, err = arg.EvalJSON(b.ctx, row) + if isNull || err != nil { + return res, isNull, err + } + values = append(values, value) + } + res = json.MergeBinary(values) + return res, false, nil } type jsonPrettyFunctionClass struct { diff --git a/expression/builtin_json_test.go b/expression/builtin_json_test.go index 7b78081803a7e..b7cd94b39a2f2 100644 --- a/expression/builtin_json_test.go +++ b/expression/builtin_json_test.go @@ -191,6 +191,35 @@ func (s *testEvaluatorSuite) TestJSONMerge(c *C) { } } +func (s *testEvaluatorSuite) TestJSONMergePreserve(c *C) { + defer testleak.AfterTest(c)() + fc := funcs[ast.JSONMergePreserve] + tbl := []struct { + Input []interface{} + Expected interface{} + }{ + {[]interface{}{nil, nil}, nil}, + {[]interface{}{`{}`, `[]`}, `[{}]`}, + {[]interface{}{`{}`, `[]`, `3`, `"4"`}, `[{}, 3, "4"]`}, + } + for _, t := range tbl { + args := types.MakeDatums(t.Input...) + f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) + c.Assert(err, IsNil) + d, err := evalBuiltinFunc(f, chunk.Row{}) + c.Assert(err, IsNil) + + switch x := t.Expected.(type) { + case string: + j1, err := json.ParseBinaryFromString(x) + c.Assert(err, IsNil) + j2 := d.GetMysqlJSON() + cmp := json.CompareBinary(j1, j2) + c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j1.String(), j2.String())) + } + } +} + func (s *testEvaluatorSuite) TestJSONArray(c *C) { defer testleak.AfterTest(c)() fc := funcs[ast.JSONArray] From b13e43285cc0ad1725bce3ee823462dd366d23f0 Mon Sep 17 00:00:00 2001 From: shinytang6 <1074461480@qq.com> Date: Tue, 8 Jan 2019 23:14:17 +0800 Subject: [PATCH 2/4] use builtinJSONMergeSig --- expression/builtin_json.go | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/expression/builtin_json.go b/expression/builtin_json.go index 1cc975991cf54..92bdf99b786f8 100644 --- a/expression/builtin_json.go +++ b/expression/builtin_json.go @@ -722,16 +722,6 @@ type jsonMergePreserveFunctionClass struct { baseFunctionClass } -type builtinJSONMergePreserveSig struct { - baseBuiltinFunc -} - -func (b *builtinJSONMergePreserveSig) Clone() builtinFunc { - newSig := &builtinJSONMergePreserveSig{} - newSig.cloneFrom(&b.baseBuiltinFunc) - return newSig -} - func (c *jsonMergePreserveFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) { if err := c.verifyArgs(args); err != nil { return nil, err @@ -741,25 +731,11 @@ func (c *jsonMergePreserveFunctionClass) getFunction(ctx sessionctx.Context, arg argTps = append(argTps, types.ETJson) } bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETJson, argTps...) - sig := &builtinJSONMergePreserveSig{bf} + sig := &builtinJSONMergeSig{bf} sig.setPbCode(tipb.ScalarFuncSig_JsonMergePreserveSig) return sig, nil } -func (b *builtinJSONMergePreserveSig) evalJSON(row chunk.Row) (res json.BinaryJSON, isNull bool, err error) { - values := make([]json.BinaryJSON, 0, len(b.args)) - for _, arg := range b.args { - var value json.BinaryJSON - value, isNull, err = arg.EvalJSON(b.ctx, row) - if isNull || err != nil { - return res, isNull, err - } - values = append(values, value) - } - res = json.MergeBinary(values) - return res, false, nil -} - type jsonPrettyFunctionClass struct { baseFunctionClass } From 7183e383f3793dd3f0c7b9c5c2a667733dc5b1ed Mon Sep 17 00:00:00 2001 From: shinytang6 <1074461480@qq.com> Date: Wed, 9 Jan 2019 14:14:27 +0800 Subject: [PATCH 3/4] judge pbCode --- expression/builtin_json.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/expression/builtin_json.go b/expression/builtin_json.go index 92bdf99b786f8..7fb2aec1e2164 100644 --- a/expression/builtin_json.go +++ b/expression/builtin_json.go @@ -405,7 +405,9 @@ func (b *builtinJSONMergeSig) evalJSON(row chunk.Row) (res json.BinaryJSON, isNu res = json.MergeBinary(values) // function "JSON_MERGE" is deprecated since MySQL 5.7.22. Synonym for function "JSON_MERGE_PRESERVE". // See https://dev.mysql.com/doc/refman/5.7/en/json-modification-functions.html#function_json-merge - b.ctx.GetSessionVars().StmtCtx.AppendWarning(errDeprecatedSyntaxNoReplacement.GenWithStackByArgs("JSON_MERGE")) + if b.pbCode == tipb.ScalarFuncSig_JsonMergeSig { + b.ctx.GetSessionVars().StmtCtx.AppendWarning(errDeprecatedSyntaxNoReplacement.GenWithStackByArgs("JSON_MERGE")) + } return res, false, nil } From 675d82761b6a63a6f56e6662e45146b574bf5826 Mon Sep 17 00:00:00 2001 From: shinytang6 <1074461480@qq.com> Date: Fri, 11 Jan 2019 13:05:26 +0800 Subject: [PATCH 4/4] improve test --- expression/builtin_json_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/expression/builtin_json_test.go b/expression/builtin_json_test.go index b7cd94b39a2f2..8f6888e8c035c 100644 --- a/expression/builtin_json_test.go +++ b/expression/builtin_json_test.go @@ -187,6 +187,8 @@ func (s *testEvaluatorSuite) TestJSONMerge(c *C) { j2 := d.GetMysqlJSON() cmp := json.CompareBinary(j1, j2) c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j1.String(), j2.String())) + case nil: + c.Assert(d.IsNull(), IsTrue) } } } @@ -216,6 +218,8 @@ func (s *testEvaluatorSuite) TestJSONMergePreserve(c *C) { j2 := d.GetMysqlJSON() cmp := json.CompareBinary(j1, j2) c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j1.String(), j2.String())) + case nil: + c.Assert(d.IsNull(), IsTrue) } } }