'use strict' const mysql = require('mysql2/promise') const config = require('../config.json').database const TARGET_COLLATION = 'utf8mb4_general_ci' const TARGET_CHARSET = 'utf8mb4' async function main() { const conn = await mysql.createConnection({ host: config.host, port: config.port, user: config.user, password: config.password, database: config.database, multipleStatements: true }) try { const dbName = config.database const [schemaRows] = await conn.query( `SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?`, [dbName] ) console.log('=== 库默认 ===', schemaRows[0]) const [badTablesBefore] = await conn.query( `SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' AND TABLE_COLLATION != ? ORDER BY TABLE_NAME`, [dbName, TARGET_COLLATION] ) console.log(`=== 需转换的表: ${badTablesBefore.length} ===`) badTablesBefore.forEach((r) => console.log(` ${r.TABLE_NAME} -> ${r.TABLE_COLLATION}`)) console.log('\n=== 修改库默认字符集 ===') await conn.query( `ALTER DATABASE \`${dbName}\` CHARACTER SET ${TARGET_CHARSET} COLLATE ${TARGET_COLLATION}` ) const [allTables] = await conn.query( `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, [dbName] ) console.log(`\n=== 开始转换 ${allTables.length} 张表 ===`) for (const row of allTables) { const table = row.TABLE_NAME process.stdout.write(` CONVERT ${table} ... `) try { await conn.query( `ALTER TABLE \`${dbName}\`.\`${table}\` CONVERT TO CHARACTER SET ${TARGET_CHARSET} COLLATE ${TARGET_COLLATION}` ) console.log('OK') } catch (err) { console.log('FAIL') console.error(` ${err.message}`) } } const [badTablesAfter] = await conn.query( `SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' AND TABLE_COLLATION != ? ORDER BY TABLE_NAME`, [dbName, TARGET_COLLATION] ) const [badColsAfter] = await conn.query( `SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND COLLATION_NAME IS NOT NULL AND COLLATION_NAME != ? ORDER BY TABLE_NAME, ORDINAL_POSITION`, [dbName, TARGET_COLLATION] ) console.log('\n=== 验证结果 ===') const [schemaAfter] = await conn.query( `SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?`, [dbName] ) console.log('库默认:', schemaAfter[0]) console.log(`剩余非 ${TARGET_COLLATION} 的表: ${badTablesAfter.length}`) badTablesAfter.forEach((r) => console.log(` ${r.TABLE_NAME} -> ${r.TABLE_COLLATION}`)) console.log(`剩余非 ${TARGET_COLLATION} 的列: ${badColsAfter.length}`) badColsAfter.slice(0, 20).forEach((r) => console.log(` ${r.TABLE_NAME}.${r.COLUMN_NAME} -> ${r.COLLATION_NAME}`) ) console.log('\n=== 测试赠送审核 JOIN ===') try { await conn.query( `SELECT r.id FROM lepao_send_count_request r LEFT JOIN users su ON su.uuid = r.sender_uuid LIMIT 1` ) console.log('JOIN 测试: OK') } catch (err) { console.log('JOIN 测试: FAIL -', err.message) } } finally { await conn.end() } } main().catch((err) => { console.error(err.message || err) process.exit(1) })