分享

理解 DB2 Universal Database 的字符转换

 jollyme 2005-09-21



2005 年 6 月 27 日

学习 DB2 Universal Database(DB2 UDB)如何处理字符转换。本文首先将讨论字符代码的基本概念,包括代码页、代码点和编码模式,接着将更为详细地解释如何设置代码页以及如何发生字符转换。为了易于理解,本文还展示了一些通用的场景和示例。

简介
在当今世界中,许多数据库应用程序都在多个平台上使用多个数据库组件。数据库应用程序可以在 Windows 系统上运行,但却通过 AIX 上所运行的 DB2 Connect 服务器与 DB2 UDB for z/OS 数据库进行交互。在这些不同服务器之间流动的信息可能经历多次字符转换,而且大多数情况下,这些转换对用户是透明的。

然而,偶尔也需要进行一些配置。在这些情况中,理解这些转换如何工作以及哪个组件处理它们就十分有用。例如,请考虑以下情况:

  • “我在 SPUFI 中 DB2 UDB for OS/390 表的一列里存储了感叹号(!)。当我从 DB2 UDB for Linux,UNIX and Windows 命令行处理器(CLP)检索同一列时,感叹号就转换成为一个方括号(])。”
  • “我的 DB2 UDB for Linux,UNIX and Windows 数据库中有西班牙语(Spanish)信息。Java 应用程序检索这些西班牙语数据(重音符号),但它们都遭到了损坏,即使我可以用 CLP 看到正确内容。”

这些例子都是来自于 DB2 UDB 客户的疑问和问题。本文通过描述 DB2 UDB 字符转换过程,解决了所有这些以及类似的问题。

本文重点关注下列产品和版本:DB2 UDB for Linux, UNIX, and Windows version 8.2、DB2 UDB for iSeries 5.3 和 DB2 UDB for z/OS version 8。本文可能也适用于这些产品的早期版本。

术语
为了理解字符转换过程如何工作,您需要理解一些关键概念。图 1、2 和 3 提供了其中一些概念的概述。

图 1. 字符转换的关键概念 —— ASCII 编码模式
字符转换的关键概念 —— ASCII 编码模式

图 2. 字符转换的关键概念 —— EBCDIC 编码模式
字符转换的关键概念 —— EBCDIC 编码模式

图 3. 字符转换的关键概念 —— Unicode 编码模式
字符转换的关键概念 —— Unicode 编码模式

在这些图中,每个页码中的实线阴影边框表示的是十六进制数。

代码页(code page)可以定义为字母数字代码及其二进制表示的映射表。图 1 展示了几个用于不同语言和平台的代码页。在本图中,对于代码页 1252,字母“K”可以用二进制数“01001011”(或十六进制表示法:“4B”)表示。而在另一代码页中,则可能用不同的二进制表示来表示这同一字符。

代码点(code point)是字符在代码页中的位置。在图 1 中,代码页 1252 中的代码点“4B”对应字符“K”。

字符集(character set)是一个定义的字符集。例如,一个字符集可以由大写字母 A 到 Z、小写字母 a 到 z 以及数字 0 到 9 组成。该字符集可以在多个代码页中重复。例如,在图 1图 2 中,不同代码页中带点背景的单元格都表示同一字符集。

代码页可以分成下列几类:

  • 单字节代码页(有时称作单字节字符集或 SBCS)是一个最多可以容纳 256 (28) 个代码点的代码页。SBCS 中代码点的实际数目可能要少一些。例如,对于地域标识符 US 和代码集 ISO 8859-1,AIX 上的地区 en_US 就是 SBCS 代码页 819。
  • 双字节代码页(有时称作双字节字符集或 DBCS)是一个最多可以容纳 65536 (216) 个代码点的代码页。DBCS 中代码点的实际数目可能要少一些。例如,对于地域标识符 JP 和代码集 IBM-932,AIX 上的地区 Ja_JP 就是 DBCS 代码页 932。
  • 复合或混合代码页包含不止一个代码页。例如,Extended UNIX Code(EUC)代码页可以包含多达四个不同的代码页,其中第一个代码页总是单字节的。例如,用于日语的 IBM-eucJP(代码页 954)根据 EUC 编码规则引用日本工业标准(Japanese Industrial Standard)字符的编码。

在大型机(z/OS, OS/390)和 iSeries(i5/OS、OS/400)领域中,使用术语编码字符集标识符(Coded Character Set Identifier,CCSID)来代替代码页。CCSID 是一个 16 位的无符号整数,惟一地标识一个特定的代码页。例如,在大型机上,US-English 代码页由 CCSID 37 表示。German 代码页是 CCSID 273。其中一些代码页包含了其语言中特定字符的代码点;一些代码页具有相同的字符,但由不同 CCSID 中的不同代码点来表示。CCSID 是基于字符数据表示架构(Character Data Representation Architecture,CDRA)的,这是一个 IBM 架构,其中定义了一组标识符、资源、服务和约定以在异构环境中取得图形字符数据的一致表示、处理和交换。OS/400 完全支持 CDRA。OS/390 支持 CDRA 的部分元素。

编码模式(encoding scheme)是为在特定计算平台上所使用的不同语言提供的代码页集合。常见的编码模式有:

  • American Standard Code for Information Interchange(ASCII),用于基于 Intel 的平台(如 Windows)和基于 UNIX 的平台,如 AIX。图 1 展示了 ASCII 编码模式的简化表示。
  • Extended Binary Coded Decimal Information Code(EBCDIC),这是由 IBM 设计的编码模式。它通常用于 z/OS 和 iSeries 上。图 2 展示了 EBCDIC 编码模式的简化表示。
  • Unicode 字符编码标准是固定长度的字符,它为世界上的每一个字符都提供了一个惟一的代码点,无论平台、程序或语言如何。它包含近 100,000 个字符,并且还在增加。Unicode 标准已经为很多行业巨头所采用,如 IBM、Microsoft 以及其他许多公司。诸如 XML、Java、LDAP、CORBA 3.0 等现代标准都要求使用 Unicode,它还是实现 ISO/IEC 10646 的官方方式。图 3 展示了 Unicode 编码模式的简化表示。

DB2 UDB 字符转换过程
通过前面的讨论,应该已经清楚“代码页”的概念对于理解字符转换至关重要。可以在不同级别上定义代码页:

  • 在应用程序所运行的操作系统上
  • 在应用程序级别上,根据编程语言使用特定语句
  • 在数据库所运行的操作系统上
  • 在数据库级别上

在应用程序所运行的操作系统上定义代码页
在 Windows 上,代码页派生于 Windows 注册表中的 ANSI 代码页设置。您可以从 Regional Settings 控制面板查看您的设置。图 4 展示了一台 Windows XP 机器上的区域设置。

图 4. Windows XP 机器上的区域设置
图 4. Windows XP 机器上的区域设置

在基于 UNIX 的环境中,代码页派生于地区(locale)设置。命令 locale 可以用于确定该值,如图 5 中所示。命令 localedef 可以编译新的 locale 文件,而 /etc/environment 中的 LANG 变量可以用新的 locale 进行更新。

图 5. UNIX 机器上使用 locale 的区域设置
图 5. UNIX 机器上使用 locale 的区域设置

对于 iSeries 和 z/OS,请与您的系统管理员联系。

在应用程序级别上定义代码页
本文没有详细讨论应用程序代码页的设置,因为重点主要是在数据库方面。然而,本文提到了一些可能十分有用的概念。

默认情况下,应用程序代码页派生于它所运行的操作系统。对于嵌入式 SQL 程序而言,应用程序代码页在预编译/绑定时以及执行时确定。在预编译和绑定时,代码页派生于用于预编译语句和 SQLCA 中返回的所有字符数据的数据库连接。在执行时,当建立数据库连接时,确定用户应用程序代码页,而且它只在连接期间有效。所有数据,包括动态 SQL 语句、用户输入数据、用户输出数据以及 SQLCA 中的字符字段,都是基于该代码页进行解释的。因此,如果程序包含常量字符串,您就应该使用相同的代码页预编译、绑定、编译和执行该应用程序。

对于 Unicode 数据库,您应使用主机变量来代替字符串常量。该建议的理由就是服务器可能在绑定和执行阶段都进行数据转换;如果程序中使用了常量字符串,这可能是一个忧虑。在绑定时,将基于在绑定期间有效的代码页转换这些嵌入的字符串。7 位 ASCII 字符通用于 DB2 Universal Databas 所支持的所有代码页,并且不会产生问题。对于非 ASCII 字符,用户应该确保具有相同活动代码页的绑定和执行使用相同的转换表。

对于 ODBC 或 CLI 应用程序,您或许可以在 odbc.ini 文件或 db2cli.ini 文件中使用不同的关键字来调整应用程序代码页。例如,Windows ODBC 应用程序可以使用关键字 TRANSLATEDLL 来表示 DB2TRANS.DLL 的位置,该文件包含代码页映射表,以及使用关键字 TRANSLATEOPTION 来定义数据库的代码页数目。DISABLEUNICODE 关键字可以用于显式地启用或禁用 Unicode。默认情况下,没有设置该关键字,这意味着如果目标数据库支持 Unicode,DB2 CLI 应用程序就将使用 Unicode 进行连接。否则,DB2 CLI 应用程序将使用应用程序代码页进行连接。当您显式地设置 DISABLEUNICODE=0 时,DB2 CLI 应用程序将总是用 Unicode 进行连接,无论目标数据库是否支持 Unicode。当 DISABLEUNICODE=1 时,DB2 CLI 应用程序则总是用应用程序代码页进行连接,无论目标数据库是否支持 Unicode。

使用 Java Universal Type 4 驱动程序的 Java 应用程序不需要在客户端机器上安装 DB2 UDB 客户机。通用 JDBC 驱动程序客户端将数据作为 Unicode 发送给数据库服务器,而数据库服务器则将数据从 Unicode 转换成所支持的代码页。从数据库服务器发送给客户端的字符数据是使用诸如 sun.io.* 转换例程的 Java 的内置字符转换器(converter)进行转换的。DB2 Universal JDBC Driver 支持的转换限于底层 Java Runtime Environment(JRE)实现所支持的那些。对于 CLI 和遗留(legacy)JDBC 驱动程序,要使用代码页转换表。

z/OS 上运行的应用程序使用 DB2 UDB for z/OS 安装面板上指定的应用程序编码 CCSID 值。此外,应用程序编码绑定(bind)选项也可以为程序中的主机变量定义 CCSID。对于动态 SQL 应用程序而言,就要使用 APPLICATION ENCODING 专用寄存器来覆盖 CCSID。还可以通过在 DECLARE VARIABLE 语句中使用 CCSID 子句,在更细粒度的级别上指定 CCSID。(例如:EXEC SQL DECLARE :TEST VARIABLE CCSID UNICODE;)

在数据库所运行的操作系统上定义代码页
本小节的讨论与上面的阐述完全相同。

在数据库级别上定义代码页
根据 DB2 UDB 平台,按不同方式定义代码页。

在 DB2 UDB for Linux, UNIX, and Windows 上
数据库可以只有一个代码页,它是在您通过 CREATE DATABASE 命令首次创建数据库时使用 CODESETTERRORITY 子句设置的。例如,下列命令创建了数据库“spaindb”,使用代码集 1252 和地域 ID 34,这确定了 Windows 平台上用于西班牙语的代码页。(关于不同国家的代码集和地域 ID 列表,请查阅 支持的地域代码和代码页。)

CREATE DATABASE spaindb USING CODESET 1252 TERRITORY es

创建数据库之后,您就可以通过发出图 6 中所示的命令 get db cfg for spaindb 查看该代码页的设置。

图 6. 查看 DB2 UDB for Linux, UNIX, and Windows 数据库的代码页
图 6. 查看 DB2 UDB for Linux, UNIX, and Windows 数据库的代码页

表 1 提供了图 6 中每个字段的描述。

表 1. 代码页数据库配置参数描述

字段名称 描述
Database territory 确定一个国家的地域标识符。
Database code page 指定用于创建该数据库的代码页。
Database country/region code 指定用于创建该数据库的地域代码。
Database collating sequence 指定用于进行字符数据排序的方法。
Alternate collating sequence 指定在非 Unicode 数据库中用于 Unicode 表的排序序列。在设置该参数以前,都无法在非 Unicode 数据库中创建 Unicode 表和例程。

排序序列将在小节其他注意事项中进行更详细的讨论。如果您使用默认值创建数据库,那么所使用的代码页就来自于操作系统的信息。一旦用给定的代码页创建了数据库,您就无法修改它,除非导出数据、删除数据库后,再用正确的代码页重新创建该数据库并导入数据。

在 DB2 UDB for iSeries 上
在 DB2 UDB for iSeries 上,数据库中的每个物理文件或表都可以指定一个代码页。因此,一个 iSeries 数据库可以容纳多个代码页,甚至是 ASCII 代码页,这取决于指定的代码页。

为了指定用于物理文件或表的代码页,要使用下面两种方法之一:

  • 创建一个物理文件,并使用 CCSID 子句。例如,下列命令使用 Data Description Source(DDS)通过 CCSID 62251 创建一个单成员(one-member)文件,并将其置于名为 DSTPRODLB 的库中。
    
    CRTPF FILE(DSTPRODLB/ORDHDRP)
      TEXT(‘Order header physical file‘)
      CCSID(62251)
    

    这假定 DDS 源存在,并已经正确定义。请注意,CCSID 值仅仅对于源物理文件 FILETYPE(*SRC) 有效。iSeries 表存储在数据物理文件 FILETYPE(*DATA) 中,因此,您必须按那样使用 DDS,并指定 CCSID。

  • 使用带有 CCSID 子句的 CREATE TABLE SQL 语句。例如,下列 SQL 语句创建了表 DEPARTMENT(并对两列指定了 CCSID 37):
    
    CREATE TABLE DEPARTMENT
     (DEPTNO    CHAR(3)     CCSID 37 NOT NULL,
      DEPTNAME  VARCHAR(36) CCSID 37 NOT NULL,
      PRENDATE  DATE 	    DEFAULT  NULL)
    

为了在作业级查看代码页的当前值,您可以从 OS/400 命令行键入下列命令:DSPJOB OPTION(*DFNA)

如果您向下滚动到第三页,就可以看到代码页设置,例如:
Language identifier . . . . . . . . . . . . . . . : ENU
Country or region identifier . . . . . . . . . . : CA
Coded character set identifier . . . . . . . . . : 37
Default coded character set identifier . . . . . : 37

如果未指定 CCSID,所使用的代码页就是下列三层之一所指定的:

  • 分布式数据库管理(Distributed Data Management,DDM)
  • 作业(即在 OS 级)
  • 用户配置文件(即在系统级)

客户机将在 DDM 请求(DDM 层)中发送其代码页。在 OS400 级上,CCSID 是按下列优先级确定的:

  1. 使用字段定义中的 CCSID。
  2. 如果字段定义中没有 CCISD,就使用文件级的 CCSID。
  3. 如果未指定文件级的 CCSID,就使用当前作业的 CCSID。

作业的 CCSID 是按下列方式确定的:

  1. 检查用户配置文件,并从中获得 CCSID。
  2. 如果用户配置文件未指定 CCSID,就通过系统值 QCCSID 确定该值。

在 DB2 UDB for z/OS 上
在 DB2 UDB for z/OS 上,CCSID(代码页)需要当安装 DB2 UDB for z/OS 子系统时在面板 DSNTIPF 上指定。如图 7 中所示。

图 7. 应用程序编程默认值面板:DSNTIPF

DSNTIPF         INSTALL DB2 - APPLICATION PROGRAMMING DEFAULTS PANEL 1
 ===> _
 Enter data below:

  1  LANGUAGE DEFAULT     ===> IBMCOB   ASM,C,CPP,IBMCOB,FORTRAN,PLI
  2  DECIMAL POINT IS     ===> .      . or ,
  3  STRING DELIMITER     ===> DEFAULT  DEFAULT, " or ‘ (COBOL or COB2 only)
  4  SQL STRING DELIMITER ===> DEFAULT  DEFAULT, " or ‘
  5  DIST SQL STR DELIMTR ===> ‘        ‘ or "
  6  MIXED DATA           ===> NO       NO or YES for mixed DBCS data
  7  EBCDIC CCSID         ===>          CCSID of SBCS or mixed data. 1-65533.
  8  ASCII CCSID          ===>          CCSID of SBCS or mixed data. 1-65533.
  9  UNICODE CCSID        ===> 1208     CCSID of UNICODE UTF-8 data.
 10  DEF ENCODING SCHEME  ===> EBCDIC   EBCDIC, ASCII, or UNICODE
 11  APPLICATION ENCODING ===> EBCDIC   EBCDIC, ASCII, UNICODE, cssid (1-65533)
 12  LOCALE LC_CTYPE      ===> 

PRESS:   ENTER to continue   RETURN to exit   HELP for more information

表 2 提供了图 7 中每个相关字段的描述。

表 2. 代码页参数描述

字段名称 描述
MIXED DATA 指定 EBCDIC CCSID 和 ASCII CCSID 字段是否包含混合型数据。
EBCDIC CCSID 指定 EBCDIC 编码数据的默认 CCSID。
ASCII CCSID 指定 ASCII 编码字符数据的默认 CCSID。
UNICODE CCSID 指定 Unicode 的默认 CCSID。DB2 UDB for z/OS 当前仅仅支持 CCSID 1208 用于 Unicode。
DEF ENCODING SCHEME 指定在 DB2 中存储数据的默认格式。
APPLICATION ENCODING 指定影响 DB2 UDB for z/OS 如何解释进入 DB2 的数据的系统默认应用程序编码模式。
LOCALE LC_CTYPE 指定系统 LOCALE_LC_CTYPE。地区(locale)是系统环境中的一部分,取决于语言和文化习俗。LC_TYPE 是应用于字符函数的地区(locale)子集。例如,在美国指定 En_US 用于英语,或在加拿大指定 Fr_CA 用于法语。

如果语言仅仅使用单字节的 CCSID,那么 CCSID 中的混合型和双字节 CCSID 就默认设置为预留的 CCSID 65534。由于诸如中文和日语等一些语言字符的复杂性和繁多,这些字符集就使用双字节和混合型字符集。所有单字节和混合型 CCSID 都存储在 DB2 UDB for z/OS 子系统参数作业中称作 DSNHDECP 的宏中。此外,DB2 UDB for z/OS 目录表 SYSIBM.SYSSTRINGS 必须为所有必要的代码页转换指出转换表。

DB2 UDB for z/OS 使用 ASCII CCSID 值来执行从 ASCII 外部源(包括其他数据库)收到的字符数据的转换。您必须为 ASCII CCSID 字段指定一个值,即使您不必或不打算创建 ASCII 编码的对象。

为了在表中存储 ASCII 格式的数据,您可以在表、表空间或数据库级上使用带有 CCSID ASCII 子句的 CREATE 语句。例如,在表级别上,按下列方式使用 CREATE TABLE 语句:
CREATE TABLE T1 (C1 int CCSID ASCII, C2 char(10) CCSID ASCII)

来自于上面 CREATE TABLE 语句的 CCSID ASCII 值是从面板 DSNTIPF 中获得的。

下列语句使用面板 DSNTIPF 中指定的默认编码模式:

  • CREATE DATABASE
  • CREATE DISTINCT TYPE
  • CREATE FUNCTION
  • CREATE GLOBAL TEMPORARY TABLE
  • DECLARE GLOBAL TEMPORARY TABLE
  • CREATE TABLESPACE(在 DSNDB04 数据库中)

如果 DSNTIPF 面板字段中的 CCSID 值不正确,字符转换也将产生不正确的结果。正确的 CCSID 指定您站点的 I/O 设备、诸如 IMS 和 QMF 等本地应用程序以及诸如 CICS Transaction Server 等远程应用程序所支持的编码字符集。

若没有 IBM DB2 UDB Technical Support 的特定指导,永远不要修改现有 DB2 UDB for z/OS 系统的 CCSID;否则,您可能损坏数据!

字符转换场景
前面的小节展示了在不同的平台中如何可以为应用程序或数据库确定和修改代码页值。本小节将通过两个通用场景描述字符转换过程。(它假定已经为应用程序和数据库确定了代码页值)。转换过程的基本规则就是接收系统将总是执行代码页的转换。

场景 1:客户机到 DB2 UDB 服务器的转换
图 8 中所展示的通用场景代表了下列情形:

  • Linux, UNIX, or Windows 客户机上运行的应用程序到 DB2 UDB for Linux, UNIX, and Windows 服务器
  • iSeries 客户机上运行的应用程序到 DB2 UDB for Linux, UNIX, and Windows 服务器
  • iSeries 客户机上运行的应用程序到 DB2 UDB for iSeries 服务器
  • iSeries 客户机上运行的应用程序到 DB2 UDB for z/OS 服务器
  • z/OS 客户机上运行的应用程序到 DB2 UDB for Linux, UNIX, and Windows 服务器
  • z/OS 客户机上运行的应用程序到 DB2 UDB for iSeries 服务器
  • z/OS 客户机上运行的应用程序到 DB2 UDB for z/OS 服务器

图 8. 客户机到 DB2 UDB 服务器的转换
图 8. 客户机到 DB2 UDB 服务器的转换

场景 2:客户机到 DB2 Connect Gateway 到 DB2 UDB 服务器的转换
图 9 中所展示的通用场景代表了下列情形:

  • Linux, UNIX, or Windows 客户机上运行的应用程序到 DB2 UDB for iSeries
  • Linux, UNIX, or Windows 客户机上运行的应用程序到 DB2 UDB for z/OS

图 9. 客户机到 DB2 Connect Gateway 到 DB2 UDB 服务器的转换
图 9. 客户机到 DB2 Connect Gateway 到 DB2 UDB 服务器的转换

在图 8 和 图9 中,当应用程序所运行的操作系统是 Linux、UNIX 或 Windows 时,就可能需要安装 DB2 UDB for Linux, UNIX, and Windows 客户机。如果应用程序是在 Java 中使用 JDBC Type 4 驱动程序编写的,就不需要 DB2 UDB for Linux, UNIX, and Windows 客户机。

在这两个通用场景中,如果用于所有系统的代码页相同,就不会发生代码页转换。当您处理访问 DB2 UDB for iSeries 或 z/OS 数据(使用 EBCDIC 编码模式)的 Linux、UNIX 或 Windows 应用程序(使用 ASCII 编码模式)时,这就不可能,除非所有这些系统都使用 Unicode。

字符转换示例
下列例子说明了字符转换的过程。让我们假定您具有下列配置:

  • 一个 ODBC 应用程序运行在 Windows 机器上,默认情况下,该应用程序使用操作系统的代码页,本例子中就是 1252(Windows,English)。
  • 将运行 DB2 Connect 的 AIX 服务器设置为使用 Unicode。
  • iSeries 服务器使用代码页 66535,并具有一个包含表 DEPARTMENT 的数据库,表 DEPARTMENT 的定义如下:
    
    CREATE TABLE DEPARTMENT
      (DEPTNO    CHAR(3)              NOT NULL,
       DEPTNAME  VARCHAR(36) CCSID 37 NOT NULL,
       PRENDATE DATE                  DEFAULT NULL)
    

列 DEPTNO 和 PRENDATE 将使用 iSeries 代码页 66535 作为默认值。

当 Windows 应用程序发出诸如下面的请求时:
SELECT DEPTNO FROM DEPARTMENT

将发生下列转换:

  1. Windows 通过代码页 1252 向 DB2 Connect 服务器发送请求。
  2. DB2 Connect 服务器将之转换成代码页 1208(Unicode),然后发送给 iSeries 服务器。
  3. iSeries 服务器将之转换成 CCSID 66535,并访问 DEPARTMENT 表中的数据。
  4. 因为从表中获得的数据是在 CCSID 66535 中,所以将在该代码页中,将数据发送给请求者(本例中,DB2 Connect 服务器)。
  5. DB2 Connect 服务器将数据转换成代码页 1208,然后发送给 Windows 应用程序。
  6. Windows 操作系统将代码页 1208 转回到 1252。

其他注意事项

强制子集转换
在代码页转换期间,源代码页 X 中的字符也许不存在于目标代码页 Y 中。例如,让我们假定一家跨国公司存储了日语和德语这两种语言的信息。一个相应的日语应用程序将数据插入这个使用 German 代码页创建的 DB2 UDB 数据库中。在这样的情形中,许多字符在 DB2 所使用的 CCSID 中没有代码点。这种情形下,解决该问题的一种方法就是通过仅将源 CCSID 中的字符映射到目标 CCSID 中的相应字符。那些没有映射的字符将通过预留的代码点来代替。(每一个代码页至少预留了一个代码点,以便进行替代。)那些无法映射到目标代码页的字符将永远丢失。该方法称作强制子集转换。

往返转换
另一种转换方法称作往返转换。两个 CCSID 之间的往返转换确保所有进行“往返”的字符都以初始的样子到达,即使接收 CCSID 不支持某一给定字符。往返转换确保从 CCSID X 转换成 CCSID Y,并返回为 CCSID X 的代码点的过程得到保护,即使 CCSID Y 无法完全表示这些代码点。这是通过使用转换表实现的。

使用其他 DB2 UDB for Linux, UNIX, and Windows 转换代码页表
当您需要使用转换表的不同版本时,如 Microsoft 版本,就必须手工替换默认的转换表(.cnv)文件,该文件驻留在 UNIX 和 Linux 平台的 .../sqllib/conv 目录或 Windows 上的 ...\sqllib\conv 中。这些表是用于在不同代码页之间转换值的外部代码页转换表。在替换 sqllib/conv 目录中现有的代码页转换表之前,您应该备份该文件。

DB2 UDB Unicode 支持
在所有平台上,DB2 UDB 都支持 International Standards Organization(ISO)/International Electrotechnical Commission(IEC)标准 10646(ISO/IEC 标准 10646)Universal 2-Octect Coded Character Set(UCS-2)。UCS-2 是用 Unicode Transformation Format 8 位编码格式(UTF-8)实现的。UTF-8 是为了易于使用现有基于 ASCII 的系统而设计的。UTF-8 格式中数据的代码页/CCSID 值是 1208。用于 UCS-2 的 CCSID 值是 1200。UTF-8 被选择为字符数据列的默认格式,其中 UTF-16 用于图形数据列。

使用默认值创建的 DB2 UDB for Linux, UNIX, and Windows 数据库将在 ASCII 中创建表。为了创建 Unicode 数据库,要使用带有 CODESET 和 TERRITORY 子句的 CREATE DATABASE,如下:
CREATE DATABASE unidb USING CODESET UTF-8 TERRITORY US

这个 Unicode 数据库中的表都将默认为代码页 1208。您无法在 Unicode 数据库中用 ASCII 代码页定义表。然而,反过来则可以;即您可以在非 Unicode 的数据库中创建 Unicode 表。这可以通过调用使用了 CCSID UNICODE 子句的 CREATE TABLE 语句来执行。例如:
CREATE TABLE unitbl (col1 char(10), col3 int) CSSID UNICODE

为了使之工作,您首先需要激活数据库配置参数 alt_collate。一旦设置好了,该参数就无法进行修改或重新设置。
UPDATE DB CFG FOR nonunidb USING ALT_COLLATE IDENTITY_16BIT

在 DB2 UDB for iSeries 中,CCSID 子句可以用于单独的列上。例如,下列 SQL 语句创建表 U_TABLE。U_TABLE 包含一个名为 EMPNO 的字符列,以及两个 Unicode 图形列。NAME 是一个固定长度的 Unicode 图形列,而 DESCRIPTION 是一个可变长度的 Unicode 图形列。EMPNO 字段仅仅包含数字,且不需要 Unicode 支持。NAME 和 DESCRIPTION 字段则都是 Unicode 字段。这两个字段可能包含不止一个 EBCDIC 代码页中的数据。


CREATE TABLE U_TABLE (EMPNO CHAR(6) NOT NULL,
                      NAME GRAPHIC(30) CCSID 1200,
                      DESCRIPTION VARGRAPHIC(500) CCSID 1200)

关于 iSeries 中有效的 CCSID 值列表,请查阅 Supported CCSID mappings

与 DB2 UDB for Linux, UNIX, and Windows 相似,在 DB2 UDB for z/OS 中,如果您在对象定义上使用了 CCSID UNICODE 子句,就可以存储并检索 Unicode 数据,例如:


CREATE TABLE DBTBDWR.WBMTEBCD
    (CUSTNO  CHAR(8),
     CUSTBU  CHAR(6),
     CUSTEXT CHAR(3),
     CNAME   VARCHAR(80) FOR MIXED DATA)
  IN TEST.CUSTTS
  CCSID UNICODE

DB2 UDB for z/OS 使用 LE(语言环境)的 ICONV 执行字符转换,除非安装了 z/OS Unicode Conversion Services。为了了解如何设置用于 DB2 的 z/OS Unicode Conversion Services,请查看信息 APAR II13048 和 II13049。为了查看是否安装了转换,请通过控制台使用命令 /d uni, all,如图 10 中所示。

图 10. 查看 z/OS 上安装的字符转换
图 10. 查看 z/OS 上安装的字符转换

例如,图 10 展示了有从 1252 到 1208 以及 1208 到 1252(即从 Windows English 到 Unicode 以及反向进行)的转换。

在所有系统之间使用 Unicode 编码模式将避免进行字符转换,并提高性能。

排序序列
排序序列是字符集的一种次序,确定每个字符与另一字符相比排列更高、更低或相同。排序序列将代码点映射至每个字符在已排序序列中的期望位置。例如,ASCII 中的排序序列是:空格、数字值、大小字符、小写字符。另一方面,EBCDIC 中的排序序列则是:空格、小写字符、大写字符和数字值。

如果在 EBCDIC 数据库上使用设计于操作 ASCII 数据库的应用程序,就可能产生问题,因为其排序序列不同。您可以创建定制的排序序列。关于更多细节,请查阅 Application Development Guide: Programming Client Applications 手册(参见 参考资料)。

对于联邦系统的特殊注意事项
联邦系统不支持某些数据映射。例如,DB2 UDB 联邦服务器不支持数据类型 LONG VARCHAR 的映射。因此,所讨论的场景可能不起作用。关于更多细节,请查看 Federated Systems Guide(参见 参考资料)。

在不同的代码页中移动数据
您无法用给定的代码页备份数据库,并用不同的代码页将之恢复为另一种。在 DB2 UDB for Linux, UNIX, and Windows 上,您应使用 export 或 db2move 实用程序,用新要求的代码页创建新的数据库,并对数据进行 import 或反向 db2move。在使用该方法时,DB2 UDB 将正确地执行字符转换。

处理二进制数据
通过 BLOB 数据类型或使用 FOR BIT DATA 子句定义的列将以二进制形式从源传递到目标,所使用的代码页是零。这表示不会发生任何代码页转换。

字符转换问题的确定与问题来源的识别
当您碰到字符转换方面的问题时,首先要识别应用程序和所涉及的 DB2 UDB 数据库服务器使用哪些代码页。

识别 DB2 UDB 环境中的代码页
除了前面所讨论的用于确定操作系统或 DB2 UDB 数据库服务器的代码页值的方法之外,下列方法将向您展示目标和源中的代码页。本小节中的讨论适用于 DB2 UDB for Linux, UNIX, and Windows。

使用带有“-a”选项的 CLP 来显示 SQLCA 信息
当您使用 CLP 的“-a”选项来显示 SQLCA 信息时,将展示源应用程序(本例中,CLP)和目标数据库的代码页。图 11 展示了一个从 Windows 上 CLP 连接到 Windows 上数据库的例子。

图 11. 显示 SQLCA 信息以查看代码页值
图 11. 显示 SQLCA 信息以查看代码页值

在图 11 中,请注意下行:
sqlerrmc: 1 1252 ARFCHONG SAMPLE QDB2/NT 557 557 0 1252 1

第一个实例“1252”指明目标上所使用的代码页,即 Windows US-English。第二个实例指明源上所使用的代码页,同样也是 Windows US-English。

图 12 展示了另一例子,这次是从 Windows CLP(其中安装了 DB2 Connect)连接到 DB2 UDB for z/OS 目标数据库。

图 12. 显示 SQLCA 信息以查看代码页值 —— 另一例子
图 12. 显示 SQLCA 信息以查看代码页值 —— 另一例子

在图 12,请注意下行:
sqlerrmc: 1208 TS56692 HOSTV8 QDB2 1252

1208 指明目标 DB2 UDB for z/OS 子系统使用 Unicode。
1252 指明源 CLP 应用程序使用 Windows US-English。

为 CLI、ODBC 或 JDBC Type 2 应用程序使用 CLI 跟踪
为了标识 CLI 和 JDBC type 2 应用程序的代码页,您可以使用 DB2 CLI on Linux, UNIX, and Windows 所提供的跟踪工具。默认情况下,该跟踪工具是禁用的,并且不使用任何附加的计算资源。启用时,无论应用程序何时访问 CLI 驱动程序,都将生成文本日志文件。您可以通过在 db2cli.ini 文件中添加下列 DB2 CLI 关键字来打开 CLI 跟踪,如下:


[COMMON] 
trace=1 
TraceFileName=\temp\clitrace.txt 
TraceFlush=1 
\temp\clitrace.txt 可以是任意的名称,用来做为跟踪存储的目录和文件名。

您可以在跟踪输出文件中从 SQLConnect() 或 SQLDriverConnectW() 调用找到应用程序和数据库代码页。例如,应用程序和数据库服务器在下列消息中使用相同的代码页(1252):


(Application Codepage=1252, Database Codepage=
1252, Char Send/Recv Codepage=1252, Graphic
Send/Recv Codepage=1200, Application Char
Codepage=1252, Application Graphic Codepage=1200

验证转换表或定义可用
在大多数情况下,没有定义源和目标代码页之间的转换表或定义。DB2 UDB for Linux, UNIX, and Windows 中的转换表存储在 sqllib/conv 目录下,它们通常处理大多数转换场景。

在 iSeries 上,IBM 提供的表可以在 QUSRSYS 库中找到。您还可以使用 Create Table(CRTTBL)命令创建自己的转换表。iSeries Information Center 中的 Globalization 主题包括了转换表列表(参见 参考资料)。

您还可以运行下列查询来查看字符集名称列表:
SELECT character_set_name from sysibm.syscharsets

在 DB2 UDB for z/OS 上,如图 10 中所示,您可能需要发出 /d uni, all 命令来显示已经安装了的转换。如果该命令的输出没有列出您所需要的转换,例如从 1252 到 1208,您就要向 Unicode Conversion Services 添加一个转换条目(示例 JCL hlq.SCUNJCL(CUNJIUTL)),例如:CONVERSION 1252,1208,ER

您还要在 DB2 UDB for z/OS 目录表 SYSIBM.SYSTRINGS 中验证存在给定的转换条目。例如,查看该表中的条目列表,就要发出该查询:
SELECT inccsid, outccsid FROM sysibm.sysstrings

如果这些还没有解决您的问题,请联系 DB2 UDB Technical Support。您可能被要求收集 DB2 跟踪,并用 fmt -c 选项(以前称作 DDCS 跟踪)将其格式化。该跟踪将展示源和目标之间传递和检索了什么。

结束语
本文提供了对于 DB2 UDB 数据库内部以及数据库之间发生的字符转换过程的概述。它首先解释了诸如代码页、代码点和编码模式等关键概念,并说明了如何查看它们的当前值以及如何更新该值。接着,提供了通用场景以展示字符转换的过程。本文阐述了转换期间的一些特殊注意事项,并提供了一个两步确定导致转换问题原因的方法。

理想情况下,您应通过在转换的源和目标之间使用相同的代码页,尽力避免字符转换以提高性能。但是如果您的数据库场景十分复杂,您无法避免字符转换,那么本文的知识将帮助您尽可能顺利地完成该过程。



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多