我尝试从sql文件导入数据库转储,并且插入字符串Mér插入到定义为变量(3)的字段时失败.我没有捕获确切的错误,但是它指出了具有变化(3)的约束的具体值.
鉴于我认为这对我当时正在做的事情并不重要,所以我把价值改为了Mer,它的工作,我继续前进.
考虑到字节串的长度,它的极限是否是一个变化的字段?真正令人难以置信的是,这是从另一个Postgresql数据库转储的.所以约束可以允许最初写入值是没有意义的.
由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');
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数据库将其视为四个字符,因此将其视为违反约束.它打印出的值,我的终端然后重新组合为三个字符.