วิธีแก้ข้อผิดพลาดการคัดลอกลำดับไบต์ UTF8 ที่ไม่ถูกต้องในการกู้คืนเมื่อฐานข้อมูลต้นทางถูกเข้ารหัสใน UTF8


17

ฉันได้รับมอบหมายให้ย้ายฐานข้อมูล PostgreSQL 8.2.x ไปยังเซิร์ฟเวอร์อื่น เมื่อต้องการทำสิ่งนี้ฉันใช้ pgAdmin 1.12.2 (บน Ubuntu 11.04 โดยวิธี) และใช้การสำรองข้อมูลและคืนค่าโดยใช้รูปแบบที่กำหนดเอง / บีบอัด (.backup) และการเข้ารหัส UTF8

ฐานข้อมูลดั้งเดิมอยู่ใน UTF8 ดังนี้:

-- Database: favela

-- DROP DATABASE favela;

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

ฉันกำลังสร้างฐานข้อมูลนี้อย่างนี้บนเซิร์ฟเวอร์ปลายทาง แต่เมื่อฉันกู้คืนฐานข้อมูลจากไฟล์. backup โดยใช้ตัวเลือก Restore มันทำให้ฉันมีข้อผิดพลาดบางอย่าง:

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

เมื่อฉันตรวจสอบว่าระเบียนใดที่ทริกเกอร์ข้อผิดพลาดนี้อันที่จริงแล้วบางฟิลด์ vartext มีอักขระกำกับเช่นç (ใช้ในภาษาโปรตุเกสเช่น "caça") และเมื่อฉันลบพวกเขาออกจากข้อความในบันทึกข้อผิดพลาดที่ผ่านไปยังระเบียนถัดไป ที่มีพวกเขา - เนื่องจากเมื่อการคัดลอกมีข้อผิดพลาดมันจะหยุดการแทรกข้อมูลในตารางนี้ และฉันไม่ต้องการแทนที่ด้วยตนเองทีละคนเพื่อให้บรรลุนี้

แต่มันค่อนข้างแปลกเพราะ UTF8 ไม่น่าจะมีปัญหาแบบนี้ใช่มั้ย

ฉันไม่รู้ว่าพวกเขาไปถึงที่นั่นได้อย่างไรตั้งแต่แรก ฉันเพิ่งย้ายฐานข้อมูลและฉันคิดว่าอย่างใดฐานข้อมูลเป็นเหมือนใน LATIN1 แล้วเปลี่ยนเป็น UTF8 อย่างไม่เหมาะสม

มีวิธีใดบ้างในการตรวจสอบว่าตาราง / ฐานข้อมูลมีลำดับ UTF8 ที่ไม่ถูกต้องหรือไม่ หรือวิธีใด ๆ ในการบังคับใช้ / เปลี่ยนอักขระเหล่านี้กลับเป็น UFT8 ดังนั้นฉันจึงไม่พบปัญหาใด ๆ เมื่อฉันทำการกู้คืน

ขอบคุณล่วงหน้า.

คำตอบ:


8

เมื่อขุดไปทั่วอินเทอร์เน็ตฉันได้เห็นแล้วว่านี่เป็นปัญหาที่พบได้บ่อย วิธีแก้ปัญหาทั่วไปคือการใช้การถ่ายโอนข้อมูลรูปแบบข้อความธรรมดาและป้อนผ่าน iconv เพื่อแก้ไขการเข้ารหัส

นี่คือข้อมูลเพิ่มเติมเกี่ยวกับสิ่งนั้น


ใช้ iconv เพื่อแปลงเป็น UTF-32 ทิ้งสัญลักษณ์ที่ไม่ถูกต้องแล้วกลับไปที่ UTF-8 การแปลง UTF-8 เป็น UTF-8 จะไม่จับจุดรหัสที่ไม่ดีทั้งหมด (เช่นตัวแทนเด็กกำพร้า)
Jasen

7

"ฉันไม่รู้ว่าพวกเขาไปถึงที่นั่นได้อย่างไรตั้งแต่แรก"

อาจเกิดขึ้นตามที่อธิบายไว้ที่นี่ - แม้ว่าสิ่งนี้จะสร้างข้อผิดพลาดใน 8.4:

หากคุณสร้างตารางที่มีประเภทข้อความใด ๆ (เช่นข้อความ, varchar (10), ฯลฯ ) จากนั้นคุณสามารถแทรกลำดับไบต์ที่ไม่ถูกต้องลงในฟิลด์นั้นโดยใช้การยกเว้นฐานแปด

ตัวอย่างเช่นหากคุณมีฐานข้อมูลที่เข้ารหัส UTF8 คุณสามารถทำได้:

=> สร้างตาราง foo (t TEXT);

=> INSERT INTO foo VALUES (E '\ 377');

ตอนนี้หากคุณคัดลอกตารางออกมาคุณจะไม่สามารถคัดลอกไฟล์ผลลัพธ์กลับมาได้นั่นหมายความว่าการสำรองข้อมูล pg_dump ของคุณจะไม่สามารถกู้คืนได้ วิธีเดียวที่จะนำข้อมูลของคุณกลับมาใช้ใหม่คือการหลีกเลี่ยงค่านั้น

มีโพสต์ที่ดีในบล็อกที่ยอดเยี่ยมนี้เกี่ยวกับปัญหาทั่วไปและวิธีการจัดการกับพวกเขา


1

อาจเป็นเพราะการเข้ารหัสเริ่มต้นที่ใช้ในสภาพแวดล้อม Unix / Linux ของคุณ ในการตรวจสอบการเข้ารหัสที่ปัจจุบันเป็นค่าเริ่มต้นให้ดำเนินการดังต่อไปนี้:

$ echo $LANG
en_US

ในกรณีนี้เราสามารถเห็นได้อย่างชัดเจนว่าไม่ใช่การเข้ารหัส UTF-8 ซึ่งเป็นสิ่งที่คำสั่ง copy อาศัย

ดังนั้นเพื่อแก้ไขปัญหานี้เราเพิ่งตั้งค่าตัวแปร LANG เป็นตัวอย่างดังต่อไปนี้:

$ export LANG=en_US.UTF-8

หมายเหตุ: จะมีให้เฉพาะในเซสชันปัจจุบันเท่านั้น เพิ่มลงใน ~ / .bashrc หรือคล้ายกันเพื่อให้พร้อมใช้งานเมื่อเริ่มต้นเซสชันเชลล์ใด ๆ ในอนาคต

การอ้างอิง


1

ฉันไม่แนะนำให้ใช้ iconv ที่สุ่มสี่สุ่มห้าในการถ่ายโอนข้อมูลข้อความธรรมดาเพราะมันอาจแปลงอักขระที่ถูกต้อง (เช่น: ตัวอักษรจีน) เป็นอักขระอื่น มันจะดีกว่าที่จะหาตัวอักษร UTF8 ที่ไม่ถูกต้องโดยใช้คำสั่งด้านล่าง

grep -naxv '.*' plain_text_dump.sql

จากนั้นเรียกใช้ iconv บนข้อมูลเฉพาะ ตรวจสอบเอกสารนี้สำหรับขั้นตอนรายละเอียดโดยคำอธิบายขั้นตอน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.