@@ -308,15 +308,47 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
308
308
func (m Migrator ) AlterColumn (value interface {}, field string ) error {
309
309
return m .RunWithValue (value , func (stmt * gorm.Statement ) error {
310
310
if stmt .Schema != nil {
311
- if field := stmt .Schema .LookUpField (field ); field != nil {
312
- fileType := m .FullDataTypeOf (field )
311
+ if f := stmt .Schema .LookUpField (field ); f != nil {
312
+ columnTypes , err := m .ColumnTypes (value )
313
+ if err != nil {
314
+ return err
315
+ }
316
+
317
+ var currentNullable bool
318
+ var currentType string
319
+ for _ , col := range columnTypes {
320
+ if strings .EqualFold (col .Name (), f .DBName ) {
321
+ currentNullable , _ = col .Nullable ()
322
+ currentType = strings .ToUpper (col .DatabaseTypeName ())
323
+ break
324
+ }
325
+ }
326
+
327
+ desiredNullable := ! f .NotNull
328
+ desiredType := strings .ToUpper (m .DataTypeOf (f ))
329
+
330
+ // nullable → non-nullable → skip
331
+ if currentNullable && ! desiredNullable {
332
+ return nil
333
+ }
334
+
335
+ // same type + same nullability → skip
336
+ if currentNullable == desiredNullable && strings .Contains (currentType , desiredType ) {
337
+ return nil
338
+ }
339
+
340
+ sql := "ALTER TABLE ? MODIFY ? " + m .DataTypeOf (f )
341
+ if f .NotNull {
342
+ sql += " NOT NULL"
343
+ } else if ! currentNullable && desiredNullable {
344
+ sql += " NULL"
345
+ }
346
+
313
347
return m .DB .Exec (
314
- "ALTER TABLE ? MODIFY ? ?" ,
348
+ sql ,
315
349
clause.Table {Name : stmt .Schema .Table },
316
- clause.Column {Name : field .DBName },
317
- fileType ,
350
+ clause.Column {Name : f .DBName },
318
351
).Error
319
-
320
352
}
321
353
}
322
354
return fmt .Errorf ("failed to look up field with name: %s" , field )
0 commit comments