• 理解CCSID,LANGID对系统内码的影响(转)


    论坛里一直有朋友困惑于总是出现系统内一些程序乱码等问题,这些都是由于代码页转换问题.

    我这里有篇文章就是详细介绍这个的,作者是IBM的陈兵. <iseries技术指南>;这本书的附录里面也有该部分,有书的朋友可以拿书看看.

    希望对大家有用

    ===============================================


    值得注意的是,在这里我们使用了“简体中文”这四个字,是为了对应在iSeries上、语言编码为2989的Simplified Chinese,也就是为了对应那些与简体中文相关的编码标准。它决不意味着我们系统仅仅支持简体字。

    我们知道,当一个作业被启动的时候,系统会为它确定各项属性的取值,其中包括:

            作业的语言代码
            作业的CCSID
            作业的缺省CCSID

    通常,前两项属性都会去参照与该作业相关的用户简要表(User Profile),而用户简要表中的上述参数又往往会进一步去参照系统值。对于作业的缺省CCSID,系统则会依据下面的条件判断加以确定:

            当作业的CCSID不为65535时,作业的缺省CCSID即等于作业的CCSID;
            当作业的CCSID为65535时,作业的缺省CCSID会依据作业的语言代码来确定;

    由上一节我们可以知道,当我们选择DBCS大小写英文(编号为2984)作为系统的主语言时,系统值中的语言代码会被设定为美国英语ENU。用户登录所产生的作业,其各项属性会以美国英语为基础,特别是会将37作为作业的缺省CCSID。而当我们选择简体中文(编号为2989)作为系统的主语言时,系统值中的语言代码会被设定为简体中文CHS。用户登录所产生的作业,其各项属性会以简体中文为基础,特别是会将935或1388作为作业的缺省CCSID。

    了解作业的缺省CCSID很重要,因为当作业要创建任何具有CCSID属性的对象的时候,系统会参照当前作业的缺省CCSID,为该对象赋予相应的CCSID取值。

    目前在大陆的iSeries用户,由于其用户简要表中的设置不同,其登录所产生的作业,针对上述三项属性的取值也会有所不同。稍加留意便可发现,以下五种情况最为常见:

    用户实例        用户简要表中的语言代码        用户简要表中的CCSID        作业的语言
    代码        作业的CCSID        作业的缺省CCSID
    USER01        ENU        37        ENU        37        37
    USER02        CHS        935        CHS        935        935
    USER03        CHS        1388        CHS        1388        1388
    USER11        ENU        65535        ENU        65535        37
    USER12        CHS        65535        CHS        65535        935

    考察以用户USER01,或用户USER11登录系统所产生的作业,它们都将以37作为作业的缺省CCSID。由于37是一种单字节的CCSID,因此以37作为缺省CCSID的作业是无法完全正确地处理双字节字符的。比如,用户在利用如下的DDS源文件编译物理文件的时候,

    0 ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
         A* CUSTOMER INFORMATION TABLE                                               
         A                                                                           
         A          R CUSTOMER                  TEXT('CUST INFO')                    
         A            CUSTID        12A         TEXT('CUSTOMER ID')                  
         A            CUSTNAME      10O         TEXT('CUSTOMER NAME')               
         A            ADDRESS       10O         TEXT('CUSTOMER ADDRESS')            

    或者在利用STRSQL运行如下的建表语句的时候,

    CREATE TABLE CRMINFO/CUSTOMER
    (
      CUSTID   CHAR (12 ) FOR SBCS  DATA NOT NULL,
    CUSTNAME CHAR (10 ) FOR MIXED DATA NOT NULL,
    ADDRESS  CHAR (10 ) FOR MIXED DATA NOT NULL  
    );                                                            

    都会生成一个以937作为CCSID的对象。其中,单字节字段CUSTID的CCSID为37,双字节字段CUSTNAME和ADDRESS的CCSID皆为937。在一个以37为缺省CCSID的作业环境中,系统为什么会以937作为这些物理文件或数据库表当中的双字节字段的CCSID呢?原因很简单,对于物理文件或数据库表中的那些双字节字段,以37作为缺省CCSID的作业无法确定它们应该属于日文、韩文、简体中文、抑或繁体中文,也就无法为这些字段标上正确的CCSID。在这种情况下,系统会给这些双字节字段都标上937,权当作为它们的CCSID,进而937也成为了这些物理文件或数据库表的CCSID。糟糕的是,937是繁体中文的主机代码页。这样一来,一旦这些物理文件被用来存放简体中文字符,那么,含有简体中文字符的字段在文件传输当中往往就会出现乱码。

    正确的方法应是在系统安装完毕后,将相关的系统值设置成针对简体中文的取值,特别是将系统值QLANGID设置成CHS,将系统值QCCSID设置成935或1388。这样就可使作业的CCSID和作业的缺省CCSID都变为935或1388。由于935和1388都是针对简体中文的混合字节CCSID,在一个以935或1388作为缺省CCSID的作业环境中,当我们编译那些含有双字节字段的物理文件的时候,或是当我们创建那些含有双字节字段的数据库表的时候,系统就会生成一个以935或1388作为CCSID的对象,并给那些双字节字段都标上正确的CCSID。在上面的例子中,单字节字段CUSTID的CCSID应为836或13124,双字节字段CUSTNAME和ADDRESS的CCSID应为935或1388。

    至此,你也许还会问,935和1388之间又有什么差异呢?问得好。

    虽然935和1388都是针对简体中文的混合字节CCSID,但是它们在字汇方面,935的双字节代码页837代表着GB2312标准中的双字节字符部分,俗称“GB码”;而1388的双字节代码页4933则代表着GB18030标准中的双字节字符部分,俗称“GBK码”。我们知道,GB2312是汉字编码的基本集,共收录近七千个常用汉字。然而,随着计算机应用的普及,人们越来越多地会遇到需要输入或显示繁体字和某些冷僻汉字的情况。就拿客户的姓名来说,遇上在GB2312标准中找不到的汉字是常有的事。为了包容这样的汉字,使之在显示和传输过程中不出现差错,我们就应该使用1388作为那些用于存放中文字符的物理文件、数据库表及其字段的CCSID。

    935和1388都是在iSeries端、基于EBCDIC编码体系的代码页。在PC端,与935和1388分别对应的是1381和1386。它们是基于ASCII编码体系的代码页。同样的,在字汇方面,1381的双字节代码页1380代表着“GB码”;而1386的双字节代码页1385则代表着“GBK码”。

    关于GBK码,也就是GB18030的双字节字符部分,下表针对着1386编码和1388编码分别给出了其详细的编码分布:

    类别        简称        1386编码        1388编码        码位数        字符数        备注
    符号
    标准
    区        双字节1区        A1A1-A9FE                846        718        符号(GB2312)
            双字节5区        A840-A9A0                192        166        符号
            小计                1038        883       

    汉字
    区        双字节2区        B0A1-F7FE        48A0-6C9F        6768        6763        汉字(GB2312)
            双字节3区        8140-A0FE        8141-A181        6080        6080        汉字
            双字节4区        AA40-FEA0        A182-CEA6        8160        8160        汉字
            小计                21008        21003       
    用户
    自定
    义区        双字节用户1区        AAA1-AFFE        7641-78FD        564               
            双字节用户2区        F8A1-FEFE        7941-7C9F        658               
            双字节用户3区        A140-A7A0        7C80-804E        672               
            小计                1894               
    总计        23940                21886       

    很明显,想要使物理文件或数据库表在显示和传输过程中能够正确处理简体中文字符,其文件以及字段的CCSID,往往起着最为关键的作用。除了935和1388以外,现在越来越多的应用,选择使用UCS-2,也就是13488,作为文件及其双字节字段的CCSID。这被证明是明智的选择,它将使在iSeries上的软件国际化更趋便捷。比如,SAP R/3系统在iSeries上的双字节版本,就是采用了UCS-2,其上万张数据库表的CCSID都是13488,其间的简体中文字符皆以UCS-2编码存放。

    我们可以利用如下的DDS源文件编译含有UCS-2字段的物理文件:

    0 ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
         A* CUSTOMER INFORMATION TABLE                                               
         A                                                                           
         A          R CUSTOMER                  TEXT('CUST INFO')                    
         A            CUSTID        12G         CCSID(13488)                         
         A            CUSTNAME      10G         CCSID(13488)                        
         A            ADDRESS       10G         CCSID(13488)                       

    或是利用STRSQL运行如下的建表语句创建含有UCS-2字段的数据库表:

    CREATE TABLE CRMINFO/CUSTOMER
    (
      CUSTID   GRAPHIC (12 ) CCSID 13488  NOT NULL,
    CUSTNAME GRAPHIC (10 ) CCSID 13488  NOT NULL,
    ADDRESS  GRAPHIC (10 ) CCSID 13488  NOT NULL  
    );                                                              

    它们都将生成一个以13488作为CCSID的对象,其中的每个字段都被标上CCSID13488。

    在i5/OS,也就是OS/400 V5R3当中,又增加了对以UTF-8(代码页1208)和UTF-16(代码页1200)作为字段编码方式的支持。

    我们可以利用如下的DDS源文件分别编译含有UTF-8和UTF-16字段的物理文件:

    0 ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
         A* CUSTOMER INFORMATION TABLE                                               
         A                                                                           
         A          R CUSTOMER                  TEXT('CUST INFO')                    
         A            CUSTID        12A         CCSID(1208)                          
         A            CUSTNAME      20A         CCSID(1208)                          
         A            ADDRESS       20A         CCSID(1208)                          

    0 ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
         A* CUSTOMER INFORMATION TABLE                                               
         A                                                                           
         A          R CUSTOMER                  TEXT('CUST INFO')                    
         A            CUSTID        12G         CCSID(1200)                          
         A            CUSTNAME      10G         CCSID(1200)                          
         A            ADDRESS       10G         CCSID(1200)                          

    或是利用STRSQL运行如下的建表语句分别创建含有UTF-8和UTF-16字段的数据库表:

    CREATE TABLE CRMINFO/CUSTOMER
    (
      CUSTID   CHAR (12 ) CCSID 1208  NOT NULL,
    CUSTNAME CHAR (20 ) CCSID 1208  NOT NULL,
    ADDRESS  CHAR (20 ) CCSID 1208  NOT NULL  
    );                                                         

    CREATE TABLE CRMINFO/CUSTOMER
    (
    CUSTID   GRAPHIC (12 ) CCSID 1200 NOT NULL,
    CUSTNAME GRAPHIC (10 ) CCSID 1200 NOT NULL,
    ADDRESS  GRAPHIC (10 ) CCSID 1200 NOT NULL  
    );                                                         

    它们将分别生成一个以1208或1200作为CCSID的对象,其中的每个字段都被标上相应的CCSID。

    在这里,我们为了简单,所以对文件中的所有双字节字段都采用了同一种编码方式。其实,在一个文件中,字段与字段的编码方式完全可以互不相同。在这种情况下,文件本身的CCSID将变得不再重要。

    要了解文件及其字段的CCSID信息,可以通过键入DSPFD和DSPFFD命令获得。另一方面,要了解文件的编码内容,则可以通过键入DSPPFM命令并按F10获得。

    CCSID作为文件和字段的标签,如果它和实际存放的编码内容不相一致,那么这个文件就将被视作不符合规范的文件。具体地,当我们见到针对简体中文的文件或字段出现37或937这样的CCSID,即表明这是不符合规范的文件,这样的文件在传输过程中极有可能产生乱码。解决的办法,应该首先考虑创建符合规范的文件,也就是文件及其字段应具有针对简体中文的CCSID,如935、1388、13488、1200、1208等等。

    然而在实践中,很有可能用户的数据库已经建立,不符合规范的文件很多,其中可能含有很多数据,其上还可能建有若干逻辑文件或数据库索引和视图。遇到这样的情况,就需要加以分析,结合多种因素,寻求最适合最有效最经济的解决方案。一般而言,通过CHGPF命令可以为多数的物理文件和数据库表标上正确的CCSID,而通过ALTER TABLE语句更可以进一步为多数的字段标上正确的CCSID。

    至此,我们可以为目前在大陆的iSeries用户罗列几种其经常遇到的文件与字段的CCSID。同样,稍加留意便可发现,我们最有可能遇到的是以下九种情况:

    文件实例        文件与字段的CCSID        字段类型        是否适合存放简体中文字符
    FILE00        37        CHAR        不适合,因为37是单字节CCSID
    FILE01        836        CHAR        不适合,因为836是单字节CCSID
    FILE02        65535        CHAR        一般不适合,但要视情况而定
    FILE10        935        CHAR        适合,但不适合存放繁体字或冷僻汉字
    FILE11        937        CHAR        不适合,因为937针对的是繁体中文
    FILE12        1388        CHAR        适合
    FILE20        13488        GRAPHIC        适合
    FILE21        1200        GRAPHIC        适合
    FILE22        1208        CHAR        适合
  • 相关阅读:
    Oracle Linux 6.1 说明
    Oracle Golden Gate 系列 小结
    Oracle 执行计划 提示 'PLAN_TABLE' is old version 解决方法
    Oracle 聚合函数(Aggregate Functions)说明
    Oracle 11g 行列互换 pivot 和 unpivot 说明
    Oracle 聚合函数(Aggregate Functions)说明
    MySQL 数据文件 说明
    MySQL 启动故障 处理 小记
    Oracle Validated Configurations 安装使用 说明
    Oracle DBMS_STATS 包 和 Analyze 命令的区别
  • 原文地址:https://www.cnblogs.com/13590/p/1459227.html
Copyright © 2020-2023  润新知