PostgreSQL: Как хранить необработанные (UTF8) необработанные байты как байты, используя GnuCOBOL? - PullRequest
0 голосов
/ 24 апреля 2018

Приложение, которое я использую, хранит 32-битную маску (1 и 0) в качестве 4-символьного поля в базе данных путем преобразования его в шестнадцатеричное. (Это довольно старое приложение, поэтому изменить его нельзя).

Раньше это хорошо работало с Oracle & DB2 (кодировка UTF8), однако с PostgreSQL (кодировка UTF8), когда я пытаюсь вставить значение с помощью программы COBOL, которая выдает ошибку ниже:

ERROR: invalid byte sequence for encoding "SJIS": 0xa0

Binary = 01101000001001110000110010100000

Hex=0x68270CA0

Кодировка базы данных и определение таблицы

diginst=> \encoding
UTF8
diginst=> \d tab_1
 Column |     Type     | Collation | Nullable | Default
--------+--------------+-----------+----------+---------
 code   | character(5) |           | not null |
 mask   | bytea        |           |          |

Программа COBOL

   IDENTIFICATION              DIVISION.
   PROGRAM-ID.                 ENCODE.
   DATE-WRITTEN.               2013-06-28.
   DATA                        DIVISION.
   WORKING-STORAGE             SECTION.

       EXEC SQL BEGIN DECLARE SECTION END-EXEC.
   01  DBNAME                PIC  X(30) VALUE SPACE.
   01  SOC-REC-VARS.
       05  D-CODE             PIC X(5).
       05  D-MASK             PIC X(4).
       EXEC SQL END DECLARE SECTION END-EXEC.

       EXEC SQL INCLUDE SQLCA END-EXEC.

   PROCEDURE                   DIVISION.
   MAIN-RTN.
       MOVE  "/@diginst"         TO   DBNAME.
       EXEC SQL
           CONNECT :DBNAME
       END-EXEC.
       IF  SQLCODE NOT = ZERO DISPLAY "ERROR CONNECTING".
       MOVE "00001" TO D-CODE.
       MOVE X"68270CA0" TO D-MASK.

       EXEC SQL
         INSERT INTO TAB_1
         (CODE,
          MASK)
         VALUES(:D-CODE,
                :D-MASK)
       END-EXEC.
       IF SQLCODE = ZERO DISPLAY "INSERT SUCCESSFUL"
       ELSE DISPLAY "INSERT FAILED " SQLERRMC
            GO TO EXIT-0.
       EXEC SQL
          SELECT CODE,MASK
                 INTO :D-CODE, :D-MASK FROM TAB_1
       END-EXEC.
       IF SQLCODE = ZERO DISPLAY "SELECT SUCCESSFUL"
       ELSE DISPLAY "SELECT FAILED " SQLERRMC.
   EXIT-0.
       STOP RUN.

Не уверен, почему он выбирает кодировку как SJIS, хотя client_encoding и server_encoding имеют UTF8. Однако даже если бы это был UTF8 (я вручную сделал SET CLIENT_ENCODING TO 'UTF8' в приведенном выше коде) 0xA0 не является допустимым символом в наборе символов UTF8.

Из документации PostgreSQL по bytea

Короче говоря, двоичные строки подходят для хранения данных, которые программист считает «необработанными байтами», тогда как символьные строки подходит для хранения текста.

Я не уверен, что я делаю неправильно в этом случае, поскольку bytea должен работать (согласно документации).

Также хотелось бы знать, почему программа выбирает кодировку по умолчанию как SJIS, когда она должна быть UTF8. Я также попытался установить переменную окружения PGCLIENTENCODING=UTF8, но она по-прежнему выдает ту же ошибку, что и SJIS.

* Не думал задавать отдельный вопрос для этого, так как я считаю, что это тоже связано с основной проблемой.

Обновление : после еще нескольких копаний DB2 хранит необработанные байты (даже если кодировка БД не поддерживает это), добавляя предложение FOR BIT DATA в операторе создания таблицы как-

create table tab_db2 (key_part char(5) not null, raw_data char (100) for bit data); 

В Oracle используется набор символов AL32UTF8, который поддерживает больше символов ( дополнительных символов ), чем UTF8.

В PostgreSQL нет эквивалентного набора символов для AL32UTF8, поэтому я прибегаю к использованию LATIN1 на данный момент, пока не найду что-то еще.

...