fix(database): improve MySQL Chinese character support validation
This commit is contained in:
@@ -389,12 +389,7 @@ func CloseDB() error {
|
|||||||
// default charset/collation can store Chinese characters. It allows common
|
// default charset/collation can store Chinese characters. It allows common
|
||||||
// Chinese-capable charsets (utf8mb4, utf8, gbk, big5, gb18030) and panics otherwise.
|
// Chinese-capable charsets (utf8mb4, utf8, gbk, big5, gb18030) and panics otherwise.
|
||||||
func checkMySQLChineseSupport(db *gorm.DB) error {
|
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
|
// Read current schema defaults
|
||||||
var schemaCharset, schemaCollation string
|
var schemaCharset, schemaCollation string
|
||||||
@@ -416,20 +411,68 @@ func checkMySQLChineseSupport(db *gorm.DB) error {
|
|||||||
csLower := toLower(cs)
|
csLower := toLower(cs)
|
||||||
clLower := toLower(cl)
|
clLower := toLower(cl)
|
||||||
if prefix, ok := allowedCharsets[csLower]; ok {
|
if prefix, ok := allowedCharsets[csLower]; ok {
|
||||||
// collation should correspond to the charset when available
|
|
||||||
if clLower == "" {
|
if clLower == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return strings.HasPrefix(clLower, prefix)
|
return strings.HasPrefix(clLower, prefix)
|
||||||
}
|
}
|
||||||
|
// 如果仅提供了排序规则,尝试按排序规则前缀判断
|
||||||
|
for _, prefix := range allowedCharsets {
|
||||||
|
if strings.HasPrefix(clLower, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// We strictly require the CONNECTION and SCHEMA defaults to be Chinese-capable.
|
// 1) 当前库默认值必须支持中文
|
||||||
// We also check database/server variables and include them in the error for visibility.
|
if !isChineseCapable(schemaCharset, schemaCollation) {
|
||||||
if !isChineseCapable(charsetConn, collationConn) || !isChineseCapable(schemaCharset, schemaCollation) || !isChineseCapable(charsetDBVar, collationDBVar) {
|
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",
|
||||||
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)",
|
schemaCharset, schemaCollation, schemaCharset, schemaCollation)
|
||||||
charsetServer, collationServer, charsetDBVar, collationDBVar, charsetConn, collationConn, 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user