postgresql 9.5 - декодирование/выбор регистра для устранения ошибки с utf8 не работает

В продолжении к моему последнее сообщение - "миграция оракула на postgresql неверная последовательность байтов для кодировки "UTF8": 0x00"

Я пытаюсь вставить в локальную таблицу данных postgresql из удаленной таблицы оракула (через расширение oracle_fdw). В моей таблице оракула есть столбец с именем street, и он имеет допустимые строковые значения, а иногда и следующую недопустимую (в postgresql) строку: ' ' (пробел). Когда я пытаюсь скопировать значение столбца, я получаю сообщение об ошибке, упомянутое выше и в моем последнем сообщении. Я понял, что мне нужно изменить данные оракула, прежде чем я вставлю их в postgresql. Я должен сделать это на лету, поэтому я попытался найти функцию декодирования оракула в postgresql. Я нашел 2 решения и использовал их оба, но получил ту же ошибку:

1.используя выбор с регистром:

mydb=>select *,(case when v.street=' ' then null END) from customer_prod v;
ERROR:  invalid byte sequence for encoding "UTF8": 0x00
CONTEXT:  converting column "street" for foreign table scan of 
 "customer_prod", row 254148

2. Использование функции декодирования из расширения orafce:

mydb=>select decode(street,' ',null) from customer_prod;
ERROR:  invalid byte sequence for encoding "UTF8": 0x00

Итак, я все еще получаю сообщение об ошибке. Любая идея, как я могу решить эту проблему?


person JeyJ    schedule 25.07.2017    source источник


Ответы (1)


Ошибка возникает, когда значения передаются из Oracle в PostgreSQL, поэтому постобработка не предотвратит ошибку.

Для демонстрации давайте создадим таблицу Oracle, демонстрирующую проблему:

CREATE TABLE nulltest(
   id number(5) CONSTRAINT nulltest_pkey PRIMARY KEY,
   val varchar2(10 CHAR)
);

INSERT INTO nulltest VALUES (1, 'schön');
INSERT INTO nulltest VALUES (2, 'bö' || CHR(0) || 'se');
INSERT INTO nulltest VALUES (3, 'egal');

COMMIT;

Создадим для него внешнюю таблицу в PostgreSQL:

CREATE FOREIGN TABLE nulltest (
   id integer OPTIONS (key 'true') NOT NULL,
   val varchar(10)
) SERVER oracle
   OPTIONS (table 'NULLTEST');

SELECT * FROM nulltest;

ERROR:  invalid byte sequence for encoding "UTF8": 0x00
CONTEXT:  converting column "val" for foreign table scan of "nulltest", row 2

Теперь проще всего создать внешнюю таблицу, которая отфильтровывает нулевые символы:

CREATE FOREIGN TABLE filter_nulltest (
   id integer OPTIONS (key 'true') NOT NULL,
   val varchar(10)
) SERVER oracle
   OPTIONS (table '(SELECT id, replace(val, CHR(0), NULL) FROM nulltest)');

SELECT * FROM filter_nulltest;

┌────┬───────┐
│ id │  val  │
├────┼───────┤
│  1 │ schön │
│  2 │ böse  │
│  3 │ egal  │
└────┴───────┘
(3 rows)

Другой, менее эффективный вариант — создать функцию, которая отлавливает и сообщает вам о неверных строках, чтобы вы могли исправить их на стороне Oracle:

CREATE OR REPLACE FUNCTION get_nulltest() RETURNS SETOF nulltest
   LANGUAGE plpgsql AS
$$DECLARE
   v_id integer;
   n nulltest;
BEGIN
   FOR v_id IN SELECT id FROM nulltest
   LOOP
      BEGIN
         SELECT nulltest.* INTO n
            FROM nulltest
            WHERE id = v_id;
         RETURN NEXT n;
      EXCEPTION
         WHEN OTHERS THEN
            RAISE NOTICE 'Caught error % for id=%: %', SQLSTATE, v_id, SQLERRM;
      END;
   END LOOP;
END;$$;

SELECT * FROM get_nulltest();

NOTICE:  Caught error 22021 for id=2: invalid byte sequence for encoding "UTF8": 0x00
┌────┬───────┐
│ id │  val  │
├────┼───────┤
│  1 │ schön │
│  3 │ egal  │
└────┴───────┘
(2 rows)
person Laurenz Albe    schedule 25.07.2017
comment
Большое спасибо Лауренсу! Вы мне очень помогли в последних сообщениях. Ты лучший ! - person JeyJ; 25.07.2017
comment
CHR(0) = ' ' (ПРОБЕЛ)? Когда я переключаю CHR (0) С '', ВЫБОР РАБОТАЕТ, НО ЕСЛИ Я ИСПОЛЬЗУЮ CHR (0), Я ПОЛУЧАЮ ОШИБКУ: нулевой символ не разрешен - person JeyJ; 25.07.2017
comment
CHR(0) <> ' ' в Oracle. В PostgreSQL у вас не может быть CHR(0), как объяснено. - person Laurenz Albe; 25.07.2017
comment
Я спросил об этом, потому что значение, которое у меня есть в проблемном столбце, равно ' '. Поэтому я хотел знать, является ли ' ' CHR (0) в postgresql. - person JeyJ; 25.07.2017
comment
Я понял, что у меня есть 3 проблемных столбца, поэтому я запускаю функцию замены для всех из них. Размер моей таблицы 600M. Когда я запускаю выбор, я убиваю сообщение. Является ли это проблемой производительности? У меня не было проблем с выбором из таблиц, размер которых составляет 10 ГБ. - person JeyJ; 25.07.2017
comment
Кажется, это другой вопрос. - person Laurenz Albe; 25.07.2017
comment
Я создал представление на своей стороне оракула, которое: выберите столбец1, столбец2... замените (столбец5, '', нуль) из table_name. Когда я создаю таблицу foregin в postgresql, я просто выбираю из представления. Однако, когда я запускаю в postgresql select * from external_table_Name, я все еще получаю эту ошибку для столбца 5. - person JeyJ; 27.07.2017
comment
Конечно, потому что CHR(0) сильно отличается от пробела. Вам придется использовать replace(column5, CHR(0), null). - person Laurenz Albe; 28.07.2017