Подсчитывает ли Postgresql varchar длину символа Юникод или длину символа ASCII? - PullRequest
21 голосов
/ 22 ноября 2010

Я попытался импортировать дамп базы данных из файла SQL, и вставка не удалась при вставке строки Mér в поле, определенное как varying(3). Я не уловил точную ошибку, но она указала на это конкретное значение с ограничением varying(3).

Учитывая, что я считал это неважным для того, что я делал в то время, я просто изменил значение на Mer, оно сработало и я пошел дальше.

Является ли поле varying с пределом, учитывающим длину строки байтов? Что меня действительно поражает, так это то, что это было сброшено из другой базы данных PostgreSQL. Так что не имеет смысла, как ограничение может позволить изначально записать значение.

Ответы [ 2 ]

32 голосов
/ 15 марта 2011

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

4 голосов
/ 15 марта 2011

Это зависит от того, какое значение вы использовали при создании базы данных. createdb -E UNICODE создает базу данных Unicode, которая также должна принимать многобайтовые символы и считать их как один символ.

Вы можете использовать

psql -l

чтобы увидеть, какая кодировка была использована. Эта страница содержит таблицу с информацией о том, сколько байтов на символ используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...