Index: java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java =================================================================== --- java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java (revision 474413) +++ java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java (working copy) @@ -408,8 +408,33 @@ for (int i = 0; i < cols.length; i++) { ColumnReference ref = (ColumnReference) cols[i]; + + /* + ** Only occurrences of those OLD/NEW transition tables/variables + ** are of interest here. There may be intermediate nodes in the + ** parse tree that have its own RCL which contains copy of + ** column references(CR) from other nodes. e.g.: + ** + ** CREATE TRIGGER tt + ** AFTER INSERT ON x + ** REFERENCING NEW AS n + ** FOR EACH ROW + ** INSERT INTO y VALUES (n.i), (999), (333); + ** + ** The above trigger action will result in InsertNode that + ** contains a UnionNode of RowResultSetNodes. The UnionNode + ** will have a copy of the CRs from its left child and those CRs + ** will not have its beginOffset set which indicates they are + ** not relevant for the conversion processing here, so we can + ** safely skip them. + */ + if (ref.getBeginOffset() == -1) + { + continue; + } + TableName tableName = ref.getTableNameNode(); - if ((tableName == null) || + if ((tableName == null) || ((oldTableName == null || !oldTableName.equals(tableName.getTableName())) && (newTableName == null || !newTableName.equals(tableName.getTableName())))) { Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (revision 474413) +++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (working copy) @@ -779,3 +779,51 @@ drop trigger tropt; drop table topt2; drop table topt1; + +-- DERBY-1204 +-- CREATE TRIGGER with an INSERT action statement with multiple rows and a referenced column +-- throws a StringIndexOutOfBoundsException +create table x (i int); +create table y (i int); +-- ok +create trigger tgood after insert on x +for each statement insert into y values (666), (999), (333); +drop trigger tgood; +-- ok +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i); +drop trigger tgood; +-- ok +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (333), (999), (333); +drop trigger tgood; +-- ok. This used to throw StringIndexOutOfBoundsException +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i), (999), (333); +insert into x values (888); +select * from y; +drop trigger tgood; +delete from x; +delete from y; +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i), (n.i+1), (n.i+2); +insert into x values (1), (4), (7); +select * from y; +drop trigger tgood; +drop table x; +drop table y; +create table x (i int, j varchar(10)); +create table y (i int, j varchar(10)); +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (0, 'X'), (n.i, 'Y'), (0, n.j), (n.i,n.j); +insert into x values (1,'A'), (2,'B'), (3, 'C'); +select * from y; +drop trigger tgood; +drop table x; +drop table y; + Index: java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (revision 474413) +++ java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (working copy) @@ -1400,4 +1400,105 @@ 0 rows inserted/updated/deleted ij(USER1)> drop table topt1; 0 rows inserted/updated/deleted +ij(USER1)> -- DERBY-1204 +-- CREATE TRIGGER with an INSERT action statement with multiple rows and a referenced column +-- throws a StringIndexOutOfBoundsException +create table x (i int); +0 rows inserted/updated/deleted +ij(USER1)> create table y (i int); +0 rows inserted/updated/deleted +ij(USER1)> -- ok +create trigger tgood after insert on x +for each statement insert into y values (666), (999), (333); +0 rows inserted/updated/deleted +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> -- ok +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i); +0 rows inserted/updated/deleted +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> -- ok +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (333), (999), (333); +0 rows inserted/updated/deleted +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> -- ok. This used to throw StringIndexOutOfBoundsException +create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i), (999), (333); +0 rows inserted/updated/deleted +ij(USER1)> insert into x values (888); +1 row inserted/updated/deleted +ij(USER1)> select * from y; +I +----------- +888 +999 +333 +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> delete from x; +1 row inserted/updated/deleted +ij(USER1)> delete from y; +3 rows inserted/updated/deleted +ij(USER1)> create trigger tgood after insert on x +referencing new as n +for each row insert into y values (n.i), (n.i+1), (n.i+2); +0 rows inserted/updated/deleted +ij(USER1)> insert into x values (1), (4), (7); +3 rows inserted/updated/deleted +ij(USER1)> select * from y; +I +----------- +1 +2 +3 +4 +5 +6 +7 +8 +9 +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> drop table x; +0 rows inserted/updated/deleted +ij(USER1)> drop table y; +0 rows inserted/updated/deleted +ij(USER1)> create table x (i int, j varchar(10)); +0 rows inserted/updated/deleted +ij(USER1)> create table y (i int, j varchar(10)); +0 rows inserted/updated/deleted +ij(USER1)> create trigger tgood after insert on x +referencing new as n +for each row insert into y values (0, 'X'), (n.i, 'Y'), (0, n.j), (n.i,n.j); +0 rows inserted/updated/deleted +ij(USER1)> insert into x values (1,'A'), (2,'B'), (3, 'C'); +3 rows inserted/updated/deleted +ij(USER1)> select * from y; +I |J +---------------------- +0 |X +1 |Y +0 |A +1 |A +0 |X +2 |Y +0 |B +2 |B +0 |X +3 |Y +0 |C +3 |C +ij(USER1)> drop trigger tgood; +0 rows inserted/updated/deleted +ij(USER1)> drop table x; +0 rows inserted/updated/deleted +ij(USER1)> drop table y; +0 rows inserted/updated/deleted ij(USER1)>