diff --git a/model/main.go b/model/main.go index d6cd38aa..dbf27152 100644 --- a/model/main.go +++ b/model/main.go @@ -389,12 +389,7 @@ func CloseDB() error { // default charset/collation can store Chinese characters. It allows common // Chinese-capable charsets (utf8mb4, utf8, gbk, big5, gb18030) and panics otherwise. func checkMySQLChineseSupport(db *gorm.DB) error { - // Read session/server variables - var charsetServer, collationServer, charsetDBVar, collationDBVar, charsetConn, collationConn string - row := db.Raw("SELECT @@character_set_server, @@collation_server, @@character_set_database, @@collation_database, @@character_set_connection, @@collation_connection").Row() - if err := row.Scan(&charsetServer, &collationServer, &charsetDBVar, &collationDBVar, &charsetConn, &collationConn); err != nil { - return fmt.Errorf("读取 MySQL 字符集变量失败 / Failed to read MySQL charset variables: %v", err) - } + // 仅检测:当前库默认字符集/排序规则 + 各表的排序规则(隐含字符集) // Read current schema defaults var schemaCharset, schemaCollation string @@ -416,20 +411,68 @@ func checkMySQLChineseSupport(db *gorm.DB) error { csLower := toLower(cs) clLower := toLower(cl) if prefix, ok := allowedCharsets[csLower]; ok { - // collation should correspond to the charset when available if clLower == "" { return true } return strings.HasPrefix(clLower, prefix) } + // 如果仅提供了排序规则,尝试按排序规则前缀判断 + for _, prefix := range allowedCharsets { + if strings.HasPrefix(clLower, prefix) { + return true + } + } return false } - // We strictly require the CONNECTION and SCHEMA defaults to be Chinese-capable. - // We also check database/server variables and include them in the error for visibility. - if !isChineseCapable(charsetConn, collationConn) || !isChineseCapable(schemaCharset, schemaCollation) || !isChineseCapable(charsetDBVar, collationDBVar) { - return fmt.Errorf("MySQL 字符集/排序规则必须支持中文(允许 utf8mb4/utf8/gbk/big5/gb18030),请调整服务器、数据库或连接设置。/ MySQL charset/collation must be Chinese-capable (one of utf8mb4/utf8/gbk/big5/gb18030). Details: server(%s/%s), database_var(%s/%s), connection(%s/%s), schema(%s/%s)", - charsetServer, collationServer, charsetDBVar, collationDBVar, charsetConn, collationConn, schemaCharset, schemaCollation) + // 1) 当前库默认值必须支持中文 + if !isChineseCapable(schemaCharset, schemaCollation) { + return fmt.Errorf("当前库默认字符集/排序规则不支持中文:schema(%s/%s)。请将库设置为 utf8mb4/utf8/gbk/big5/gb18030 / Schema default charset/collation is not Chinese-capable: schema(%s/%s). Please set to utf8mb4/utf8/gbk/big5/gb18030", + schemaCharset, schemaCollation, schemaCharset, schemaCollation) + } + + // 2) 所有物理表的排序规则(隐含字符集)必须支持中文 + type tableInfo struct { + Name string + Collation *string + } + var tables []tableInfo + if err := db.Raw("SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE'").Scan(&tables).Error; err != nil { + return fmt.Errorf("读取表排序规则失败 / Failed to read table collations: %v", err) + } + + var badTables []string + for _, t := range tables { + // NULL 或空表示继承库默认设置,已在上面校验库默认,视为通过 + if t.Collation == nil || *t.Collation == "" { + continue + } + cl := *t.Collation + // 仅凭排序规则判断是否中文可用 + ok := false + lower := strings.ToLower(cl) + for _, prefix := range allowedCharsets { + if strings.HasPrefix(lower, prefix) { + ok = true + break + } + } + if !ok { + badTables = append(badTables, fmt.Sprintf("%s(%s)", t.Name, cl)) + } + } + + if len(badTables) > 0 { + // 限制输出数量以避免日志过长 + maxShow := 20 + shown := badTables + if len(shown) > maxShow { + shown = shown[:maxShow] + } + return fmt.Errorf( + "存在不支持中文的表,请修复其排序规则/字符集。示例(最多展示 %d 项):%v / Found tables not Chinese-capable. Please fix their collation/charset. Examples (showing up to %d): %v", + maxShow, shown, maxShow, shown, + ) } return nil }