Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/userDefMethods.java =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/lang/userDefMethods.java (revision 226401) +++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/userDefMethods.java (working copy) @@ -76,5 +76,82 @@ pstmt.close(); } + /* **** + * Derby-388: When a set of inserts & updates is performed on a table + * and each update fires a trigger that in turn performs other updates, + * Derby will sometimes try to recompile the trigger in the middle + * of the update process and will throw an NPE when doing so. + */ + public static void derby388() throws SQLException + { + System.out.println("Running DERBY-388 Test."); + Connection conn = DriverManager.getConnection("jdbc:default:connection"); + boolean needCommit = !conn.getAutoCommit(); + Statement s = conn.createStatement(); + // Create our objects. + s.execute("CREATE TABLE D388_T1 (ID INT)"); + s.execute("CREATE TABLE D388_T2 (ID_2 INT)"); + s.execute( + "CREATE TRIGGER D388_TRIG1 AFTER UPDATE OF ID ON D388_T1" + + " REFERENCING NEW AS N_ROW FOR EACH ROW MODE DB2SQL" + + " UPDATE D388_T2" + + " SET ID_2 = " + + " CASE WHEN (N_ROW.ID <= 0) THEN N_ROW.ID" + + " ELSE 6 END " + + " WHERE N_ROW.ID < ID_2" + ); + + if (needCommit) + conn.commit(); + + // Statement to insert into D388_T1. + PreparedStatement ps1 = conn.prepareStatement( + "INSERT INTO D388_T1 VALUES (?)"); + + // Statement to insert into D388_T2. + PreparedStatement ps2 = conn.prepareStatement( + "INSERT INTO D388_T2(ID_2) VALUES (?)"); + + // Statement that will cause the trigger to fire. + Statement st = conn.createStatement(); + for (int i = 0; i < 20; i++) { + + for (int id = 0; id < 10; id++) { + + ps2.setInt(1, id); + ps2.executeUpdate(); + ps1.setInt(1, 2*id); + ps1.executeUpdate(); + + if (needCommit) + conn.commit(); + + } + + // Execute an update, which will fire the trigger. + // Note that having the update here is important + // for the reproduction. If we try to remove the + // outer loop and just insert lots of rows followed + // by a single UPDATE, the problem won't reproduce. + st.execute("UPDATE D388_T1 SET ID=5"); + if (needCommit) + conn.commit(); + + } + + // Clean up. + s.execute("DROP TABLE D388_T1"); + s.execute("DROP TABLE D388_T2"); + + if (needCommit) + conn.commit(); + + st.close(); + ps1.close(); + ps2.close(); + + System.out.println("DERBY-388 Test Passed."); + } + } Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (revision 226401) +++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (working copy) @@ -579,3 +579,15 @@ delete from x; drop table x; + +-- Derby-388: When a set of inserts/updates is performed on a table +-- and each update fires a trigger that in turn performs other updates, +-- Derby will sometimes try to recompile the trigger in the middle +-- of the update process and will throw an NPE when doing so. + +create procedure d388 () language java parameter style java modifies sql data + external name 'org.apache.derbyTesting.functionTests.tests.lang.userDefMethods.derby388'; + +-- Just call the procedure; it will do the rest. +call d388(); + Index: java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (revision 226401) +++ java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (working copy) @@ -1227,4 +1227,16 @@ 1 row inserted/updated/deleted ij> drop table x; 0 rows inserted/updated/deleted +ij> -- Derby-388: When a set of inserts/updates is performed on a table +-- and each update fires a trigger that in turn performs other updates, +-- Derby will sometimes try to recompile the trigger in the middle +-- of the update process and will throw an NPE when doing so. +create procedure d388 () language java parameter style java modifies sql data + external name 'org.apache.derbyTesting.functionTests.tests.lang.userDefMethods.derby388'; +0 rows inserted/updated/deleted +ij> -- Just call the procedure; it will do the rest. +call d388(); +Running DERBY-388 Test. +DERBY-388 Test Passed. +0 rows inserted/updated/deleted ij>