我try 从SQL文件导入数据库转储,但在将字符串Mér
插入定义为varying(3)
的字段时,插入失败.我没有捕捉到确切的错误,但它指向了特定的值,限制为varying(3)
.
考虑到我认为这对我当时正在做的事情并不重要,我只是将值改为Mer
,它起了作用,我继续前进.
varying
字段的限制是否考虑了字节字符串的长度?真正让我吃惊的是,这是从另一个PostgreSQL数据库中转储的.因此,约束如何允许最初写入值是没有意义的.
我try 从SQL文件导入数据库转储,但在将字符串Mér
插入定义为varying(3)
的字段时,插入失败.我没有捕捉到确切的错误,但它指向了特定的值,限制为varying(3)
.
考虑到我认为这对我当时正在做的事情并不重要,我只是将值改为Mer
,它起了作用,我继续前进.
varying
字段的限制是否考虑了字节字符串的长度?真正让我吃惊的是,这是从另一个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');
然后将其转储并try 将其加载到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,那么它的加载很好.
出现此问题的原因是,将数据库转储为多字节字符编码,然后try 将其恢复为SQL_ASCII数据库.使用SQL_ASCII基本上会禁用客户端数据到服务器数据的转码,并假设每个字符有一个字节,让客户端负责使用正确的字符映射.由于转储文件包含存储为UTF-8的字符串,即四个字节,因此SQL_ASCII数据库将其视为四个字符,因此认为它违反了约束.它打印出值,然后我的终端将其重新组合为三个字符.