From 1b200bdcbabf02c141802336c583250e15ebd34e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Sep 2020 15:40:26 +0000 Subject: [PATCH] Fix bug of ToDB when update on a nil pointer (#1786) Fix test Fix bug Fix bug Add test for insert nil struct field Fix test Fix bug of ToDB when update on a nil pointer Reviewed-on: https://gitea.com/xorm/xorm/pulls/1786 --- integrations/session_update_test.go | 54 +++++++++++++++++++++++++++-- internal/statements/update.go | 2 +- internal/statements/values.go | 25 +++++++------ 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/integrations/session_update_test.go b/integrations/session_update_test.go index 1bc1f32a..07c722bd 100644 --- a/integrations/session_update_test.go +++ b/integrations/session_update_test.go @@ -188,6 +188,9 @@ func TestForUpdate(t *testing.T) { // lock is NOT used wg.Add(1) + + wg2 := &sync.WaitGroup{} + wg2.Add(1) go func() { f3 := new(ForUpdate) session3.Where("id = ?", 1) @@ -201,10 +204,10 @@ func TestForUpdate(t *testing.T) { t.Errorf("read lock failed") } wg.Done() + wg2.Done() }() - // wait for go rountines - time.Sleep(50 * time.Millisecond) + wg2.Wait() f := new(ForUpdate) f.Name = "updated by session1" @@ -1350,3 +1353,50 @@ func TestUpdateMultiplePK(t *testing.T) { _, err = testEngine.ID(&MySlice{test.Id, test.Name}).Update(test) assert.NoError(t, err) } + +type TestFieldType1 struct { + cb []byte +} + +func (a *TestFieldType1) FromDB(src []byte) error { + a.cb = src + return nil +} + +func (a TestFieldType1) ToDB() ([]byte, error) { + return a.cb, nil +} + +type TestTable1 struct { + Id int64 + Field1 *TestFieldType1 `xorm:"text"` + UpdateTime time.Time +} + +func TestNilFromDB(t *testing.T) { + assert.NoError(t, PrepareEngine()) + assertSync(t, new(TestTable1)) + + cnt, err := testEngine.Insert(&TestTable1{ + Field1: &TestFieldType1{ + cb: []byte("string"), + }, + UpdateTime: time.Now(), + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + cnt, err = testEngine.Update(TestTable1{ + UpdateTime: time.Now().Add(time.Second), + }, TestTable1{ + Id: 1, + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + cnt, err = testEngine.Insert(&TestTable1{ + UpdateTime: time.Now(), + }) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) +} diff --git a/internal/statements/update.go b/internal/statements/update.go index b6ae118e..ff5f82b7 100644 --- a/internal/statements/update.go +++ b/internal/statements/update.go @@ -130,7 +130,7 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value, } } - if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok { + if structConvert, ok := fieldValue.Interface().(convert.Conversion); ok && !fieldValue.IsNil() { data, err := structConvert.ToDB() if err != nil { return nil, nil, err diff --git a/internal/statements/values.go b/internal/statements/values.go index a1102c54..99eaa766 100644 --- a/internal/statements/values.go +++ b/internal/statements/values.go @@ -36,18 +36,21 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl } } - if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok { - data, err := fieldConvert.ToDB() - if err != nil { - return nil, err + isNil := fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() + if !isNil { + if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok { + data, err := fieldConvert.ToDB() + if err != nil { + return nil, err + } + if col.SQLType.IsBlob() { + return data, nil + } + if nil == data { + return nil, nil + } + return string(data), nil } - if col.SQLType.IsBlob() { - return data, nil - } - if nil == data { - return nil, nil - } - return string(data), nil } fieldType := fieldValue.Type()