El límite de longitud impuesto por varchar(N)
tipos y calculado por la length
la función está en caracteres, no en bytes. Entonces 'abcdef'::char(3)
se trunca a 'abc'
pero 'a€cdef'::char(3)
se trunca a 'a€c'
, incluso en el contexto de una base de datos codificada como UTF-8, donde 'a€c'
se codifica usando 5 bytes.
Si restaurar un archivo de volcado se quejó de que 'Mér'
no entraría en un varchar(3)
columna, lo que sugiere que estaba restaurando un archivo de volcado codificado en 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 descargué esto e intenté 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 por supuesto:
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 codificando LATIN1 o UTF8, se carga bien.
Este problema surge debido a una combinación de volcar una base de datos con una codificación de caracteres de varios bytes e intentar restaurarla en una base de datos SQL_ASCII. El uso de SQL_ASCII básicamente deshabilita la transcodificación de datos del cliente a datos del servidor y asume un byte por carácter, dejando que los clientes asuman la responsabilidad de usar el mapa de caracteres correcto. Dado que el archivo de volcado contiene la cadena almacenada como UTF-8, es decir, cuatro bytes, una base de datos SQL_ASCII ve eso como cuatro caracteres y, por lo tanto, considera que viola la restricción. E imprime el valor, que luego mi terminal vuelve a ensamblar como tres caracteres.