Ограничение длины, налагаемое типами 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 воспринимает это как четыре символа и поэтому считает, что это нарушает ограничение. И он выводит значение, которое мой терминал затем собирает в виде трех символов.