サーバー文字セットがUnicodeなのでクライアント文字セットをUTF-8にしたら、判定文が軒並みスルーされたでござるの巻
JDBC Type4ドライバー(Implementation-Version: 12.00.00.01)でCHAR型の文字長計算があれな件。
準備
サーバー文字セットがLATINの列を持つテーブルを用意する。(Teradata Sql Assistant等を使って、JDBC以外から実行)
CREATE MULTISET TABLE FOO ( COL1 CHAR(2) CHARACTER SET LATIN, COL2 CHAR(2) CHARACTER SET LATIN, COL3 CHAR(2) CHARACTER SET LATIN ); INSERT INTO FOO VALUES('00', '€0', '€€');
JDBCでテスト
JDBC接続で、上で作ったテーブルの確認を行う。
- クライアント文字セット=UTF8で接続時
- 00△△, €0, €△
- クライアント文字セット=UTF16で接続時
- 00, €0, €€
何故かUTF8で接続すると、COL1には入るはずのない空白が2文字くっついてしまう。
また、COL3は2文字目の€が空白に代わってしまった。
ResultSetMetaData#getColumnDisplaySizeを確認しても、全て2が返って来る。
なんで???
仮説
LATINサーバー文字セットの場合、1文字8bitで格納されるとあったので、てっきりASCIIなのかと思ったら、Latin-1とLatin-9も含む事になっている模様。*1
UTF-8の場合、ASCIIと同じ領域の文字は1Byteで表現されるため、文字'00'は2文字 * 1Byte = 2Byteになりますが、列サイズはLatin-1やLatin-9の仕様どおり、一律1文字2Byteとしているような気がします。
結果、列のサイズは、2文字 * 2Byte = 4Byteと解釈されて、差し引き2Byte分の空白が付いているものと思われます。
また、€のような、Latin-9では1ByteなのにUTF-8では3Byteになってしまう文字は、うっかり使うとサイズ超過が発生するようです。
COL2の文字列は3 + 1 = 4Byteで列サイズと同一なので問題ないですが、COL3の文字列は以下のような複雑な処理の結果でしょうか?
- 3Byte * 2文字 = 6Byte > 4Byteでサイズ超過なので、1文字削除。
- 1文字削除すると、3Byte < 4Byteでサイズ不足なので、空白1文字追加。
UTF-16の場合は、文字も領域も一律2Byteなので問題ないのかも。
追記
列のCHARSETがUnicodeの場合、末尾に空白が4文字付与されます。
どうやら、列のサイズが常に1文字3Byteで解釈されているようです。