Comment résoudre les erreurs de copie de séquence d'octets non valides UTF8 lors d'une restauration, lorsque la base de données source est codée en UTF8?

17

On m'a confié la tâche de migrer une base de données PostgreSQL 8.2.x vers un autre serveur. Pour ce faire, j'utilise pgAdmin 1.12.2 (sur Ubuntu 11.04 d'ailleurs) et j'utilise la sauvegarde et la restauration en utilisant le format personnalisé / compressé (.backup) et l'encodage UTF8.

La base de données d'origine est en UTF8, comme ceci:

-- Database: favela

-- DROP DATABASE favela;

CREATE DATABASE favela
  WITH OWNER = favela
       ENCODING = 'UTF8'
       TABLESPACE = favela
       CONNECTION LIMIT = -1;

Je crée cette base de données exactement comme ça sur le serveur de destination. Mais lorsque je restaure la base de données à partir du fichier .backup à l'aide de l'option de restauration, cela me donne certaines de ces erreurs:

pg_restore: restoring data for table "arena"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 2173; 0 35500 TABLE DATA arena favela
pg_restore: [archiver (db)] COPY failed: ERROR:  invalid byte sequence for encoding "UTF8": 0xe3a709
HINT:  This error can also happen if the byte sequence does not match the encoding expected by the server, which is controlled by "client_encoding".
CONTEXT:  COPY arena, line 62

Lorsque je vérifie quel enregistrement a déclenché cette erreur, en fait, certains champs vartext ont des caractères diacritiques comme ç (utilisé en portugais, par exemple, "caça"), et lorsque je les supprime manuellement du texte dans les enregistrements, l'erreur passe à l'enregistrement suivant cela les a - puisque lorsque la copie a une erreur, elle cesse d'insérer des données sur cette table. Et je ne veux pas les remplacer manuellement un par un pour y parvenir.

Mais c'est un peu étrange car avec UTF8 il ne devrait pas y avoir ce genre de problèmes, non?

Je ne sais pas comment ils y sont arrivés en premier lieu. Je ne fais que migrer la base de données, et je suppose que la base de données était en quelque sorte comme dans LATIN1, puis a été incorrectement modifiée en UTF8.

Existe-t-il un moyen de vérifier si une table / base de données contient des séquences UTF8 non valides? Ou n'importe quel moyen pour appliquer / reconvertir ces caractères en UFT8 afin que je ne rencontre aucun problème lorsque j'exécute la restauration?

Merci d'avance.

pedrosanta
la source

Réponses:

8

En fouillant sur Internet, j'ai vu que c'est un problème assez courant. La solution courante consiste à utiliser le vidage au format texte brut et à le faire passer par iconv pour corriger l'encodage.

Voici plus d'informations à ce sujet.

Richard
la source
utilisez iconv pour convertir en UTF-32 en supprimant les symboles invalides, puis de nouveau en UTF-8, une conversion UTF-8 en UTF-8 n'attrapera pas tous les mauvais points de code. (par exemple, orphelins de substitution)
Jasen
7

"Je ne sais pas comment ils y sont arrivés en premier lieu"

Cela aurait pu se produire comme décrit ici - bien que cela génère une erreur sur 8.4:

Si vous créez une table avec n'importe quel type de texte (c'est-à-dire texte, varchar (10), etc.), vous pouvez insérer une séquence d'octets invalide dans ce champ en utilisant des échappements octaux.

Par exemple, si vous avez une base de données encodée en UTF8, vous pouvez faire:

=> CRÉER TABLE foo (t TEXT);

=> INSÉRER DANS foo VALEURS (E '\ 377');

Maintenant, si vous copiez le tableau, vous ne pouvez pas copier le fichier résultant. Cela signifie que vos sauvegardes pg_dump ne pourront pas être restaurées. La seule façon de récupérer vos données est de rééchapper à cette valeur.

Il y a un bon article sur cet excellent blog sur les problèmes généraux et quelques façons de les traiter

Jack Douglas
la source
1

C'est probablement avec l'encodage par défaut utilisé dans votre environnement Unix / Linux. Pour vérifier quel encodage est actuellement celui par défaut, exécutez ce qui suit:

$ echo $LANG
en_US

Dans ce cas, nous pouvons clairement voir qu'il ne s'agit pas d'un encodage UTF-8, celui sur lequel s'appuie la commande de copie.

Donc, pour résoudre ce problème, nous avons simplement défini la variable LANG dans l'exemple comme suit:

$ export LANG=en_US.UTF-8

Remarque: cela ne sera disponible que pour la session en cours. Ajoutez-le à ~ / .bashrc ou similaire pour le rendre disponible au démarrage de toute future session shell.

Référence

arulraj.net
la source
1

Je ne recommande pas d'exécuter aveuglément iconv sur le vidage de texte brut car il peut convertir des caractères valides (par exemple: des caractères chinois) en d'autres caractères. Il est préférable de trouver le caractère UTF8 non valide en exécutant la commande ci-dessous.

grep -naxv '.*' plain_text_dump.sql

puis exécutez iconv sur les données particulières. Consultez ce document pour une explication détaillée étape par étape .

Nijil
la source