如何调试 Etherpad Lite 数据库中 MySQL utf8mb4 列中的无效数据

Posted

技术标签:

【中文标题】如何调试 Etherpad Lite 数据库中 MySQL utf8mb4 列中的无效数据【英文标题】:How to debug invalid data in MySQL utf8mb4 column in Etherpad Lite database 【发布时间】:2018-02-14 22:32:00 【问题描述】:

我们正在运行 Etherpad Lite,并且正在尝试将数据库从 mysql 迁移到 PostgreSQL。

MySQL 数据库“值”列的类型为 utf8mb4。但是,大约 10% 的行包含实际上以 Windows-1252 或 ISO-8859-15 而不是 UTF-8 编码的值。这怎么可能? MySQL 在输入列之前不验证 UTF-8 吗?

PostgreSQL 在迁移期间不能接受无效值,因为它确实验证了数据并命中例如原始字节 0xE4 (ISO-8859-15: ä) 应编码为 UTF-8 中的字节序列 0xC3 0xA4。

这是 MySQL 的一个已知“特性”吗?有什么方法可以始终从utf8mb4 列获取真正的 UTF-8?

【问题讨论】:

【参考方案1】:

如果

你说客户端正在使用latin1(等等),并且 您说是utf8(或utf8mb4),并且 你提供十六进制E4

那么一切都很好。 E4 将在INSERT 期间转换为C3A4,这就是存储的内容。做SELECT HEX(...) ...验证。

如果

你说客户端正在使用utf8(或utf8mb4),并且 您说是utf8(或utf8mb4),并且 你提供十六进制C3A4

再次,一切都很好。 C3A4 直接进入表格。

这是一个混乱的案例:

如果

你说客户端正在使用latin1,并且 您说是utf8(或utf8mb4),并且 但是你提供十六进制C3A4

然后,MySQL 有义务将 两个 字符(C3 和 A4)转换为 utf8,产生C383C2A4。我称之为“双重编码”。

遵循Trouble with UTF-8 characters; what I see is not what I stored 中的最佳实践并使用其建议的方法来测试数据。然后回来提供更多细节。

可能导致 10% 的数据被错误解释的唯一方法是对 10% 的数据进行不同的编码。因此,请为 10% 的示例和 90% 的示例提供十六进制。并在插入前在客户端提供十六进制,插入后在表格中提供。

【讨论】:

我有一个案例,客户端说set names utf8 并且数据库列的类型为utf8mb4SELECT 仍然返回包含原始字节\xE4 的字符串,而不是ä 或U+00E4 .请注意,UTF-8 应该将该字符编码为\xC3\xA4。数据最初由 node.js 服务输入,以防万一。 那么你已经“撒谎”了字节是 utf8。十六进制 E4 是 latin1。 U+00E4 可能看起来很相似,但那是 unicode,不是 latin1,也不是 utf8。说 set names utf8 是说 client 将具有十六进制 C3A4 用于 ä 我同意纯 0xE4 不应出现在 UTF-8 字符串中。但是,Etherpad Lite(在 node.js 上运行)有时会在 UTF-8 字符串中间发出原始 Windows-1252 字符(我认为这是 node.js 或 Etherpad Lite 中的一个错误),MySQL 会很乐意将这样的字符串存储在MyISAM 表。如果 MySQL 确实抛出异常而不是接受这样的无效字符串,我就不会问这个问题。 UTF-8 字符串可能包含字节 0xE4,如果它后面跟着设置了第 8 位的其他字节。比如U+4494就是字节序列0xE4 0x92 0x94 我不知道如何重现问题(将数据插入数据库),但事实是 MySQL 正在使用 Windows-1252 编码从数据库返回部分数据,即使连接设置为UTF-8 和数据库列类型为utf8mb4【参考方案2】:

没有已知的解决方案。这可能是 MySQL 中的一个错误,它应该禁止存储非 UTF-8 数据以防 client 连接和 列类型 都是 utf8mb4。

我不再将 MySQL 用于任何事情,所以我不再费心去尝试解决这个错误。现在,我用 PostgreSQL 代替一切。

【讨论】:

以上是关于如何调试 Etherpad Lite 数据库中 MySQL utf8mb4 列中的无效数据的主要内容,如果未能解决你的问题,请参考以下文章

如何删除 etherpad-lite 中的焊盘

如何列出 etherpad-lite 中的所有焊盘

如何在 cPanel 上安装 etherpad-lite(共享主机)

如何在 Sandstorm 上安装 Etherpad Lite 插件?

etherpad-lite 权限被拒绝,打开 './SESSIONKEY.txt'

Etherpad-lite 有序列表格式化