Pas de NULL, mais séquence d'octets non valide pour le codage "UTF8": 0x00

12

J'ai passé les 8 dernières heures à essayer d'importer la sortie de 'mysqldump --compatible = postgresql' dans PostgreSQL 8.4.9, et j'ai déjà lu au moins 20 threads différents ici et ailleurs sur ce problème spécifique, mais je n'ai trouvé aucun vraie réponse utilisable qui fonctionne.

Données MySQL 5.1.52 vidées:

mysqldump -u root -p --compatible=postgresql --no-create-info --no-create-db --default-character-set=utf8 --skip-lock-tables rt3 > foo

Serveur PostgreSQL 8.4.9 comme destination

Le chargement des données avec 'psql -U rt_user -f foo' rapporte (beaucoup d'entre eux, voici un exemple):

psql:foo:29: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
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".

Selon ce qui suit, il n'y a pas de caractères NULL (0x00) dans le fichier d'entrée.

database-dumps:rcf-temp1# sed 's/\x0/ /g' < foo > nonulls
database-dumps:rcf-temp1# sum foo nonulls
04730 2545610 foo
04730 2545610 nonulls
database-dumps:rcf-temp1# rm nonulls

De même, une autre vérification avec Perl ne montre aucun NULL:

database-dumps:rcf-temp1# perl -ne '/\000/ and print;' foo
database-dumps:rcf-temp1#

Comme l'indique le "CONSEIL" dans l'erreur, j'ai essayé de toutes les manières possibles de définir "client_encoding" sur "UTF8", et je réussis, mais cela n'a aucun effet sur la résolution de mon problème.

database-dumps:rcf-temp1# psql -U rt_user --variable=client_encoding=utf-8 -c "SHOW client_encoding;" rt3
 client_encoding
-----------------
 UTF8
(1 row)

database-dumps:rcf-temp1#

Parfait, pourtant:

database-dumps:rcf-temp1# psql -U rt_user -f foo --variable=client_encoding=utf-8 rt3
...
psql:foo:29: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
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".
...

À l'exception de la bonne réponse «Selon Hoyle», qui serait fantastique à entendre, et sachant que je ne me soucie vraiment pas de conserver des caractères non ASCII pour ces données rarement référencées, quelles suggestions avez-vous?

Mise à jour: j'obtiens la même erreur avec une version ASCII uniquement du même fichier de vidage au moment de l'importation. Vraiment ahurissant:

database-dumps:rcf-temp1# # convert any non-ASCII character to a space
database-dumps:rcf-temp1# perl -i.bk -pe 's/[^[:ascii:]]/ /g;' mysql5-dump.sql
database-dumps:rcf-temp1# sum mysql5-dump.sql mysql5-dump.sql.bk
41053 2545611 mysql5-dump.sql
50145 2545611 mysql5-dump.sql.bk
database-dumps:rcf-temp1# cmp mysql5-dump.sql mysql5-dump.sql.bk
mysql5-dump.sql mysql5-dump.sql.bk differ: byte 1304850, line 30
database-dumps:rcf-temp1# # GOOD!
database-dumps:rcf-temp1# psql -U postgres -f mysql5-dump.sql --variable=client_encoding=utf-8 rt3
...
INSERT 0 416
psql:mysql5-dump.sql:30: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 455
INSERT 0 424
INSERT 0 483
INSERT 0 447
INSERT 0 503
psql:mysql5-dump.sql:36: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 502
INSERT 0 507
INSERT 0 318
INSERT 0 284
psql:mysql5-dump.sql:41: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 382
INSERT 0 419
INSERT 0 247
psql:mysql5-dump.sql:45: ERROR:  invalid byte sequence for encoding "UTF8": 0x00
HINT:  This error can also happen if the byte sequence does not match the encod.
INSERT 0 267
INSERT 0 348
^C

L'un des tableaux en question est défini comme:

                                        Table "public.attachments"
     Column      |            Type             |                        Modifie
-----------------+-----------------------------+--------------------------------
 id              | integer                     | not null default nextval('atta)
 transactionid   | integer                     | not null
 parent          | integer                     | not null default 0
 messageid       | character varying(160)      |
 subject         | character varying(255)      |
 filename        | character varying(255)      |
 contenttype     | character varying(80)       |
 contentencoding | character varying(80)       |
 content         | text                        |
 headers         | text                        |
 creator         | integer                     | not null default 0
 created         | timestamp without time zone |
Indexes:
    "attachments_pkey" PRIMARY KEY, btree (id)
    "attachments1" btree (parent)
    "attachments2" btree (transactionid)
    "attachments3" btree (parent, transactionid)

Je n'ai pas la liberté de changer le type pour aucune partie du schéma DB. Cela interromprait probablement les futures mises à niveau du logiciel , etc.

La colonne susceptible de poser problème est le «contenu» de type «texte» (peut-être aussi dans d'autres tableaux). Comme je le sais déjà par des recherches précédentes, PostgreSQL n'autorisera pas NULL dans les valeurs de 'texte'. Cependant, veuillez voir ci-dessus où sed et Perl ne montrent aucun caractère NULL, puis plus bas où je supprime tous les caractères non ASCII de tout le fichier de vidage, mais il barfs toujours.

jblaine
la source
2
À quoi ressemble la ligne 29 de votre fichier de vidage? Quelque chose comme ça head -29 foo | tail -1 | cat -vpourrait être utile.
mu est trop court
Quelle est la définition de la table affectée et à quoi ressemble la ligne incriminée?
tscho
C'est ~ 1 Mo de données d'entreprise. Je comprends bien sûr où vous vous dirigez. Voici la fin de cette ligne de pensée (veuillez pardonner mon français à la fin de l'essentiel / coller): gist.github.com/1525788
jblaine
tscho: Comme indiqué, cet exemple de ligne d'erreur est l'une des centaines de ces erreurs.
jblaine

Réponses:

3

Un ou plusieurs de ces champs de caractères / texte PEUVENT avoir 0x00 pour son contenu.

Essayez ce qui suit:

SELECT * FROM rt3 where some_text_field = 0x00 LIMIT 1;

Si cela renvoie une seule ligne, essayez de mettre à jour ces champs de caractères / texte avec:

UPDATE rt3 SET some_text_field = '' WHERE some_text_field = 0x00;

Ensuite, essayez un autre MYSQLDUMP ... (et la méthode d'importation PostgreSQL).

Farley Inglis
la source
Cela m'a aidé à trouver mes caractères nuls errants, même si je devais les utiliser colname LIKE concat('%', 0x00, '%'). Je les ai trouvés dans des champs contenant des tableaux PHP sérialisés.
cimmanon
5

J'ai eu le même problème avec MySQL version 5.0.51 et Postgres version 9.3.4.0. J'ai résolu le problème de la "séquence d'octets invalide pour l'encodage" UTF8 ": 0x00" après avoir vu le commentaire de Daniel Vérité selon lequel "mysqldump en mode postgresql videra les octets nuls en tant que \ 0 dans les chaînes, donc vous voudrez probablement rechercher cette séquence de caractères."

Effectivement, un grep a finalement révélé les caractères NULL.

grep \\\\0 dump.sql

J'ai remplacé les caractères NULL à l'aide de la commande suivante

sed -i BAK 's/\\0//g' dump.sql

Postgres a ensuite réussi à charger dump.sql

Jadence
la source
4

Vous pouvez obtenir cette erreur sans octet NULL ni caractère non ascii dans le fichier. Exemple dans une base de données utf8:

select E'ab\0cd';

donnera:

ERREUR: séquence d'octets invalide pour le codage "UTF8": 0x00 CONSEIL: Cette erreur peut également se produire si la séquence d'octets ne correspond pas au codage attendu par le serveur, qui est contrôlé par "client_encoding".

mysqldump en mode postgresql videra les octets nuls en tant que \ 0 dans les chaînes, donc vous voudrez probablement rechercher cette séquence de caractères.

Daniel Vérité
la source
0

Je me souviens à moitié d'un problème comme celui-ci. Je pense que j'ai fini par migrer le schéma, puis vider les données au format csv et charger les données du fichier csv. Je me souviens avoir dû mettre à jour le fichier csv (en utilisant des outils Unix comme sed ou unixtodos) ou utiliser open office calc (excell) pour corriger certains éléments qui étaient des erreurs lors de l'étape d'importation - cela pourrait être aussi simple que d'ouvrir et de réenregistrer le fichier.

adam f
la source