Ошибка Postgres при вставке - ОШИБКА: неверная последовательность байтов для кодировки "UTF8": 0x00
Я получаю следующую ошибку при вставке данных из mysql в postgres.
Нужно ли вручную удалять все нулевые символы из моих входных данных? Есть ли способ получить postgres, чтобы сделать это для меня?
ERROR: invalid byte sequence for encoding "UTF8": 0x00
8 ответов
PostgreSQL не поддерживает хранение символов NULL (\0x00) в текстовых полях (это, очевидно, отличается от значения NULL базы данных, которое полностью поддерживается).
Источник: http://www.postgresql.org/docs/9.1/static/sql-syntax-lexical.html
Если вам нужно сохранить символ NULL, вы должны использовать поле bytea, которое должно хранить все, что вы хотите, но не поддерживает текстовые операции с ним.
Учитывая, что PostgreSQL не поддерживает его в текстовых значениях, нет хорошего способа заставить его удалить его. Вы можете импортировать ваши данные в bytea, а затем преобразовать их в текст, используя специальную функцию (в perl или что-то, может быть?), Но, вероятно, будет проще сделать это при предварительной обработке перед загрузкой.
Если вы используете Java, вы можете просто заменить символы x00 перед вставкой, как показано ниже:
myValue.replaceAll("\u0000", "")
Решение было предоставлено и объяснено Csaba в следующем посте:
https://www.postgresql.org/message-id/1171970019.3101.328.camel%40coppola.muc.ecircle.de
Соответственно:
в Java вы можете иметь символ "0x0" в вашей строке, и это допустимый юникод. Так что это переводится в символ 0x0 в UTF8, что, в свою очередь, не принимается, потому что сервер использует строки с нулевым символом в конце... поэтому единственный способ - убедиться, что ваши строки не содержат символа '\u0000'.
Только это регулярное выражение работало для меня:
sed 's/\\0//g'
Итак, когда вы получите ваши данные, сделайте это: $ get_data | sed 's/\\0//g'
который выведет ваши данные без 0x00
Если вам нужно хранить нулевые символы в текстовых полях и не хотите менять тип данных, кроме текста, вы также можете следовать моему решению:
Перед вставкой:
myValue = myValue.replaceAll("\u0000", "SomeVerySpecialText")
После выбора:
myValue = myValue.replaceAll("SomeVerySpecialText","\u0000")
Я использовал "null" в качестве SomeVerySpecialText, и я уверен, что в моих значениях не будет никакой "нулевой" строки.
Вы можете сначала вставить данные в поле blob, а затем скопировать в текстовое поле с помощью следующей функции
CREATE OR REPLACE FUNCTION blob2text() RETURNS void AS $$
Declare
ref record;
i integer;
Begin
FOR ref IN SELECT id, blob_field FROM table LOOP
-- find 0x00 and replace with space
i := position(E'\\000'::bytea in ref.blob_field);
WHILE i > 0 LOOP
ref.bob_field := set_byte(ref.blob_field, i-1, 20);
i := position(E'\\000'::bytea in ref.blobl_field);
END LOOP
UPDATE table SET field = encode(ref.blob_field, 'escape') WHERE id = ref.id;
END LOOP;
End; $$ LANGUAGE plpgsql;
-
SELECT blob2text();
Подобная ошибка также может возникнуть при использовании COPY и наличии экранированной строки, содержащей значения NULL (00
) Такие как:
"H\x00\x00\x00tj\xA8\x9E#D\x98+\xCA\xF0\xA7\xBBl\xC5\x19\xD7\x8D\xB6\x18\xEDJ\x1En"
Если вы используете COPY
без указания format 'CSV'
postgres по умолчанию примет format 'text'
. Это имеет другое взаимодействие с люфтами, см. Текстовый формат.
Если вы используете COPY
или file_fdw
не забудьте указать format 'CSV'
чтобы избежать ошибок такого рода.
Если кто-то приходит сюда и ищет, как удалить0x00
в Питоне:
new_row = row.replace("\x00", "")