From db8534b4a367a8854c03ad152d16a13f2d888d01 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Fri, 27 Feb 2026 14:47:20 +0800 Subject: [PATCH 1/3] fix: change token model_limits column from varchar(1024) to text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3033 — users with many model limits hit PostgreSQL's varchar length constraint. The text type is supported across all three databases (SQLite, MySQL, PostgreSQL) with no length restriction. --- model/token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/token.go b/model/token.go index 773b2d792..1c9ad3ed7 100644 --- a/model/token.go +++ b/model/token.go @@ -23,7 +23,7 @@ type Token struct { RemainQuota int `json:"remain_quota" gorm:"default:0"` UnlimitedQuota bool `json:"unlimited_quota"` ModelLimitsEnabled bool `json:"model_limits_enabled"` - ModelLimits string `json:"model_limits" gorm:"type:varchar(1024);default:''"` + ModelLimits string `json:"model_limits" gorm:"type:text"` AllowIps *string `json:"allow_ips" gorm:"default:''"` UsedQuota int `json:"used_quota" gorm:"default:0"` // used quota Group string `json:"group" gorm:"default:''"` From 52c29e75829f145337bea23d64fb9fc991571c29 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Sat, 28 Feb 2026 18:49:06 +0800 Subject: [PATCH 2/3] fix: migrate model_limits column from varchar(1024) to text for existing tables --- model/main.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/model/main.go b/model/main.go index 21a5d4c08..fc2b4ff3d 100644 --- a/model/main.go +++ b/model/main.go @@ -250,6 +250,8 @@ func InitLogDB() (err error) { func migrateDB() error { // Migrate price_amount column from float/double to decimal for existing tables migrateSubscriptionPlanPriceAmount() + // Migrate model_limits column from varchar to text for existing tables + migrateTokenModelLimitsToText() err := DB.AutoMigrate( &Channel{}, @@ -445,6 +447,56 @@ PRIMARY KEY (` + "`id`" + `) return nil } +// migrateTokenModelLimitsToText migrates model_limits column from varchar(1024) to text +// This is safe to run multiple times - it checks the column type first +func migrateTokenModelLimitsToText() { + // SQLite uses type affinity, so TEXT and VARCHAR are effectively the same — no migration needed + if common.UsingSQLite { + return + } + + tableName := "tokens" + columnName := "model_limits" + + if !DB.Migrator().HasTable(tableName) { + return + } + + if !DB.Migrator().HasColumn(&Token{}, columnName) { + return + } + + var alterSQL string + if common.UsingPostgreSQL { + var dataType string + DB.Raw(`SELECT data_type FROM information_schema.columns + WHERE table_name = ? AND column_name = ?`, tableName, columnName).Scan(&dataType) + if dataType == "text" { + return + } + alterSQL = fmt.Sprintf(`ALTER TABLE %s ALTER COLUMN %s TYPE text`, tableName, columnName) + } else if common.UsingMySQL { + var columnType string + DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`, + tableName, columnName).Scan(&columnType) + if strings.ToLower(columnType) == "text" { + return + } + alterSQL = fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s text", tableName, columnName) + } else { + return + } + + if alterSQL != "" { + if err := DB.Exec(alterSQL).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to migrate %s.%s to text: %v", tableName, columnName, err)) + } else { + common.SysLog(fmt.Sprintf("Successfully migrated %s.%s to text", tableName, columnName)) + } + } +} + // migrateSubscriptionPlanPriceAmount migrates price_amount column from float/double to decimal(10,6) // This is safe to run multiple times - it checks the column type first func migrateSubscriptionPlanPriceAmount() { From 43e068c0c0ffa3a7b1041050adbe5c2617f17176 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Sat, 28 Feb 2026 19:08:03 +0800 Subject: [PATCH 3/3] fix: enhance migrateTokenModelLimitsToText function to return errors and improve migration checks --- model/main.go | 58 +++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/model/main.go b/model/main.go index fc2b4ff3d..f37cb667c 100644 --- a/model/main.go +++ b/model/main.go @@ -251,7 +251,9 @@ func migrateDB() error { // Migrate price_amount column from float/double to decimal for existing tables migrateSubscriptionPlanPriceAmount() // Migrate model_limits column from varchar to text for existing tables - migrateTokenModelLimitsToText() + if err := migrateTokenModelLimitsToText(); err != nil { + return err + } err := DB.AutoMigrate( &Channel{}, @@ -449,52 +451,55 @@ PRIMARY KEY (` + "`id`" + `) // migrateTokenModelLimitsToText migrates model_limits column from varchar(1024) to text // This is safe to run multiple times - it checks the column type first -func migrateTokenModelLimitsToText() { +func migrateTokenModelLimitsToText() error { // SQLite uses type affinity, so TEXT and VARCHAR are effectively the same — no migration needed if common.UsingSQLite { - return + return nil } tableName := "tokens" columnName := "model_limits" if !DB.Migrator().HasTable(tableName) { - return + return nil } if !DB.Migrator().HasColumn(&Token{}, columnName) { - return + return nil } var alterSQL string if common.UsingPostgreSQL { var dataType string - DB.Raw(`SELECT data_type FROM information_schema.columns - WHERE table_name = ? AND column_name = ?`, tableName, columnName).Scan(&dataType) - if dataType == "text" { - return + if err := DB.Raw(`SELECT data_type FROM information_schema.columns + WHERE table_schema = current_schema() AND table_name = ? AND column_name = ?`, + tableName, columnName).Scan(&dataType).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err)) + } else if dataType == "text" { + return nil } alterSQL = fmt.Sprintf(`ALTER TABLE %s ALTER COLUMN %s TYPE text`, tableName, columnName) } else if common.UsingMySQL { var columnType string - DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns - WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`, - tableName, columnName).Scan(&columnType) - if strings.ToLower(columnType) == "text" { - return + if err := DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`, + tableName, columnName).Scan(&columnType).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err)) + } else if strings.ToLower(columnType) == "text" { + return nil } alterSQL = fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s text", tableName, columnName) } else { - return + return nil } if alterSQL != "" { if err := DB.Exec(alterSQL).Error; err != nil { - common.SysLog(fmt.Sprintf("Warning: failed to migrate %s.%s to text: %v", tableName, columnName, err)) - } else { - common.SysLog(fmt.Sprintf("Successfully migrated %s.%s to text", tableName, columnName)) + return fmt.Errorf("failed to migrate %s.%s to text: %w", tableName, columnName, err) } + common.SysLog(fmt.Sprintf("Successfully migrated %s.%s to text", tableName, columnName)) } + return nil } // migrateSubscriptionPlanPriceAmount migrates price_amount column from float/double to decimal(10,6) @@ -523,9 +528,11 @@ func migrateSubscriptionPlanPriceAmount() { if common.UsingPostgreSQL { // PostgreSQL: Check if already decimal/numeric var dataType string - DB.Raw(`SELECT data_type FROM information_schema.columns - WHERE table_name = ? AND column_name = ?`, tableName, columnName).Scan(&dataType) - if dataType == "numeric" { + if err := DB.Raw(`SELECT data_type FROM information_schema.columns + WHERE table_schema = current_schema() AND table_name = ? AND column_name = ?`, + tableName, columnName).Scan(&dataType).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err)) + } else if dataType == "numeric" { return // Already decimal/numeric } alterSQL = fmt.Sprintf(`ALTER TABLE %s ALTER COLUMN %s TYPE decimal(10,6) USING %s::decimal(10,6)`, @@ -533,10 +540,11 @@ func migrateSubscriptionPlanPriceAmount() { } else if common.UsingMySQL { // MySQL: Check if already decimal var columnType string - DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns - WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`, - tableName, columnName).Scan(&columnType) - if strings.HasPrefix(strings.ToLower(columnType), "decimal") { + if err := DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`, + tableName, columnName).Scan(&columnType).Error; err != nil { + common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err)) + } else if strings.HasPrefix(strings.ToLower(columnType), "decimal") { return // Already decimal } alterSQL = fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s decimal(10,6) NOT NULL DEFAULT 0",