Index: java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java =================================================================== --- java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java (revision 431287) +++ java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java (working copy) @@ -94,7 +94,13 @@ @exception StandardException thrown if something goes wrong */ - public void addDependency(Dependent d, Provider p, ContextManager cm) throws StandardException { + public void addDependency(Dependent d, Provider p, ContextManager cm) + throws StandardException { + addDependency(d, p, cm, null); + } + + private void addDependency(Dependent d, Provider p, ContextManager cm, + TransactionController tc) throws StandardException { synchronized(this) { @@ -145,13 +151,14 @@ LanguageConnectionContext lcc = getLanguageConnectionContext(cm); DataDictionary dd = getDataDictionary(); DependencyDescriptor dependencyDescriptor; + boolean wait = (tc == null); dependencyDescriptor = new DependencyDescriptor(d, p); /* We can finally call the DataDictionary to store the dependency */ dd.addDescriptor(dependencyDescriptor, null, DataDictionary.SYSDEPENDS_CATALOG_NUM, true, - lcc.getTransactionExecute()); + ((wait)?lcc.getTransactionExecute():tc), wait); } } } @@ -422,6 +429,14 @@ * @exception StandardException Thrown on failure */ public void clearDependencies(LanguageConnectionContext lcc, Dependent d) throws StandardException { + clearDependencies(lcc, d, null); + } + + /** + * @inheritDoc + */ + public void clearDependencies(LanguageConnectionContext lcc, + Dependent d, TransactionController tc) throws StandardException { List deps = (List) dependents.get(d.getObjectID()); synchronized(this) @@ -430,9 +445,11 @@ if (d.isPersistent()) { DataDictionary dd = getDataDictionary(); - + boolean wait = (tc == null); + dd.dropDependentsStoredDependencies(d.getObjectID(), - lcc.getTransactionExecute()); + ((wait)?lcc.getTransactionExecute():tc), + wait); } /* Now remove the in-memory dependencies */ @@ -697,11 +714,23 @@ * * @exception StandardException Thrown on error. */ + public void copyDependencies(Dependent copy_From, + Dependent copyTo, + boolean persistentOnly, + ContextManager cm) throws StandardException + { + copyDependencies(copy_From, copyTo, persistentOnly, cm, null); + } + + /** + * @inheritDoc + */ public synchronized void copyDependencies( Dependent copy_From, Dependent copyTo, boolean persistentOnly, - ContextManager cm) + ContextManager cm, + TransactionController tc) throws StandardException { @@ -715,7 +744,7 @@ if (!persistentOnly || provider.isPersistent()) { - this.addDependency(copyTo, provider, cm); + this.addDependency(copyTo, provider, cm, tc); } } } Index: java/engine/org/apache/derby/impl/sql/catalog/TabInfoImpl.java =================================================================== --- java/engine/org/apache/derby/impl/sql/catalog/TabInfoImpl.java (revision 431287) +++ java/engine/org/apache/derby/impl/sql/catalog/TabInfoImpl.java (working copy) @@ -664,9 +664,26 @@ null, key, ScanController.GT, - indexNumber); + indexNumber, + true); } + public int deleteRow( TransactionController tc, ExecIndexRow key, + int indexNumber, boolean wait) + throws StandardException + { + // Always row locking + return deleteRows(tc, + key, + ScanController.GE, + null, + null, + key, + ScanController.GT, + indexNumber, + wait); + } + /** * LOCKING: row locking if there is both a start and * stop key; otherwise table locking @@ -675,13 +692,37 @@ * @see TabInfo#deleteRows */ public int deleteRows(TransactionController tc, + ExecIndexRow startKey, + int startOp, + Qualifier[][] qualifier, + TupleFilter filter, + ExecIndexRow stopKey, + int stopOp, + int indexNumber) throws StandardException + { + return deleteRows(tc, + startKey, + startOp, + qualifier, + filter, + stopKey, + stopOp, + indexNumber, + true); + } + + /** + * @inheritDoc + */ + public int deleteRows(TransactionController tc, ExecIndexRow startKey, int startOp, Qualifier[][] qualifier, TupleFilter filter, ExecIndexRow stopKey, int stopOp, - int indexNumber) + int indexNumber, + boolean wait) throws StandardException { ConglomerateController heapCC; @@ -726,14 +767,16 @@ heapCC = tc.openConglomerate( getHeapConglomerate(), false, - TransactionController.OPENMODE_FORUPDATE, + (TransactionController.OPENMODE_FORUPDATE | + ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)), lockMode, TransactionController.ISOLATION_REPEATABLE_READ); drivingScan = tc.openScan( getIndexConglomerate(indexNumber), // conglomerate to open false, // don't hold open across commit - TransactionController.OPENMODE_FORUPDATE, // for update + (TransactionController.OPENMODE_FORUPDATE | + ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)), lockMode, isolation, (FormatableBitSet) null, // all fields as objects Index: java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java =================================================================== --- java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (revision 431287) +++ java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (working copy) @@ -1638,10 +1638,13 @@ TransactionController tc) throws StandardException { - addDescriptorNow(td, parent, catalogNumber, duplicatesAllowed, tc, true); + addDescriptor(td, parent, catalogNumber, duplicatesAllowed, tc, true); } - private void addDescriptorNow(TupleDescriptor td, TupleDescriptor parent, + /** + * @inheritDoc + */ + public void addDescriptor(TupleDescriptor td, TupleDescriptor parent, int catalogNumber, boolean duplicatesAllowed, TransactionController tc, boolean wait) throws StandardException @@ -3244,7 +3247,7 @@ uuid, (UUID) null, 0, 0); - addDescriptorNow(cd, null, SYSCOLUMNS_CATALOG_NUM, + addDescriptor(cd, null, SYSCOLUMNS_CATALOG_NUM, false, // no chance of duplicates here tc, wait); } @@ -5875,6 +5878,17 @@ TransactionController tc) throws StandardException { + dropDependentsStoredDependencies(dependentsUUID, tc, true); + } + + /** + * @inheritDoc + */ + public void dropDependentsStoredDependencies(UUID dependentsUUID, + TransactionController tc, + boolean wait) + throws StandardException + { ExecIndexRow keyRow1 = null; DataValueDescriptor dependentIDOrderable; TabInfo ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); @@ -5888,7 +5902,8 @@ keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); keyRow1.setColumn(1, dependentIDOrderable); - ti.deleteRow( tc, keyRow1, SYSDEPENDSRowFactory.SYSDEPENDS_INDEX1_ID ); + ti.deleteRow( tc, keyRow1, SYSDEPENDSRowFactory.SYSDEPENDS_INDEX1_ID, + wait ); } Index: java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java =================================================================== --- java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java (revision 431287) +++ java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java (working copy) @@ -27,6 +27,7 @@ import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.iapi.store.access.TransactionController; /** Dependency Manager Interface @@ -491,4 +492,54 @@ @exception java.sql.SQLException thrown if something goes wrong */ public String dumpDependencies() throws StandardException, java.sql.SQLException; + + /** + Erases all of the dependencies the dependent has, be they + valid or invalid, of any dependency type. This action is + usually performed as the first step in revalidating a + dependent; it first erases all the old dependencies, then + revalidates itself generating a list of new dependencies, + and then marks itself valid if all its new dependencies are + valid. +
+ There might be a future want to clear all dependencies for + a particular provider, e.g. when destroying the provider. + However, at present, they are assumed to stick around and + it is the responsibility of the dependent to erase them when + revalidating against the new version of the provider. +
+ clearDependencies will delete dependencies if they are + stored; the delete is finalized at the next commit. + + @param lcc Compiler state + @param d the dependent + @param tc transaction controller + + @exception StandardException Thrown on failure + */ + public void clearDependencies(LanguageConnectionContext lcc, + Dependent d, + TransactionController tc) + throws StandardException; + + + /** + * Copy dependencies from one dependent to another. + * + * @param copy_From the dependent to copy from + * @param copyTo the dependent to copy to + * @param persistentOnly only copy persistent dependencies + * @param cm Current ContextManager + * @param tc Transaction Controller + * + * @exception StandardException Thrown on error. + */ + public void copyDependencies( + Dependent copy_From, + Dependent copyTo, + boolean persistentOnly, + ContextManager cm, + TransactionController tc) + throws StandardException; + } Index: java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java =================================================================== --- java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java (revision 431287) +++ java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java (working copy) @@ -260,13 +260,15 @@ * @param lcc the language connection context * @param triggerTable the table descriptor to bind against. Had * better be null if this isn't a trigger sps. + * @param tc the transaction controller * * @exception StandardException on error */ public final synchronized void prepareAndRelease ( LanguageConnectionContext lcc, - TableDescriptor triggerTable + TableDescriptor triggerTable, + TransactionController tc ) throws StandardException { if (SanityManager.DEBUG) @@ -277,10 +279,36 @@ } } - compileStatement(lcc, triggerTable); + compileStatement(lcc, triggerTable, tc); preparedStatement.makeInvalid(DependencyManager.PREPARED_STATEMENT_RELEASE, lcc); } + + /** + * FOR TRIGGERS ONLY + *
+ * Generate the class for this SPS and immediately + * release it. This is useful for cases where we + * don't want to immediately execute the statement + * corresponding to this sps (e.g. CREATE STATEMENT). + *
+ * SIDE EFFECTS: will update and SYSDEPENDS + * with the prepared statement dependency info. + * + * @param lcc the language connection context + * @param triggerTable the table descriptor to bind against. Had + * better be null if this isn't a trigger sps. + * + * @exception StandardException on error + */ + public final synchronized void prepareAndRelease + ( + LanguageConnectionContext lcc, + TableDescriptor triggerTable + ) throws StandardException + { + prepareAndRelease(lcc, triggerTable, (TransactionController)null); + } /** * Generate the class for this SPS and immediately @@ -297,13 +325,14 @@ */ public final synchronized void prepareAndRelease(LanguageConnectionContext lcc) throws StandardException { - prepareAndRelease(lcc, (TableDescriptor)null); + prepareAndRelease(lcc, (TableDescriptor)null, (TransactionController)null); } private void compileStatement ( LanguageConnectionContext lcc, - TableDescriptor triggerTable + TableDescriptor triggerTable, + TransactionController tc ) throws StandardException { @@ -388,7 +417,7 @@ ** before we recreate them so we don't grow ** SYS.SYSDEPENDS forever. */ - dm.clearDependencies(lcc, this); + dm.clearDependencies(lcc, this, tc); /* ** Copy over all the dependencies to me @@ -396,7 +425,8 @@ dm.copyDependencies(preparedStatement, // from this, // to false, // persistent only - cm); + cm, + tc); } // mark it as valid @@ -673,7 +703,7 @@ */ LanguageConnectionContext lcc = (LanguageConnectionContext) cm.getContext(LanguageConnectionContext.CONTEXT_ID); - prepareAndRelease(lcc); + if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) (lcc.getDataDictionary())).readOnlyUpgrade) { @@ -697,6 +727,7 @@ try { + prepareAndRelease(lcc, null, nestedTC); updateSYSSTATEMENTS(lcc, RECOMPILE, nestedTC); } catch (StandardException se) @@ -711,6 +742,7 @@ } // if we couldn't do this with a nested xaction, retry with // parent-- we need to wait this time! + prepareAndRelease(lcc, null, null); updateSYSSTATEMENTS(lcc, RECOMPILE, null); } else throw se; Index: java/engine/org/apache/derby/iapi/sql/dictionary/TabInfo.java =================================================================== --- java/engine/org/apache/derby/iapi/sql/dictionary/TabInfo.java (revision 431287) +++ java/engine/org/apache/derby/iapi/sql/dictionary/TabInfo.java (working copy) @@ -465,4 +465,64 @@ * @return The Properties associated with creating the specified index. */ public Properties getCreateIndexProperties(int indexNumber); + + /** + * Given a key row, delete all matching heap rows and their index + * rows. + *
+ * LOCKING: row locking if there is a key; otherwise, + * table locking. + * + * @param tc transaction controller + * @param key key to delete by. + * @param indexNumber Key is appropriate for this index. + * @param wait If true, then the caller wants to wait for locks. + * False will be when we using a nested user xaction + * - we want to timeout right away if the parent holds + * the lock. + * @return the number of rows deleted. If key is not unique, + * this may be more than one. + * @exception StandardException Thrown on failure + */ + public int deleteRow( TransactionController tc, + ExecIndexRow key, + int indexNumber, + boolean wait) + throws StandardException; + + /** + * Delete the set of rows defined by a scan on an index + * from the table. Most of the parameters are simply passed + * to TransactionController.openScan. Please refer to the + * TransactionController documentation for details. + *
+ * LOCKING: row locking if there is a start and a stop + * key; otherwise, table locking + * + * @param tc transaction controller + * @param startKey key to start the scan. + * @param startOp operation to start the scan. + * @param stopKey key to start the scan. + * @param qualifier a qualifier for the scan. + * @param filter filter on base rows + * @param stopOp operation to start the scan. + * @param indexNumber Key is appropriate for this index. + * @param wait If true, then the caller wants to wait for locks. + * False will be when we using a nested user xaction + * - we want to timeout right away if the parent holds + * the lock. + * @return the number of rows deleted. + * @exception StandardException Thrown on failure + * @see TransactionController#openScan + */ + public int deleteRows(TransactionController tc, + ExecIndexRow startKey, + int startOp, + Qualifier[][] qualifier, + TupleFilter filter, + ExecIndexRow stopKey, + int stopOp, + int indexNumber, + boolean wait) + throws StandardException; } Index: java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java =================================================================== --- java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (revision 431287) +++ java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (working copy) @@ -1712,4 +1712,52 @@ public String getVTIClass(TableDescriptor td) throws StandardException; + + /** + * Adds a descriptor to a system catalog identified by the catalogNumber. + * + * @param tuple descriptor to insert. + * @param parent parent descriptor; e.g for a column parent is the + * tabledescriptor to which the descriptor is beign inserted. for most other + * objects it is the schema descriptor. + * @param catalogNumber a value which identifies the catalog into which + * the descriptor should be inserted. It is the users responsibility to + * ensure that the catalogNumber is consistent with the tuple being + * inserted. + * @see DataDictionary#SYSCONGLOMERATES_CATALOG_NUM + * @param allowsDuplicates whether an exception should be thrown if the + * insert results in a duplicate; if this parameter is FALSE then one + * of the following exception will be thrown; LANG_OBJECT_ALREADY_EXISTS (if + * parent is null) or LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT (if parent is not + * null). The error message is created by getting the name and type of the + * tuple and parent. + * @see org.apache.derby.impl.sql.catalog.DataDictionaryImpl#duplicateDescriptorException + * @param tc the transaction controller to use to do all of this. + * @param wait If true, then the caller wants to wait for locks. False will + * be when we using a nested user xaction - we want to timeout + * right away if the parent holds the lock. + * @see #addDescriptorArray + */ + public void addDescriptor(TupleDescriptor tuple, TupleDescriptor parent, + int catalogNumber, boolean allowsDuplicates, + TransactionController tc, boolean wait) + throws StandardException; + + /** + * Remove all of the stored dependencies for a given dependent's ID + * from the data dictionary. + * + * @param dependentsUUID Dependent's uuid + * @param tc TransactionController for the transaction + * @param wait If true, then the caller wants to wait for locks. False will + * be when we using a nested user xaction - we want to timeout + * right away if the parent holds the lock. + * + * @exception StandardException Thrown on failure + */ + public void dropDependentsStoredDependencies(UUID dependentsUUID, + TransactionController tc, + boolean wait) + throws StandardException; + } Index: java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java =================================================================== --- java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java (revision 431287) +++ java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java (working copy) @@ -689,17 +689,29 @@ // the trigger table, so there is a very large number of actions // that we would have to check against. This is hard to maintain, // so don't bother. - // When REVOKE_PRIVILEGE gets sent (this happens for privilege - // types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER), we - // make the TriggerDescriptor drop itself. - if (action == DependencyManager.REVOKE_PRIVILEGE) + + switch (action) { - DropTriggerConstantAction.dropTriggerDescriptor( - lcc,getDataDictionary().getDependencyManager(), - getDataDictionary(), lcc.getTransactionExecute(), this, - null); - return; + // invalidate this trigger descriptor + case DependencyManager.USER_RECOMPILE_REQUEST: + DependencyManager dm = getDataDictionary().getDependencyManager(); + dm.invalidateFor(this, DependencyManager.PREPARED_STATEMENT_RELEASE, lcc); + break; + + // When REVOKE_PRIVILEGE gets sent (this happens for privilege + // types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER), we + // make the TriggerDescriptor drop itself. + case DependencyManager.REVOKE_PRIVILEGE: + DropTriggerConstantAction.dropTriggerDescriptor( + lcc, getDataDictionary().getDependencyManager(), + getDataDictionary(), lcc.getTransactionExecute(), this, + null); + break; + + default: + break; } + } /** Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (revision 431287) +++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerGeneral.sql (working copy) @@ -625,3 +625,77 @@ SELECT * FROM T10642; SELECT * FROM T10641_DELETIONS; SELECT * FROM T10642_DELETIONS; + +-- creating and dropping index on the table in the trigger action +drop table t1; +drop table t2; +drop table t3; +drop table t4; +create table t1 (i int); +create table t2 (i int); +create trigger tt after insert on t1 for each statement mode db2sql insert into t2 values 1; +insert into t1 values 1; +create unique index tu on t2(i); +insert into t1 values 1; +select * from t2; +insert into t1 values 1; +select * from t2; +drop index tu; +select * from t2; +insert into t1 values 1; +select * from t2; +drop trigger tt; + +-- dropping and recreating a table which the trigger references +create table t3 (i int); +create table t4 (i int); +create trigger tt2 after insert on t3 for each statement mode db2sql insert into t4 values 1; +insert into t3 values 1; +select * from t4; +drop table t4; +insert into t3 values 1; +create table t4 (i int); +insert into t3 values 1; +select * from t4; + +-- dropping a function which the trigger references +create function max_value(x int, y int) returns int language java parameter style java external name 'java.lang.Math.max'; +create table test(a integer); +create trigger test_trigger AFTER insert on test FOR EACH ROW MODE DB2SQL values max_value(2,4); + +insert into test values(1); + +--- drop function and again do inserts. these should not work as the trigger would be invalid +drop function max_value; +insert into test values(2); +insert into test values(1); + + +-- dropping a view which the trigger references +create table t11TriggerTest (c111 int not null primary key, c112 int); +insert into t11TriggerTest values(1,1); +insert into t11TriggerTest values(2,2); + +-- create a view based on table t11TriggerTest +create view v21ViewTest as select * from t11TriggerTest; + +-- get ready to create a trigger. Trigger is created on t31TriggerTest and it inserts into t32TriggerTest +create table t31TriggerTest (c311 int); +create table t32TriggerTest (c321 int); +create trigger tr31t31TriggerTest after insert on t31TriggerTest for each statement mode db2sql + insert into t32TriggerTest values (select c111 from v21ViewTest where c112=1); + +-- try an insert which will fire the trigger +insert into t31TriggerTest values(1); +select * from t31TriggerTest; +-- we know the trigger got fired if there is one row in t32TriggerTest +select * from t32TriggerTest; + +-- drop the view used by the trigger. +drop view v21ViewTest; + +-- try an insert which would cause insert trigger to fire. The insert trigger should have failed because view doesn't +-- exist anymore. +insert into t31TriggerTest values(1); +select * from t31TriggerTest; +select * from t32TriggerTest; Index: java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (revision 431287) +++ java/testing/org/apache/derbyTesting/functionTests/master/triggerGeneral.out (working copy) @@ -1133,4 +1133,136 @@ ----------- 0 1 +ij> -- creating and dropping index on the table in the trigger action +drop table t1; +ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T1' because it does not exist. +ij> drop table t2; +ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T2' because it does not exist. +ij> drop table t3; +ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T3' because it does not exist. +ij> drop table t4; +ERROR 42Y55: 'DROP TABLE' cannot be performed on 'T4' because it does not exist. +ij> create table t1 (i int); +0 rows inserted/updated/deleted +ij> create table t2 (i int); +0 rows inserted/updated/deleted +ij> create trigger tt after insert on t1 for each statement mode db2sql insert into t2 values 1; +0 rows inserted/updated/deleted +ij> insert into t1 values 1; +1 row inserted/updated/deleted +ij> create unique index tu on t2(i); +0 rows inserted/updated/deleted +ij> insert into t1 values 1; +ERROR 23505: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'TU' defined on 'T2'. +ij> select * from t2; +I +----------- +1 +ij> insert into t1 values 1; +ERROR 23505: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'TU' defined on 'T2'. +ij> select * from t2; +I +----------- +1 +ij> drop index tu; +0 rows inserted/updated/deleted +ij> select * from t2; +I +----------- +1 +ij> insert into t1 values 1; +1 row inserted/updated/deleted +ij> select * from t2; +I +----------- +1 +1 +ij> drop trigger tt; +0 rows inserted/updated/deleted +ij> -- dropping and recreating a table which the trigger references +create table t3 (i int); +0 rows inserted/updated/deleted +ij> create table t4 (i int); +0 rows inserted/updated/deleted +ij> create trigger tt2 after insert on t3 for each statement mode db2sql insert into t4 values 1; +0 rows inserted/updated/deleted +ij> insert into t3 values 1; +1 row inserted/updated/deleted +ij> select * from t4; +I +----------- +1 +ij> drop table t4; +0 rows inserted/updated/deleted +ij> insert into t3 values 1; +ERROR 42X05: Table/View 'T4' does not exist. +ij> create table t4 (i int); +0 rows inserted/updated/deleted +ij> insert into t3 values 1; +1 row inserted/updated/deleted +ij> select * from t4; +I +----------- +1 +ij> -- dropping a function which the trigger references +create function max_value(x int, y int) returns int language java parameter style java external name 'java.lang.Math.max'; +0 rows inserted/updated/deleted +ij> create table test(a integer); +0 rows inserted/updated/deleted +ij> create trigger test_trigger AFTER insert on test FOR EACH ROW MODE DB2SQL values max_value(2,4); +0 rows inserted/updated/deleted +ij> insert into test values(1); +1 row inserted/updated/deleted +ij> --- drop function and again do inserts. these should not work as the trigger would be invalid +drop function max_value; +0 rows inserted/updated/deleted +ij> insert into test values(2); +ERROR 42Y03: 'MAX_VALUE' is not recognized as a function or procedure. +ij> insert into test values(1); +ERROR 42Y03: 'MAX_VALUE' is not recognized as a function or procedure. +ij> -- dropping a view which the trigger references +create table t11TriggerTest (c111 int not null primary key, c112 int); +0 rows inserted/updated/deleted +ij> insert into t11TriggerTest values(1,1); +1 row inserted/updated/deleted +ij> insert into t11TriggerTest values(2,2); +1 row inserted/updated/deleted +ij> -- create a view based on table t11TriggerTest +create view v21ViewTest as select * from t11TriggerTest; +0 rows inserted/updated/deleted +ij> -- get ready to create a trigger. Trigger is created on t31TriggerTest and it inserts into t32TriggerTest +create table t31TriggerTest (c311 int); +0 rows inserted/updated/deleted +ij> create table t32TriggerTest (c321 int); +0 rows inserted/updated/deleted +ij> create trigger tr31t31TriggerTest after insert on t31TriggerTest for each statement mode db2sql + insert into t32TriggerTest values (select c111 from v21ViewTest where c112=1); +0 rows inserted/updated/deleted +ij> -- try an insert which will fire the trigger +insert into t31TriggerTest values(1); +1 row inserted/updated/deleted +ij> select * from t31TriggerTest; +C311 +----------- +1 +ij> -- we know the trigger got fired if there is one row in t32TriggerTest +select * from t32TriggerTest; +C321 +----------- +1 +ij> -- drop the view used by the trigger. +drop view v21ViewTest; +0 rows inserted/updated/deleted +ij> -- try an insert which would cause insert trigger to fire. The insert trigger should have failed because view doesn't +-- exist anymore. +insert into t31TriggerTest values(1); +ERROR 42X05: Table/View 'V21VIEWTEST' does not exist. +ij> select * from t31TriggerTest; +C311 +----------- +1 +ij> select * from t32TriggerTest; +C321 +----------- +1 ij>