From 64c0de14d2dd906d3d3c038c2637b2992775a6cc Mon Sep 17 00:00:00 2001 From: Jeffry Luqman Date: Sun, 28 May 2023 14:32:19 +0700 Subject: [PATCH] fix : fail to alter existing boolean column from smallint with default value to boolean in postgres (#180) (#181) * fix : fail to alter column from smallint to boolean * fix : fail to alter column from smallint to boolean * fix : fail to alter column from string to boolean * fix : fail to alter column from string to boolean if the value is "false" in string * move using conversion expression to func * move using expression to func * fix : fail to alter existing boolean column from smallint with default value to boolean in postgres (#180) * isUncastableDefaultValue * ModifyColumn & DropDefaultValue * ModifyColumn + DropDefaultValue > modifyColumn --- migrator.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/migrator.go b/migrator.go index e4d8e92..c9a5761 100644 --- a/migrator.go +++ b/migrator.go @@ -326,8 +326,7 @@ func (m Migrator) AlterColumn(value interface{}, field string) error { return err } } else { - if err := m.DB.Exec("ALTER TABLE ? ALTER COLUMN ? TYPE ?"+m.genUsingExpression(fileType.SQL, fieldColumnType.DatabaseTypeName()), - m.CurrentTable(stmt), clause.Column{Name: field.DBName}, fileType, clause.Column{Name: field.DBName}, fileType).Error; err != nil { + if err := m.modifyColumn(stmt, field, fileType, fieldColumnType); err != nil { return err } } @@ -387,14 +386,27 @@ func (m Migrator) AlterColumn(value interface{}, field string) error { return nil } -func (m Migrator) genUsingExpression(targetType, sourceType string) string { - if targetType == "boolean" { - switch sourceType { +func (m Migrator) modifyColumn(stmt *gorm.Statement, field *schema.Field, targetType clause.Expr, existingColumn *migrator.ColumnType) error { + alterSQL := "ALTER TABLE ? ALTER COLUMN ? TYPE ? USING ?::?" + isUncastableDefaultValue := false + + if targetType.SQL == "boolean" { + switch existingColumn.DatabaseTypeName() { case "int2", "int8", "numeric": - return " USING ?::INT::?" + alterSQL = "ALTER TABLE ? ALTER COLUMN ? TYPE ? USING ?::int::?" + } + isUncastableDefaultValue = true + } + + if dv, _ := existingColumn.DefaultValue(); dv != "" && isUncastableDefaultValue { + if err := m.DB.Exec("ALTER TABLE ? ALTER COLUMN ? DROP DEFAULT", m.CurrentTable(stmt), clause.Column{Name: field.DBName}).Error; err != nil { + return err } } - return " USING ?::?" + if err := m.DB.Exec(alterSQL, m.CurrentTable(stmt), clause.Column{Name: field.DBName}, targetType, clause.Column{Name: field.DBName}, targetType).Error; err != nil { + return err + } + return nil } func (m Migrator) HasConstraint(value interface{}, name string) bool {