2014年11月11日火曜日

SQLデータベースの話(その2)ODBCドライバと各社RDBクライアント文字コードの関係

こんにちは。大須賀です。

前回はSQLiteのODBCドライバの話をしました。

前回の投稿はこちら

アプリケーション開発の観点から言うと、ODBCでは以下の場所で文字コードを意識することが必要であることがわかりました。
  1. ① APIとパラメータでやりとりする文字列の文字コード
  2. ② ODBCとバインドバッファでやりとりする文字型データの文字コード
①は、EXEがMBCSアプリケーションであるか、Unicodeアプリケーションであるかによって決まります。
MBCSの場合、シフトJIS(実際には、そのプロセスのロケールによって決定します)
Unicodeアプリケーションの場合はUnicode(Windowsではワイド文字と表現する)になります。

②はODBCに指示するバインドバッファの型(SQL C型)がSQL_C_CHARの場合はロケールに沿ったコード、SQL_C_WCHARの場合にはワイド文字になります。

SQLiteはMBCSでのデータはすべてUTF8という標準でない動きをするため、シフトJISを期待していたアプリケーションは文字化けしていたわけですが、その他のRDBではこのあたりはどうなっているのでしょうか。


WindowsのMBCSアプリケーションでは、シフトJIS以外の文字コードで獲得してもあまり意味がないのですが、OracleとDB2は環境変数で指定できます。これはUnix/Linux上での動作との互換性のためでしょう。一方、Windows以外では動作しないSQL Serverでは潔くシフトJIS一択です。
黄色い部分は通常の実装と異なる部分です。SQLite3はここまでで説明しました。
よくわからないのはMySQLとPostgreSQLのODBCドライバが「ANSI」と「Unicode」の2種類あることですね。しかし、MySQLとPostgreSQLでは意味が異なるようです。

PostgreSQLでは、Unicodeドライバを選択すると、テーブル構造の取得において、CHAR、VARCHAR等の文字型のカラムはすべてWCHAR、WVARCHARでレポートされるようになります。そのため、テーブルの構造を読んで自動的にクエリを生成するタイプのアプリケーションは、バインドバッファの型がSQL_C_WCHARに設定されることになり、文字化けの可能性が少なくなります。私が調べたところではそれ以外に違いは見つけられていません。

一方、MySQLでは、実装に間違いがあるように思えます。WindowsのDLLは、関数エントリにMBCS用とUnicode用の2つを実装している必要があり、これらはVC++のコンパイル時に、自動的に適切な関数にリンクされます。しかし、MySQLではANSI用ドライバにUnicode関数が完全には実装されていないようです。MBCSアプリはANSIドライバを、UnicodeアプリはUnicodeドライバを選択すればきちんと動作しますが、それ以外の組み合わせでは、文字化けが起こってしまいます。

また、MySQLはODBC設定のDetailsボタン→ConnectionタブのCharacterSetを正しく「cp932」に設定する必要があります。デフォルトは空白なので、一見正しく動作しているようでも文字化けが発生する可能性がありますので、このオプションは要注意です。
(cp932はコードページ932でWindowsのシフトJISを表します)

文字コード変換に対する実装の解釈がDBMSごとに異なるのは迷惑なのですが、それでも一昔前よりはよほど統一されてきました。文字コード問題は当ブログでもいろいろと話していますが、最近ではUnicode系に統一することで(JavaやWeb系の対応のため、実質的には統一せざるを得ない)文字化け問題はほとんど起きなくなっています。

シフトJISは日本のPC開発の現場で提唱された方式です。当時は私もWindowsNTがUnicodeを選択することにはずいぶん反発したのですが、ついにVisual Studio 2013では、MBCSアプリケーションのライブラリがオプションになりました。マイクロソフトの「もうそろそろサポートやめたいんだけど、いい?ダイジョブ?」という声が聞こえてきます。

コンピュータ業界のソフトウェアの「時間(=ハードウェア能力の向上)が解決する」というのを実感しますが、ちょっと悔しい気がしますね。

0 件のコメント:

コメントを投稿