fix-collation.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. 'use strict'
  2. const mysql = require('mysql2/promise')
  3. const config = require('../config.json').database
  4. const TARGET_COLLATION = 'utf8mb4_general_ci'
  5. const TARGET_CHARSET = 'utf8mb4'
  6. async function main() {
  7. const conn = await mysql.createConnection({
  8. host: config.host,
  9. port: config.port,
  10. user: config.user,
  11. password: config.password,
  12. database: config.database,
  13. multipleStatements: true
  14. })
  15. try {
  16. const dbName = config.database
  17. const [schemaRows] = await conn.query(
  18. `SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
  19. FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?`,
  20. [dbName]
  21. )
  22. console.log('=== 库默认 ===', schemaRows[0])
  23. const [badTablesBefore] = await conn.query(
  24. `SELECT TABLE_NAME, TABLE_COLLATION
  25. FROM information_schema.TABLES
  26. WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'
  27. AND TABLE_COLLATION != ?
  28. ORDER BY TABLE_NAME`,
  29. [dbName, TARGET_COLLATION]
  30. )
  31. console.log(`=== 需转换的表: ${badTablesBefore.length} ===`)
  32. badTablesBefore.forEach((r) => console.log(` ${r.TABLE_NAME} -> ${r.TABLE_COLLATION}`))
  33. console.log('\n=== 修改库默认字符集 ===')
  34. await conn.query(
  35. `ALTER DATABASE \`${dbName}\` CHARACTER SET ${TARGET_CHARSET} COLLATE ${TARGET_COLLATION}`
  36. )
  37. const [allTables] = await conn.query(
  38. `SELECT TABLE_NAME FROM information_schema.TABLES
  39. WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'
  40. ORDER BY TABLE_NAME`,
  41. [dbName]
  42. )
  43. console.log(`\n=== 开始转换 ${allTables.length} 张表 ===`)
  44. for (const row of allTables) {
  45. const table = row.TABLE_NAME
  46. process.stdout.write(` CONVERT ${table} ... `)
  47. try {
  48. await conn.query(
  49. `ALTER TABLE \`${dbName}\`.\`${table}\`
  50. CONVERT TO CHARACTER SET ${TARGET_CHARSET} COLLATE ${TARGET_COLLATION}`
  51. )
  52. console.log('OK')
  53. } catch (err) {
  54. console.log('FAIL')
  55. console.error(` ${err.message}`)
  56. }
  57. }
  58. const [badTablesAfter] = await conn.query(
  59. `SELECT TABLE_NAME, TABLE_COLLATION
  60. FROM information_schema.TABLES
  61. WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'
  62. AND TABLE_COLLATION != ?
  63. ORDER BY TABLE_NAME`,
  64. [dbName, TARGET_COLLATION]
  65. )
  66. const [badColsAfter] = await conn.query(
  67. `SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME
  68. FROM information_schema.COLUMNS
  69. WHERE TABLE_SCHEMA = ? AND COLLATION_NAME IS NOT NULL
  70. AND COLLATION_NAME != ?
  71. ORDER BY TABLE_NAME, ORDINAL_POSITION`,
  72. [dbName, TARGET_COLLATION]
  73. )
  74. console.log('\n=== 验证结果 ===')
  75. const [schemaAfter] = await conn.query(
  76. `SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
  77. FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?`,
  78. [dbName]
  79. )
  80. console.log('库默认:', schemaAfter[0])
  81. console.log(`剩余非 ${TARGET_COLLATION} 的表: ${badTablesAfter.length}`)
  82. badTablesAfter.forEach((r) => console.log(` ${r.TABLE_NAME} -> ${r.TABLE_COLLATION}`))
  83. console.log(`剩余非 ${TARGET_COLLATION} 的列: ${badColsAfter.length}`)
  84. badColsAfter.slice(0, 20).forEach((r) =>
  85. console.log(` ${r.TABLE_NAME}.${r.COLUMN_NAME} -> ${r.COLLATION_NAME}`)
  86. )
  87. console.log('\n=== 测试赠送审核 JOIN ===')
  88. try {
  89. await conn.query(
  90. `SELECT r.id
  91. FROM lepao_send_count_request r
  92. LEFT JOIN users su ON su.uuid = r.sender_uuid
  93. LIMIT 1`
  94. )
  95. console.log('JOIN 测试: OK')
  96. } catch (err) {
  97. console.log('JOIN 测试: FAIL -', err.message)
  98. }
  99. } finally {
  100. await conn.end()
  101. }
  102. }
  103. main().catch((err) => {
  104. console.error(err.message || err)
  105. process.exit(1)
  106. })