From 222427c474a3146bf79cb782fe50fae7d80aae69 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Tue, 8 Sep 2020 18:12:14 -0500 Subject: [PATCH 1/4] Release the connection when discovering the column types in the migrator When the migrator is used to discover the column types, such as when used with `AutoMigrate()`, it does not close the query result. This changes the migrator to close the query result and it also changes the query to use `LIMIT 1` to prevent additional work against the database when only discovering the schema. Fixes #3432. --- migrator/migrator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrator/migrator.go b/migrator/migrator.go index 98e92c96..c0e22ae0 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -388,9 +388,10 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy func (m Migrator) ColumnTypes(value interface{}) (columnTypes []*sql.ColumnType, err error) { err = m.RunWithValue(value, func(stmt *gorm.Statement) error { - rows, err := m.DB.Session(&gorm.Session{}).Raw("select * from ?", clause.Table{Name: stmt.Table}).Rows() + rows, err := m.DB.Session(&gorm.Session{}).Raw("select * from ? limit 1", clause.Table{Name: stmt.Table}).Rows() if err == nil { columnTypes, err = rows.ColumnTypes() + _ = rows.Close() } return err }) From 839e09e98558d946b4bf316bcd142edcf727ac37 Mon Sep 17 00:00:00 2001 From: caelansar <819711623@qq.com> Date: Tue, 8 Sep 2020 21:28:04 +0800 Subject: [PATCH 2/4] correct generated sql --- clause/expression.go | 3 +++ tests/query_test.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/clause/expression.go b/clause/expression.go index 3b914e68..55599571 100644 --- a/clause/expression.go +++ b/clause/expression.go @@ -37,6 +37,9 @@ func (expr Expr) Build(builder Builder) { } else { switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() { case reflect.Slice, reflect.Array: + if rv.Len() == 0 { + builder.AddVar(builder, nil) + } for i := 0; i < rv.Len(); i++ { if i > 0 { builder.WriteByte(',') diff --git a/tests/query_test.go b/tests/query_test.go index 795186da..e695e825 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -202,6 +202,22 @@ func TestFind(t *testing.T) { } } }) + + var models []User + if err := DB.Where("name in ?", []string{"find"}).Find(&models).Error; err != nil || len(models) != 3 { + t.Errorf("errors happened when query find with in clause: %v, length: %v", err, len(models)) + } else { + for idx, user := range users { + t.Run("FindWithInClause#"+strconv.Itoa(idx+1), func(t *testing.T) { + CheckUser(t, models[idx], user) + }) + } + } + + var none []User + if err := DB.Where("name in ?", []string{}).Find(&none).Error; err != nil || len(none) != 0 { + t.Errorf("errors happened when query find with in clause and zero length parameter: %v, length: %v", err, len(none)) + } } func TestQueryWithAssociation(t *testing.T) { From e7188c04ca9d81767ff090bc584177f4b6fb9fcc Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Wed, 9 Sep 2020 10:31:48 +0800 Subject: [PATCH 3/4] Fix tests & refactor for PR #3429 --- clause/expression.go | 11 ++++++----- tests/go.mod | 4 ++++ tests/query_test.go | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/clause/expression.go b/clause/expression.go index 55599571..dde236d3 100644 --- a/clause/expression.go +++ b/clause/expression.go @@ -39,12 +39,13 @@ func (expr Expr) Build(builder Builder) { case reflect.Slice, reflect.Array: if rv.Len() == 0 { builder.AddVar(builder, nil) - } - for i := 0; i < rv.Len(); i++ { - if i > 0 { - builder.WriteByte(',') + } else { + for i := 0; i < rv.Len(); i++ { + if i > 0 { + builder.WriteByte(',') + } + builder.AddVar(builder, rv.Index(i).Interface()) } - builder.AddVar(builder, rv.Index(i).Interface()) } default: builder.AddVar(builder, expr.Vars[idx]) diff --git a/tests/go.mod b/tests/go.mod index 76db6764..4ddb0b69 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -6,6 +6,10 @@ require ( github.com/google/uuid v1.1.1 github.com/jinzhu/now v1.1.1 github.com/lib/pq v1.6.0 + gorm.io/driver/mysql v1.0.1 + gorm.io/driver/postgres v1.0.0 + gorm.io/driver/sqlite v1.1.1 + gorm.io/driver/sqlserver v1.0.3 gorm.io/gorm v1.9.19 ) diff --git a/tests/query_test.go b/tests/query_test.go index e695e825..14150038 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -204,7 +204,7 @@ func TestFind(t *testing.T) { }) var models []User - if err := DB.Where("name in ?", []string{"find"}).Find(&models).Error; err != nil || len(models) != 3 { + if err := DB.Where("name in (?)", []string{"find"}).Find(&models).Error; err != nil || len(models) != 3 { t.Errorf("errors happened when query find with in clause: %v, length: %v", err, len(models)) } else { for idx, user := range users { @@ -215,7 +215,7 @@ func TestFind(t *testing.T) { } var none []User - if err := DB.Where("name in ?", []string{}).Find(&none).Error; err != nil || len(none) != 0 { + if err := DB.Where("name in (?)", []string{}).Find(&none).Error; err != nil || len(none) != 0 { t.Errorf("errors happened when query find with in clause and zero length parameter: %v, length: %v", err, len(none)) } } From 567597f000606b2266ff4b43950f5a801c2f2f63 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Wed, 9 Sep 2020 10:53:13 +0800 Subject: [PATCH 4/4] Fix fail on sqlserver, #3433 --- migrator/migrator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migrator/migrator.go b/migrator/migrator.go index c0e22ae0..53fd5ac0 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -388,10 +388,10 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy func (m Migrator) ColumnTypes(value interface{}) (columnTypes []*sql.ColumnType, err error) { err = m.RunWithValue(value, func(stmt *gorm.Statement) error { - rows, err := m.DB.Session(&gorm.Session{}).Raw("select * from ? limit 1", clause.Table{Name: stmt.Table}).Rows() + rows, err := m.DB.Session(&gorm.Session{}).Table(stmt.Table).Limit(1).Rows() if err == nil { + defer rows.Close() columnTypes, err = rows.ColumnTypes() - _ = rows.Close() } return err })