よくあるmysqldumpの文字コード問題とか
もともと、2006年ごろに話題になった話で、いまさらすぎるんですけどメモ。
(要するに、使う文字コードを明示的に指定しとけばいいんですけど、デフォルトのまんまなら要らんことしないで欲しかったという愚痴)
- バージョン4.1以降のMySQL付属のmysqldumpコマンドは、デフォルトでutf8の文字コードに変換してdumpしてくれようとする。参照:MySQL :: MySQL 4.1 リファレンスマニュアル :: 9 各国キャラクタセットと Unicode
- 大抵のデータベースは、デフォルトのまんまだとlatin1の文字コード設定になっている
- データベースの文字コード設定がlatin1にもかかわらず、EUC-JPの文字コードのデータが格納されている場合がある
さて、この状態で
$ mysqldump データベース名 > ダンプファイル
とかを実行すると、ダンプファイルの中身が化けてしまう。
それを回避するには、オプションとして-–default-character-set=binary という指定をすれば、変換はしなくなるようです。
$ mysqldump --default-character-set=binary データベース名 > ダンプファイル
(追記)リカバリーの方法
参考記事:The page is not found
DBの文字コード:latin1、登録されたデータの文字コード:euc-jpをmysqldumpでutf8で出力してしまった場合(file1.txtとする)の対処(復元したEUC-JPのファイルをfile2.txtとする)コード。
註:このコードでは、入力はutf8で、出力がlatin1になることは分かると思うが、実は、スクリプトの内部ではutf8で処理が行われている(use utf8の指定のため)。たまたま今回はfile1.txtの文字コードはutf8だが、それ以外の場合は、文字コードの変換が起きる。(これがPerlでよくあるdouble encodingという後述の問題の原因らしい)
#!/bin/env perl use utf8; use Encode; open READ, '<:encoding(utf8)', 'file1.txt'; open WRITE, '>:encoding(latin1)', 'file2.txt'; while(my $data = <READ>){ print WRITE $data; } close WRITE; close READ; exit;
上記のコードでは、ファイル名がプログラムに埋め込まれているので、コマンドとして使いづらいので、標準入力、標準出力を使うと下記のようなコードになる
#!/bin/env perl use utf8; use Encode; binmode STDIN, ':encoding(utf8)'; binmode STDOUT, ':encoding(latin1)'; while(<>) { print $_; }
(追記)dumpしたファイル内のDEFAULT CHARSETの定義によって出力を切り替えるコード
実用にするなら、DEFAULT CHARSETのパターンはもっと精密にしなくてはダメだし、文字コードの変換テーブルも充実させる必要がある。
#/bin/env perl use utf8; use Encode; binmode STDIN, ':encoding(utf8)'; binmode STDOUT, ':bytes'; $outputcharset = 'utf8'; %table = ('latin1', 'latin1', 'sjis', 'shiftjis', 'ujis', 'euc-jp', 'utf8', 'utf8'); while(<>) { $line = $_; print encode($outputcharset, $line); if ($line =~ /^\) ENGINE=[^ ]+ DEFAULT CHARSET=(\w*)[ ;]/) { $outputcharset = $table{$1}; } }
どんな文字コードがサポートされているかは以下参照。
参考記事
- MySQL :: MySQL 5.1 リファレンスマニュアル :: 7.12 mysqldump — データベースバックアッププログラム
- pg_dumpのリストアでエラー − Database Expert − @IT
- MySQL4.1 で dump ファイルが文字化けした際の対処法 | バシャログ。
- Page not found | Overlasting←Perlでありがちな「latin1の文字列だと思い込んで、utf8に自動変換してしまう問題」の対処
MySQLと文字コードの関係は、深い(汗
もっとも、MySQLの文字コードの変換については、データベースの文字コード、mysqldの運用文字コード、サーバOS(system)の文字コードにくわえて、SQLのクライアントの文字コードの間で自動変換してくれるようなので、油断がなりません(汗
現在も、関連の記事を読み中です。
Postgresqlは、とりあえずas isベースのdumpのようです
自分はPostgresqlのpg_dumpコマンドでは、内容が化けてしまったという経験はありません。
Postgresqlの場合、どちらかというとデータベースの文字コードをどうやって指定するか、ということがマニュアルのデータベースの作成の項目にはストレートに書いてありません→。実際には、文字セットサポートのところに記述があります。
EUC-JPの文字コードのデータベースを作成する場合は、データベースに次のようなqueryを発行します。
CREATE DATABASE データベース名 WITH ENCODING 'EUC_JP';
もしくは
CREATE DATABASE データベース名 ENCODING = 'EUC_JP';
コマンドラインでは次の様になります。
createdb -E EUC_KR データベース名