Il limite di lunghezza imposto da varchar(N)
tipi e calcolati dalla length
la funzione è in caratteri, non in byte. Quindi 'abcdef'::char(3)
viene troncato in 'abc'
ma 'a€cdef'::char(3)
viene troncato in 'a€c'
, anche nel contesto di un database codificato come UTF-8, dove 'a€c'
è codificato utilizzando 5 byte.
Se il ripristino di un file dump si è lamentato che 'Mér'
non entrerebbe in un varchar(3)
colonna, che suggerisce che stavi ripristinando un file di dump codificato UTF-8 in un database SQL_ASCII.
Ad esempio, l'ho fatto in un database UTF-8:
create schema so4249745;
create table so4249745.t(key varchar(3) primary key);
insert into so4249745.t values('Mér');
E poi l'ho scaricato e ho provato a caricarlo in un database SQL_ASCII:
pg_dump -f dump.sql --schema=so4249745 --table=t
createdb -E SQL_ASCII -T template0 enctest
psql -f dump.sql enctest
E abbastanza sicuro:
psql:dump.sql:34: ERROR: value too long for type character varying(3)
CONTEXT: COPY t, line 1, column key: "Mér"
Al contrario, se creo il database enctest come codifica LATIN1 o UTF8, viene caricato correttamente.
Questo problema si verifica a causa di una combinazione di dumping di un database con una codifica di caratteri multibyte e del tentativo di ripristinarlo in un database SQL_ASCII. L'utilizzo di SQL_ASCII disabilita sostanzialmente la transcodifica dei dati del client in dati del server e assume un byte per carattere, lasciando ai client la responsabilità dell'utilizzo della corretta mappa dei caratteri. Poiché il file di dump contiene la stringa archiviata come UTF-8, ovvero quattro byte, un database SQL_ASCII lo vede come quattro caratteri e quindi lo considera una violazione del vincolo. E stampa il valore, che poi il mio terminale riassembla come tre caratteri.