From f95084369d8b2ba237d59d92b880715216c51c49 Mon Sep 17 00:00:00 2001 From: Nomango Date: Fri, 30 Dec 2022 15:38:16 +0800 Subject: [PATCH] fix(migrator): Tag default:'null' always causes field migration #5953 --- migrator/migrator.go | 2 +- tests/migrate_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/migrator/migrator.go b/migrator/migrator.go index eafe7bb29..f1340f9c2 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -487,7 +487,7 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy // check default value if !field.PrimaryKey { - currentDefaultNotNull := field.HasDefaultValue && !strings.EqualFold(field.DefaultValue, "NULL") + currentDefaultNotNull := field.HasDefaultValue && (field.DefaultValueInterface != nil || !strings.EqualFold(field.DefaultValue, "NULL")) dv, dvNotNull := columnType.DefaultValue() if dvNotNull && !currentDefaultNotNull { // defalut value -> null diff --git a/tests/migrate_test.go b/tests/migrate_test.go index 9df626fd2..33862ec33 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -1203,3 +1203,74 @@ func TestMigrateSameEmbeddedFieldName(t *testing.T) { _, err = findColumnType(&GameUser{}, "rate_ground_rb_ground_destory_count") AssertEqual(t, nil, err) } + +func TestMigrateDefaultNullString(t *testing.T) { + if DB.Dialector.Name() == "sqlite" || DB.Dialector.Name() == "sqlserver" { + // sqlite and sqlserver driver treats NULL and 'NULL' the same + t.Skip("skip sqlite and sqlserver") + } + + type NullModel struct { + ID uint + Content string `gorm:"default:null"` + } + + type NullStringModel struct { + ID uint + Content string `gorm:"default:'null'"` + } + + tableName := "null_string_model" + + DB.Migrator().DropTable(tableName) + + err := DB.Table(tableName).AutoMigrate(&NullModel{}) + AssertEqual(t, err, nil) + + // default null -> 'null' + err = DB.Table(tableName).AutoMigrate(&NullStringModel{}) + AssertEqual(t, err, nil) + + columnType, err := findColumnType(tableName, "content") + AssertEqual(t, err, nil) + + defVal, ok := columnType.DefaultValue() + AssertEqual(t, defVal, "null") + AssertEqual(t, ok, true) + + // default 'null' -> 'null' + session := DB.Session(&gorm.Session{Logger: Tracer{ + Logger: DB.Config.Logger, + Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { + sql, _ := fc() + if strings.HasPrefix(sql, "ALTER TABLE") { + t.Errorf("shouldn't execute: sql=%s", sql) + } + }, + }}) + err = session.Table(tableName).AutoMigrate(&NullStringModel{}) + AssertEqual(t, err, nil) + + columnType, err = findColumnType(tableName, "content") + AssertEqual(t, err, nil) + + defVal, ok = columnType.DefaultValue() + AssertEqual(t, defVal, "null") + AssertEqual(t, ok, true) + + // default 'null' -> null + err = DB.Table(tableName).AutoMigrate(&NullModel{}) + AssertEqual(t, err, nil) + + columnType, err = findColumnType(tableName, "content") + AssertEqual(t, err, nil) + + if DB.Dialector.Name() == "postgres" { + // TODO postgres migrator.AlterColumn has a bug that it treats 'NULL' and NULL the same + // see https://github.com/go-gorm/postgres/blob/915abc3969652fd88d6f4133edaba9af2894e3b2/migrator.go#L329 + return + } + defVal, ok = columnType.DefaultValue() + AssertEqual(t, defVal, "") + AssertEqual(t, ok, false) +}