Ошибка 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'.

Просто выведите нулевые байты:

s/\x00//g;

Только это регулярное выражение работало для меня:

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", "")
Другие вопросы по тегам