没有 NULL,但编码“UTF8”的字节序列无效:0x00

jbl*_*ine 13 mysql postgresql mysqldump

我花了过去 8 个小时试图将 'mysqldump --compatible=postgresql' 的输出导入 PostgreSQL 8.4.9,并且我已经在这里和其他地方阅读了至少 20 个不同的线程来讨论这个特定问题,但没有发现真正有用的答案。

MySQL 5.1.52 数据转储:

mysqldump -u root -p --compatible=postgresql --no-create-info --no-create-db --default-character-set=utf8 --skip-lock-tables rt3 > foo
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 8.4.9 服务器作为目标

使用 'psql -U rt_user -f foo' 加载数据正在报告(其中许多,这是一个示例):

psql:foo:29: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encoding expected by the server, which is controlled by "client_encoding".
Run Code Online (Sandbox Code Playgroud)

根据以下内容,输入文件中没有 NULL (0x00) 字符。

database-dumps:rcf-temp1# sed 's/\x0/ /g' < foo > nonulls
database-dumps:rcf-temp1# sum foo nonulls
04730 2545610 foo
04730 2545610 nonulls
database-dumps:rcf-temp1# rm nonulls
Run Code Online (Sandbox Code Playgroud)

同样,对 Perl 的另一项检查显示没有 NULL:

database-dumps:rcf-temp1# perl -ne '/\000/ and print;' foo
database-dumps:rcf-temp1#
Run Code Online (Sandbox Code Playgroud)

正如错误中的“提示”所提到的,我已经尝试了所有可能的方法将“client_encoding”设置为“UTF8”,但我成功了,但对解决我的问题没有任何影响。

database-dumps:rcf-temp1# psql -U rt_user --variable=client_encoding=utf-8 -c "SHOW client_encoding;" rt3
 client_encoding
-----------------
 UTF8
(1 row)

database-dumps:rcf-temp1#
Run Code Online (Sandbox Code Playgroud)

完美,然而:

database-dumps:rcf-temp1# psql -U rt_user -f foo --variable=client_encoding=utf-8 rt3
...
psql:foo:29: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encoding expected by the server, which is controlled by "client_encoding".
...
Run Code Online (Sandbox Code Playgroud)

除非听到“根据霍伊尔的说法”正确答案,这会很棒,并且知道我真的不关心为这个很少引用的数据保留任何非 ASCII 字符,你有什么建议?

更新:我在导入时使用相同转储文件的纯 ASCII 版本遇到相同的错误。真是让人摸不着头脑:

database-dumps:rcf-temp1# # convert any non-ASCII character to a space
database-dumps:rcf-temp1# perl -i.bk -pe 's/[^[:ascii:]]/ /g;' mysql5-dump.sql
database-dumps:rcf-temp1# sum mysql5-dump.sql mysql5-dump.sql.bk
41053 2545611 mysql5-dump.sql
50145 2545611 mysql5-dump.sql.bk
database-dumps:rcf-temp1# cmp mysql5-dump.sql mysql5-dump.sql.bk
mysql5-dump.sql mysql5-dump.sql.bk differ: byte 1304850, line 30
database-dumps:rcf-temp1# # GOOD!
database-dumps:rcf-temp1# psql -U postgres -f mysql5-dump.sql --variable=client_encoding=utf-8 rt3
...
INSERT 0 416
psql:mysql5-dump.sql:30: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 455
INSERT 0 424
INSERT 0 483
INSERT 0 447
INSERT 0 503
psql:mysql5-dump.sql:36: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 502
INSERT 0 507
INSERT 0 318
INSERT 0 284
psql:mysql5-dump.sql:41: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 382
INSERT 0 419
INSERT 0 247
psql:mysql5-dump.sql:45: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 267
INSERT 0 348
^C
Run Code Online (Sandbox Code Playgroud)

有问题的表之一定义为:

                                        Table "public.attachments"
     Column      |            Type             |                        Modifie
-----------------+-----------------------------+--------------------------------
 id              | integer                     | not null default nextval('atta)
 transactionid   | integer                     | not null
 parent          | integer                     | not null default 0
 messageid       | character varying(160)      |
 subject         | character varying(255)      |
 filename        | character varying(255)      |
 contenttype     | character varying(80)       |
 contentencoding | character varying(80)       |
 content         | text                        |
 headers         | text                        |
 creator         | integer                     | not null default 0
 created         | timestamp without time zone |
Indexes:
    "attachments_pkey" PRIMARY KEY, btree (id)
    "attachments1" btree (parent)
    "attachments2" btree (transactionid)
    "attachments3" btree (parent, transactionid)
Run Code Online (Sandbox Code Playgroud)

我无权更改 DB 模式任何部分的类型。这样做可能会破坏软件的未来升级等。

可能的问题列是“文本”类型的“内容”(也许其他表格中的其他表格也是如此)。正如我从之前的研究中已经知道的那样,PostgreSQL 不允许在“文本”值中使用 NULL。但是,请参阅上面 sed 和 Perl 都没有显示 NULL 字符的地方,然后再往下看,我从整个转储文件中删除了所有非 ASCII 字符,但它仍然是 barfs。

小智 6

我在使用 MySQL 5.0.51 版和 Postgres 9.3.4.0 版时遇到了同样的问题。在看到 Daniel Vérité 的评论“postgresql 模式下的 mysqldump 会将空字节转储为字符串中的 \0,因此您可能想要搜索该字符序列”后,我解决了“用于编码“UTF8”的无效字节序列:0x00”问题。

果然,grep 终于显示了 NULL 字符。

grep \\\\0 dump.sql
Run Code Online (Sandbox Code Playgroud)

我使用以下命令替换了 NULL 字符

sed -i BAK 's/\\0//g' dump.sql
Run Code Online (Sandbox Code Playgroud)

然后 Postgres 能够成功加载 dump.sql


小智 4

这些字符/文本字段中的一个或多个其内容可能为 0x00。

请尝试以下操作:

SELECT * FROM rt3 where some_text_field = 0x00 LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

如果这返回任何单行,则尝试使用以下命令更新这些字符/文本字段:

UPDATE rt3 SET some_text_field = '' WHERE some_text_field = 0x00;
Run Code Online (Sandbox Code Playgroud)

然后,尝试另一种 MYSQLDUMP ...(和 PostgreSQL 导入方法)。

  • 这帮助我找到了杂散的空字符,尽管我需要使用 `colname LIKE concat('%', 0x00, '%')`。在包含序列化 PHP 数组的字段中找到它们。 (2认同)