由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数据库将其视为四个字符,因此将其视为违反约束。它打印出我的终端重新组装为三个字符的值。
字符编码是每个数据库的东西。 PostgreSQL支持各种编码,但对于给定的数据库只能有一种编码有效。也许你的源数据库被设置为与目标不同的编码。 – Pointy 2010-11-22 20:14:44