21.2. Character Set Support #
PostgreSQL中的字符集支持允许你以多种字符集(也称为编码)存储文本,包括 ISO 8859 系列之类的单字节字符集,以及
EUC(扩展 Unix 编码)、UTF-8 和 Mule 内部编码等多字节字符集。所有受支持的字符集都可以被客户端透明地使用,但其中少数不支持在服务器内部使用(即不能作为服务器端编码)。默认字符集是在使用
initdb初始化PostgreSQL
数据库集簇时选定的。创建数据库时可以覆盖该设置,因此你可以拥有多个数据库,并让每个数据库使用不同的字符集。
21.2.1. 支持的字符集 #
表 21.1显示了PostgreSQL中可用的字符集。
表 21.1. PostgreSQL 字符集
| 名称 | 描述 | 语言 | 是否服务器端? | 字节数/字符 | 别名 |
|---|---|---|---|---|---|
BIG5 | Big Five | 繁体中文 | 否 | 1-2 | WIN950, 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-4 | |
GBK | 扩展国家标准 | 简体中文 | 否 | 1-2 | WIN936, Windows936 |
ISO_8859_5 | ISO 8859-5, ECMA 113 | 拉丁语/西里尔语 | 是 | 1 | |
ISO_8859_6 | ISO 8859-6, ECMA 114 | 拉丁语/阿拉伯语 | 是 | 1 | |
ISO_8859_7 | ISO 8859-7, ECMA 118 | 拉丁语/希腊语 | 是 | 1 | |
ISO_8859_8 | ISO 8859-8, ECMA 121 | 拉丁语/希伯来语 | 是 | 1 | |
JOHAB | JOHAB | 韩语 | 否 | 1-3 | |
KOI8 | KOI8-R(U) | 西里尔语 | 是 | 1 | KOI8R |
LATIN1 | ISO 8859-1, ECMA 94 | 西欧 | 是 | 1 | ISO88591 |
LATIN2 | ISO 8859-2, ECMA 94 | 中欧 | 是 | 1 | ISO88592 |
LATIN3 | ISO 8859-3, ECMA 94 | 南欧 | 是 | 1 | ISO88593 |
LATIN4 | ISO 8859-4, ECMA 94 | 北欧 | 是 | 1 | ISO88594 |
LATIN5 | ISO 8859-9, ECMA 128 | 土耳其语 | 是 | 1 | ISO88599 |
LATIN6 | ISO 8859-10, ECMA 144 | 北欧 | 是 | 1 | ISO885910 |
LATIN7 | ISO 8859-13 | 波罗的海 | 是 | 1 | ISO885913 |
LATIN8 | ISO 8859-14 | 凯尔特语 | 是 | 1 | ISO885914 |
LATIN9 | ISO 8859-15 | 带欧元符号和重音字符的 LATIN1 | 是 | 1 | ISO885915 |
LATIN10 | ISO 8859-16, ASRO SR 14111 | 罗马尼亚语 | 是 | 1 | ISO885916 |
MULE_INTERNAL | Mule 内部编码 | 多语种 Emacs | 是 | 1-4 | |
SJIS | Shift JIS | 日语 | 否 | 1-2 | Mskanji, ShiftJIS, WIN932, Windows932 |
SQL_ASCII | 未指定(见正文) | 任意 | 是 | 1 | |
UHC | 统一韩语编码 | 韩语 | 否 | 1-2 | WIN949, Windows949 |
UTF8 | Unicode,8 位 | 所有 | 是 | 1-4 | Unicode |
WIN866 | Windows CP866 | 西里尔语 | 是 | 1 | ALT |
WIN874 | Windows CP874 | 泰语 | 是 | 1 | |
WIN1250 | Windows CP1250 | 中欧 | 是 | 1 | |
WIN1251 | Windows CP1251 | 西里尔语 | 是 | 1 | WIN |
WIN1252 | Windows CP1252 | 西欧 | 是 | 1 | |
WIN1253 | Windows CP1253 | 希腊语 | 是 | 1 | |
WIN1254 | Windows CP1254 | 土耳其语 | 是 | 1 | |
WIN1255 | Windows CP1255 | 希伯来语 | 是 | 1 | |
WIN1256 | Windows CP1256 | 阿拉伯语 | 是 | 1 | |
WIN1257 | Windows CP1257 | 波罗的海 | 是 | 1 | |
WIN1258 | Windows CP1258 | 越南语 | 是 | 1 | ABC, TCVN, TCVN5712, VSCII |
并非所有客户端API都支持上表中的全部字符集。例如,PostgreSQL JDBC 驱动就不支持
MULE_INTERNAL、LATIN6、LATIN8和LATIN10。
SQL_ASCII 设置的行为与其他设置有很大不同。当服务器字符集为 SQL_ASCII 时,服务器按 ASCII 标准解释字节值 0-127,而将字节值 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
这将创建一个名为korean的数据库,它使用
EUC_KR字符集。另一种实现方式是使用下面的 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)
重要
尽管你可以为数据库指定任意编码,但选择一种与所选区域设置的期望不相符的编码是不明智的。LC_COLLATE和
LC_CTYPE设置隐含着一种特定的编码,区域设置相关的操作(例如排序)很可能会错误解释以不兼容编码存储的数据。
由于这些区域设置被initdb冻结,在一个集簇的不同数据库中使用不同编码的表面灵活性实际上更多只是理论上的。这些机制将来很可能会在PostgreSQL的未来版本中重新考虑。
安全使用多种编码的办法之一,是在initdb时把区域设置选为C或POSIX,从而关闭任何真正的区域感知。
21.2.3. 服务器和客户端之间的自动字符集转换
PostgreSQL 支持在服务器和客户端之间,对某些字符集组合进行自动字符集转换。转换信息保存在系统目录 pg_conversion 中。PostgreSQL 提供了一些预定义转换,如表 21.2所示。可以使用 SQL 命令 CREATE CONVERSION 创建新的转换。
表 21.2. 客户端/服务器字符集转换
| 服务器字符集 | 可用的客户端字符集 |
|---|---|
BIG5 | 不支持作为服务器编码 |
EUC_CN | EUC_CN,
MULE_INTERNAL,
UTF8
|
EUC_JP | EUC_JP,
MULE_INTERNAL,
SJIS,
UTF8
|
EUC_KR | EUC_KR,
MULE_INTERNAL,
UTF8
|
EUC_TW | EUC_TW,
BIG5,
MULE_INTERNAL,
UTF8
|
GB18030 | 不支持用作服务器编码 |
GBK | 不支持作为服务器编码 |
ISO_8859_5 | ISO_8859_5,
KOI8R,
MULE_INTERNAL,
UTF8,
WIN866,
WIN1251
|
ISO_8859_6 | ISO_8859_6,
UTF8
|
ISO_8859_7 | ISO_8859_7,
UTF8
|
ISO_8859_8 | ISO_8859_8,
UTF8
|
JOHAB | JOHAB,
UTF8
|
KOI8 | KOI8,
ISO_8859_5,
MULE_INTERNAL,
UTF8,
WIN866,
WIN1251
|
LATIN1 | LATIN1,
MULE_INTERNAL,
UTF8
|
LATIN2 | LATIN2,
MULE_INTERNAL,
UTF8,
WIN1250
|
LATIN3 | LATIN3,
MULE_INTERNAL,
UTF8
|
LATIN4 | LATIN4,
MULE_INTERNAL,
UTF8
|
LATIN5 | LATIN5,
UTF8
|
LATIN6 | LATIN6,
UTF8
|
LATIN7 | LATIN7,
UTF8
|
LATIN8 | LATIN8,
UTF8
|
LATIN9 | LATIN9,
UTF8
|
LATIN10 | LATIN10,
UTF8
|
MULE_INTERNAL | MULE_INTERNAL,
BIG5,
EUC_CN,
EUC_JP,
EUC_KR,
EUC_TW,
ISO_8859_5,
KOI8R,
LATIN1 to LATIN4,
SJIS,
WIN866,
WIN1250,
WIN1251
|
SJIS | 不支持用作服务器编码 |
SQL_ASCII | 任意(不执行转换) |
UHC | 不支持作为服务器编码 |
UTF8 | all supported encodings |
WIN866 | WIN866,
ISO_8859_5,
KOI8R,
MULE_INTERNAL,
UTF8,
WIN1251
|
WIN874 | WIN874,
UTF8
|
WIN1250 | WIN1250,
LATIN2,
MULE_INTERNAL,
UTF8
|
WIN1251 | WIN1251,
ISO_8859_5,
KOI8R,
MULE_INTERNAL,
UTF8,
WIN866
|
WIN1252 | WIN1252,
UTF8
|
WIN1253 | WIN1253,
UTF8
|
WIN1254 | WIN1254,
UTF8
|
WIN1255 | WIN1255,
UTF8
|
WIN1256 | WIN1256,
UTF8
|
WIN1257 | WIN1257,
UTF8
|
WIN1258 | WIN1258,
UTF8
|
若要启用自动字符集转换,必须告诉PostgreSQL 你希望客户端使用哪种字符集(编码)。有几种方法可以做到这一点:
在psql中使用
\encoding命令。\encoding允许动态更改客户端编码。例如,要把编码改成SJIS,可以输入:\encoding SJIS
使用 libpq 函数。
\encoding实际上是通过调用PQsetClientEncoding()来实现其功能的:int PQsetClientEncoding(PGconn *
conn, const char *encoding);其中
conn是到服务器的连接,encoding是你想使用的编码。如果该函数成功设置了编码,它返回 0,否则返回 -1。此连接的当前编码可以用下面的函数确定:int PQclientEncoding(const PGconn *
conn);注意,它返回的是编码 ID,而不是像
EUC_JP这样的符号字符串。要把编码 ID 转换为编码名,可以使用:char *pg_encoding_to_char(int
encoding_id);使用
SET client_encoding TO。可以使用以下 SQL 命令设置客户端编码:SET CLIENT_ENCODING TO '
value';也可以为此使用标准 SQL 语法
SET NAMES:SET NAMES '
value';要查询当前客户端编码:
SHOW client_encoding;
要返回到默认编码:
RESET client_encoding;
使用
PGCLIENTENCODING。如果在客户端环境中定义了PGCLIENTENCODING环境变量,那么连接服务器时会自动选择该客户端编码。(之后仍可以用上面提到的任何其他方法覆盖它。)使用配置变量client_encoding。如果设置了
client_encoding变量,那么连接服务器时会自动选择该客户端编码。(之后仍可以用上面提到的任何其他方法覆盖它。)
如果某个特定字符无法完成转换,就会报错。例如,假设服务器使用
EUC_JP而客户端使用LATIN1,此时若返回了一些在LATIN1中没有表示形式的日语字符,就会出现错误。
如果客户端字符集定义为 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
其中对
EUC_JP、EUC_CN、EUC_KR和EUC_TW的详细说明见第 3.2 节。- http://www.unicode.org/
Unicode Consortium 网站。
- RFC 3629
这里定义了UTF-8(8 位 UCS/Unicode 转换格式)。