@@ -79,14 +79,28 @@ func (m Migrator) AlterColumn(value interface{}, name string) error {
79
79
return m .RunWithoutForeignKey (func () error {
80
80
return m .recreateTable (value , nil , func (ddl * ddl , stmt * gorm.Statement ) (* ddl , []interface {}, error ) {
81
81
if field := stmt .Schema .LookUpField (name ); field != nil {
82
- if ddl .alterColumn (field .DBName , fmt .Sprintf ("`%s` ?" , field .DBName )) {
83
- return nil , nil , fmt .Errorf ("field `%s` not found in origin ddl, ddl= '%s'" , name , ddl .compile ())
82
+ var sqlArgs []interface {}
83
+ for i , f := range ddl .fields {
84
+ if matches := columnRegexp .FindStringSubmatch (f ); len (matches ) > 1 && matches [1 ] == field .DBName {
85
+ ddl .fields [i ] = fmt .Sprintf ("`%v` ?" , field .DBName )
86
+ sqlArgs = []interface {}{m .FullDataTypeOf (field )}
87
+ // table created by old version might look like `CREATE TABLE ? (? varchar(10) UNIQUE)`.
88
+ // FullDataTypeOf doesn't contain UNIQUE, so we need to add unique constraint.
89
+ if strings .Contains (strings .ToUpper (matches [3 ]), " UNIQUE" ) {
90
+ uniName := m .DB .NamingStrategy .UniqueName (stmt .Table , field .DBName )
91
+ uni , _ := m .GuessConstraintInterfaceAndTable (stmt , uniName )
92
+ if uni != nil {
93
+ uniSQL , uniArgs := uni .Build ()
94
+ ddl .addConstraint (uniName , uniSQL )
95
+ sqlArgs = append (sqlArgs , uniArgs ... )
96
+ }
97
+ }
98
+ break
99
+ }
84
100
}
85
-
86
- return ddl , []interface {}{m .FullDataTypeOf (field )}, nil
101
+ return ddl , sqlArgs , nil
87
102
}
88
-
89
- return nil , nil , fmt .Errorf ("failed to alter field with name `%s`" , name )
103
+ return nil , nil , fmt .Errorf ("failed to alter field with name %v" , name )
90
104
})
91
105
})
92
106
}
@@ -153,7 +167,7 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
153
167
154
168
func (m Migrator ) CreateConstraint (value interface {}, name string ) error {
155
169
return m .RunWithValue (value , func (stmt * gorm.Statement ) error {
156
- constraint , chk , table := m .GuessConstraintAndTable (stmt , name )
170
+ constraint , table := m .GuessConstraintInterfaceAndTable (stmt , name )
157
171
158
172
return m .recreateTable (value , & table ,
159
173
func (ddl * ddl , stmt * gorm.Statement ) (* ddl , []interface {}, error ) {
@@ -164,12 +178,8 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
164
178
)
165
179
166
180
if constraint != nil {
167
- constraintName = constraint .Name
168
- constraintSql , constraintValues = buildConstraint (constraint )
169
- } else if chk != nil {
170
- constraintName = chk .Name
171
- constraintSql = "CONSTRAINT ? CHECK (?)"
172
- constraintValues = []interface {}{clause.Column {Name : chk .Name }, clause.Expr {SQL : chk .Constraint }}
181
+ constraintName = constraint .GetName ()
182
+ constraintSql , constraintValues = constraint .Build ()
173
183
} else {
174
184
return nil , nil , nil
175
185
}
@@ -182,11 +192,9 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
182
192
183
193
func (m Migrator ) DropConstraint (value interface {}, name string ) error {
184
194
return m .RunWithValue (value , func (stmt * gorm.Statement ) error {
185
- constraint , chk , table := m .GuessConstraintAndTable (stmt , name )
195
+ constraint , table := m .GuessConstraintInterfaceAndTable (stmt , name )
186
196
if constraint != nil {
187
- name = constraint .Name
188
- } else if chk != nil {
189
- name = chk .Name
197
+ name = constraint .GetName ()
190
198
}
191
199
192
200
return m .recreateTable (value , & table ,
@@ -200,11 +208,9 @@ func (m Migrator) DropConstraint(value interface{}, name string) error {
200
208
func (m Migrator ) HasConstraint (value interface {}, name string ) bool {
201
209
var count int64
202
210
m .RunWithValue (value , func (stmt * gorm.Statement ) error {
203
- constraint , chk , table := m .GuessConstraintAndTable (stmt , name )
211
+ constraint , table := m .GuessConstraintInterfaceAndTable (stmt , name )
204
212
if constraint != nil {
205
- name = constraint .Name
206
- } else if chk != nil {
207
- name = chk .Name
213
+ name = constraint .GetName ()
208
214
}
209
215
210
216
m .DB .Raw (
@@ -317,26 +323,44 @@ func (m Migrator) DropIndex(value interface{}, name string) error {
317
323
})
318
324
}
319
325
320
- func buildConstraint (constraint * schema.Constraint ) (sql string , results []interface {}) {
321
- sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??"
322
- if constraint .OnDelete != "" {
323
- sql += " ON DELETE " + constraint .OnDelete
324
- }
325
-
326
- if constraint .OnUpdate != "" {
327
- sql += " ON UPDATE " + constraint .OnUpdate
328
- }
329
-
330
- var foreignKeys , references []interface {}
331
- for _ , field := range constraint .ForeignKeys {
332
- foreignKeys = append (foreignKeys , clause.Column {Name : field .DBName })
333
- }
326
+ type Index struct {
327
+ Seq int
328
+ Name string
329
+ Unique bool
330
+ Origin string
331
+ Partial bool
332
+ }
334
333
335
- for _ , field := range constraint .References {
336
- references = append (references , clause.Column {Name : field .DBName })
337
- }
338
- results = append (results , clause.Table {Name : constraint .Name }, foreignKeys , clause.Table {Name : constraint .ReferenceSchema .Table }, references )
339
- return
334
+ // GetIndexes return Indexes []gorm.Index and execErr error,
335
+ // See the [doc]
336
+ //
337
+ // [doc]: https://www.sqlite.org/pragma.html#pragma_index_list
338
+ func (m Migrator ) GetIndexes (value interface {}) ([]gorm.Index , error ) {
339
+ indexes := make ([]gorm.Index , 0 )
340
+ err := m .RunWithValue (value , func (stmt * gorm.Statement ) error {
341
+ rst := make ([]* Index , 0 )
342
+ if err := m .DB .Debug ().Raw (fmt .Sprintf ("PRAGMA index_list(%q)" , stmt .Table )).Scan (& rst ).Error ; err != nil {
343
+ return err
344
+ }
345
+ for _ , index := range rst {
346
+ if index .Origin == "u" { // skip the index was created by a UNIQUE constraint
347
+ continue
348
+ }
349
+ var columns []string
350
+ if err := m .DB .Raw (fmt .Sprintf ("SELECT name from PRAGMA_index_info(%q)" , index .Name )).Scan (& columns ).Error ; err != nil { // alias `PRAGMA index_info(?)`
351
+ return err
352
+ }
353
+ indexes = append (indexes , & migrator.Index {
354
+ TableName : stmt .Table ,
355
+ NameValue : index .Name ,
356
+ ColumnList : columns ,
357
+ PrimaryKeyValue : sql.NullBool {Bool : index .Origin == "pk" , Valid : true }, // The exceptions are INTEGER PRIMARY KEY
358
+ UniqueValue : sql.NullBool {Bool : index .Unique , Valid : true },
359
+ })
360
+ }
361
+ return nil
362
+ })
363
+ return indexes , err
340
364
}
341
365
342
366
func (m Migrator ) getRawDDL (table string ) (string , error ) {
0 commit comments