「Linuxから投入したデータが、Windowsで読み出すと文字化けする」


エンコーディングの構成が

というシステムについて、「Linuxからは正しく読み書きできているデータを、Windowsから読み出すと文字化けする」と言われたので見に行ったら、何だか見たことのない強烈な化け方をしている。
ODBCデータソースのエンコーディング設定が間違っているのだろう」と思ってチェックしてみたが、ちゃんとShift_JISになっていた。
よくわからないので試しにクライアントエンコーディングShift_JISからASCIIに変更してみたら、

、ウ、ヒ、チ、マ。。、ェ、マ、隍ヲ、エ、カ、、、゙、ケ。。、、、
鬢テ、キ、网、、゙、サ、オ、隍ヲ、ハ、鬘。、ハ、テ、ニ

みたいな、おなじみの「EUC-JPエンコードの文字列をShift_JISのつもりで表示した場合の化け方」に変わった。
つまり、UnicodeのDBにASCIIで接続したらEUC-JPエンコーディングの文字列が出てきた、ということ。データソースの設定の問題ではなくて、データ自体が腐っている。

何が間違っていたか

結局、あるLinuxクライアントの、ODBCデータソースのエンコーディング設定が ASCII になっていたことが原因だった。
そのクライアントから日本語を投入したら、DBとのセッションエンコーディングがASCIIなので、Teradataはクライアントが送った'あ'という文字を 0xA4, 0xA2 の2文字と判断して内部エンコーディング(=UTF-16)に変換して保存する。
読み出すときはその逆の変換がかかり、Teradataからは 0xA4, 0xA2 の2文字を送信するが、問題のクライアント自身はそれを日本語として表示できるので、エンコーディング設定の異常に誰も気付かなかった。
幸いテストDBだったので、問題のクライアントから投入したデータは捨ててしまった。

DBまわりの3つのエンコーディング

DB内のデータの文字化けを防ぐには、以下の3つが整合*1していなくてはならない。

  1. クライアントが理解するエンコーディング
  2. クライアント−データベース間のセッションエンコーディング
  3. データベースの内部エンコーディング

ここ数年扱ったシステムは上から下までUnicodeだったのでほとんど意識しないで済んだが、今回のように「クライアントが理解するエンコーディングShift_JIS だったり、EUC-JPだったり」というシステムの場合は、クライアントごとにセッションエンコーディングをきっちり指定しなくてはならない。指定が漏れていても、今回のように文字化けを起こしている本人が気付かない可能性があってやばい。

*1:同一か、相互変換可能