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'繹ア'
おなじみの文字.