21.2. 字符集支持

PostgreSQL 里面的字符集支持你能够以各种字符集存储文本, 包括单字节的字符集,比如 ISO 8859 系列和 EUC (扩展 Unix 编码 Extended Unix Code),UTF-8 和 Mule 国际编码。所有字符集都可以在服务器上透明地使用。 (如果你使用了来自其它数据源地扩展函数,那么它取决于他们是否正确地书写了代码。) 缺省的字符集是在使用 initdb 初始化你的 PostgreSQL 数据库集群的时候选择的。 在你的使用 createdb 或者 SQL 命令 CREATE DATABASE 的时候是可以覆盖这个缺省的。因此,你可以有多个数据库,每个都有不同的字符集。

21.2.1. 支持字符集编码

Table 21-1 显示了可以用在服务器的字符集。

Table 21-1. 服务器字符集

名字描述语言字节/字符别名
BIG5大五繁体中文1-2WIN950, Windows950
EUC_CN扩展的 UNIX 代码-CN简体中文1-3 
EUC_JP扩展的 UNIX 代码-JP日文1-3 
EUC_KR扩展的 UNIX 代码-KR韩文1-3 
EUC_TW扩展的 UNIX 代码-TW繁体中文,中国台湾省1-3 
GB18030国家标准中文1-2 
GBK扩展的国家标准简体中文1-2WIN936, Windows936
ISO_8859_5ISO 8859-5, ECMA 113拉丁/西里尔语1 
ISO_8859_6ISO 8859-6, ECMA 114拉丁/阿拉伯语1 
ISO_8859_7ISO 8859-7, ECMA 118拉丁/希腊语1 
ISO_8859_8ISO 8859-8, ECMA 121拉丁/希伯莱语1 
JOHABJOHAB韩语(Hangul)1-3 
KOI8KOI8-R(U)西里尔语1KOI8R
LATIN1ISO 8859-1, ECMA 94西欧语1ISO88591
LATIN2ISO 8859-2, ECMA 94中欧语1ISO88592
LATIN3ISO 8859-3, ECMA 94南欧语1ISO88593
LATIN4ISO 8859-4, ECMA 94北欧语1ISO88594
LATIN5ISO 8859-9, ECMA 128土耳其语1ISO88599
LATIN6ISO 8859-10, ECMA 144北欧,日耳曼语(Nordic)1ISO885910
LATIN7ISO 8859-13波罗的海语(Baltic)1ISO885913
LATIN8ISO 8859-14凯尔特语(Celtic)1ISO885914
LATIN9ISO 8859-15带有欧洲语系和语调的 LATIN11ISO885915
LATIN10ISO 8859-16, ASRO SR 14111罗马尼亚语(Romanian)1ISO885916
MULE_INTERNALMule 国际编码多语种 Emacs1-4 
SJISShift JIS日语1-2Mskanji, ShiftJIS, WIN932, Windows932
SQL_ASCII未声明(见文本)任意1 
UHC统一韩语(Hangul)编码韩语1-2WIN949, Windows949
UTF8Unicode, 8-bit全部1-4Unicode
WIN866Windows CP866西里尔语1ALT
WIN874Windows CP874泰国语1 
WIN1250Windows CP1250中欧语1 
WIN1251Windows CP1251西里尔语1WIN
WIN1252Windows CP1252西欧语1 
WIN1256Windows CP1256阿拉伯语1 
WIN1258Windows CP1258越南语1ABC, TCVN, TCVN5712, VSCII

并非所有API支持上面列出的编码。比如, PostgreSQL JDBC 驱动就不支持MULE_INTERNALLATIN6LATIN8LATIN10

SQL_ASCII 设置与其它设置表现得相当不同。如果服务器字符集是 SQL_ASCII, 服务器把字节值 0-127 的数值根据 ASCII 标准解析,而字节值未 128-255 的则当作未解析的字符。 如果设置为 SQL_ASCII,就不会有编码转换。因此,这个设置基本不是用来声明所使用的编码的, 因为这个声明会忽略编码。在大多数情况下,如果你使用了任何非 ASCII 数据,那么使用 SQL_ASCII 设置都是不明智的,因为 PostgreSQL 会无法帮助你转换或者校验非 ASCII 字符。

21.2.2. 设置字符集

initdb 为一个 PostgreSQL 集群定义缺省的字符集,比如:

initdb -E EUC_JP

把缺省字符集设置为 EUC_JP (用于日文的扩展的 Unix 编码)。 如果你喜欢用长选项声明的话,你可以用 --encoding 代替 -E。 如果没有给出-E或者--encoding选项, initdb 将基于制定的区域或者缺省区域试图判断合适的编码。

你可以创建一个有着不同编码的数据库:

createdb -E EUC_KR korean

将创建一个使用EUC_KR字符集的名字叫 korean 的数据库。 另外一种实现方法是使用 SQL 命令:

CREATE DATABASE korean WITH ENCODING 'EUC_KR';

数据库的编码是用系统表 pg_database 里的一个 编码字段代表的。 你可以用psql-l选项或 \l命令列出这些编码。

$ psql -l
            List of databases
   Database    |  Owner  |   Encoding
---------------+---------+---------------
 euc_cn        | t-ishii | EUC_CN
 euc_jp        | t-ishii | EUC_JP
 euc_kr        | t-ishii | EUC_KR
 euc_tw        | t-ishii | EUC_TW
 mule_internal | t-ishii | MULE_INTERNAL
 postgres      | t-ishii | EUC_JP
 regression    | t-ishii | SQL_ASCII
 template1     | t-ishii | EUC_JP
 test          | t-ishii | EUC_JP
 utf8          | t-ishii | UTF8
(9 rows)

Important: 虽然你可以给一个数据库声明你需要的任何编码,但选择一个与你选择的区域不一致的编码还是不妥的做法。 LC_COLLATELC_CTYPE 设置暗示一个特定的编码, 与区域相关的操作(比如排序)在不兼容的编码里很有可能产生错误的解析。

因为这些区域设置都是由 initdb 冻结的, 所以在不同的数据库里使用不同的编码更多是理论而不是现实。 这些机制很有可能在将来版本的 PostgreSQL 得到改进。

一个安全使用多种编码的方法是在 initdb 的时候把区域设置为 C 或者 POSIX,这样旧关闭了任何实际的区域敏感性。

21.2.3. 服务器和客户端之间的自动字符集转换

PostgreSQL 支持一些编码在服务器和前端之间的自动编码转换。 转换信息在系统表 pg_conversion 中存储。 你可以使用 SQL 命令 CREATE CONVERSION 创建一个新的转换。 PostgreSQL带着一些预定义的转换。它们在 Table 21-2 中列出。

Table 21-2. 客户/服务器字符集转换

服务器字符集可用客户端字符集
BIG5不支持做服务器端编码
EUC_CNEUC_CN, MULE_INTERNAL, UTF8
EUC_JPEUC_JP, MULE_INTERNAL, SJIS, UTF8
EUC_KREUC_KR, MULE_INTERNAL, UTF8
EUC_TWEUC_TW, BIG5, MULE_INTERNAL, UTF8
GB18030不支持做服务器端编码
GBK不支持做服务器端编码
ISO_8859_5ISO_8859_5, KOI8, MULE_INTERNAL, UTF8, WIN866, WIN1251
ISO_8859_6ISO_8859_6, UTF8
ISO_8859_7ISO_8859_7, UTF8
ISO_8859_8ISO_8859_8, UTF8
JOHABJOHAB, UTF8
KOI8KOI8, ISO_8859_5, MULE_INTERNAL, UTF8, WIN866, WIN1251
LATIN1LATIN1, MULE_INTERNAL, UTF8
LATIN2LATIN2, MULE_INTERNAL, UTF8, WIN1250
LATIN3LATIN3, MULE_INTERNAL, UTF8
LATIN4LATIN4, MULE_INTERNAL, UTF8
LATIN5LATIN5, UTF8
LATIN6LATIN6, UTF8
LATIN7LATIN7, UTF8
LATIN8LATIN8, UTF8
LATIN9LATIN9, UTF8
LATIN10LATIN10, UTF8
MULE_INTERNALMULE_INTERNAL, BIG5, EUC_CN, EUC_JP, EUC_KR, EUC_TW, ISO_8859_5, KOI8, LATIN1 to LATIN4, SJIS, WIN866, WIN1250, WIN1251
SJIS不支持做服务器端编码
SQL_ASCII任意(不会发生编码转换)
UHC不支持做服务器端编码
UTF8所有支持的编码
WIN866WIN866, ISO_8859_5, KOI8, MULE_INTERNAL, UTF8, WIN1251
WIN874WIN874, UTF8
WIN1250WIN1250, LATIN2, MULE_INTERNAL, UTF8
WIN1251WIN1251, ISO_8859_5, KOI8, MULE_INTERNAL, UTF8, WIN866
WIN1252WIN1252, UTF8
WIN1256WIN1256, UTF8
WIN1258WIN1258, UTF8

要想打开自动字符集转换功能,你必须告诉 PostgreSQL 你想在客户端使用的字符集(编码)。你可以用好几种方法实现这个目的。

假如无法进行特定的字符转换 — 比如, 你选的服务器编码是EUC_JP, 客户端是LATIN1,那么有些日文字符不能转换成LATIN1。这时, 不能用LATIN1字符集表示的字母将被转换成圆括弧包围的十六进制,像,(826C) 这样。

如果客户端字符集定义成了 SQL_ASCII,那么编码转换会被关闭, 不管服务器的字符集是什么都一样。和服务器一样,除非你的工作环境全部是 ASCII 数据, 否则使用 SQL_ASCII 是不明智的。

21.2.4. 进一步阅读

下面是学习各种类型的编码系统的好地方。

http://www.i18ngurus.com/docs/984813247.html

一整套有关字符集,编码以及代码页的文档。

ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/cjk.inf

详细地解释了第3.2节出现的EUC_JPEUC_CNEUC_KREUC_TW

http://www.unicode.org/

Unicode 的家目录。

RFC 2044

定义了UTF-8。