一、区域支持
区域支持指的是应用遵守文化偏好的问题,包括字母表、排序、数字格式等。PostgreSQL使用服务器操作系统提供的标准 ISO C 和POSIX的区域机制。更多的信息请参考你的系统的文档。
1.1. 概述
区域支持是在使用initdb
创建一个数据库集簇时自动被初始化的。默认情况下,initdb
将会按照它的执行环境的区域设置初始化数据库集簇; 因此如果你的系统已经设置为你的数据库集簇想要使用的区域, 那么你就没有什么可干的。如果你想使用其它的区域(或者你还不知道你的系统设置的区域是什么),那么你可以用--locale
选项准确地告诉initdb
你要用哪一个区域。 比如:
initdb --locale=sv_SE
这个Unix系统上的例子把区域设置为瑞典(SE
)瑞典语(sv
)。 其他的可能性包括 en_US
(美国英语)和fr_CA
(加拿大法语)。如果有多于一种字符集可以用于区域,那么声明可以采用如下的形式:language_territory.codeset
。例如fr_BE.UTF-8
表示在比利时(BE)讲的法语(fr),使用一个UTF-8字符集编码。
在你的系统上有哪些区域可用取决于操作系统提供商提供了什么以及安装了什么。在大部分Unix系统上,命令locale -a
将会提供一个所有可用区域的列表。Windows使用一些更繁琐的区域名,例如German_Germany
或者Swedish_Sweden.1252
,但是其原则是相同的。
有时候,把几种区域规则混合起来也很有用,比如,使用英语排序规则而用西班牙语消息。 为了支持这些,我们有一套区域子类用于控制本地化规则的某些方面:
LC_COLLATE | 字符串排序顺序 |
LC_CTYPE | 字符分类(什么是一个字符?它的大写形式是否等效?) |
LC_MESSAGES | 消息使用的语言Language of messages |
LC_MONETARY | 货币数量使用的格式 |
LC_NUMERIC | 数字的格式 |
LC_TIME | 日期和时间的格式 |
这些类名转换成initdb
的选项名来覆盖某个特定分类的区域选择。比如,要把区域设置为加拿大法语,但使用 U.S. 规则格式化货币,可以使用initdb --locale=fr_CA --lc-monetary=en_US
。
如果你想让系统表现得象没有区域支持,那么使用特殊的区域名C
或者等效的POSIX
。
一些区域分类的值必需在数据库被创建时的就被固定。你可以为不同的数据库使用不同的设置,但是一旦一个数据库被创建,你就不能在数据库上修改这些区域分类的值。LC_COLLATE
和LC_CTYPE
就是这样的分类。它们影响索引的排序顺序,因此它们必需保持固定, 否则在文本列上的索引将会崩溃(但是你可以使用排序规则放松这种限制,讨论见二节)。这些分类的默认值在initdb
运行时被确定,并且这些值在新数据库被创建时使用,除非在CREATE DATABASE
命令中特别指定。
其它区域分类可以在任何时候被更改,更改的方式是设置与区域分类同名的服务器配置参数。被initdb
选中的值实际上只是被写入到配置文件postgresql.conf
中作为服务器启动时的默认值。如果你将这些赋值从postgresql.conf
中除去,那么服务器将会从其执行环境中继承该设置。
请注意服务器的区域行为是由它看到的环境变量决定的,而不是由任何客户端的环境变量影响的。 因此,我们要在启动服务器之前认真地设置好这些变量。这样带来的一种后果是如果客户端和服务器设置成不同的区域, 那么消息可能以不同的语言呈现,实际情况取决于它们的起源地。
注意:
在我们谈到从执行环境继承区域的时候,我们的意思是在大多数操作系统上的下列动作: 对于一个给定的区域分类,比如排序规则,按照下面的顺序评估这些环境变量, 直到找到一个被设置了的:
LC_ALL
、LC_COLLATE
(或者对应于相应分类的变量)、LANG
。如果这些环境变量一个都没有被设置,那么将区域缺省设置为C
。一些消息本地化库也查看环境变量
LANGUAGE
,它覆盖所有其它用于设置消息语言的区域设置。如果有疑问, 请参考你的操作系统的文档,特别是有关gettext的文档。
要允许消息被翻译成用户喜欢的语言,编译时必需打开NLS(configure --enable-nls
)。所有其他区域支持都会被自动编译。
1.2. 行为
区域设置特别影响下面的 SQL 特性:
PostgreSQL中使用非C
或非POSIX
区域的缺点是性能影响。它降低了字符处理的速度并且阻止了在LIKE
中对普通索引的使用。因此,只能在真正需要的时候才使用它。
作为允许PostgreSQL在非 C 区域下为LIKE
子句使用索引, 有好几种自定义操作符类可用。这些操作符类允许创建一个执行严格按字符比较的索引。另一种方法是创建使用C
排序规则的索引,如二节所讨论的。
1.3. 问题
如果根据上面解释区域支持仍然不能运转,检查一下操作系统的区域支持是否被正确配置。 要检查系统中安装了哪些区域,你可以使用命令locale -a
(如果你的操作系统提供了该命令)。
请检查PostgreSQL确实正在使用你认为它该用的区域设置。LC_COLLATE
和LC_CTYPE
设置都是在数据库创建时决定的,并且在除了创建数据库之外的操作中都不能被更改。其它的区域设置包括LC_MESSAGES
和LC_MONETARY
都是由服务器启动的环境决定的, 但是可以在运行时修改。你可以用SHOW
命令检查活跃的区域设置。
源代码目录的src/test/locale
中包含PostgreSQL的区域支持的测试套件。
那些通过分析错误消息来处理服务器端错误的客户端应用很明显会有问题,因为服务器来的消息可能会是以不同语言表示的。 我们建议这类应用的开发人员改用错误代码机制。
维护消息翻译目录需要许多志愿者的坚持不懈的努力, 他们希望PostgreSQL以他们的语言说话。 如果以你的语言表示的消息目前还不可用或者没有完全翻译完成,那么我们很感谢你的协助。如果你想帮忙,那么请向开发者邮递列表发邮件。
二、排序规则支持
排序规则特性允许指定每一列甚至每一个操作的数据的排序顺序和字符分类行为。这放松了数据库的LC_COLLATE
和LC_CTYPE
设置自创建以后就不能更改这一限制。
2.1. 概念
在概念上,一种可排序数据类型的每一种表达式都有一个排序规则(内建的可排序数据类型是text
、varchar
和char
。用户定义的基础类型也可以被标记为可排序的,并且在一种可排序数据类型上的域也是可排序的)。如果该表达式是一个列引用,该表达式的排序规则就是列所定义的排序规则。如果该表达式是一个常量,排序规则就是该常量数据类型的默认排序规则。更复杂表达式的排序规则根据其输入的排序规则得来,如下所述:
一个表达式的排序规则可以是“默认”排序规则,它表示数据库的区域设置。一个表达式的排序规则也可能是不确定的。在这种情况下,排序操作和其他需要知道排序规则的操作会失败。
当数据库系统必须要执行一次排序或者字符分类时,它使用输入表达式的排序规则。这会在使用例如ORDER BY
子句以及函数或操作符调用(如<
)时发生。应用于ORDER BY
子句的排序规则就是排序键的排序规则。应用于函数或操作符调用的排序规则从它们的参数得来,具体如下文所述。除比较操作符之外,在大小写字母之间转换的函数会考虑排序规则,例如lower
、upper
和initcap
。模式匹配操作符和to_char
及相关函数也会考虑排序规则。
对于一个函数或操作符调用,其排序规则通过检查在执行指定操作时参数的排序规则来获得。如果该函数或操作符调用的结果是一种可排序的数据类型,万一有外围表达式要求函数或操作符表达式的排序规则,在解析时结果的排序规则也会被用作函数或操作符表达式的排序规则。
一个表达式的排序规则派生可以是显式或隐式。该区别会影响多个不同的排序规则出现在同一个表达式中时如何组合它们。当使用一个COLLATE
子句时,将发生显式排序规则派生。所有其他排序规则派生都是隐式的。当多个排序规则需要被组合时(例如在一个函数调用中),将使用下面的规则:
-
如果任何一个输入表达式具有一个显式排序规则派生,则在输入表达式之间的所有显式派生的排序规则必须相同,否则将产生一个错误。如果任何一个显式派生的排序规则存在,它就是排序规则组合的结果。
-
否则,所有输入表达式必须具有相同的隐式排序规则派生或默认排序规则。如果任何一个非默认排序规则存在,它就是排序规则组合的结果。否则,结果是默认排序规则。
-
如果在输入表达式之间存在冲突的非默认隐式排序规则,则组合被认为是具有不确定排序规则。这并非一种错误情况,除非被调用的特定函数要求提供排序规则的知识。如果它确实这样做,运行时将发生一个错误。
例如,考虑这个表定义:
CREATE TABLE test1 (
a text COLLATE "de_DE",
b text COLLATE "es_ES",
...
);
然后在
SELECT a < 'foo' FROM test1;
中,<
比较被根据de_DE
规则执行,因为表达式组合了一个隐式派生的排序规则和默认排序规则。但是在
SELECT a < ('foo' COLLATE "fr_FR") FROM test1;
中,比较被使用fr_FR
规则执行,因为显式排序规则派生重载了隐式排序规则。更进一步,给定
SELECT a < b FROM test1;
解析器不能确定要应用哪个排序规则,因为a
列和b
列具有冲突的隐式排序规则。由于<
操作符不需要知道到底使用哪一个排序规则,这将会导致一个错误。该错误可以通过在一个输入表达式上附加一个显式排序规则说明符来解决,因此:
SELECT a < b COLLATE "de_DE" FROM test1;
或者等效的
SELECT a COLLATE "de_DE" < b FROM test1;
在另一方面,结构相似的情况
SELECT a || b FROM test1;
不会导致一个错误,因为||
操作符不关心排序规则:不管排序规则怎样它的结果都相同。
如果一个函数或操作符发送一个具有可排序数据类型的结果,分配给该函数或操作符的组合输入表达式的排序规则也被考虑应用在函数或操作符的结果。因此,在
SELECT * FROM test1 ORDER BY a || 'foo';
中排序将根据de_DE
规则完成。但这个查询:
SELECT * FROM test1 ORDER BY a || b;
会导致一个错误,因为即使||
操作符不需要知道排序规则,但ORDER BY
子句需要。按照以前,冲突可以通过使用一个显式排序规则说明符来解决:
SELECT * FROM test1 ORDER BY a || b COLLATE "fr_FR";
2.2. 管理排序规则
排序规则是SQL模式对象,它将SQL名称映射到操作系统中安装的库提供的语言环境。 排序规则定义中有一个提供程序, 它指定哪个库提供语言环境数据。一个标准的提供者名称是libc
, 它使用操作系统C库提供的语言环境。这些是操作系统提供的大多数工具使用的语言环境。 另一个提供者是icu
,它使用外部ICU库。 只有在构建PostgreSQL时配置了对ICU的支持,才能使用ICU区域设置。
libc
提供的一个排序规则对象映射到LC_COLLATE
和LC_CTYPE
设置的组合, 如setlocale()
系统库调用所接受的。 (正如其名字所说的,一个排序规则的主要目的是设置LC_COLLATE
, 它控制排序顺序。但是在实际中LC_CTYPE
设置与LC_COLLATE
不同是很少有必要的,因此通过一个概念来收集这些信息比为了设置每一个表达式的 LC_CTYPE
而创建另一种架构要更加方便)。此外, 一个libc
排序规则是和一个字符集编码(见三节) 绑定在一起的。相同的排序规则名字可能存在于不同的编码中。
由icu
提供的排序规则对象映射到由ICU库提供的指定整理器。 ICU不支持单独的“collate”和“ctype”设置, 所以它们总是相同的。此外,ICU排序规则与编码无关, 因此在数据库中总是只有一个给定名称的ICU排序规则。
2.2.1. 标准的排序规则
在所有的平台上,名为default
、C
和POSIX
的排序规则都可用。附加的排序规则是否可用取决于操作系统的支持。default
排序规则选择在数据库创建时指定的LC_COLLATE
和LC_CTYPE
值。C
和POSIX
排序规则都指定了“传统的C”行为,在其中只有ASCII字母“A
”到“Z
”被视为字母,并且排序严格地按照字符编码的字节值完成。
此外,SQL标准排序规则名称ucs_basic
可用于编码UTF8
。 它相当于C
,并按Unicode代码点排序。
2.2.2. 预定义的排序规则
如果操作系统支持在一个程序中使用多个区域(newlocale
和相关函数), 或者配置了ICU支持,那么在一个数据集簇被初始化时,initdb
将以它在操作系统中能找到的所有区域为基础在系统目录pg_collation
中填充排序规则。
要检查当前可用的语言环境,请在psql中使用查询 SELECT * FROM pg_collation
或命令\dOS +
。
2.2.2.1. libc 排序规则
例如,操作系统可能会提供一个名为de_DE.utf8
的区域。initdb
则会创建一个用于编码UTF8
的名为de_DE.utf8
的排序规则,在其中LC_COLLATE
和LC_CTYPE
都被设置为de_DE.utf8
。它也会创建一个具有去掉名称的.utf8
标签的排序规则。这样你也可以使用名字de_DE
来使用该排序规则,这写起来更简单并且使得名字更加独立于编码。不过要注意,最初的排序规则名称的集合是平台依赖的。
由libc
提供的默认排序规则直接映射到操作系统中安装的语言环境, 可以使用命令locale -a
列出。如果所需的libc
排序规则与LC_COLLATE
和LC_CTYPE
的值不同, 或者在数据库系统初始化之后, 操作系统中安装了新的语言环境,可以使用CREATE COLLATION命令创建新的排序规则。新的操作系统语言环境也可以使用 pg_import_system_cpllations()函数集中导入。
在任何特定的数据库中,只有使用数据库编码的排序规则是令人感兴趣的。其他pg_collation
中的项会被忽略。因此,一个如de_DE
的被剥离的排序规则名在一个给定数据库中可以被认为是唯一的,即使它在全局上并不唯一。我们推荐使用被剥离的排序规则名,因为在你决定要更改到另一个数据库编码时需要做的事情更少。但是要注意default
、C
和POSIX
排序规则在使用时可以不考虑数据库编码。
PostgreSQL在碰到具有相同属性的不同排序规则对象时会认为它们是不兼容的。因此对于例子:
SELECT a COLLATE "C" < b COLLATE "POSIX" FROM test1;
将会得到一个错误,即使C
和POSIX
排序规则具有相同的行为。因此,我们不推荐混合使用被剥离的和非被剥离的排序规则名。
2.2.2.2. ICU 排序规则
对于ICU,枚举所有可能的语言环境名称并不明智。 ICU为语言环境使用特定的命名系统,但命名语言环境的方法多于实际上不同的语言环境。 initdb
使用ICU API提取一组不同的语言环境以填充初始排序规则集合。 由ICU提供的排序规则是在SQL环境中创建的,名称采用BCP 47语言标记格式, 并附有一个“专用”扩展名-x-icu
, 以将它们与libc语言环境区分开来。
以下是可能创建的一些排序规则的示例:
de-x-icu
德语排序规则,默认变体
de-AT-x-icu
奥地利的德语排序规则,默认变体
(也就是说de-DE-x-icu
或de-CH-x-icu
,但是这种写法,相当于 de-x-icu
。)
und-x-icu (for “undefined”)
ICU “root” 排序规则。 使用它获取合理的语言无关的排序顺序
一些(不常用的)编码不受ICU支持。当数据库编码是其中之一时, 忽略pg_collation
中的ICU排序规则项。 试图使用其中一个将会抛出一个类似“collation "de-x-icu" for encoding "WIN874" does not exist”的错误。
2.2.3. 创建新的排序规则对象
如果标准和预定义的排序规则不够用,用户可以使用SQL命令 CREATE COLLATION创建自己的排序规则对象。
与所有预定于的对象一样,标准和预定义的排序规则在模式 pg_catalog
中。用户定义的排序规则应该在用户模式中创建。 这也确保它们由pg_dump
保存。
2.2.3.1. libc 排序规则
可以像这样创建新的libc排序规则:
CREATE COLLATION german (provider = libc, locale = 'de_DE');
该命令中locale
子句可接受的确切值取决于操作系统。 在类Unix系统上,命令locale -a
将显示一个列表。
由于预定义的libc排序规则已经包含了数据库实例初始化时在操作系统中定义的所有排序规则, 因此通常不需要手动创建新排序规则。如果需要不同的命名系统(在这种情况下, 另请参阅第2.2.3.3节), 或者操作系统已经升级以提供新的区域设置定义(在这种情况下, 另请参阅pg_import_system_collations()), 可能需要手动创建。
2.2.3.2. ICU 排序规则
ICU允许自定义超出由initdb
预加载的基本语言+国家/地区集的排序规则。鼓励用户定义他们自己的排序规则对象, 利用这些条件来满足他们排序行为的需求。请参阅 ICU User Guide | ICU Documentation和 ICU User Guide | ICU Documentation 获取有关ICU区域设置命名的信息。可接受的名称和属性集取决于特定的ICU版本。
这里有些例子:
CREATE COLLATION "de-u-co-phonebk-x-icu" (provider = icu, locale = 'de-u-co-phonebk');
CREATE COLLATION "de-u-co-phonebk-x-icu" (provider = icu, locale = 'de@collation=phonebook');
德语排序规则和电话簿排序规则类型
第一个例子使用“语言标签”根据 BCP 47选择了ICU区域设置。 第二个示例使用传统的ICU特定区域设置语法。第一种风格是首选, 但它不受旧版ICU支持。
请注意,您可以在SQL环境中任意指定排序规则对象的名称。 在这个例子中,我们遵循预定义排序规则使用的命名风格, 而这种风格又遵循BCP 47,但这对于用户定义的排序规则不是必需的。
CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = 'und-u-co-emoji');
CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = '@collation=emoji');
根据Unicode技术标准#51,使用表情符号排序规则类型的根排序规则
观察传统ICU区域命名系统中的方式,根区域设置由空字符串选择。
CREATE COLLATION digitslast (provider = icu, locale = 'en-u-kr-latn-digit');
CREATE COLLATION digitslast (provider = icu, locale = 'en@colReorder=latn-digit');
在拉丁字母后面排列数字。(默认是字母前的数字。)
CREATE COLLATION upperfirst (provider = icu, locale = 'en-u-kf-upper');
CREATE COLLATION upperfirst (provider = icu, locale = 'en@colCaseFirst=upper');
在小写字母前面排列大写字母。(默认是小写字母在前面。)
CREATE COLLATION special (provider = icu, locale = 'en-u-kf-upper-kr-latn-digit');
CREATE COLLATION special (provider = icu, locale = 'en@colCaseFirst=upper;colReorder=latn-digit');
结合上述两个选项。
CREATE COLLATION numeric (provider = icu, locale = 'en-u-kn-true');
CREATE COLLATION numeric (provider = icu, locale = 'en@colNumeric=yes');
数字排序,按数字值排序数字序列,例如: A-21
< A-123
(也称为自然排序)。
参阅Unicode 技术标准 #35 和BCP 47获取详细信息。 可能的排序规则类型(co
子标签)列表可以在 CLDR 仓库中找到。 区域设置浏览器 可以用于检查一个特定区域设置定义的细节。使用k*
子标签的示例至少要求ICU版本54。
请注意,虽然此系统允许创建“忽略大小写”或“忽略重音符” 或类似(使用ks
键)的排序规则, 但PostgreSQL目前不允许这样的排序规则以真正的不区分大小写或不区分重音的方式进行操作。 根据排序规则比较相等但按照字节不相等的任何字符串将根据其字节值进行排序。
注意:
根据设计,ICU几乎可以接受任何字符串作为区域名称, 并使用其文档中描述的后备程序将其与最接近的区域设置相匹配。因此, 如果使用给定ICU安装实际上不支持的功能组合排序规范,则不会有直接反馈。 因此建议创建应用程序级别的测试用例,以检查排序规则定义是否满足需求。
2.2.3.3. 复制排序规则
也可以使用命令CREATE COLLATION 从现有的排序规则创建新的排序规则, 这对于能够在应用程序中使用与操作系统无关的排序规则名称、 创建兼容性名称或以更易读的名称使用ICU提供的排序规则很有帮助。例如:
CREATE COLLATION german FROM "de_DE";
CREATE COLLATION french FROM "fr-x-icu";
三、字符集支持
PostgreSQL里面的字符集支持你能够以各种字符集存储文本,包括单字节字符集,比如 ISO 8859 系列,以及多字节字符集 ,比如EUC(扩展 Unix 编码 Extended Unix Code)、UTF-8 和 Mule 内部编码。所有被支持的字符集都可以被客户端透明地使用,但少数只能在服务器上使用(即作为一种服务器方编码)。默认的字符集是在使用 initdb
初始化你的PostgreSQL数据库集簇时选择的。在你创建一个数据库时可以重载它,因此你可能会有多个数据库并且每一个使用不同的字符集。
但是,一个重要的限制是每个数据库的字符集必须和数据库的LC_CTYPE
(字符分类)和LC_COLLATE
(字符串排序顺序)设置兼容。对于 C
或POSIX
环境,任何字符集都是允许的, 但是对于其他libc提供的环境只有一种字符集可以正确工作(不过, 在Windows上UTF-8编码可以和任何环境配合使用)。 如果您配置了ICU支持,则ICU提供的区域设置可用于大多数服务器端编码, 但不能用于所有服务器端编码。
3.1. 被支持的字符集
表3.1.1 显示了PostgreSQL中可用的字符集。
表 3.1.1. PostgreSQL字符集
名称 | 描述 | 语言 | 是否服务器端? | ICU? | 字节/字符 | 别名 |
---|---|---|---|---|---|---|
BIG5 | Big Five | 繁体中文 | 否 | 否 | 1-2 | WIN950 , Windows950 |
EUC_CN | 扩展UNIX编码-中国 | 简体中文 | 是 | 是 | 1-3 | |
EUC_JP | 扩展UNIX编码-日本 | 日文 | 是 | 是 | 1-3 | |
EUC_JIS_2004 | 扩展UNIX编码-日本, JIS X 0213 | 日文 | 是 | 否 | 1-3 | |
EUC_KR | 扩展UNIX编码-韩国 | 韩文 | 是 | 是 | 1-3 | |
EUC_TW | 扩展UNIX编码-台湾 | 繁体中文,台湾话 | 是 | 是 | 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 | |
KOI8R | KOI8-R | 西里尔语(俄语) | 是 | 是 | 1 | KOI8 |
KOI8U | KOI8-U | 西里尔语(乌克兰语) | 是 | 是 | 1 | |
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内部编码 | 多语种编辑器 | 是 | 否 | 1-4 | |
SJIS | Shift JIS | 日语 | 否 | 否 | 1-2 | Mskanji , ShiftJIS , WIN932 , Windows932 |
SHIFT_JIS_2004 | Shift JIS, JIS X 0213 | 日语 | 否 | 否 | 1-2 | |
SQL_ASCII | 未指定(见文本) | 任意 | 是 | 否 | 1 | |
UHC | 统一韩语编码 | 韩语 | 否 | 否 | 1-2 | WIN949 , Windows949 |
UTF8 | Unicode, 8-bit | 所有 | 是 | 是 | 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
,服务器把字节值0-127根据 ASCII标准解释,而字节值128-255则当作无法解析的字符。如果设置为SQL_ASCII
,就不会有编码转换。因此,这个设置基本不是用来声明所使用的指定编码, 因为这个声明会忽略编码。在大多数情况下,如果你使用了任何非ASCII数据,那么使用 SQL_ASCII
设置都是不明智的,因为PostgreSQL将无法帮助你转换或者校验非ASCII字符。
3.2. 设置字符集
initdb
为一个PostgreSQL集簇定义缺省的字符集(编码)。比如:
initdb -E EUC_JP
把缺省字符集设置为EUC_JP
(用于日文的扩展Unix 编码)。如果你喜欢用长选项字符串,你可以用--encoding
代替-E
。 如果没有给出-E
或者--encoding
选项,initdb
会尝试基于指定的或者默认的区域判断要使用的合适编码。
你可以在数据库创建时指定一个非默认编码,提供的编码应和选择的区域兼容:
createdb -E EUC_KR -T template0 --lc-collate=ko_KR.euckr --lc-ctype=ko_KR.euckr korean
将创建一个使用EUC_KR
字符集和ko_KR
区域的名为korean
的数据库。 另外一种实现方法是使用 SQL 命令:
CREATE DATABASE korean WITH ENCODING 'EUC_KR' LC_COLLATE='ko_KR.euckr' LC_CTYPE='ko_KR.euckr' TEMPLATE=template0;
注意上述命令指定拷贝template0
数据库。在拷贝任何其他数据库时,不能更改从源数据库得来的编码和区域设置,因为这可能会导致破坏数据。
数据库的编码存储在系统目录pg_database
中。你可以使用psql
-l
选项或者\l
命令来查看。
$ psql -l
List of databases
Name | Owner | Encoding | Collation | Ctype | Access Privileges
-----------+----------+-----------+-------------+-------------+-------------------------------------
clocaledb | hlinnaka | SQL_ASCII | C | C |
englishdb | hlinnaka | UTF8 | en_GB.UTF8 | en_GB.UTF8 |
japanese | hlinnaka | UTF8 | ja_JP.UTF8 | ja_JP.UTF8 |
korean | hlinnaka | EUC_KR | ko_KR.euckr | ko_KR.euckr |
postgres | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 |
template0 | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 | {=c/hlinnaka,hlinnaka=CTc/hlinnaka}
template1 | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 | {=c/hlinnaka,hlinnaka=CTc/hlinnaka}
(7 rows)
重要:
在大部分现代操作系统上,PostgreSQL可以判断LC_CTYPE
设置意味着哪一种字符集,并且它强制只有匹配的数据库编码被使用。在老的系统上你需要自己负责确保所使用的编码就是你所选择的区域所期望的。在这里的一个错误很可能导致区域依赖的操作产生奇怪的行为,例如排序。
即使LC_CTYPE
不是C
或POSIX
时,PostgreSQL将允许超级用户使用SQL_ASCII
编码创建数据库。正如前文所述,SQL_ASCII
并不强制存储在数据库中的数据具有任何特定的编码,并且这样这种选择存在着区域依赖的不正当行为的风险。使用这种设置组合的做法已经被废弃,并且在某天将被完全禁止。
3.3. 服务器和客户端之间的自动字符集转换
PostgreSQL支持一些编码在服务器和前端之间的自动编码转换。转换信息在系统目录pg_conversion
中存储。PostgreSQL带着一些预定义的转换,如表3.3.1所示。你可以使用SQL命令CREATE CONVERSION
创建一个新的转换。
表 3.3.1 客户/服务器字符集转换
服务器字符集 | 可用的客户端字符集 |
---|---|
BIG5 | 不支持作为一个服务器编码 |
EUC_CN | EUC_CN, MULE_INTERNAL , UTF8 |
EUC_JP | EUC_JP, MULE_INTERNAL , SJIS , UTF8 |
EUC_JIS_2004 | EUC_JIS_2004, SHIFT_JIS_2004 , 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 | 不支持作为服务端编码 |
KOI8R | KOI8R, ISO_8859_5 , MULE_INTERNAL , UTF8 , WIN866 , WIN1251 |
KOI8U | KOI8U, UTF8 |
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 | 不支持作为一个服务器编码 |
SHIFT_JIS_2004 | 不支持作为一个服务器编码 |
SQL_ASCII | 任意(不会执行任何转换) |
UHC | 不支持作为一个服务器编码 |
UTF8 | 所有支持的编码 |
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中提供函数控制客户端编码。
-
使用
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
是不明智的。
3.4. 进一步阅读
下面是学习各种类型的编码系统的好资源。
CJKV Information Processing: Chinese, Japanese, Korean & Vietnamese Computing
包含对EUC_JP
、 EUC_CN
、EUC_KR
、 EUC_TW
的详细解释。
Unicode联盟的网站。
RFC 3629
UTF-8 (8-bit UCS/Unicode转换格式)在这里定义。