HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

パラメータマーカーに指定する文字列が長すぎるとSQLエラー

以下のような表を作成する。

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で確認してみた。

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

OraclePostgreSQLMySQLではSELECTとDELETEは正常終了するのに、DB2は、SELECTとDELETEでもエラーになる。
これって、結構迷惑な仕様のような気がするのは私だけ!?

ちなみに、DB2だけは、パラメータマーカーを使った場合と使わない場合でINSERTの際のSQLCODEが異なる(パラメータマーカーを使うと-302、使わないと-433)。