Skip to content

Commit

Permalink
Fix auto migration with transaction, close go-gorm/gorm#5175
Browse files Browse the repository at this point in the history
  • Loading branch information
jinzhu committed Apr 3, 2022
1 parent 915f678 commit 1648e29
Showing 1 changed file with 69 additions and 66 deletions.
135 changes: 69 additions & 66 deletions migrator.go
Expand Up @@ -155,90 +155,93 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
return err
}

defer func() {
err = rows.Close()
}()

var (
rawColumnTypes, _ = rows.ColumnTypes()
columnTypeSQL = "SELECT column_name, data_type, column_default, is_nullable, character_maximum_length, numeric_precision, numeric_precision_radix, numeric_scale, datetime_precision FROM INFORMATION_SCHEMA.COLUMNS WHERE table_catalog = ? AND table_name = ?"
columns, rowErr = m.DB.Raw(columnTypeSQL, m.CurrentDatabase(), stmt.Table).Rows()
)

if rowErr != nil {
return rowErr
}

defer columns.Close()
rawColumnTypes, _ := rows.ColumnTypes()
rows.Close()

for columns.Next() {
{
var (
column = migrator.ColumnType{
PrimaryKeyValue: sql.NullBool{Valid: true},
UniqueValue: sql.NullBool{Valid: true},
}
datetimePrecision sql.NullInt64
radixValue sql.NullInt64
nullableValue sql.NullString
values = []interface{}{
&column.NameValue, &column.ColumnTypeValue, &column.DefaultValueValue, &nullableValue, &column.LengthValue, &column.DecimalSizeValue, &radixValue, &column.ScaleValue, &datetimePrecision,
}
columnTypeSQL = "SELECT column_name, data_type, column_default, is_nullable, character_maximum_length, numeric_precision, numeric_precision_radix, numeric_scale, datetime_precision FROM INFORMATION_SCHEMA.COLUMNS WHERE table_catalog = ? AND table_name = ?"
columns, rowErr = m.DB.Raw(columnTypeSQL, m.CurrentDatabase(), stmt.Table).Rows()
)

if scanErr := columns.Scan(values...); scanErr != nil {
return scanErr
if rowErr != nil {
return rowErr
}

if nullableValue.Valid {
column.NullableValue = sql.NullBool{Bool: strings.EqualFold(nullableValue.String, "YES"), Valid: true}
}
for columns.Next() {
var (
column = migrator.ColumnType{
PrimaryKeyValue: sql.NullBool{Valid: true},
UniqueValue: sql.NullBool{Valid: true},
}
datetimePrecision sql.NullInt64
radixValue sql.NullInt64
nullableValue sql.NullString
values = []interface{}{
&column.NameValue, &column.ColumnTypeValue, &column.DefaultValueValue, &nullableValue, &column.LengthValue, &column.DecimalSizeValue, &radixValue, &column.ScaleValue, &datetimePrecision,
}
)

if datetimePrecision.Valid {
column.DecimalSizeValue = datetimePrecision
}
if scanErr := columns.Scan(values...); scanErr != nil {
return scanErr
}

if column.DefaultValueValue.Valid {
matches := defaultValueTrimRegexp.FindStringSubmatch(column.DefaultValueValue.String)
for len(matches) > 1 {
column.DefaultValueValue.String = matches[1]
matches = defaultValueTrimRegexp.FindStringSubmatch(column.DefaultValueValue.String)
if nullableValue.Valid {
column.NullableValue = sql.NullBool{Bool: strings.EqualFold(nullableValue.String, "YES"), Valid: true}
}

if datetimePrecision.Valid {
column.DecimalSizeValue = datetimePrecision
}

if column.DefaultValueValue.Valid {
matches := defaultValueTrimRegexp.FindStringSubmatch(column.DefaultValueValue.String)
for len(matches) > 1 {
column.DefaultValueValue.String = matches[1]
matches = defaultValueTrimRegexp.FindStringSubmatch(column.DefaultValueValue.String)
}
} else {
column.DefaultValueValue.Valid = true
}
} else {
column.DefaultValueValue.Valid = true
}

for _, c := range rawColumnTypes {
if c.Name() == column.NameValue.String {
column.SQLColumnType = c
break
for _, c := range rawColumnTypes {
if c.Name() == column.NameValue.String {
column.SQLColumnType = c
break
}
}

columnTypes = append(columnTypes, column)
}

columnTypes = append(columnTypes, column)
columns.Close()
}

columnTypeRows, err := m.DB.Raw("SELECT c.column_name, t.constraint_type FROM information_schema.table_constraints t JOIN information_schema.constraint_column_usage c ON c.constraint_name=t.constraint_name WHERE t.constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_name = ?", m.CurrentDatabase(), stmt.Table).Rows()
if err != nil {
return err
}
defer columnTypeRows.Close()

for columnTypeRows.Next() {
var name, columnType string
columnTypeRows.Scan(&name, &columnType)
for idx, c := range columnTypes {
mc := c.(migrator.ColumnType)
if mc.NameValue.String == name {
switch columnType {
case "PRIMARY KEY":
mc.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true}
case "UNIQUE":
mc.UniqueValue = sql.NullBool{Bool: true, Valid: true}
{
columnTypeRows, err := m.DB.Raw("SELECT c.column_name, t.constraint_type FROM information_schema.table_constraints t JOIN information_schema.constraint_column_usage c ON c.constraint_name=t.constraint_name WHERE t.constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_name = ?", m.CurrentDatabase(), stmt.Table).Rows()
if err != nil {
return err
}

for columnTypeRows.Next() {
var name, columnType string
columnTypeRows.Scan(&name, &columnType)
for idx, c := range columnTypes {
mc := c.(migrator.ColumnType)
if mc.NameValue.String == name {
switch columnType {
case "PRIMARY KEY":
mc.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true}
case "UNIQUE":
mc.UniqueValue = sql.NullBool{Bool: true, Valid: true}
}
columnTypes[idx] = mc
break
}
columnTypes[idx] = mc
break
}
}

columnTypeRows.Close()
}

return
Expand Down

0 comments on commit 1648e29

Please sign in to comment.