5.20にしたら、DBIが何やら不可解な動作をするようになりました。扱う機能が増えたみたいです。DBIの接続時のパラメーターにこんなものが増えています。アップグレードしたところ文字化け発生。at」の警告がなぜか出まくります。日本語UTF-8として保存した文字列が文字化けしまくるのですが、そのデータだけ単独に取り出して表示しても化けない。調べてみると以下のことがわかりました。保存するとき「ASCII文字列に特殊な文字が混ざってる」と解釈してエスケープ処理を行う。文字列ではないので、データベースの中身を直接覗くと、保存した文字列ではなく特殊なエスケープ文字列として表示される。PostgreSQLではこんな感じです。文字列「あいう」を保存。同じUTF8文字列でありながら、違う内部表現になっています。元の「あいう」と文字列比較を行うと異なると判定されます。MySQLではこんな感じです。ついていない元の文字列。問題を整理すると2つに集約できます。DBにきちんとしたUTF8文字列として保存されない。文字列が生成されてしまう(PostgreSQL)。後者も問題と言えば問題ですが、前者はとても気持ち悪い問題です。解決策utf8フラグはうまく使えば「Perlによきに計らってもらい」文字コードの問題が楽になるものですが、utf8文字列をutf8として「そのまま扱いたい」時には問題が多すぎる仕組みです。入出力の都度にencode、decodeが発生し処理を重くする原因にもなります。utf8フラグありとフラグなしのUTF8文字列が混在すると、それらを連結したときに文字化けする危険があります。なるとutf8フラグなしで扱いたいのですが、そうするためにはどうしたらいいのでしょうか。DBD::Pg編utf8フラグのない文字列は、必要に応じて特殊エンコードされてDBに保存される。「pg_enable_utf8」を設定しないとき。フラグが付いて取り出される。「pg_enable_utf8」を設定しないときと同様。フラグは付けなくなる。特殊エンコードされた文字列は文字化けする。3.5.3utf8フラグを付けた文字列を保存すれば、そのままutf8文字列としてDBに保存される。utf8フラグの付いていな文字列は特殊エンコードされる。0」のとき、utf8フラグの付いた文字列を渡すとエラーになる。1」のとき、utf8フラグの付いていない文字列を渡すと特殊エンコードされる。0」を設定して、保存時や「検索時」にutf8フラグを付けるのがよさそうです。DBD::MySQLDB保存時はutf8フラグの有無はすべて無視する(動作は変化しない)。「mysql_enable_utf8」を設定しないとき。いかなる場合もutf8フラグは付かない。非ASCII文字列は特殊エンコードされたDBに保存される。文字列で取り出される。文字列は、エンコード失敗の「?」に置換されDBから取り出される。「mysql_enable_utf8」を設定しないときと同様。文字列としてDBに保存される。フラグが付いて取り出される。特殊エンコードされた文字列は文字化けする。DBD::Pgとは実装がまるで違う事がわかります。utf8;」というSQL文を発行することで、同じ効果を得て、かつutf8フラグに影響がでないことがわかりました。この状態では、特殊エンコードされた文字列を読み込むときに文字化けするので注意が必要です。比べるとDBD::Pgの実装のほうが謎かもしれない。DBD::Pgはトランザクション処理がおかしいという素敵な実績があるからなあ......。0」のとき保存データのutf8フラグも無視しないと矛盾するのはすぐに分かりそうなもんなんだけど。非Unicode(iso-8859-1)の2つの文字コードをサポートします。使用可能な文字列に変換する必要があります。取り出す段階でutf8に変換すべきです。3.6.0あたりから挙動が異なる(正しい挙動に近くなっている)ようです。entry」エラーが発生します。0」のときは、$DBD::Pg::VERSIONを参照し「3.3.0~3.5.3の間の時だけUTF8フラグをつけてDBIに渡す」必要があります。クソバグを仕込んだ上に、互換性考えない中途半端なクソ修正をして、そびえ立つクソ状態なDBD::Pgには呆れるばかり......。悩むとは思わなかった。実装は相変わらずクソ。