Mientras importaba una base de datos Postgres desde un dump SQL en un nuevo servidor me topé con este inconveniente:
ERROR: encoding UTF8 does not match locale es_ES.iso88591 DETAIL: The chosen LC_CTYPE setting requires encoding LATIN1.
La codificación el template no coincide con el locale "es_ES.iso88591" y se requiere utilizar "LATIN1".
Las instrucciones SQL dentro del dump que causan este inconveniente son las siguientes:
SET client_encoding = 'LATIN1'; CREATE DATABASE pepe WITH TEMPLATE = template0 OWNER = postgres LC_COLLATE = 'es_ES.iso88591' LC_CTYPE = 'es_ES.iso88591';
Se observa que se trata de crear la base de datos "pepe" utilizando el conjunto de caracteres "es_ES.iso88591". Sin embargo, la codificación utilizada por el sistema operativo es UTF-8:
postgres@debian:~$ locale LANG=en_US.UTF-8 LANGUAGE= LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL=
Al mismo tiempo, la codificación del "template0" (plantilla utilizada para la creación de la base de datos en el servidor PostgreSQL) también es UTF-8:
postgres@debian:~$ psql -c "\l" List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- postgres | postgres | UTF8 | es_AR.UTF-8 | es_AR.UTF-8 | template0 | postgres | UTF8 | es_AR.UTF-8 | es_AR.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | es_AR.UTF-8 | es_AR.UTF-8 | postgres=CTc/postgres+ | | | | | =c/postgres (3 rows)
Aquí hay dos problemas: tanto el locale del sistema operativo, como la codificación del template no coinciden con el conjunto de caracteres con el que se pretende crear la nueva base de datos.
A fin de evitar errores en la codificación (que afectan principalmente a la visualización y presentación de los datos) es recomendable mantener la consistencia entre las codificaciones (conjuntos de caracteres) usadas por el sistema operativo, plantillas y bases de datos.
El sistema operativo (en este caso Debian) tiene disponibles los siguientes locales:
postgres@debian:~$ locale -a C C.UTF-8 en_US.utf8 es_AR es_AR.iso88591 es_AR.utf8 es_ES es_ES.iso88591 es_ES.utf8 POSIX spanish
Si el locale necesario no está listado, es posible generarlo utilizando locale-gen
.
Editar el archivo de configuración /etc/default/locale
para cambiar el locale a nivel sistema operativo:
postgres@debian:~$ nano /etc/default/locale
Establecer el locale deseado y guardar los cambios:
# File generated by update-locale #LANG="en_US.UTF-8" LANG="es_ES.iso88591" LANGUAGE= LC_CTYPE="es_ES.iso88591" LC_NUMERIC="es_ES.iso88591" LC_TIME="es_ES.iso88591" LC_COLLATE="es_ES.iso88591" LC_MONETARY="es_ES.iso88591" LC_MESSAGES="es_ES.iso88591" LC_PAPER="es_ES.iso88591" LC_NAME="es_ES.iso88591" LC_ADDRESS="es_ES.iso88591" LC_TELEPHONE="es_ES.iso88591" LC_MEASUREMENT="es_ES.iso88591" LC_IDENTIFICATION="es_ES.iso88591" LC_ALL=
Al iniciar sesión nuevamente, se observa el nuevo locale. Tener en cuenta que esto puede afectar la correcta visualización en nombres de directorios, archivos y su contenido.
root@debian:~# locale LANG=es_ES.iso88591 LANGUAGE= LC_CTYPE=es_ES.iso88591 LC_NUMERIC=es_ES.iso88591 LC_TIME=es_ES.iso88591 LC_COLLATE=es_ES.iso88591 LC_MONETARY=es_ES.iso88591 LC_MESSAGES=es_ES.iso88591 LC_PAPER=es_ES.iso88591 LC_NAME=es_ES.iso88591 LC_ADDRESS=es_ES.iso88591 LC_TELEPHONE=es_ES.iso88591 LC_MEASUREMENT=es_ES.iso88591 LC_IDENTIFICATION=es_ES.iso88591 LC_ALL=
El siguiente paso consiste en cambiar la codificación y collation del template.
Es posible cambiar el encoding del template eliminándolo y creándolo nuevamente mediante sentencias SQL. Sin embargo, en el caso de una importación (donde la instancia está aún vacía) una solución simple y rápida consiste en detener el servidor PostgreSQL, eliminar la instancia (rm -fr
al directorio que contiene la instancia) y crearla nuevamente corriendo initdb
.
Esto se debe a que la codificación de los templates se toma por defecto de la codificación utilizada por el sistema operativo. De esta forma, tanto el conjunto de caracteres como la collation quedan consistentes a nivel sistema operativo y bases de datos:
postgres@debian:~$ psql -c "\l" List of databases Name | Owner | Encoding | Collation | Ctype | Access privileges -----------+----------+----------+----------------+----------------+----------------------- postgres | postgres | LATIN1 | es_ES.iso88591 | es_ES.iso88591 | template0 | postgres | LATIN1 | es_ES.iso88591 | es_ES.iso88591 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | LATIN1 | es_ES.iso88591 | es_ES.iso88591 | postgres=CTc/postgres+ | | | | | =c/postgres (3 rows)
Luego se procede con la importación sin errores.