2010-11-22 105 views
17

我试图从SQL文件导入数据库转储,并且在将字符串Mér插入定义为varying(3)的字段时,插入失败。我没有捕获确切的错误,但它指出具有varying(3)约束的具体值。Postgresql varchar使用unicode字符长度或ASCII字符长度计数吗?

鉴于我认为这不重要,我当时正在做什么,我只是将其值改为Mer,它的工作,我继续前进。

是一个varying字段与其限制考虑到字节字符串的长度?我的脑海里真是令人难以置信的是,这是从另一个PostgreSQL数据库转储出来的。因此,约束如何允许最初写入该值是没有意义的。

+6

字符编码是每个数据库的东西。 PostgreSQL支持各种编码,但对于给定的数据库只能有一种编码有效。也许你的源数据库被设置为与目标不同的编码。 – Pointy 2010-11-22 20:14:44

回答

26

varchar(N)类型施加的长度限制和由length函数计算的长度限制是以字符而不是字节计算的。因此,'abcdef'::char(3)被截断为'abc',但即使在编码为UTF-8的数据库的上下文中,'a€cdef'::char(3)也被截断为'a€c',其中'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数据库将其视为四个字符,因此将其视为违反约束。它打印出我的终端重新组装为三个字符的值。

4

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

您可以使用

的psql -l

来查看使用了哪种编码。 页面http://www.postgresql.org/docs/8.4/interactive/multibyte.html有一个表格,其中包含每个字符使用多少个字节的信息。