http://wota.jp/ac/?date=20061011
http://blog.cheki.net/archives/349
http://www.y2sunlight.com/ground/?MySQL4.1%2F9.MySQL%A4%CE%BC%C2%B8%B3%2F1.%A5%B7%A5%B9%A5%C6%A5%E0%CA%D1%BF%F4%A4%CE%BB%B2%BE%C8%A4%C8%CA%D1%B9%B9#content_1_8
ビンゴ中西のほげほげ2007年11月11日
上から順番に読んでいけばだいたい解決する。はず。
二行でまとめると、
文字コード関連で重要な設定は default-character-set と skip-character-set-client-handshake の二つ。
文字コードの設定がどうなっているかを調べるには status と show variables like 'char%' を使う。
少し補足。 utf8 でビルドされた MySQL だとする。
[client] default-character-set = ujis [mysqld] default-character-set = ujis
とやっていても、 DBI (DBD::mysql) から接続したときに ujis になっているとは限らない。というか、ならない。
文字コード設定を調査するためにこんなスクリプトを書いてみると、
#!/usr/local/bin/perl use strict; use DBI; my $dbh = DBI->connect('dbi:mysql:test;hostname=127.0.0.1','user','password'); my $sth = $dbh->prepare(q{show variables like 'char%'}); $sth->execute; while (my $row = $sth->fetchrow_arrayref) { print sprintf("%s => %s\n", $row->[0], $row->[1]); } $sth->finish;
手元の環境ではこんな風に出力された。
character_set_client => utf8 character_set_connection => utf8 character_set_database => ujis character_set_filesystem => binary character_set_results => utf8 character_set_server => ujis character_set_system => utf8
つまり、この設定で euc-jp のバイト列を DBI (DBD::mysql) から挿入しようとすると、 character_set_connection -> character_set_database 間で utf8 -> ujis へと自動変換されるが、もともと utf8 ではなくて euc-jp なバイト列だったのだから変換はうまくいかない。で、化ける。
Perl で書くと、こんな風にしてしまっているのだと思う。
use strict; use utf8; use Encode; my $str = '餃子の王将'; #flagged UTF-8 my $euc = encode('euc-jp', $str); my $broken_str = encode('euc-jp', decode('utf8', $euc));
で、これを解決するにはクライアント側の文字コード設定を正しく、この場合 ujis に変更してやればいいのだが、 DBD::mysql の perldoc などを見た感じだとオプションとかではできなそうな感じ。いちいち SET ... とかやるのも大変。そこで skip-character-set-client-handshake を [mysqld] セクションに追記すると、クライアントがどんな文字コード設定をもっていようが問答無用で character_set_* を (_system をのぞいて) すべて同じ値に統一してくれる。
[client] default-character-set = ujis [mysqld] default-character-set = ujis skip-character-set-client-handshake
こういう設定にかえて mysql を再起動し、文字コード調査用スクリプトを実行すると、
character_set_client => ujis character_set_connection => ujis character_set_database => ujis character_set_filesystem => binary character_set_results => ujis character_set_server => ujis character_set_system => utf8
こうなる。 ujis で統一された。これで、文字コードの自動変換はおこらない。この設定で euc-jp のバイト列を挿入しようとすると、バイト列はそのまま ujis なテーブルに保存される。ので、化けない。