我今天登录了我们的一个生产数据库,并尝试使用列出的数据库\l
并得到:
ERROR: invalid byte sequence for encoding “UTF8”: 0xe5 0xc6 0xf5
由于我没有触及任何内容,只是数据库上的元数据,我不知道从哪里开始攻击它。除了多余的类似错误之外,我看不到类似问题的答案如何直接提供帮助。如果我猜的话,我会认为数据库的名称之一包含无法使用 utf8 表示的字符。
线索?
调试信息
在 Windows Server 2016 上运行 Postgresql 版本 10.4 64 位。
mydb=> SHOW client_encoding;
client_encoding
-----------------
WIN1252
mydb=> SHOW server_encoding;
server_encoding
-----------------
UTF8
mydb=> SELECT datname::bytea, encoding FROM pg_database;
datname | encoding
----------------------+----------
\x706f737467726573 | 6
\x74656d706c61746531 | 6
\x74656d706c61746530 | 6
\x6e696d626c656462 | 6
快速修复:更改客户端编码以匹配内容
我通过更改客户端编码以匹配服务器编码来完成这项工作。更改客户端编码起到了作用,因为它阻止了 Postgres 在编码为 cp1252 时对 utf8 文本进行编码。(我不知道这些
Collate
东西是什么。)为什么(进入原始字节领域)
这需要一段时间才能深入研究,但我使用了评论部分的提示,
\l
它实际上相当于pg_catalog.pg_database
. 通过切换要列出的列,我能够找到证明有问题的列,并将其显示为原始字节,我可以准确地确定位置:因此,
datcollate
事实证明这是有问题的专栏。根据文档,此列是 typename
并且是LC_COLLATE for this database
. 显然,有些东西是不让人注意的,因为 UTF8 编码的输出中没有任何“非 ascii”,但输出有点奇怪,因为语言环境名称有一些似乎已经消失的字符:“å “挪威 Bokml_Norway.1252”中的字符缺失(应为“...Bokmål...”)。这只是巧合吗?让我们将标准 ascii 的输出与上面的输出进行比较:
如果将其与上面的原始输出进行比较,您会看到 psql 输出有一个额外的字节:
e5
between6d
and6c
。这没有显示。这就是
å
我的 UTF8 终端中的编码方式:所以
å
在 UTF8 中使用两个字节(c3a5),而在它上面只有一个字节。WIN1252中可以å吗?确实如此!所以问题是区域设置名称在内部postgres数据库中编码为WIN1252,当服务器编码设置为UTF8时似乎无法正确处理,因为客户端似乎假设它接收的数据都是有效的utf8 .
奖励:已修复 VIEW 查询问题
巧合的是,这也修复了我正在修复的另一个相关问题,该问题在尝试列出
VIEW
包含 UTF8 挪威语字符的内容时发生:您的排序规则
Norwegian Bokmål_Norway.1252
来自操作系统 (Windows) 并按原样使用。现在 Windows 使用十六进制 E5 中的Windows-1252编码,其中å
代码点 226。此字符串
pg_database.datcollate
按原样输入,但 PostgreSQL 期望名称为 UTF-8 格式,这会导致错误。PostgreSQL 必须清理那个 string ,所以这是一个 PostgreSQL 错误(虽然,诚然,Windows 应该归咎于将其语言环境名称从一个版本更改为另一个版本)。
这种特殊情况实际上已在 2019 年修复,因此如果您使用了 PostgreSQL 的最新错误修复级别,则可以避免该问题。
已经提出了一个补丁来在更一般的基础上处理此类问题,但它从未被提交,因为 Windows 上没有人对其进行测试。您可以将其推送到 -hackers 列表中,最好是测试补丁(但这需要在 Windows 上构建 PostgreSQL,这需要一些设置)。