GaussDB(DWS) GDS导入fixed格式数据文件字符转换问题
在GaussDB(DWS)数据库中,支持的字符编码有GBK、UTF8、Latin1和SQL_ASCII,其中Latin1和SQL_ASCII属于单字节编码,可以存储任何编码规则字符。GBK是中文字符集,使用2个字节编码一个中文字符,而在UTF8中一般使用3个字节编码一个中文字符。对于fixed格式的数据文件,如果里面包含中文,当字符编码从GBK转为UTF8时,字符存储长度增加,会导致根据长度确定字段的位置发生错误,出现数据混乱。
我们使用GDS进行测试,数据库版本为8.0.0.8,数据文件格式为fixed,字符编码为GBK,GDS外表定义如下,将其导入GBK编码的数据库后,中文字段可正常显示,如下图:
CREATE FOREIGN TABLE f_imp_tb95 (
c1 character varying(5) position(0,5),
c2 character varying(5) position(5,5),
c3 character varying(5) position(10,5),
c4 character varying(1) position(15,1),
c5 character varying(40) position(16,40),
c6 character varying(1) position(56,1),
c7 character varying(1) position(57,1),
c8 character varying(5) position(58,5),
c9 character varying(3) position(63,3),
c10 character varying(7) position(66,7),
c11 character varying(60) position(73,60),
c12 character varying(5) position(133,5),
c13 character varying(50) position(138,50))
SERVER gsmpp_server OPTIONS (location 'gsfs://192.168.10.4:5000/*',format 'FIXED' ,encoding 'GBK' ,mode 'Normal' ,compatible_illegal_chars 'true') with f_imp_err_tb95;
由于Latin1字符编码可以存储任意编码规则的字符,如果将外表字符编码设置为encoding ‘Latin1’,客户端和服务端编码一致,则字符可在不转码的情况下存储到Latin1编码的库中,数据仍然可以正常显示,如下图:
上述两种情况由于GBK编码的字符均未发生转码,因此根据定长格式可以正常识别到字符位置。倘若将该数据文件导入UTF8编码的数据库中(外表定义:encoding 'GBK'),此时由于存在转码,数据显示混乱。如下图:
造成上面结果混乱的原因为,字符从GBK到UTF8转码时,数据库先对字符进行了转码操作,然后根据fixed格式定义的字段长度进行截取,由于中文字符由GBK转为UTF8后字段长度增加,导致取值错乱。针对这种情况,8.0.0.3补丁对此进行了优化,对于GDS导入fixed格式文件的场景,当外表设置了conflict_delimiter参数(该参数一般要配合compatible_illegal_chars参数使用)时,内核先不对数据进行转码,而是根据fixed的position参数先识别出每一个字段后再对每一个字段进行GBK->UTF8转码。
根据上述说明,在外表定义中增加参数compatible_illegal_chars 'true',conflict_delimiter 'true',然后将该数据文件导入UTF8编码的数据库中,数据显示正常,如下图:由于中文字段c5、c11、c13转码后长度增加,因此在外表定义中需要将这3个字段的数据类型从varchar2(n)改为varchar2或者text,这样可以保证中文字符转码后能够正常存储。
在GaussDB(DWS) 8.1.3的版本中,该功能已经得到了进一步增强,外表定义中无需再设置参数conflict_delimiter,直接将中文字段类型改为varchar2或者text,数据导入UTF8编码的数据库后,即可正常显示,如下图:
- 点赞
- 收藏
- 关注作者
评论(0)