Нет NULL, но недопустимая последовательность байтов для кодирования «UTF8»: 0x00

12

Последние 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

Сервер 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".

Согласно следующему, во входном файле нет символов 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

Аналогично, другая проверка с Perl не показывает NULL:

database-dumps:rcf-temp1# perl -ne '/\000/ and print;' foo
database-dumps:rcf-temp1#

Как упоминается в разделе «СОВЕТ» в сообщении об ошибке, я пытался всеми возможными способами установить «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#

Идеально, но:

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".
...

За исключением правильного ответа «Согласно Хойлу», который было бы замечательно услышать, и зная, что я действительно не забочусь о сохранении каких-либо не-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

Одна из рассматриваемых таблиц определяется как:

                                        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)

У меня нет свободы изменять тип для какой-либо части схемы БД. Это может повредить будущие обновления программного обеспечения и т. Д.

Вероятный проблемный столбец - это «содержимое» типа «текст» (возможно, другие в других таблицах). Как я уже знаю из предыдущего исследования, PostgreSQL не допустит NULL в «текстовых» значениях. Тем не менее, смотрите выше, где sed и Perl не показывают NULL-символов, а затем далее, где я удаляю все не-ASCII-символы из всего файла дампа, но это все еще barfs.

jblaine
источник
2
Как выглядит строка 29 вашего файла дампа? Нечто подобное head -29 foo | tail -1 | cat -vможет быть полезным.
Му слишком коротко
Каково определение затронутой таблицы и как выглядит оскорбительная строка?
tscho
Это ~ 1 МБ данных компании. Я, конечно, понимаю, куда ты направляешься. Вот конец этой мысли (прошу прощения за мой французский в конце суть / паста): gist.github.com/1525788
jblaine
tscho: как указано, эта строка ошибки является одной из сотен этих ошибок.
jblaine

Ответы:

3

Одно или несколько из этих символьных / текстовых полей МОГУТ иметь 0x00 для своего содержимого.

Попробуйте следующее:

SELECT * FROM rt3 where some_text_field = 0x00 LIMIT 1;

Если это возвращает какую-либо строку, попробуйте обновить эти символьные / текстовые поля:

UPDATE rt3 SET some_text_field = '' WHERE some_text_field = 0x00;

Затем попробуйте другой MYSQLDUMP ... (и метод импорта PostgreSQL).

Фарли Инглис
источник
Это помогло мне найти моих случайных нулевых персонажей, хотя мне нужно было их использовать colname LIKE concat('%', 0x00, '%'). Нашел их в полях, содержащих сериализованные массивы PHP.
Цимманон
5

У меня была та же проблема с использованием MySQL версии 5.0.51 и Postgres версии 9.3.4.0. Я решил проблему «недопустимой последовательности байтов для кодирования« UTF8 »: 0x00» после того, как увидел комментарий Даниэля Верите о том, что «mysqldump в режиме postgresql будет выводить нулевые байты как \ 0 в строках, так что вы, вероятно, захотите найти эту последовательность символов».

Конечно же, grep наконец-то показал NULL-символы.

grep \\\\0 dump.sql

Я заменил NULL-символы, используя следующую команду

sed -i BAK 's/\\0//g' dump.sql

После этого Postgres смог успешно загрузить dump.sql

Jadence
источник
4

Вы можете получить эту ошибку без какого-либо NULL-байта или любого не-ascii символа в файле. Пример в базе данных utf8:

select E'ab\0cd';

будет давать:

ОШИБКА: недопустимая последовательность байтов для кодировки «UTF8»: 0x00 СОВЕТ: Эта ошибка также может произойти, если последовательность байтов не соответствует кодировке, ожидаемой сервером, который управляется «client_encoding».

mysqldump в режиме postgresql будет сбрасывать нулевые байты как \ 0 в строках, поэтому вы, вероятно, захотите найти эту последовательность символов.

Даниэль Верите
источник
0

Я наполовину помню такую ​​проблему. Я думаю, что я закончил миграцию схемы, затем выгрузил данные как csv и загрузил данные из файла csv. Я помню, что мне приходилось обновлять файл csv (используя инструменты Unix, такие как sed или unixtodos) или использовать open office calc (excell), чтобы исправить некоторые элементы, которые были ошибками на этапе импорта - это может быть так же просто, как открыть и повторно сохранить файл.

Адам Ф
источник