Ver código fonte

🔧 chore(db): drop legacy single-column UNIQUE indexes to prevent duplicate-key errors after soft-delete

Why
Previous versions created single-column UNIQUE constraints (`models.model_name`, `vendors.name`).
After introducing composite indexes on `(model_name, deleted_at)` and `(name, deleted_at)` for soft-delete support, those legacy constraints could still exist in user databases.
When a record was soft-deleted and re-inserted with the same name, MySQL raised `Error 1062 … for key 'models.model_name'`.

What
• In `migrateDB` and `migrateDBFast` paths of `model/main.go`, proactively drop:
  – `models.uk_model_name` and fallback `models.model_name`
  – `vendors.uk_vendor_name` and fallback `vendors.name`
• Keeps existing helper `dropIndexIfExists` to ensure the operation is MySQL-only and error-free when indexes are already absent.

Result
Startup migration now removes every possible legacy UNIQUE index, ensuring composite index strategy works correctly.
Users can soft-delete and recreate models/vendors with identical names without hitting duplicate-entry errors.
t0ng7u 4 meses atrás
pai
commit
e64b13c925
1 arquivos alterados com 23 adições e 15 exclusões
  1. 23 15
      model/main.go

+ 23 - 15
model/main.go

@@ -66,18 +66,18 @@ var LOG_DB *gorm.DB
 
 // dropIndexIfExists drops a MySQL index only if it exists to avoid noisy 1091 errors
 func dropIndexIfExists(tableName string, indexName string) {
-    if !common.UsingMySQL {
-        return
-    }
-    var count int64
-    // Check index existence via information_schema
-    err := DB.Raw(
-        "SELECT COUNT(1) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = ? AND index_name = ?",
-        tableName, indexName,
-    ).Scan(&count).Error
-    if err == nil && count > 0 {
-        _ = DB.Exec("ALTER TABLE " + tableName + " DROP INDEX " + indexName + ";").Error
-    }
+	if !common.UsingMySQL {
+		return
+	}
+	var count int64
+	// Check index existence via information_schema
+	err := DB.Raw(
+		"SELECT COUNT(1) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = ? AND index_name = ?",
+		tableName, indexName,
+	).Scan(&count).Error
+	if err == nil && count > 0 {
+		_ = DB.Exec("ALTER TABLE " + tableName + " DROP INDEX " + indexName + ";").Error
+	}
 }
 
 func createRootAccountIfNeed() error {
@@ -252,8 +252,12 @@ func InitLogDB() (err error) {
 
 func migrateDB() error {
 	// 修复旧版本留下的唯一索引,允许软删除后重新插入同名记录
-	dropIndexIfExists("models", "uk_model_name")
-	dropIndexIfExists("vendors", "uk_vendor_name")
+	// 删除单列唯一索引(列级 UNIQUE)及早期命名方式,防止与新复合唯一索引 (model_name, deleted_at) 冲突
+	dropIndexIfExists("models", "uk_model_name") // 新版复合索引名称(若已存在)
+	dropIndexIfExists("models", "model_name")    // 旧版列级唯一索引名称
+
+	dropIndexIfExists("vendors", "uk_vendor_name") // 新版复合索引名称(若已存在)
+	dropIndexIfExists("vendors", "name")           // 旧版列级唯一索引名称
 	if !common.UsingPostgreSQL {
 		return migrateDBFast()
 	}
@@ -284,8 +288,12 @@ func migrateDB() error {
 
 func migrateDBFast() error {
 	// 修复旧版本留下的唯一索引,允许软删除后重新插入同名记录
+	// 删除单列唯一索引(列级 UNIQUE)及早期命名方式,防止与新复合唯一索引冲突
 	dropIndexIfExists("models", "uk_model_name")
+	dropIndexIfExists("models", "model_name")
+
 	dropIndexIfExists("vendors", "uk_vendor_name")
+	dropIndexIfExists("vendors", "name")
 
 	var wg sync.WaitGroup
 
@@ -305,7 +313,7 @@ func migrateDBFast() error {
 		{&QuotaData{}, "QuotaData"},
 		{&Task{}, "Task"},
 		{&Model{}, "Model"},
-        {&Vendor{}, "Vendor"},
+		{&Vendor{}, "Vendor"},
 		{&PrefillGroup{}, "PrefillGroup"},
 		{&Setup{}, "Setup"},
 		{&TwoFA{}, "TwoFA"},