Repository: ariga/atlas
Pull request #1017 (2022-08-06 20:52:59)

sql/sqlite: expand DEFAULT args in plan statements


Patch:
diff --git a/sql/migrate/migrate.go b/sql/migrate/migrate.go
index 9cc59cf3..9a13c689 100644
--- a/sql/migrate/migrate.go
+++ b/sql/migrate/migrate.go
@@ -84,9 +84,6 @@ type (
 	// StateReader wraps the method for reading a database/schema state.
 	// The types below provides a few builtin options for reading a state
 	// from a migration directory, a static object (e.g. a parsed file).
-	//
-	// In next Go version, the State will be replaced with the following
-	// union type `interface { Realm | Schema }`.
 	StateReader interface {
 		ReadState(ctx context.Context) (*schema.Realm, error)
 	}
diff --git a/sql/sqlite/migrate.go b/sql/sqlite/migrate.go
index 745b144a..71e4c072 100644
--- a/sql/sqlite/migrate.go
+++ b/sql/sqlite/migrate.go
@@ -332,10 +332,7 @@ func (s *state) fks(b *sqlx.Builder, fks ...*schema.ForeignKey) {
 }
 
 func (s *state) copyRows(from *schema.Table, to *schema.Table, changes []schema.Change) (bool, error) {
-	var (
-		args       []interface{}
-		fromC, toC []string
-	)
+	var fromC, toC []string
 	for _, column := range to.Columns {
 		// Skip generated columns in INSERT as they are computed.
 		if sqlx.Has(column.Attrs, &schema.GeneratedExpr{}) {
@@ -376,12 +373,11 @@ func (s *state) copyRows(from *schema.Table, to *schema.Table, changes []schema.
 		case *schema.ModifyColumn:
 			toC = append(toC, column.Name)
 			if !column.Type.Null && column.Default != nil && change.Change.Is(schema.ChangeNull|schema.ChangeDefault) {
-				fromC = append(fromC, fmt.Sprintf("IFNULL(`%[1]s`, ?) AS `%[1]s`", column.Name))
 				x, err := defaultValue(column)
 				if err != nil {
 					return false, err
 				}
-				args = append(args, x)
+				fromC = append(fromC, fmt.Sprintf("IFNULL(`%[1]s`, %s) AS `%[1]s`", column.Name, x))
 			} else {
 				fromC = append(fromC, column.Name)
 			}
@@ -398,7 +394,6 @@ func (s *state) copyRows(from *schema.Table, to *schema.Table, changes []schema.
 				"INSERT INTO `%s` (%s) SELECT %s FROM `%s`",
 				to.Name, identComma(toC), identComma(fromC), from.Name,
 			),
-			Args:    args,
 			Comment: fmt.Sprintf("copy rows from old table %q to new temporary table %q", from.Name, to.Name),
 		})
 	}
@@ -533,7 +528,12 @@ func Build(phrase string) *sqlx.Builder {
 func defaultValue(c *schema.Column) (string, error) {
 	switch x := c.Default.(type) {
 	case *schema.Literal:
-		return sqlx.SingleQuote(x.V)
+		switch c.Type.Type.(type) {
+		case *schema.BoolType, *schema.DecimalType, *schema.IntegerType, *schema.FloatType:
+			return x.V, nil
+		default:
+			return sqlx.SingleQuote(x.V)
+		}
 	case *schema.RawExpr:
 		return x.X, nil
 	default:


Test patch:
diff --git a/sql/sqlite/migrate_test.go b/sql/sqlite/migrate_test.go
index 13918678..78b6516f 100644
--- a/sql/sqlite/migrate_test.go
+++ b/sql/sqlite/migrate_test.go
@@ -191,7 +191,9 @@ func TestPlanChanges(t *testing.T) {
 					users := &schema.Table{
 						Name: "users",
 						Columns: []*schema.Column{
-							{Name: "id", Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}}},
+							schema.NewIntColumn("id", "bigint"),
+							schema.NewIntColumn("rank", "int").SetDefault(&schema.Literal{V: "1"}),
+							schema.NewStringColumn("nick", "text").SetDefault(&schema.Literal{V: "a8m"}),
 						},
 						Attrs: []schema.Attr{
 							&schema.Check{Expr: "(id <> 0)"},
@@ -200,6 +202,16 @@ func TestPlanChanges(t *testing.T) {
 					return &schema.ModifyTable{
 						T: users,
 						Changes: []schema.Change{
+							&schema.ModifyColumn{
+								From:   schema.NewNullIntColumn("id", "bigint"),
+								To:     users.Columns[1],
+								Change: schema.ChangeNull | schema.ChangeDefault,
+							},
+							&schema.ModifyColumn{
+								From:   schema.NewNullStringColumn("nick", "text"),
+								To:     users.Columns[2],
+								Change: schema.ChangeNull | schema.ChangeDefault,
+							},
 							&schema.DropColumn{
 								C: &schema.Column{Name: "name", Type: &schema.ColumnType{Type: &schema.StringType{T: "varchar(255)"}}},
 							},
@@ -214,8 +226,8 @@ func TestPlanChanges(t *testing.T) {
 				Transactional: true,
 				Changes: []*migrate.Change{
 					{Cmd: "PRAGMA foreign_keys = off"},
-					{Cmd: "CREATE TABLE `new_users` (`id` bigint NOT NULL, CHECK (id <> 0))", Reverse: "DROP TABLE `new_users`"},
-					{Cmd: "INSERT INTO `new_users` (`id`) SELECT `id` FROM `users`"},
+					{Cmd: "CREATE TABLE `new_users` (`id` bigint NOT NULL, `rank` int NOT NULL DEFAULT 1, `nick` text NOT NULL DEFAULT 'a8m', CHECK (id <> 0))", Reverse: "DROP TABLE `new_users`"},
+					{Cmd: "INSERT INTO `new_users` (`id`, `rank`, `nick`) SELECT `id`, IFNULL(`rank`, 1) AS `rank`, IFNULL(`nick`, 'a8m') AS `nick` FROM `users`"},
 					{Cmd: "DROP TABLE `users`"},
 					{Cmd: "ALTER TABLE `new_users` RENAME TO `users`"},
 					{Cmd: "PRAGMA foreign_keys = on"},