PostgreSQL:如何使用GnuCOBOL将不兼容(UTF8)的原始字节存储为bytea?
我使用的应用程序通过将32位掩码(1和0)转换为十六进制,将其作为4个字符的字段存储在数据库中。(这是一个非常旧的应用程序,因此无法更改此设置) 这在Oracle和DB2(UTF8编码)中使用得很好,但是在PostgreSQL(UTF8编码)中,当我尝试使用COBOL程序插入值时,会产生以下错误:PostgreSQL:如何使用GnuCOBOL将不兼容(UTF8)的原始字节存储为bytea?,postgresql,utf-8,gnucobol,Postgresql,Utf 8,Gnucobol,我使用的应用程序通过将32位掩码(1和0)转换为十六进制,将其作为4个字符的字段存储在数据库中。(这是一个非常旧的应用程序,因此无法更改此设置) 这在Oracle和DB2(UTF8编码)中使用得很好,但是在PostgreSQL(UTF8编码)中,当我尝试使用COBOL程序插入值时,会产生以下错误: 错误:编码“SJIS”的字节序列无效:0xa0 Binary=011010011110000110010100000 Hex=0x68270CA0 数据库编码和表定义 diginst=> \en
错误:编码“SJIS”的字节序列无效:0xa0
Binary=011010011110000110010100000
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,即使客户端编码和服务器编码为UTF8。但是,即使是UTF8(我在上面的代码中手动将CLIENT_ENCODING设置为“UTF8”),0xA0在UTF8字符集中也不是有效字符
从上的PostgreSQL文档
简而言之,二进制字符串适用于存储
程序员认为是“原始字节”,而字符串是
适合于存储文本
我不确定在这种情况下我做错了什么,因为bytea
应该可以工作(根据文档)
还想知道为什么程序选择默认编码为SJIS
,而它应该是UTF8
。我还尝试设置环境变量PGCLIENTENCODING=UTF8
,但它仍然给出与SJIS相同的错误
*我认为这也与主要问题有关,所以我不想就此提出单独的问题
Update:在进一步挖掘之后,DB2通过在CREATETABLE语句中为位数据添加子句,存储原始字节(即使db编码不支持它)-
create table tab_db2 (key_part char(5) not null, raw_data char (100) for bit data);
在Oracle中,使用的字符集是AL32UTF8
,它支持的字符数()比UTF8
多
PostgreSQL中有用于AL32UTF8
的字符集,因此我暂时使用LATIN1
,直到找到其他字符集。在Oracle和DB2中使用了什么类型?实际的表模式是什么?这两个数据库都有Unicode字符串的显式类型支持,例如nvarhar2
。他们不需要服务器编码来将char
转换为UTF8。该应用程序使用了一种只适用于那些特定类型的黑客。您不能期望它在任何其他数据库中以相同的方式工作。类型是什么?@PanagiotisKanavos DB2对位数据的定义是CHAR(4)
,在Oracle中NLS\u字符集
是AL32UTF8。不确定AL32UTF8和UTF8之间有什么区别。PostgreSQL中是否有AL32UTF8的等效项?看起来您已经正确诊断了问题-Postgres似乎在将字符串转换为二进制之前验证字符串在字符集中是否有效。如果您能够将COBOL更改为05d-MASK SQL类型为BINARY(4)
或可能的05d-MASK S9(9)BINARY
,这可能会解决问题-但不是COBOL专家。