Postgresql varchar是否使用unicode字符长度或ASCII字符长度?

时间:2010-11-22 20:07:54

标签: postgresql unicode

我尝试从SQL文件导入数据库转储,并且在将字符串Mér插入定义为varying(3)的字段时插入失败。我没有捕获确切的错误,但它指出了具有varying(3)约束的特定值。

鉴于我认为这对我当时正在做的事情不重要,我只是将值更改为Mer,它有效,我继续前进。

varying字段的限制是否考虑了字节字符串的长度?令我难以置信的是,这是从另一个PostgreSQL数据库转储的。因此,约束如何允许最初写入值是没有意义的。

2 个答案:

答案 0 :(得分:32)

varchar(N)类型强加的长度限制由length函数计算,以字符为单位,而不是字节。因此,'abcdef'::char(3)被截断为'abc',但'a€cdef'::char(3)被截断为'a€c',即使在编码为UTF-8的数据库的上下文中,'a€c'也会被编码使用5个字节。

如果恢复转储文件,则抱怨'Mér'不会进入varchar(3)列,这表示您正在将UTF-8编码的转储文件还原到SQL_ASCII数据库中。

例如,我在UTF-8数据库中执行了此操作:

create schema so4249745;
create table so4249745.t(key varchar(3) primary key);
insert into so4249745.t values('Mér');

然后将其转储并尝试将其加载到SQL_ASCII数据库中:

pg_dump -f dump.sql --schema=so4249745 --table=t
createdb -E SQL_ASCII -T template0 enctest
psql -f dump.sql enctest

果然:

psql:dump.sql:34: ERROR:  value too long for type character varying(3)
CONTEXT:  COPY t, line 1, column key: "Mér"

相比之下,如果我创建数据库enctest作为编码LATIN1或UTF8,它加载正常。

由于将数据库转储为多字节字符编码并尝试将其还原到SQL_ASCII数据库中,因此会出现此问题。使用SQL_ASCII基本上禁止将客户端数据转码为服务器数据,并假定每个字符占一个字节,让客户端负责使用正确的字符映射。由于转储文件包含存储的字符串为UTF-8,即四个字节,因此SQL_ASCII数据库将其视为四个字符,因此将其视为违反约束。它打印出值,然后我的终端重组为三个字符。

答案 1 :(得分:4)

它取决于您在创建数据库时使用的值。 createdb -E UNICODE创建一个Unicode DB,它也应该接受多字节字符并将它们计为一个字符。

您可以使用

psql -l

查看使用了哪种编码。 This page有一个表,其中包含有关每个字符使用的字节数的信息。