PostgreSQL 能够以各种字符集存储文本,比如 ISO-8859 系列和 EUC(扩展 Unix 编码)、UTF-8 、Mule 国际编码。所有字符集都可以在服务器上透明地使用。如果你使用了来自其它数据源的扩展函数,那么它取决于他们是否正确地书写了代码。缺省的字符集是在使用 initdb 初始化数据库集群的时候选择的。在你创建数据库的时候是可以覆盖这个缺省的。因此,你可以有多个数据库,每个都有不同的字符集。
表21-1 显示了可以用在服务器的字符集。
表21-1. PostgreSQL 服务器字符集
名字 | 描述 | 语言 | 服务端? | 字节/字符 | 别名 |
---|---|---|---|---|---|
BIG5 | 大五码 | 繁体中文 | No | 1-2 | WIN950, Windows950 |
EUC_CN | 扩展UNIX代码-CN | 简体中文 | Yes | 1-3 | |
EUC_JP | 扩展UNIX代码-JP | 日文 | Yes | 1-3 | |
EUC_KR | 扩展UNIX代码-KR | 韩文 | Yes | 1-3 | |
EUC_TW | 扩展UNIX代码-TW | 繁体中文,台湾 | Yes | 1-3 | |
GB18030 | 国标码 | 中文 | No | 1-2 | |
GBK | 扩展国标码 | 简体中文 | No | 1-2 | WIN936, Windows936 |
ISO_8859_5 | ISO 8859-5, ECMA 113 | 拉丁/西里尔语 | Yes | 1 | |
ISO_8859_6 | ISO 8859-6, ECMA 114 | 拉丁/阿拉伯语 | Yes | 1 | |
ISO_8859_7 | ISO 8859-7, ECMA 118 | 拉丁/希腊语 | Yes | 1 | |
ISO_8859_8 | ISO 8859-8, ECMA 121 | 拉丁/希伯莱语 | Yes | 1 | |
JOHAB | JOHAB | 韩语 | Yes | 1-3 | |
KOI8 | KOI8-R(U) | 西里尔语 | Yes | 1 | KOI8R |
LATIN1 | ISO 8859-1, ECMA 94 | 西欧语 | Yes | 1 | ISO88591 |
LATIN2 | ISO 8859-2, ECMA 94 | 中欧语 | Yes | 1 | ISO88592 |
LATIN3 | ISO 8859-3, ECMA 94 | 南欧语 | Yes | 1 | ISO88593 |
LATIN4 | ISO 8859-4, ECMA 94 | 北欧语 | Yes | 1 | ISO88594 |
LATIN5 | ISO 8859-9, ECMA 128 | 土耳其语 | Yes | 1 | ISO88599 |
LATIN6 | ISO 8859-10, ECMA 144 | 日耳曼语 | Yes | 1 | ISO885910 |
LATIN7 | ISO 8859-13 | 波罗的海语 | Yes | 1 | ISO885913 |
LATIN8 | ISO 8859-14 | 凯尔特语 | Yes | 1 | ISO885914 |
LATIN9 | ISO 8859-15 | 带有欧洲语系和语调的 LATIN1 | Yes | 1 | ISO885915 |
LATIN10 | ISO 8859-16, ASRO SR 14111 | 罗马尼亚语 | Yes | 1 | ISO885916 |
MULE_INTERNAL | Mule 国际编码 | 多语种 Emacs | Yes | 1-4 | |
SJIS | Shift JIS | 日语 | No | 1-2 | Mskanji, ShiftJIS, WIN932, Windows932 |
SQL_ASCII | 未声明(见文本) | 任意 | Yes | 1 | |
UHC | 统一韩语编码 | 韩语 | No | 1-2 | WIN949, Windows949 |
UTF8 | Unicode, 8-bit | 全部 | Yes | 1-4 | Unicode |
WIN866 | Windows CP866 | 西里尔语 | Yes | 1 | ALT |
WIN874 | Windows CP874 | 泰国语 | Yes | 1 | |
WIN1250 | Windows CP1250 | 中欧语 | Yes | 1 | |
WIN1251 | Windows CP1251 | 西里尔语 | Yes | 1 | WIN |
WIN1252 | Windows CP1252 | 西欧语 | Yes | 1 | |
WIN1253 | Windows CP1253 | 希腊语 | Yes | 1 | |
WIN1254 | Windows CP1254 | 土耳其语 | Yes | 1 | |
WIN1255 | Windows CP1255 | 希伯来语 | Yes | 1 | |
WIN1256 | Windows CP1256 | 阿拉伯语 | Yes | 1 | |
WIN1257 | Windows CP1257 | 波罗的语 | Yes | 1 | |
WIN1258 | Windows CP1258 | 越南语 | Yes | 1 | ABC, TCVN, TCVN5712, VSCII |
并非所有API都支持上面列出的编码。比如,PostgreSQL JDBC驱动就不支持 MULE_INTERNAL, LATIN6, LATIN8, LATIN10 。
SQL_ASCII 设置与其它设置表现得相当不同。如果服务器字符集是 SQL_ASCII ,服务器把字节值 0-127 的数值根据 ASCII 标准解析,而字节值 128-255 的则当作未解析的字符。如果设置为 SQL_ASCII 就不会有编码转换。因此,这个设置基本不用来声明所使用的编码,因为这个声明会忽略编码。在大多数情况下,如果你使用了任何非 ASCII 数据,那么使用 SQL_ASCII 设置都是不明智的,因为 PostgreSQL 会无法帮助你转换或者校验非 ASCII 字符。
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)
【重要】虽然你可以给一个数据库声明你需要的任何编码,但选择一个与你选择的区域不一致的编码还是不妥的做法。LC_COLLATE 和 LC_CTYPE 设置暗示一个特定的编码,与区域相关的操作(比如排序)在不兼容的编码里很有可能产生错误的解析。
因为这些区域设置都是由 initdb 冻结的,所以在不同的数据库里使用不同的编码更多是理论而不是现实。这些机制很有可能在将来版本的 PostgreSQL 得到改进。
一个安全使用多种编码的方法是在 initdb 的时候把区域设置为 C 或 POSIX ,这样就关闭了任何实际的区域敏感性。
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, KOI8, 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, KOI8, LATIN1 to LATIN4, SJIS, WIN866, WIN1250, WIN1251 |
SJIS | 不支持做服务器端编码 |
SQL_ASCII | 任意(不会发生编码转换) |
UHC | 不支持做服务器端编码 |
UTF8 | 所有支持的编码 |
WIN866 | WIN866, ISO_8859_5, KOI8, MULE_INTERNAL, UTF8, WIN1251 |
WIN874 | WIN874, UTF8 |
WIN1250 | WIN1250, LATIN2, MULE_INTERNAL, UTF8 |
WIN1251 | WIN1251, ISO_8859_5, KOI8, 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);
可以用 SQL 命令 SET client_encoding TO 设置客户端编码:
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 是不明智的。
下面是学习各种类型的编码系统的好地方。
一整套有关字符集,编码以及代码页的文档。
详细地解释了第3.2节出现的 EUC_JP, EUC_CN, EUC_KR, EUC_TW 编码。
Unicode 的主页。
UTF-8 的定义。