ResultSet.getNXXX() は対象Fieldのcharsetがutf8以外の場合はSQLException

投げますよ.

理由
今回のNATIONAL CHARACTER SET CONVERTIONにより追加定義されたAPIは,"NATIONAL CHARACTER"型のフィールドへアクセスするために定義されたAPIである.他の文字コードを使用するフィールドへのアクセスは従来通りのAPIで十分に可能なわけであり,"NATIONAL CHARACTER"用のAPIによって他の文字コードを使用するフィールドへアクセスすることは期待されていない.むしろ"NATIONAL CHARACTER"型ではないフィールドに対してこのメソッドを呼んだ場合,SQLExceptionをスローする実装であるほうがAPIの違いが明確であって良い."NATIONAL CHARACTER"型ではないフィールドにうっかりgetNXXX()を使ってしまった,なんていう場合にはSQLExceptionがそれを教えてくれるという意味もある.

と言う風に考えたためです.CallableStatement.getNXXX()も内部的にResultSet.getNXXX()と同じ処理になるので同様の振る舞いとするつもりです.

という感じでMM氏にメール投げてみた,だけの状態,いまんとこ.

でもね,UpdatableResultSet.updateNXXX()でUTF-8以外のフィールドに対して使うとSQLExceptionスローする方針をとっているので,↑のようになると思う.思いつき,推測ですが.

ぐわー,これ書いて,テストコード書いて,EMMA実行して,自分が追加したコードで網羅率が悪いとこあったらさらにテストコード追加して,終わりになる予定.StoredProcedure作って実行して消すテストコードめんどいよ ('A`)



と考えてみたものの,SPにおけるINOUTパラメータの文字コードって,一体どんな意味なんだっけな….

this.stmt.executeUpdate("create procedure testSetNString(INOUT foo VARCHAR(10))\n"
                      + "begin\n"
                      + "select foo;\n"
                      + "end\n");

これを実行したときのResultSet.fields[i].getCharacterSet()は"Windows-31J"だった."my.ini"でcp932指定してるからね.

this.stmt.executeUpdate("create procedure testSetNString(INOUT foo NVARCHAR(10))\n"
                      + "begin\n"
                      + "select foo;\n"
                      + "end\n");

これにしてみたら,ResultSet.fields[i].getCharacterSet()は"UTF-8"だった.NVARCHARって宣言したからだね.とりあえずこれは理解した.

General Logを見てみる.

まず以下がVARCHARの場合.

3 Query       SET NAMES cp932
3 Query       SET character_set_results = NULL
3 Query       SHOW VARIABLES
3 Query       SHOW COLLATION
3 Query       SET autocommit=1
3 Query       SELECT VERSION()
3 Query       DROP PROCEDURE IF EXISTS testSetNString
3 Query       create procedure testSetNString(INOUT foo NVARCHAR(10))
begin
select foo;
end
3 Query       USE `test`
3 Query       SELECT DATABASE()
3 Query       USE `test`
3 Query       SHOW CREATE PROCEDURE `test`.`testSetNString`
3 Query       SET @com_mysql_jdbc_outparam_foo=x'5F75746638276162636427'
3 Query       CALL testSetNString(@com_mysql_jdbc_outparam_foo)
3 Query       SELECT @com_mysql_jdbc_outparam_foo
3 Query       DROP PROCEDURE IF EXISTS testSetNString
3 Quit       

次がNVARCHARの場合.

4 Query       SET NAMES cp932
4 Query       SET character_set_results = NULL
4 Query       SHOW VARIABLES
4 Query       SHOW COLLATION
4 Query       SET autocommit=1
4 Query       SELECT VERSION()
4 Query       DROP PROCEDURE IF EXISTS testSetNString
4 Query       SHOW WARNINGS
4 Query       create procedure testSetNString(INOUT foo VARCHAR(10))
begin
select foo;
end
4 Query       USE `test`
4 Query       SELECT DATABASE()
4 Query       USE `test`
4 Query       SHOW CREATE PROCEDURE `test`.`testSetNString`
4 Query       SET @com_mysql_jdbc_outparam_foo=x'5F75746638276162636427'
4 Query       CALL testSetNString(@com_mysql_jdbc_outparam_foo)
4 Query       SELECT @com_mysql_jdbc_outparam_foo
4 Query       DROP PROCEDURE IF EXISTS testSetNString
4 Quit       

どちらもパラメータにx'5F75746638276162636427'って使ってる.これは "_utf8 'abcd'" なのだ実は.orz

このSETの部分を以下のようにしないといかんよね.

SET @com_mysql_jdbc_outparam_foo=_utf8 x'61626364'

ううむ,参った参った.CallableStatement.setNString(int, String)というのは継承メソッドそのままではいかんかったか.でもこれ継承メソッドのまんまってのがJDBC 4.0 JavaDoc様の仰ってることなんだよね.オーバーライドしないとまずい感じなんだけど,オーバーライドしちゃ標準仕様準拠的にまずいよね.

とりあえず上記みたいにやる方法さがそ・・・.

とりあえず突っ込んでるコードは見つかった.クールな多態性実装で切り抜けられるのか.



成功w

いや,まじで一瞬焦ったw

記念ログ挙げ

20 Query       SET @com_mysql_jdbc_outparam_foo=_utf8'繹ア'

おなじみの文字.