以下のような表を作成する。
CREATE TABLE HOGE(ID SMALLINT, NAME VARCHAR(10))
ポイントは「VARCHAR(10)」。
で、JDBCを使って以下のようなクエリを発行してみる。
SELECT ID, NAME FROM HOGE WHERE NAME = '0123456789a' INSERT INTO HOGE(ID, NAME) VALUES(1, '0123456789a') DELETE FROM HOGE WHERE NAME = '0123456789a'
期待される結果は「INSERTだけエラーになる」。で、もちろんそのとおりに動作する。
実際の確認に用いたプログラム(抜粋)。
Connection connection = DriverManager.getConnection(url, userId, password); try { System.out.println("=== " + url + " ==="); String name = "0123456789a"; { PreparedStatement pstmt = connection.prepareStatement("SELECT ID, NAME FROM HOGE WHERE NAME = '" + name + "'"); try { pstmt.executeQuery(); System.out.println(" SELECT(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" SELECT(" + name.length() + "): " + e.getMessage().trim()); } } { PreparedStatement pstmt = connection.prepareStatement("INSERT INTO HOGE(ID, NAME) VALUES(1, '" + name + "')"); try { pstmt.executeUpdate(); System.out.println(" INSERT(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" INSERT(" + name.length() + "): " + e.getMessage().trim()); } } { PreparedStatement pstmt = connection.prepareStatement("DELETE FROM HOGE WHERE NAME = '" + name + "'"); try { pstmt.executeUpdate(); System.out.println(" DELETE(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" DELETE(" + name.length() + "): " + e.getMessage().trim()); } } } finally { connection.close(); }
で、その結果。
=== jdbc:db2://localhost:50001/DB0616_1 === SELECT(11): OK INSERT(11): DB2 SQL Error: SQLCODE=-433, SQLSTATE=22001, SQLERRMC=0123456789a, DRIVER=3.52.95 DELETE(11): OK
しかし、これを、以下のようにパラメータマーカーを使用して書いて‥
Connection connection = DriverManager.getConnection(url, userId, password); try { System.out.println("=== " + url + " ==="); String name = "0123456789a"; { PreparedStatement pstmt = connection.prepareStatement("SELECT ID, NAME FROM HOGE WHERE NAME = ?"); pstmt.setString(1, name); try { pstmt.executeQuery(); System.out.println(" SELECT(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" SELECT(" + name.length() + "): " + e.getMessage().trim()); } } { PreparedStatement pstmt = connection.prepareStatement("INSERT INTO HOGE(ID, NAME) VALUES(?, ?)"); pstmt.setInt(1, 1); pstmt.setString(2, name); try { pstmt.executeUpdate(); System.out.println(" INSERT(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" INSERT(" + name.length() + "): " + e.getMessage().trim()); } } { PreparedStatement pstmt = connection.prepareStatement("DELETE FROM HOGE WHERE NAME = ?"); pstmt.setString(1, name); try { pstmt.executeUpdate(); System.out.println(" DELETE(" + name.length() + "): " + "OK"); } catch (SQLException e) { System.out.println(" DELETE(" + name.length() + "): " + e.getMessage().trim()); } } } finally { connection.close(); }
‥実行すると‥
=== jdbc:db2://localhost:50001/DB0616_1 === SELECT(11): DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=3.52.95 INSERT(11): DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=3.52.95 DELETE(11): DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=3.52.95
全部失敗する。
ためしに、以下のDBMSで確認してみた。
- DB2 Express-C v9.5.2
- Oracle 10g Express Edition
- PostgreSQL v8.3 + postgresql-8.3-603.jdbc3.jar
- MySQL v5.1 + mysql-connector-java-5.1.6-bin.jar
INSERTがすべてにおいて失敗するのは、まぁ当たり前だが‥
=== jdbc:oracle:thin:@//localhost:1521/xe === INSERT(11): ORA-12899: 列"ORACLEADMIN"."HOGE"."NAME"の値が大きすぎます(実際: 11、最大: 10) === jdbc:postgresql://localhost:5432/postgres === INSERT(11): ERROR: value too long for type character varying(10) === jdbc:mysql://localhost:3306/test === INSERT(11): Data truncation: Data too long for column 'NAME' at row 1
Oracle、PostgreSQL、MySQLではSELECTとDELETEは正常終了するのに、DB2は、SELECTとDELETEでもエラーになる。
これって、結構迷惑な仕様のような気がするのは私だけ!?
ちなみに、DB2だけは、パラメータマーカーを使った場合と使わない場合でINSERTの際のSQLCODEが異なる(パラメータマーカーを使うと-302、使わないと-433)。