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