PreparedStatementの罠。

PreparedStatementを使用し、CHAR項目に対してSELECT/UPDATEなどをする場合気をつけなければいけないこと。
※Java1.5/1.4/1.3+Oracle JDBCドライバ10.2/10.1で再現。

あるテーブル「TABLE1」
COL1|CHAR(3)
COL2|VARCHAR2(3)

「TABLE1」のデータ
COL1|COL2

                    • -

01 |01
012 |012

このとき、以下の結果は正しく帰ってくる。
Statement stmt=conn.createStatement();
1)ResultSet rs1=stmt.executeQuery("SELECT * FROM TABLE1 WHERE COL1='01'");
2)ResultSet rs2=stmt.executeQuery("SELECT * FROM TABLE1 WHERE COL1='012'");
3)int update1=stmt.executeUpdate("UPDATE TABLE1 SET COL2='013' WHERE COL1='01'");
4)int update2=stmt.executeUpdate("UPDATE TABLE1 SET COL2='013' WHERE COL1='012'");

しかし、次のような形だと、1)と3)が0件のヒットまたは更新0件になる。
1)
PreparedStatement pstmt1=conn.prepareStatement("SELECT * FROM TABLE1 WHERE COL1=?");
pstmt1.setString(1,"01");
ResultSet rs1=pstmt1.executeQuery();

2)
PreparedStatement pstmt2=conn.prepareStatement("SELECT * FROM TABLE1 WHERE COL1=?");
pstmt2.setString(1,"012");
ResultSet rs2=pstmt2.executeQuery();

3)
PreparedStatement pstmt3=conn.prepareStatement("UPDATE TABLE1 SET COL2='013' WHERE COL1=?");
pstmt3.setString(1,"01");
int update1=pstmt3.executeUpdate();

4)
PreparedStatement pstmt4=conn.prepareStatement("UPDATE TABLE1 SET COL2='013' WHERE COL1=?");
pstmt4.setString(1,"012");
int update2=pstmt4.executeUpdate();

違いはCHAR項目に対して、どういった値を渡しているか。
1と3の場合、CHAR項目としては「01 」になるが、渡しているStringは「01」のため0件になる。
可変長の値をCHARにつめ、かつPreparedStatementを使用する際には気をつけないといけないらしい。


回避策(1):検索項目をTRIMする※遅い
・PreparedStatement pstmt1=conn.prepareStatement("SELECT * FROM TABLE1 WHERE TRIM(COL1)=?");

回避策(2):検索条件に対し、空白をADDする。
・PreparedStatement pstmt1=conn.prepareStatement("SELECT * FROM TABLE1 WHERE COL1=?");
 pstmt1.setString(1,"01 ");//←01半角空白になるように加工する
 ResultSet rs1=pstmt1.executeQuery();