Perl 5.20 と DBI と utf8

「文字化け」とは意地でも言いたくないけど、化けるものは仕方ない。

諸悪の根源(?)は、DBI ( もしくは DBD::* ) がDBのエンコーディングを自動判別するようになったせい。

発動条件

  • Perl 5.20 以上 (らしい。自分では検証していない)
  • DBI を使う ( DBI や DBD::Pg のバージョンも関係してるはず )
  • DBのエンコードUTF-8

自分で確認したのは PostgreSQLMySQL でも出るらしい。SQLite は不明。

現象

  • perlプロセスがDBI経由でDBに保存する utf8 文字列が化ける
  • perlプロセスがDBI経由でDBから取り出した utf8 文字列が化ける

原因

対処

  • use Encode; ( Encode.pm必須!他の方法は不可 )
  • perlプロセスからDBにデータを渡す場合、Encode::decode() をかけてperl内部バイトコードの状態にして渡す
  • DBから文字列を受け取った場合、perl内部バイトコードになっているため、適宜 Encode::encode() をかけて(ファイルや標準出力に)出力する

NG事例集

  • ファイル入出力や標準入出力での受け渡しデータの文字コードが utf8 だったとしても、encode/decode を省略することは出来ない
  • pg_enable_utf8 を偽に設定し、強引に内部バイトコードや utf8 エンコード文字列を保存しても化ける(エスケープ処理される??)
  • pg_enable_utf8 を偽に設定し、「 SET CLIENT_ENCODING TO 'UTF-8' 」を実行してもダメ(エラーになる)
  • jcode.pl や Jcode.pm で文字コード変換する仕組みは全滅

影響を受けないパターン

  • DBのエンコーディングUTF-8 以外の場合、これまでと何ら変わらない処理方法が可能
  • jcode.pl だろうが Jcode.pm だろうが「 SET CLIENT_ENCODING TO '〜〜' 」でもなんでもござれ