diff --git a/oracle/migrator.go b/oracle/migrator.go index 49fef2b..9686a5f 100644 --- a/oracle/migrator.go +++ b/oracle/migrator.go @@ -308,15 +308,47 @@ func (m Migrator) DropColumn(value interface{}, name string) error { func (m Migrator) AlterColumn(value interface{}, field string) error { return m.RunWithValue(value, func(stmt *gorm.Statement) error { if stmt.Schema != nil { - if field := stmt.Schema.LookUpField(field); field != nil { - fileType := m.FullDataTypeOf(field) + if f := stmt.Schema.LookUpField(field); f != nil { + columnTypes, err := m.ColumnTypes(value) + if err != nil { + return err + } + + var currentNullable bool + var currentType string + for _, col := range columnTypes { + if strings.EqualFold(col.Name(), f.DBName) { + currentNullable, _ = col.Nullable() + currentType = strings.ToUpper(col.DatabaseTypeName()) + break + } + } + + desiredNullable := !f.NotNull + desiredType := strings.ToUpper(m.DataTypeOf(f)) + + // nullable → non-nullable → skip + if currentNullable && !desiredNullable { + return nil + } + + // same type + same nullability → skip + if currentNullable == desiredNullable && strings.Contains(currentType, desiredType) { + return nil + } + + sql := "ALTER TABLE ? MODIFY ? " + m.DataTypeOf(f) + if f.NotNull { + sql += " NOT NULL" + } else if !currentNullable && desiredNullable { + sql += " NULL" + } + return m.DB.Exec( - "ALTER TABLE ? MODIFY ? ?", + sql, clause.Table{Name: stmt.Schema.Table}, - clause.Column{Name: field.DBName}, - fileType, + clause.Column{Name: f.DBName}, ).Error - } } return fmt.Errorf("failed to look up field with name: %s", field) diff --git a/tests/migrate_test.go b/tests/migrate_test.go index a9683e9..37783d8 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -186,7 +186,6 @@ func TestAutoMigrateSelfReferential(t *testing.T) { } func TestAutoMigrateNullable(t *testing.T) { - t.Skip() type MigrateNullableColumn struct { ID uint Bonus float64 `gorm:"not null"` @@ -1397,7 +1396,7 @@ func TestMigrateExistingBoolColumnPG(t *testing.T) { func TestMigrateWithUniqueIndexAndUnique(t *testing.T) { t.Skip() - + const table = "unique_struct" checkField := func(model interface{}, fieldName string, unique bool, uniqueIndex string) { diff --git a/tests/query_test.go b/tests/query_test.go index 8881337..ee3e13e 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -725,7 +725,7 @@ func (v *Int64) Scan(val interface{}) error { switch x := val.(type) { case int64: *v = Int64(x + 1) - return nil + return nil case godror.Number: i, err := strconv.ParseInt(string(x), 10, 64) if err != nil {