fix decimal migrate error.(#7450)
Signed-off-by: Chise1 <chise123@live.com>
This commit is contained in:
		
							parent
							
								
									e5b867e785
								
							
						
					
					
						commit
						fa8072bafc
					
				| @ -474,7 +474,6 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy | ||||
| 	// found, smart migrate
 | ||||
| 	fullDataType := strings.TrimSpace(strings.ToLower(m.DB.Migrator().FullDataTypeOf(field).SQL)) | ||||
| 	realDataType := strings.ToLower(columnType.DatabaseTypeName()) | ||||
| 
 | ||||
| 	var ( | ||||
| 		alterColumn bool | ||||
| 		isSameType  = fullDataType == realDataType | ||||
| @ -513,8 +512,19 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 		// check precision
 | ||||
| 	// check precision
 | ||||
| 	if realDataType == "decimal" || realDataType == "numeric" && | ||||
| 		regexp.MustCompile(realDataType+`\(.*\)`).FindString(fullDataType) != "" { // if realDataType has no precision,ignore
 | ||||
| 		precision, scale, ok := columnType.DecimalSize() | ||||
| 		if ok { | ||||
| 			if !strings.HasPrefix(fullDataType, fmt.Sprintf("%s(%d,%d)", realDataType, precision, scale)) && | ||||
| 				!strings.HasPrefix(fullDataType, fmt.Sprintf("%s(%d)", realDataType, precision)) { | ||||
| 				alterColumn = true | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		if precision, _, ok := columnType.DecimalSize(); ok && int64(field.Precision) != precision { | ||||
| 			if regexp.MustCompile(fmt.Sprintf("[^0-9]%d[^0-9]", field.Precision)).MatchString(m.DataTypeOf(field)) { | ||||
| 				alterColumn = true | ||||
|  | ||||
| @ -12,8 +12,8 @@ require ( | ||||
| 	gorm.io/driver/mysql v1.5.7 | ||||
| 	gorm.io/driver/postgres v1.5.11 | ||||
| 	gorm.io/driver/sqlite v1.5.7 | ||||
| 	gorm.io/driver/sqlserver v1.5.4 | ||||
| 	gorm.io/gorm v1.25.12 | ||||
| 	gorm.io/driver/sqlserver v1.6.0 | ||||
| 	gorm.io/gorm v1.30.0 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| @ -24,11 +24,11 @@ require ( | ||||
| 	github.com/golang-sql/sqlexp v0.1.0 // indirect | ||||
| 	github.com/jackc/pgpassfile v1.0.0 // indirect | ||||
| 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect | ||||
| 	github.com/jackc/pgx/v5 v5.7.1 // indirect | ||||
| 	github.com/jackc/pgx/v5 v5.7.5 // indirect | ||||
| 	github.com/jinzhu/inflection v1.0.0 // indirect | ||||
| 	github.com/kr/text v0.2.0 // indirect | ||||
| 	github.com/mattn/go-sqlite3 v1.14.28 // indirect | ||||
| 	github.com/microsoft/go-mssqldb v1.7.2 // indirect | ||||
| 	github.com/microsoft/go-mssqldb v1.8.1 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/rogpeppe/go-internal v1.12.0 // indirect | ||||
| 	golang.org/x/crypto v0.38.0 // indirect | ||||
|  | ||||
| @ -1987,3 +1987,114 @@ func TestMigrateWithUniqueIndexAndUnique(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func testAutoMigrateDecimal(t *testing.T, model1, model2 any) []string { | ||||
| 	tracer := 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.Fatalf("shouldn't execute ALTER COLUMN TYPE if decimal is not change: sql: %s", sql) | ||||
| 			} | ||||
| 		}, | ||||
| 	} | ||||
| 	session := DB.Session(&gorm.Session{Logger: tracer}) | ||||
| 
 | ||||
| 	DB.Migrator().DropTable(model1) | ||||
| 	var modifySql []string | ||||
| 	if err := session.AutoMigrate(model1); err != nil { | ||||
| 		t.Fatalf("failed to auto migrate, got error: %v", err) | ||||
| 	} | ||||
| 	if err := session.AutoMigrate(model1); err != nil { | ||||
| 		t.Fatalf("failed to auto migrate, got error: %v", err) | ||||
| 	} | ||||
| 	tracer2 := Tracer{ | ||||
| 		Logger: DB.Config.Logger, | ||||
| 		Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { | ||||
| 			sql, _ := fc() | ||||
| 			modifySql = append(modifySql, sql) | ||||
| 		}, | ||||
| 	} | ||||
| 	session2 := DB.Session(&gorm.Session{Logger: tracer2}) | ||||
| 	err := session2.Table("migrate_decimal_columns").Migrator().AutoMigrate(model2) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("failed to get column types, got error: %v", err) | ||||
| 	} | ||||
| 	return modifySql | ||||
| } | ||||
| 
 | ||||
| func decimalColumnsTest[T, T2 any](t *testing.T, expectedSql []string) { | ||||
| 	var t1 T | ||||
| 	var t2 T2 | ||||
| 	modSql := testAutoMigrateDecimal(t, t1, t2) | ||||
| 	var alterSQL []string | ||||
| 	for _, sql := range modSql { | ||||
| 		if strings.HasPrefix(sql, "ALTER TABLE ") { | ||||
| 			alterSQL = append(alterSQL, sql) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(alterSQL) != 3 { | ||||
| 		t.Fatalf("decimal changed error,expected: %+v,got: %+v.", expectedSql, alterSQL) | ||||
| 	} | ||||
| 	for i := range alterSQL { | ||||
| 		if alterSQL[i] != expectedSql[i] { | ||||
| 			t.Fatalf("decimal changed error,expected: %+v,got: %+v.", expectedSql, alterSQL) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAutoMigrateDecimal(t *testing.T) { | ||||
| 	if DB.Dialector.Name() == "sqlserver" { // database/sql will replace numeric to decimal. so only support decimal.
 | ||||
| 		type MigrateDecimalColumn struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:decimal(9,0);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:decimal(8);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:decimal(8,1);not null" json:"recid3"` | ||||
| 		} | ||||
| 		type MigrateDecimalColumn2 struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:decimal(8);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:decimal(9,1);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:decimal(9,2);not null" json:"recid3"` | ||||
| 		} | ||||
| 		expectedSql := []string{ | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid1" decimal(8) NOT NULL`, | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid2" decimal(9,1) NOT NULL`, | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid3" decimal(9,2) NOT NULL`, | ||||
| 		} | ||||
| 		decimalColumnsTest[MigrateDecimalColumn, MigrateDecimalColumn2](t, expectedSql) | ||||
| 	} else if DB.Dialector.Name() == "postgres" { | ||||
| 		type MigrateDecimalColumn struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:numeric(9,0);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:numeric(8);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:numeric(8,1);not null" json:"recid3"` | ||||
| 		} | ||||
| 		type MigrateDecimalColumn2 struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:numeric(8);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:numeric(9,1);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:numeric(9,2);not null" json:"recid3"` | ||||
| 		} | ||||
| 		expectedSql := []string{ | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid1" TYPE numeric(8) USING "recid1"::numeric(8)`, | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid2" TYPE numeric(9,1) USING "recid2"::numeric(9,1)`, | ||||
| 			`ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid3" TYPE numeric(9,2) USING "recid3"::numeric(9,2)`, | ||||
| 		} | ||||
| 		decimalColumnsTest[MigrateDecimalColumn, MigrateDecimalColumn2](t, expectedSql) | ||||
| 	} else if DB.Dialector.Name() == "mysql" { | ||||
| 		type MigrateDecimalColumn struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:decimal(9,0);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:decimal(8);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:decimal(8,1);not null" json:"recid3"` | ||||
| 		} | ||||
| 		type MigrateDecimalColumn2 struct { | ||||
| 			RecID1 int64 `gorm:"column:recid1;type:decimal(8);not null" json:"recid1"` | ||||
| 			RecID2 int64 `gorm:"column:recid2;type:decimal(9,1);not null" json:"recid2"` | ||||
| 			RecID3 int64 `gorm:"column:recid3;type:decimal(9,2);not null" json:"recid3"` | ||||
| 		} | ||||
| 		expectedSql := []string{ | ||||
| 			"ALTER TABLE `migrate_decimal_columns` MODIFY COLUMN `recid1` decimal(8) NOT NULL", | ||||
| 			"ALTER TABLE `migrate_decimal_columns` MODIFY COLUMN `recid2` decimal(9,1) NOT NULL", | ||||
| 			"ALTER TABLE `migrate_decimal_columns` MODIFY COLUMN `recid3` decimal(9,2) NOT NULL", | ||||
| 		} | ||||
| 		decimalColumnsTest[MigrateDecimalColumn, MigrateDecimalColumn2](t, expectedSql) | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Chise1
						Chise1