sql_mode=NO_BACKSLASH_ESCAPES対応の件
NATIONAL CHARACTER対応実装をConnector/J 5.1へ行うために,まずその橋頭堡となる"com.mysql.jdbc.PreparedStatement"クラスのsetStringメソッドを調べていたわけですが,
http://ikda.net/fswiki/wiki.cgi?page=Connector%2FJ+5%2E0#p5
昨日の日記で書いたように"NO_BACKSLASH_ESCAPES"というのが意味不明でした.このフラグそのものの意味はOK.名前の由来は謎だがそれは気にしないってことでOK.しかしなぜsetStringでこのフラグをチェックしてHex-Escapeする必要があるのか,という件についてです.
この2のhex-escapeが必要な理由ですが,これはどうもMySQLサーバ側の"NO_BACKSLASH_ESCAPES"実装に原因があるようです.サーバ変数sql_modeに "NO_BACKSLASH_ESCAPES"が指定されている場合,hex-escapeを行わずに3のような通常のエスケープ処理を行うと以下のようになってしまいます.
my.ini(my.cnf)を以下のようにして,
[mysqld] sql_mode=NO_BACKSLASH_ESCAPES
PreparedStatement.setStringメソッド(PreparedStatement.java 3020行目付近)を以下のように改変して,
//if (this.connection.isNoBackslashEscapesSet()) { if (false) {
以下のように実行
char c = 0; pstmt.setString(2, c + "こんにちは"); pstmt.execute();
サーバに実際に送られる文字は以下であり,ここまではいいのですが,
INSERT INTO t1 (c1, c2) VALUES ('おはよう', '\0こんにちは');
これをSELECTしてみると以下のようになり意図せざる結果となっています.
おはよう, \0こんにちは
先ほどの改変を元に戻し,hex-escapeを行うようにすると正しく表示されます(以下はEclipseを使用して表示した場合です.char=0はEclipseのコンソールには□のように表示されます.)
おはよう, □こんにちは
ということでやっと納得しました.
ええ,やっとsetNString実装に着手です.調査に時間かけてますとも,ええw