From 69a41eeadc81adb08d04346512c76d62fd6203db Mon Sep 17 00:00:00 2001
From: Seefs <40468931+seefs001@users.noreply.github.com>
Date: Sun, 30 Aug 2026 22:51:50 +0800
Subject: [PATCH] fix(model): drop leftover prefill_groups unique constraints
before AutoMigrate (#7100)
---
model/main.go | 6 +++
model/prefill_group_migration.go | 81 ++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+)
create mode 100644 model/prefill_group_migration.go
diff --git a/model/main.go b/model/main.go
index dd2920b0a3..197d98d1f7 100644
--- a/model/main.go
+++ b/model/main.go
@@ -321,6 +321,9 @@ func migrateDB() error {
if err := migrateTokenModelLimitsToText(); err != nil {
return err
}
+ if err := migratePrefillGroupUniqueIndex(DB); err != nil {
+ return err
+ }
err := DB.AutoMigrate(
&Channel{},
@@ -381,6 +384,9 @@ func migrateDB() error {
}
func migrateDBFast() error {
+ if err := migratePrefillGroupUniqueIndex(DB); err != nil {
+ return err
+ }
var wg sync.WaitGroup
diff --git a/model/prefill_group_migration.go b/model/prefill_group_migration.go
new file mode 100644
index 0000000000..1cff90659b
--- /dev/null
+++ b/model/prefill_group_migration.go
@@ -0,0 +1,81 @@
+package model
+
+import (
+ "fmt"
+
+ "github.com/QuantumNous/new-api/common"
+
+ "gorm.io/gorm"
+ "gorm.io/gorm/clause"
+)
+
+// migratePrefillGroupUniqueIndex drops leftover single-column UNIQUE
+// constraints on prefill_groups.name before AutoMigrate.
+//
+// GORM 1.25.x MigrateColumnUnique treats a catalog unique column as the
+// `unique` tag and issues DROP CONSTRAINT uni_
_. Older
+// uniqueIndex migrations stored that uniqueness as idx__ or
+// PostgreSQL's __key, so the uni_* constraint does not exist
+// and AutoMigrate aborts with SQLSTATE 42704. Removing the catalog unique
+// constraint first lets AutoMigrate create uk_prefill_name (partial unique
+// index) instead.
+func migratePrefillGroupUniqueIndex(db *gorm.DB) error {
+ if db == nil || db.Dialector == nil || db.Dialector.Name() != "postgres" {
+ return nil
+ }
+ if !db.Migrator().HasTable(&PrefillGroup{}) {
+ return nil
+ }
+ stmt := &gorm.Statement{DB: db}
+ if err := stmt.Parse(&PrefillGroup{}); err != nil {
+ return err
+ }
+ return dropPrefillGroupLegacyNameUniques(db, stmt.Schema.Table)
+}
+
+func dropPrefillGroupLegacyNameUniques(db *gorm.DB, table string) error {
+ if db == nil || table == "" {
+ return nil
+ }
+ column := "name"
+ var constraintNames []string
+ if err := db.Raw(`
+SELECT tc.constraint_name
+FROM information_schema.table_constraints AS tc
+INNER JOIN information_schema.key_column_usage AS kcu
+ ON tc.constraint_catalog = kcu.constraint_catalog
+ AND tc.constraint_schema = kcu.constraint_schema
+ AND tc.constraint_name = kcu.constraint_name
+ AND tc.table_name = kcu.table_name
+WHERE tc.constraint_schema = current_schema()
+ AND tc.table_name = ?
+ AND tc.constraint_type = 'UNIQUE'
+GROUP BY tc.constraint_name
+HAVING COUNT(*) = 1 AND MIN(kcu.column_name) = ?`, table, column).Scan(&constraintNames).Error; err != nil {
+ return fmt.Errorf("list unique constraints on %s.%s: %w", table, column, err)
+ }
+ for _, name := range constraintNames {
+ if name == "" {
+ continue
+ }
+ if err := db.Exec("ALTER TABLE ? DROP CONSTRAINT IF EXISTS ?",
+ clause.Table{Name: table}, clause.Column{Name: name}).Error; err != nil {
+ return fmt.Errorf("drop unique constraint %s on %s: %w", name, table, err)
+ }
+ common.SysLog(fmt.Sprintf("dropped leftover unique constraint %s on %s.%s", name, table, column))
+ }
+
+ legacyIndexNames := []string{
+ db.NamingStrategy.IndexName(table, column),
+ db.NamingStrategy.UniqueName(table, column),
+ }
+ for _, name := range legacyIndexNames {
+ if name == "" || name == "uk_prefill_name" {
+ continue
+ }
+ if err := db.Exec("DROP INDEX IF EXISTS ?", clause.Column{Name: name}).Error; err != nil {
+ return fmt.Errorf("drop leftover unique index %s on %s: %w", name, table, err)
+ }
+ }
+ return nil
+}