NEC特殊文字テスト 再び
MySQLサーバ上のsjisテーブルにNEC特殊文字を突っ込むことができてConnector/NETを使う場合にsjisで上手くいくのなら,じゃあsjisテーブルを使うことを前提とした場合今度はConnector/J的にはどうなのかをテスト.
public class NECSpecialCharOnSJISTableTest extends TestCase { public void setUp() throws Exception { String url = "jdbc:mysql:///test?useUnicode=true&characterEncoding=sjis"; Class.forName("com.mysql.jdbc.Driver").newInstance(); Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); stmt.executeUpdate("DROP TABLE IF EXISTS t1"); stmt.executeUpdate("CREATE TABLE t1 (c1 char(1) charset sjis)"); stmt.executeUpdate("INSERT INTO t1 VALUES (0x878A)"); stmt.close(); conn.close(); } public void test1() throws Exception { Connection conn = null; Statement stmt = null; try {String url = "jdbc:mysql:///test?useUnicode=true&characterEncoding=SJIS"; Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT c1 FROM t1"); rs.next(); assertEquals("㈱", rs.getString(1)); } finally { stmt.close(); conn.close(); } } public void test2() throws Exception { Connection conn = null; Statement stmt = null; try {String url = "jdbc:mysql:///test?useUnicode=true&characterEncoding=MS932"; Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT c1 FROM t1"); rs.next(); assertEquals("㈱", rs.getString(1)); } finally { stmt.close(); conn.close(); } } public void test3() throws Exception { Connection conn = null; Statement stmt = null; try {String url = "jdbc:mysql:///test?useUnicode=true&characterEncoding=SJIS"; Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT hex(c1) FROM t1"); rs.next(); assertEquals("878A", rs.getString(1)); } finally { stmt.close(); conn.close(); } } public void test4() throws Exception { Connection conn = null; Statement stmt = null; try {String url = "jdbc:mysql:///test?useUnicode=true&characterEncoding=MS932"; Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT hex(c1) FROM t1"); rs.next(); assertEquals("878A", rs.getString(1)); } finally { stmt.close(); conn.close(); } } }
このテストケースを走らせると"test1"だけ失敗して後は成功する.SELECT時のみに限定してみた場合であってもSJISを指定するとConnector/Jでは文字化けが発生することを意味している.これはJavaのSJISがNEC特殊文字を含んでいないから.
setUpメソッド内のINSERTを0x878Aから'㈱'に変更して再度実行するとtest1からtest4まで全て失敗する.さっきも言ったようにJavaのSJISがNEC特殊文字を含んでいないために"Windowsのsjis(ソースファイル)→Javaのunicode→JavaのSJIS"へと変換されるこのSJIS変換で文字が破壊されたためであろう.General Logを見てもそれは確認することができた.既に?の状態でMySQLサーバへ渡っている.
同じパターンで今度はテーブルをcp932で作成するようにsetUpメソッドを変えて実行すると4x2の8パターン全て成功.
つまりJavaアプリケーションからは従来の検証結果通り,cp932を使うしかないというわけだ.少し前のエントリで指摘したように,現在Javaアプリと.NETアプリはMySQL上にNEC特殊文字などを含んだテーブルを共有できないということになる.
ぱっと浮かぶコネクタ側の修正による解決法
- MySQLのsjisでNEC特殊文字扱えるならいっそのことsjisでいいじゃん.Java側でMS932やWINDOWS-31Jを指定したら現在cp932にマッピングされるがこれをsjisにマッピングするようにC/Jを修正してしまえばいい.
- 早いとこC/NETにcp932対応を追加して,.NET側でsjisを指定されたら現在sjisにマッピングされるのをcp932にマッピングするように変えてしまえばいい.
結論を出す前にもう少し".NET"の文字コードの仕組みとMySQLサーバのsjis/cp932実装について調べる必要あり.