session.Insert(&[]interface{}) session.Commit() panic: reflect: call of reflect.Value.Field on interface Value #2259

Open
opened 2023-05-10 13:39:16 +00:00 by Abei1uo · 0 comments

ver: go1.19.8 xorm.io/xorm v1.3.2 github.com/go-sql-driver/mysql v1.7.1

当表结构体使用Column属性 created和updated, 执行session.Insert(&[]interface{})后,在session.Commit()时发生panic
SQL日志显示事务已提交
报错位置 [94fcec7f65/session_insert.go (L162)]
[(94fcec7f65/schemas/column.go (L93))]
报错测试用例代码如下:

func TestInsertMulti2InterfaceTransaction(t *testing.T) {

	type User struct {
		ID         uint64 `xorm:"id pk autoincr"`
		Name       string
		Alias      string
		CreateTime time.Time `xorm:"created"`
		UpdateTime time.Time `xorm:"updated"`
	}
	assert.NoError(t, PrepareEngine())
	assertSync(t, new(User))
	session := testEngine.NewSession()
	defer session.Close()
	err := session.Begin()
	assert.NoError(t, err)
	users := []interface{}{
		&User{Name: "a", Alias: "A"},
		&User{Name: "b", Alias: "B"},
		&User{Name: "c", Alias: "C"},
		&User{Name: "d", Alias: "D"},
	}
	cnt, err := session.Insert(&users)
	assert.NoError(t, err)
	assert.EqualValues(t, len(users), cnt)
	err = session.Commit()
	assert.NoError(t, err)
}

附报错堆栈:

[xorm] [info]  2023/05/10 21:23:05.229541 [SQL] BEGIN TRANSACTION []
[xorm] [info]  2023/05/10 21:23:05.230541 [SQL] INSERT INTO `user` (`name`,`alias`,`create_time`,`update_time`) VALUES (?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?) [a A 2023-05-10 13:23:05 2023-05-10 13:23:05 b B 2023-05-10 13:23:05 2023-05-10 13:23:05 c C 2023-05-10 13:23:05 2023-05-10 13:23:05 d D 2023-05-10 13:23:05 2023-05-10 13:23:05] - 1ms
[xorm] [info]  2023/05/10 21:23:05.362549 [SQL] COMMIT [] - 132.0076ms
--- PASS: TestInsertMulti2InterfaceTransaction/user (0.13s)
    panic: reflect: call of reflect.Value.Field on interface Value [recovered]
	panic: reflect: call of reflect.Value.Field on interface Value
goroutine 20 [running]:
testing.tRunner.func1.2({0x1dc0ce0, 0xc0000a8360})
	E:/go/go1.19.8/src/testing/testing.go:1396 +0x485
testing.tRunner.func1()
	E:/go/go1.19.8/src/testing/testing.go:1399 +0x616
panic({0x1dc0ce0, 0xc0000a8360})
	E:/go/go1.19.8/src/runtime/panic.go:890 +0x267
reflect.Value.Field({0x1dbb8e0, 0xc0000ae440, 0x194}, 0x3)
	E:/go/go1.19.8/src/reflect/value.go:1266 +0x26f
reflect.Value.FieldByIndex({0x1dbb8e0, 0xc0000ae440, 0x194}, {0xc000069778, 0x1, 0x1})
	E:/go/go1.19.8/src/reflect/value.go:1299 +0xbc
xorm.io/xorm/schemas.(*Column).ValueOfV(0xc0000a2f00, 0xc000069880)
	E:/GWS/xorm/schemas/column.go:93 +0x28b
xorm.io/xorm/schemas.(*Column).ValueOf(0xc0000a2f00, {0x1d86180, 0xc0000ae440})
	E:/GWS/xorm/schemas/column.go:80 +0xaf
xorm.io/xorm.setColumnTime({0x1d86180, 0xc0000ae440}, 0xc0000a2f00, {0xdae8618, 0xedbed91b9, 0x24d0b60})
	E:/GWS/xorm/session_cols.go:31 +0x85
xorm.io/xorm.(*Session).insertMultipleStruct.func1({0x1d86180, 0xc0000ae440})
	E:/GWS/xorm/session_insert.go:162 +0x9b
xorm.io/xorm.(*Session).Commit.func1(0xc0000a82e8, {0x1d86180, 0xc0000ae440})
	E:/GWS/xorm/session_tx.go:50 +0x9f
xorm.io/xorm.(*Session).Commit(0xc000032f70)
	E:/GWS/xorm/session_tx.go:56 +0x1f2
xorm.io/xorm/integrations.TestInsertMulti2InterfaceTransaction(0xc0001769c0)
	E:/GWS/xorm/integrations/session_tx_test.go:219 +0x832
testing.tRunner(0xc0001769c0, 0x1ef8358)
	E:/go/go1.19.8/src/testing/testing.go:1446 +0x1ca
created by testing.(*T).Run
	E:/go/go1.19.8/src/testing/testing.go:1493 +0x69e

可行的解决办法
在 [(94fcec7f65/schemas/column.go (L93))]
函数func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) 中添加interface的判断

if v.Kind() == reflect.Interface {
	v = reflect.Indirect(v.Elem())
}
func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {

	v := *dataStruct
	for _, i := range col.FieldIndex {
		if v.Kind() == reflect.Ptr {
			if v.IsNil() {
				v.Set(reflect.New(v.Type().Elem()))
			}
			v = v.Elem()
		}else if v.Kind() == reflect.Interface { //增加对interface的类型判断
                	v = reflect.Indirect(v.Elem())
            	}
		v = v.FieldByIndex([]int{i})
	}	
	return &v, nil
}
ver: go1.19.8 xorm.io/xorm v1.3.2 github.com/go-sql-driver/mysql v1.7.1 当表结构体使用Column属性 created和updated, 执行session.Insert(&[]interface{})后,在session.Commit()时发生panic SQL日志显示事务已提交 报错位置 [https://gitea.com/xorm/xorm/src/commit/94fcec7f65f87b4a227f2b45b6947247a6f0208d/session_insert.go#L162] [(https://gitea.com/xorm/xorm/src/commit/94fcec7f65f87b4a227f2b45b6947247a6f0208d/schemas/column.go#L93)] 报错测试用例代码如下: > func TestInsertMulti2InterfaceTransaction(t *testing.T) { type User struct { ID uint64 `xorm:"id pk autoincr"` Name string Alias string CreateTime time.Time `xorm:"created"` UpdateTime time.Time `xorm:"updated"` } assert.NoError(t, PrepareEngine()) assertSync(t, new(User)) session := testEngine.NewSession() defer session.Close() err := session.Begin() assert.NoError(t, err) users := []interface{}{ &User{Name: "a", Alias: "A"}, &User{Name: "b", Alias: "B"}, &User{Name: "c", Alias: "C"}, &User{Name: "d", Alias: "D"}, } cnt, err := session.Insert(&users) assert.NoError(t, err) assert.EqualValues(t, len(users), cnt) err = session.Commit() assert.NoError(t, err) } 附报错堆栈: > [xorm] [info] 2023/05/10 21:23:05.229541 [SQL] BEGIN TRANSACTION [] [xorm] [info] 2023/05/10 21:23:05.230541 [SQL] INSERT INTO `user` (`name`,`alias`,`create_time`,`update_time`) VALUES (?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?) [a A 2023-05-10 13:23:05 2023-05-10 13:23:05 b B 2023-05-10 13:23:05 2023-05-10 13:23:05 c C 2023-05-10 13:23:05 2023-05-10 13:23:05 d D 2023-05-10 13:23:05 2023-05-10 13:23:05] - 1ms [xorm] [info] 2023/05/10 21:23:05.362549 [SQL] COMMIT [] - 132.0076ms --- PASS: TestInsertMulti2InterfaceTransaction/user (0.13s) panic: reflect: call of reflect.Value.Field on interface Value [recovered] panic: reflect: call of reflect.Value.Field on interface Value goroutine 20 [running]: testing.tRunner.func1.2({0x1dc0ce0, 0xc0000a8360}) E:/go/go1.19.8/src/testing/testing.go:1396 +0x485 testing.tRunner.func1() E:/go/go1.19.8/src/testing/testing.go:1399 +0x616 panic({0x1dc0ce0, 0xc0000a8360}) E:/go/go1.19.8/src/runtime/panic.go:890 +0x267 reflect.Value.Field({0x1dbb8e0, 0xc0000ae440, 0x194}, 0x3) E:/go/go1.19.8/src/reflect/value.go:1266 +0x26f reflect.Value.FieldByIndex({0x1dbb8e0, 0xc0000ae440, 0x194}, {0xc000069778, 0x1, 0x1}) E:/go/go1.19.8/src/reflect/value.go:1299 +0xbc xorm.io/xorm/schemas.(*Column).ValueOfV(0xc0000a2f00, 0xc000069880) E:/GWS/xorm/schemas/column.go:93 +0x28b xorm.io/xorm/schemas.(*Column).ValueOf(0xc0000a2f00, {0x1d86180, 0xc0000ae440}) E:/GWS/xorm/schemas/column.go:80 +0xaf xorm.io/xorm.setColumnTime({0x1d86180, 0xc0000ae440}, 0xc0000a2f00, {0xdae8618, 0xedbed91b9, 0x24d0b60}) E:/GWS/xorm/session_cols.go:31 +0x85 xorm.io/xorm.(*Session).insertMultipleStruct.func1({0x1d86180, 0xc0000ae440}) E:/GWS/xorm/session_insert.go:162 +0x9b xorm.io/xorm.(*Session).Commit.func1(0xc0000a82e8, {0x1d86180, 0xc0000ae440}) E:/GWS/xorm/session_tx.go:50 +0x9f xorm.io/xorm.(*Session).Commit(0xc000032f70) E:/GWS/xorm/session_tx.go:56 +0x1f2 xorm.io/xorm/integrations.TestInsertMulti2InterfaceTransaction(0xc0001769c0) E:/GWS/xorm/integrations/session_tx_test.go:219 +0x832 testing.tRunner(0xc0001769c0, 0x1ef8358) E:/go/go1.19.8/src/testing/testing.go:1446 +0x1ca created by testing.(*T).Run E:/go/go1.19.8/src/testing/testing.go:1493 +0x69e 可行的解决办法 在 [(https://gitea.com/xorm/xorm/src/commit/94fcec7f65f87b4a227f2b45b6947247a6f0208d/schemas/column.go#L93)] 函数func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) 中添加interface的判断 > if v.Kind() == reflect.Interface { v = reflect.Indirect(v.Elem()) } > func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) { v := *dataStruct for _, i := range col.FieldIndex { if v.Kind() == reflect.Ptr { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() }else if v.Kind() == reflect.Interface { //增加对interface的类型判断 v = reflect.Indirect(v.Elem()) } v = v.FieldByIndex([]int{i}) } return &v, nil }
lunny added the
kind
bug
label 2023-05-11 03:40:45 +00:00
Sign in to join this conversation.
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: xorm/xorm#2259
There is no content yet.