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では文字化けが発生することを意味している.これはJavaSJISNEC特殊文字を含んでいないから.

setUpメソッド内のINSERTを0x878Aから'㈱'に変更して再度実行するとtest1からtest4まで全て失敗する.さっきも言ったようにJavaSJISNEC特殊文字を含んでいないために"Windowssjis(ソースファイル)→JavaunicodeJavaSJIS"へと変換されるこのSJIS変換で文字が破壊されたためであろう.General Logを見てもそれは確認することができた.既に?の状態でMySQLサーバへ渡っている.

同じパターンで今度はテーブルをcp932で作成するようにsetUpメソッドを変えて実行すると4x2の8パターン全て成功.

つまりJavaアプリケーションからは従来の検証結果通り,cp932を使うしかないというわけだ.少し前のエントリで指摘したように,現在Javaアプリと.NETアプリはMySQL上にNEC特殊文字などを含んだテーブルを共有できないということになる.

ぱっと浮かぶコネクタ側の修正による解決法

結論を出す前にもう少し".NET"の文字コードの仕組みとMySQLサーバのsjis/cp932実装について調べる必要あり.