Skip to content

Commit

Permalink
types: add deepcopy for update operation (pingcap#5098)
Browse files Browse the repository at this point in the history
  • Loading branch information
mccxj authored and jackysp committed Nov 15, 2017
1 parent 5962f14 commit e362f1e
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 2 deletions.
3 changes: 1 addition & 2 deletions executor/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -1358,8 +1358,7 @@ func (e *UpdateExec) fetchRows() error {
if row == nil {
return nil
}
newRowData := make(types.DatumRow, len(row))
copy(newRowData, row)
newRowData := row.Copy()
for _, assign := range e.OrderedList {
val, err := assign.Expr.Eval(newRowData)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2902,6 +2902,10 @@ func (s *testIntegrationSuite) TestFuncJSON(c *C) {

r = tk.MustQuery(`select json_extract(json_object(1,2,3,4), '$."1"')`)
r.Check(testkit.Rows("2"))

tk.MustExec(`update table_json set a=json_set(a,'$.a',json_object('a',1,'b',2)) where json_extract(a,'$.a[1]') = '2'`)
r = tk.MustQuery(`select json_extract(a, '$.a.a'), json_extract(a, '$.a.b') from table_json`)
r.Check(testkit.Rows("1 2", "<nil> <nil>"))
}

func (s *testIntegrationSuite) TestColumnInfoModified(c *C) {
Expand Down
14 changes: 14 additions & 0 deletions types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ type Datum struct {
x interface{} // x hold all other types.
}

// Copy deep copies a Datum.
func (d *Datum) Copy() *Datum {
ret := *d
if d.b != nil {
ret.b = make([]byte, len(d.b))
copy(ret.b, d.b)
}
// JSON object requires a deep copy, because it includes map/slice fields.
if ret.k == KindMysqlJSON {
ret.x = *ret.x.(json.JSON).Copy()
}
return &ret
}

// Kind gets the kind of the datum.
func (d *Datum) Kind() byte {
return d.k
Expand Down
18 changes: 18 additions & 0 deletions types/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ type JSON struct {
Array []JSON
}

// Copy deep copies a JSON.
func (j JSON) Copy() *JSON {
ret := j
if j.Object != nil {
ret.Object = make(map[string]JSON, len(j.Object))
for k, v := range j.Object {
ret.Object[k] = *v.Copy()
}
}
if j.Array != nil {
ret.Array = make([]JSON, len(j.Array))
for i, v := range j.Array {
ret.Array[i] = *v.Copy()
}
}
return &ret
}

// CreateJSON creates a JSON from in. Panic if any error occurs.
func CreateJSON(in interface{}) JSON {
j, err := normalize(in)
Expand Down
12 changes: 12 additions & 0 deletions types/json/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ func TestT(t *testing.T) {
TestingT(t)
}

func (s *testJSONSuite) TestCopy(c *C) {
jstr1 := `{"a": [1, "2", {"aa": "bb"}, 4, null], "b": true, "c": null}`
js1 := mustParseFromString(jstr1)
js2 := js1.Copy()
js2.Object["a"].Array[2].Object["aa"] = JSON{
TypeCode: TypeCodeString,
Str: "cc",
}
c.Assert(js1.String(), Equals, `{"a":[1,"2",{"aa":"bb"},4,null],"b":true,"c":null}`)
c.Assert(js2.String(), Equals, `{"a":[1,"2",{"aa":"cc"},4,null],"b":true,"c":null}`)
}

// mustParseFromString parse a JSON from a string.
// Panic if string is not a valid JSON.
func mustParseFromString(s string) JSON {
Expand Down
9 changes: 9 additions & 0 deletions types/row.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ var _ Row = DatumRow{}
// DatumRow is a slice of Datum, implements Row interface.
type DatumRow []Datum

// Copy deep copies a DatumRow.
func (dr DatumRow) Copy() DatumRow {
c := make(DatumRow, len(dr))
for i, d := range dr {
c[i] = *d.Copy()
}
return c
}

// Len implements Row interface.
func (dr DatumRow) Len() int {
return len(dr)
Expand Down

0 comments on commit e362f1e

Please sign in to comment.