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();

OracleでExportコマンドを実行すると、エラーが発生。

環境
Oracle8i(それ以上は不明)

内容
EXP-00008: Oracleエラー 904が発生しました。
ORA-00904: 列名が無効です。

EXP-00008: Oracleエラー 6550が発生しました。
ORA-06550: 行 1、列 29:
PLS-00302: コンポーネント IS_TRIGGER_FIRE_ONCE_INTERNALを宣言してください。
ORA-06550: 行 1、列 8:
PL/SQL: Statement ignored
EXP-00056: Oracleエラー 1403が発生しました。
ORA-01403: データが見つかりません。
EXP-00000: エラーが発生したためエクスポートを終了します。

よくバージョンが違うOracleへExport/Importする場合に発生する事象で、
通常は以下のsqlをSysユーザで実行し、再エクスポートする。
ORACLE_HOME\rdbms\ADMIN以下の、
・catalog.sql
・catproc.sql
・catexp.sql
・utlrp.sq

                                                                                                  • -

今回はOracleのDBとSQL*Plusのバージョンで、SQL*Plusのバージョンが新しかったのが原因。
同じか下位バージョンでないといけません。

org.apache.catalina.logger.FileLoggerが無いという例外が発生。

Tomcat5.0から5.5にバージョンアップしたとき。server.xml等は変更してない。

エラー内容
致命的: Begin event threw exception
java.lang.ClassNotFoundException: org.apache.catalina.logger.FileLogger


対応
CATALINA_HOME/shared/libにJAVA_HOME/lib/tools.jarをコピー。

...よくあるイージーミスでした。

文字化けに困ったらときの参考。

Microsoft】SHIFT - JIS と Unicode 間の変換問題
http://support.microsoft.com/default.aspx?scid=kb;ja;JP170559

OracleJDBC 8.1.7上でのNLS環境におけるキャラクタの整合性の問題について
http://otndnld.oracle.co.jp/tech/java/htdocs/javanls/javanls817.html

JavaJava Encoding & Aliases Table
http://www.ingrid.org/java/i18n/encoding/table-j.html

Oracle Database 8i(charset:JAPANESE_JAPAN.JA16SJIS)とoo4oの接続

1.文字化けしないバージョン
Windows2000/XP+Oracle Client 8.1.6/8.1.7のoo4o


2.文字化けするバージョン
×Windows2000/XP+Oracle Client 9.0/9.1/9.2のoo4o
 回避方法1(9.2のみ)
 oo4oを使用するexeをキックする前に、環境変数を設定する。
  ・set NLS_LANG=JAPANESE_JAPAN.JA16SJISTILDE
 ※他、レジストリに設定する方法等もある。

 回避方法2
 Export→DBをJAPANESE_JAPAN.JA16SJISTILDEで作成しなおし→Import


3.サポート外のバージョン
×Windows2000/XP+Oracle Client 10.0/10.1/10.2のoo4o
 ※SQL*PLUSからしてサポート外。