diff --git a/models/migrations/v1_27/v332.go b/models/migrations/v1_27/v332.go index a4bb71552a0..3837ac17099 100644 --- a/models/migrations/v1_27/v332.go +++ b/models/migrations/v1_27/v332.go @@ -5,23 +5,20 @@ package v1_27 import ( "code.gitea.io/gitea/models/migrations/base" + "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" "xorm.io/xorm/schemas" ) -// WidenProjectBoardSorting changes project_board.sorting from int8 (TINYINT/SMALLINT) -// to int. The previous int8 type capped projects at 127 columns and forced the API -// to truncate user-supplied sort values. SQLite uses dynamic typing so the schema -// type is cosmetic; existing rows already store the wider value. -// -// `base.ModifyColumn` is called with DefaultIsEmpty: true because MSSQL's ALTER -// COLUMN syntax does not accept inline DEFAULT (it would error on the keyword). -// On MySQL, MODIFY COLUMN without an explicit DEFAULT drops the existing default, -// so it has to be reapplied. On Postgres and MSSQL the DEFAULT constraint is -// maintained separately from the column type and is preserved automatically. +// WidenProjectBoardSorting changes project_board.sorting from int8 to int so the +// API can stop truncating sort values and the column count is no longer capped at +// 127. DefaultIsEmpty: true is required because MSSQL's ALTER COLUMN rejects an +// inline DEFAULT, and MySQL's MODIFY COLUMN drops any DEFAULT not restated, so the +// default is reapplied for MySQL afterwards. Postgres and MSSQL keep the existing +// DEFAULT constraint independently of the type change. func WidenProjectBoardSorting(x *xorm.Engine) error { - if x.Dialect().URI().DBType == schemas.SQLITE { + if setting.Database.Type.IsSQLite3() { return nil } if err := base.ModifyColumn(x, "project_board", &schemas.Column{ @@ -32,7 +29,7 @@ func WidenProjectBoardSorting(x *xorm.Engine) error { }); err != nil { return err } - if x.Dialect().URI().DBType == schemas.MYSQL { + if setting.Database.Type.IsMySQL() { if _, err := x.Exec("ALTER TABLE `project_board` ALTER `sorting` SET DEFAULT 0"); err != nil { return err } diff --git a/models/migrations/v1_27/v332_test.go b/models/migrations/v1_27/v332_test.go index f3ccb6eb10b..f186af7ebc6 100644 --- a/models/migrations/v1_27/v332_test.go +++ b/models/migrations/v1_27/v332_test.go @@ -14,8 +14,7 @@ import ( ) func Test_WidenProjectBoardSorting(t *testing.T) { - // Pre-migration shape of project_board (only the column we care about plus the - // minimum needed to pass NOT NULL constraints during INSERT). + // Pre-migration shape: int8 sorting column. type projectBoard struct { ID int64 `xorm:"pk autoincr"` Title string @@ -27,34 +26,28 @@ func Test_WidenProjectBoardSorting(t *testing.T) { x, deferrable := base.PrepareTestEnv(t, 0, new(projectBoard)) defer deferrable() - // Seed two rows: one at the int8 lower bound and one at the upper bound, - // proving the migration preserves edge values without truncation. _, err := x.Insert( &projectBoard{Title: "first", Sorting: 0, ProjectID: 1, CreatorID: 1}, - &projectBoard{Title: "boundary", Sorting: 127, ProjectID: 1, CreatorID: 1}, + &projectBoard{Title: "boundary", Sorting: 127, ProjectID: 1, CreatorID: 1}, // int8 max ) require.NoError(t, err) require.NoError(t, WidenProjectBoardSorting(x)) - // Verify column type widened (skipped on SQLite where the migration is a no-op). + // SQLite uses dynamic typing so the schema metadata still reports the original + // declared type; only verify schema metadata on real RDBMSes. if !setting.Database.Type.IsSQLite3() { table := base.LoadTableSchemasMap(t, x)["project_board"] require.NotNil(t, table) col := table.GetColumn("sorting") require.NotNil(t, col) - // Each dialect spells INT differently; verify the type is one of the wider - // names rather than TINYINT/INT2. - assert.Contains(t, - []string{"INT", "INTEGER", "INT4"}, - col.SQLType.Name, - "sorting column should have widened to int", - ) - assert.False(t, col.Nullable, "sorting column should remain NOT NULL") - assert.Equal(t, "0", col.Default, "sorting column should keep DEFAULT 0") + // MySQL and MSSQL report "INT", Postgres reports "INTEGER". + assert.Contains(t, []string{"INT", "INTEGER"}, col.SQLType.Name) + assert.False(t, col.Nullable) + assert.Equal(t, "0", col.Default) } - // Existing rows must be preserved verbatim. + // Post-migration shape: same table, int sorting. type projectBoardWide struct { ID int64 `xorm:"pk autoincr"` Title string @@ -68,8 +61,7 @@ func Test_WidenProjectBoardSorting(t *testing.T) { assert.Equal(t, 0, rows[0].Sorting) assert.Equal(t, 127, rows[1].Sorting) - // Inserting a value > 127 must succeed after widening (would have failed with - // TINYINT/INT2 either by truncation or out-of-range error). + // Value well past int8 range — proves the column genuinely widened. _, err = x.Table("project_board").Insert(&projectBoardWide{ Title: "wide", Sorting: 30000, @@ -82,5 +74,5 @@ func Test_WidenProjectBoardSorting(t *testing.T) { has, err := x.Table("project_board").Where("title=?", "wide").Get(&got) require.NoError(t, err) require.True(t, has) - assert.Equal(t, 30000, got.Sorting, "value should round-trip without truncation") + assert.Equal(t, 30000, got.Sorting) }