2010-11-22 15 views
17

Intenté importar un volcado de base de datos desde un archivo SQL y la inserción falló al insertar la cadena Mér en un campo definido como varying(3). No capturé el error exacto, pero apuntó a ese valor específico con la restricción varying(3).¿El valor de varchar de Postgresql se basa en la longitud del carácter unicode o la longitud del carácter ASCII?

Dado que consideré que esto no era importante para lo que estaba haciendo en ese momento, simplemente cambié el valor a Mer, funcionó, y seguí adelante.

¿Es un campo varying con su límite teniendo en cuenta la longitud de la cadena de bytes? Lo que realmente perturba mi mente es que esto fue abandonado de otra base de datos PostgreSQL. Por lo tanto, no tiene sentido cómo una restricción podría permitir que el valor se escriba inicialmente.

+6

La codificación de caracteres es una cuestión por base de datos. PostgreSQL admite todo tipo de codificaciones, pero solo una puede tener efecto para una base de datos determinada.Quizás su base de datos de origen fue configurada para una codificación diferente a la del objetivo. – Pointy

+0

Busque este texto (centro de la página) en el manual. Parece sugerir que la codificación determina el número de caracteres requeridos: el requisito de almacenamiento para los datos de estos tipos es de 4 bytes más la cadena real ... [con codificaciones de caracteres multibyte] (http://www.postgresql.org/docs). /8.0/interactive/datatype-character.html) el número de caracteres y bytes puede ser bastante diferente ... – frayser

+0

Comentario de Upotted Pointy: lo seleccionaría si fuera la respuesta. – bennylope

Respuesta

26

El límite de longitud impuesto por los tipos varchar(N) y calculado por la función length está en caracteres, no en bytes. Por lo tanto, 'abcdef'::char(3) se trunca en 'abc', pero 'a€cdef'::char(3) se trunca en 'a€c', incluso en el contexto de una base de datos codificada como UTF-8, donde 'a€c' se codifica utilizando 5 bytes.

Si la restauración de un archivo de volcado se quejaron de que 'Mér' no entraría en una columna varchar(3), que sugiere que estaban restaurando un archivo de volcado codificado UTF-8 en una base de datos SQL_ASCII.

Por ejemplo, hice esto en una base de datos UTF-8:

create schema so4249745; 
create table so4249745.t(key varchar(3) primary key); 
insert into so4249745.t values('Mér'); 

Y luego arrojar esto y trataron de cargarlo en una base de datos SQL_ASCII:

pg_dump -f dump.sql --schema=so4249745 --table=t 
createdb -E SQL_ASCII -T template0 enctest 
psql -f dump.sql enctest 

y bastante seguro:

psql:dump.sql:34: ERROR: value too long for type character varying(3) 
CONTEXT: COPY t, line 1, column key: "Mér" 

Por el contrario, si creo la base de datos enctest como codificación LATIN1 o UTF8, se carga bien.

Este problema se produce debido a una combinación de dumping una base de datos con una codificación de caracteres de varios bytes, y tratando de restaurar en una base de datos SQL_ASCII. El uso de SQL_ASCII básicamente deshabilita la transcodificación de los datos del cliente a los datos del servidor y asume un byte por carácter, dejando que los clientes asuman la responsabilidad de utilizar el mapa de caracteres correcto. Dado que el archivo de volcado contiene la cadena almacenada como UTF-8, es decir, cuatro bytes, por lo que una base de datos SQL_ASCII ve que como cuatro caracteres, y por lo tanto la considera como una violación de la restricción. E imprime el valor, que mi terminal vuelve a ensamblar como tres caracteres.

4

Depende del valor que utilizó cuando creó la base de datos. createdb -E UNICODE crea un db unicode que también debe aceptar caracteres multibyte y contarlos como un solo carácter.

Puede utilizar

psql -l

a ver qué codificación se utilizó. La página http://www.postgresql.org/docs/8.4/interactive/multibyte.html tiene una tabla que incluye información sobre cuántos bytes por carácter se utilizan.

Cuestiones relacionadas