Import upstream version 1.9.16+git20211120.1.5c235b7
Debian Janitor
1 year, 3 months ago
0 | Your issue may already be reported! Please search on the [issue track](https://github.com/jinzhu/gorm/issues) before creating one. | |
1 | ||
2 | ### What version of Go are you using (`go version`)? | |
3 | ||
4 | ||
5 | ### Which database and its version are you using? | |
6 | ||
7 | ||
8 | ### Please provide a complete runnable program to reproduce your issue. **IMPORTANT** | |
9 | ||
10 | Need to runnable with [GORM's docker compose config](https://github.com/jinzhu/gorm/blob/master/docker-compose.yml) or please provides your config. | |
11 | ||
12 | ```go | |
13 | package main | |
14 | ||
15 | import ( | |
16 | "github.com/jinzhu/gorm" | |
17 | _ "github.com/jinzhu/gorm/dialects/mssql" | |
18 | _ "github.com/jinzhu/gorm/dialects/mysql" | |
19 | _ "github.com/jinzhu/gorm/dialects/postgres" | |
20 | _ "github.com/jinzhu/gorm/dialects/sqlite" | |
21 | ) | |
22 | ||
23 | var db *gorm.DB | |
24 | ||
25 | func init() { | |
26 | var err error | |
27 | db, err = gorm.Open("sqlite3", "test.db") | |
28 | // db, err = gorm.Open("postgres", "user=gorm password=gorm DB.name=gorm port=9920 sslmode=disable") | |
29 | // db, err = gorm.Open("mysql", "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True") | |
30 | // db, err = gorm.Open("mssql", "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm") | |
31 | if err != nil { | |
32 | panic(err) | |
33 | } | |
34 | db.LogMode(true) | |
35 | } | |
36 | ||
37 | func main() { | |
38 | if /* failure condition */ { | |
39 | fmt.Println("failed") | |
40 | } else { | |
41 | fmt.Println("success") | |
42 | } | |
43 | } | |
44 | ``` |
0 | Make sure these boxes checked before submitting your pull request. | |
1 | ||
2 | - [] Do only one thing | |
3 | - [] No API-breaking changes | |
4 | - [] New code/logic commented & tested | |
5 | ||
6 | For significant changes like big bug fixes, new features, please open an issue to make an agreement on an implementation design/plan first before starting it. | |
7 | ||
8 | ### What did this pull request do? |
175 | 175 | // forceReloadAfterCreateCallback will reload columns that having default value, and set it back to current object |
176 | 176 | func forceReloadAfterCreateCallback(scope *Scope) { |
177 | 177 | if blankColumnsWithDefaultValue, ok := scope.InstanceGet("gorm:blank_columns_with_default_value"); ok { |
178 | var shouldScan bool | |
178 | 179 | db := scope.DB().New().Table(scope.TableName()).Select(blankColumnsWithDefaultValue.([]string)) |
179 | 180 | for _, field := range scope.Fields() { |
180 | 181 | if field.IsPrimaryKey && !field.IsBlank { |
181 | 182 | db = db.Where(fmt.Sprintf("%v = ?", field.DBName), field.Field.Interface()) |
182 | } | |
183 | } | |
183 | shouldScan = true | |
184 | } | |
185 | } | |
186 | ||
187 | if !shouldScan { | |
188 | return | |
189 | } | |
190 | ||
184 | 191 | db.Scan(scope.Value) |
185 | 192 | } |
186 | 193 | } |
64 | 64 | scope.SQL = fmt.Sprint(str) + scope.SQL |
65 | 65 | } |
66 | 66 | |
67 | if str, ok := scope.Get("gorm:query_option"); ok { | |
68 | scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str)) | |
69 | } | |
70 | ||
71 | 67 | if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { |
72 | 68 | defer rows.Close() |
73 | 69 |
27 | 27 | scope.SQL = fmt.Sprint(str) + scope.SQL |
28 | 28 | } |
29 | 29 | |
30 | if str, ok := scope.Get("gorm:query_option"); ok { | |
31 | scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str)) | |
32 | } | |
33 | ||
34 | 30 | if rowResult, ok := result.(*RowQueryResult); ok { |
35 | 31 | rowResult.Row = scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...) |
36 | 32 | } else if rowsResult, ok := result.(*RowsQueryResult); ok { |
2 | 2 | import ( |
3 | 3 | "os" |
4 | 4 | "reflect" |
5 | "strings" | |
5 | 6 | "testing" |
6 | 7 | "time" |
7 | 8 | |
8 | 9 | "github.com/jinzhu/now" |
10 | ||
11 | "github.com/jinzhu/gorm" | |
9 | 12 | ) |
10 | 13 | |
11 | 14 | func TestCreate(t *testing.T) { |
285 | 288 | t.Error("Should ignore duplicate user insert by insert modifier:IGNORE ") |
286 | 289 | } |
287 | 290 | } |
291 | ||
292 | func TestFixFullTableScanWhenInsertIgnore(t *testing.T) { | |
293 | pandaYuanYuan := Panda{Number: 200408301001} | |
294 | ||
295 | if !DB.NewRecord(pandaYuanYuan) || !DB.NewRecord(&pandaYuanYuan) { | |
296 | t.Error("Panda should be new record before create") | |
297 | } | |
298 | ||
299 | if count := DB.Create(&pandaYuanYuan).RowsAffected; count != 1 { | |
300 | t.Error("There should be one record be affected when create record") | |
301 | } | |
302 | ||
303 | DB.Callback().Query().Register("gorm:fix_full_table_scan", func(scope *gorm.Scope) { | |
304 | if strings.Contains(scope.SQL, "SELECT") && strings.Contains(scope.SQL, "pandas") && len(scope.SQLVars) == 0 { | |
305 | t.Error("Should skip force reload when ignore duplicate panda insert") | |
306 | } | |
307 | }) | |
308 | ||
309 | if DB.Dialect().GetName() == "mysql" && DB.Set("gorm:insert_modifier", "IGNORE").Create(&pandaYuanYuan).Error != nil { | |
310 | t.Error("Should ignore duplicate panda insert by insert modifier:IGNORE ") | |
311 | } | |
312 | }⏎ |
130 | 130 | additionalType = additionalType + " DEFAULT " + value |
131 | 131 | } |
132 | 132 | |
133 | if value, ok := field.TagSettingsGet("COMMENT"); ok { | |
133 | if value, ok := field.TagSettingsGet("COMMENT"); ok && dialect.GetName() != "sqlite3" { | |
134 | 134 | additionalType = additionalType + " COMMENT " + value |
135 | 135 | } |
136 | 136 |
84 | 84 | db = &DB{ |
85 | 85 | db: dbSQL, |
86 | 86 | logger: defaultLogger, |
87 | callbacks: DefaultCallback, | |
87 | ||
88 | // Create a clone of the default logger to avoid mutating a shared object when | |
89 | // multiple gorm connections are created simultaneously. | |
90 | callbacks: DefaultCallback.clone(defaultLogger), | |
88 | 91 | dialect: newDialect(dialect, dbSQL), |
89 | 92 | } |
90 | 93 | db.parent = db |
12 | 12 | "os" |
13 | 13 | "path/filepath" |
14 | 14 | "reflect" |
15 | "regexp" | |
15 | 16 | "sort" |
16 | 17 | "strconv" |
17 | 18 | "strings" |
1335 | 1336 | |
1336 | 1337 | if count != 1 { |
1337 | 1338 | t.Error("Unexpected result on query count with query_option") |
1339 | } | |
1340 | } | |
1341 | ||
1342 | func TestSubQueryWithQueryOption(t *testing.T) { | |
1343 | db := DB.New() | |
1344 | ||
1345 | subQuery := db.Model(User{}).Select("users.id"). | |
1346 | Set("gorm:query_option", "WHERE users.name='user2'"). | |
1347 | SubQuery() | |
1348 | ||
1349 | matched, _ := regexp.MatchString( | |
1350 | `^&{.+\s+WHERE users\.name='user2'.*\s\[]}$`, fmt.Sprint(subQuery)) | |
1351 | if !matched { | |
1352 | t.Error("Unexpected result of SubQuery with query_option") | |
1353 | } | |
1354 | } | |
1355 | ||
1356 | func TestQueryExprWithQueryOption(t *testing.T) { | |
1357 | db := DB.New() | |
1358 | ||
1359 | queryExpr := db.Model(User{}).Select("users.id"). | |
1360 | Set("gorm:query_option", "WHERE users.name='user2'"). | |
1361 | QueryExpr() | |
1362 | ||
1363 | matched, _ := regexp.MatchString( | |
1364 | `^&{.+\s+WHERE users\.name='user2'.*\s\[]}$`, fmt.Sprint(queryExpr)) | |
1365 | if !matched { | |
1366 | t.Error("Unexpected result of QueryExpr with query_option") | |
1338 | 1367 | } |
1339 | 1368 | } |
1340 | 1369 |
282 | 282 | } |
283 | 283 | } |
284 | 284 | |
285 | type Panda struct { | |
286 | Number int64 `gorm:"unique_index:number"` | |
287 | Name string `gorm:"column:name;type:varchar(255);default:null"` | |
288 | } | |
289 | ||
285 | 290 | func runMigration() { |
286 | 291 | if err := DB.DropTableIfExists(&User{}).Error; err != nil { |
287 | 292 | fmt.Printf("Got error when try to delete table users, %+v\n", err) |
291 | 296 | DB.Exec(fmt.Sprintf("drop table %v;", table)) |
292 | 297 | } |
293 | 298 | |
294 | values := []interface{}{&Short{}, &ReallyLongThingThatReferencesShort{}, &ReallyLongTableNameToTestMySQLNameLengthLimit{}, &NotSoLongTableName{}, &Product{}, &Email{}, &Address{}, &CreditCard{}, &Company{}, &Role{}, &Language{}, &HNPost{}, &EngadgetPost{}, &Animal{}, &User{}, &JoinTable{}, &Post{}, &Category{}, &Comment{}, &Cat{}, &Dog{}, &Hamster{}, &Toy{}, &ElementWithIgnoredField{}, &Place{}} | |
299 | values := []interface{}{&Short{}, &ReallyLongThingThatReferencesShort{}, &ReallyLongTableNameToTestMySQLNameLengthLimit{}, &NotSoLongTableName{}, &Product{}, &Email{}, &Address{}, &CreditCard{}, &Company{}, &Role{}, &Language{}, &HNPost{}, &EngadgetPost{}, &Animal{}, &User{}, &JoinTable{}, &Post{}, &Category{}, &Comment{}, &Cat{}, &Dog{}, &Hamster{}, &Toy{}, &ElementWithIgnoredField{}, &Place{}, &Panda{}} | |
295 | 300 | for _, value := range values { |
296 | 301 | DB.DropTable(value) |
297 | 302 | } |
840 | 840 | } |
841 | 841 | |
842 | 842 | func (scope *Scope) prepareQuerySQL() { |
843 | var sql string | |
843 | 844 | if scope.Search.raw { |
844 | scope.Raw(scope.CombinedConditionSql()) | |
845 | sql = scope.CombinedConditionSql() | |
845 | 846 | } else { |
846 | scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql())) | |
847 | } | |
848 | return | |
847 | sql = fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql()) | |
848 | } | |
849 | if str, ok := scope.Get("gorm:query_option"); ok { | |
850 | sql += addExtraSpaceIfExist(fmt.Sprint(str)) | |
851 | } | |
852 | scope.Raw(sql) | |
849 | 853 | } |
850 | 854 | |
851 | 855 | func (scope *Scope) inlineCondition(values ...interface{}) *Scope { |