You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by bp...@apache.org on 2007/01/04 22:06:44 UTC

svn commit: r492741 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: bpendleton
Date: Thu Jan  4 13:06:44 2007
New Revision: 492741

URL: http://svn.apache.org/viewvc?view=rev&rev=492741
Log:
DERBY-2195: Trigger problems after maximum trigger count exception

This patch was contributed by Yip Ng (yipng168@gmail.com)

The system is not cleaning up the statement context properly. The
cleanup should have been performed in GenericTriggerExecutor's executeSPS
exception handler. The GenericTriggerExecutor is responsible to make sure
the SPS execution is cleanup correctly.

In addition, there is another potential problem with the exception
handling logic in executeSPS() where it assumes that the SPS has executed
and therefore will have a new statement context and pops it off from
the LCC. This is somewhat dangerous as StandardException can occur before
pushing the new statement context to the stack; hence, this might
result in popping the wrong statement context. So the patch
also addresses this issue.


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/triggerRecursion.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerRecursion.sql

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java?view=diff&rev=492741&r1=492740&r2=492741
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java Thu Jan  4 13:06:44 2007
@@ -152,6 +152,9 @@
 				ps.setSPSAction();
 			}
 
+			// save the active statement context for exception handling purpose
+			StatementContext active_sc = lcc.getStatementContext();
+			
 			/*
 			** Execute the activation.  If we have an error, we
 			** are going to go to some extra work to pop off
@@ -182,16 +185,46 @@
 			} 
 			catch (StandardException e)
 			{
+				/* 
+				** When a trigger SPS action is executed and results in 
+				** an exception, the system needs to clean up the active 
+				** statement context(SC) and the trigger execution context
+				** (TEC) in language connection context(LCC) properly (e.g.:  
+				** "Maximum depth triggers exceeded" exception); otherwise, 
+				** this will leave old TECs lingering and may result in 
+				** subsequent statements within the same connection to throw 
+				** the same exception again prematurely.  
+				**    
+				** A new statement context will be created for the SPS before
+				** it is executed.  However, it is possible for some 
+				** StandardException to be thrown before a new statement 
+				** context is pushed down to the context stack; hence, the 
+				** trigger executor needs to ensure that the current active SC 
+				** is associated with the SPS, so that it is cleaning up the 
+				** right statement context in LCC. 
+				**    
+				** When the active SC is cleaned up, the TEC will be removed
+				** from LCC and the SC object will be popped off from the LCC 
+				** as part of cleanupOnError logic.  
+				 */
+				
+				/* retrieve the current active SC */
+				StatementContext sc = lcc.getStatementContext();
+				
+				/* make sure that the cleanup is on the new SC */
+				if (active_sc != sc) 
+				{
+					sc.cleanupOnError(e);
+				}
+				
 				/* Handle dynamic recompiles */
 				if (e.getMessageId().equals(SQLState.LANG_STATEMENT_NEEDS_RECOMPILE))
 				{
-					StatementContext sc = lcc.getStatementContext();
-					sc.cleanupOnError(e);
 					recompile = true;
 					sps.revalidate(lcc);
 					continue;
 				}
-				lcc.popStatementContext(lcc.getStatementContext(), e);
+				
 				spsActivation.close();
 				throw e;
 			}

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/triggerRecursion.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/triggerRecursion.out?view=diff&rev=492741&r1=492740&r2=492741
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/triggerRecursion.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/triggerRecursion.out Thu Jan  4 13:06:44 2007
@@ -97,9 +97,75 @@
 ij> -- The following should work, but because of defect 5602, it raises NullPointerException.
 -- After the fix for 5602, we could enable the following part of the test.
 -- Reduce the recursion level to 16. It should pass now.
--- drop trigger tr17;
--- insert  into t1 values 2;
--- prove it
--- select * from t1;
-;
+drop trigger tr17;
+0 rows inserted/updated/deleted
+ij> insert  into t1 values 2;
+1 row inserted/updated/deleted
+ij> -- prove it
+select * from t1;
+X          
+-----------
+2          
+ij> -- clean up
+drop table t17;
+0 rows inserted/updated/deleted
+ij> drop table t16;
+0 rows inserted/updated/deleted
+ij> drop table t15;
+0 rows inserted/updated/deleted
+ij> drop table t14;
+0 rows inserted/updated/deleted
+ij> drop table t13;
+0 rows inserted/updated/deleted
+ij> drop table t12;
+0 rows inserted/updated/deleted
+ij> drop table t11;
+0 rows inserted/updated/deleted
+ij> drop table t10;
+0 rows inserted/updated/deleted
+ij> drop table t9;
+0 rows inserted/updated/deleted
+ij> drop table t8;
+0 rows inserted/updated/deleted
+ij> drop table t7;
+0 rows inserted/updated/deleted
+ij> drop table t6;
+0 rows inserted/updated/deleted
+ij> drop table t5;
+0 rows inserted/updated/deleted
+ij> drop table t4;
+0 rows inserted/updated/deleted
+ij> drop table t3;
+0 rows inserted/updated/deleted
+ij> drop table t2;
+0 rows inserted/updated/deleted
+ij> drop table t1;
+0 rows inserted/updated/deleted
+ij> -- DERBY-2195
+-- Nested triggers not working properly after maximum trigger count exception is thrown
+create table t1 (i int);
+0 rows inserted/updated/deleted
+ij> insert into t1 values 1,2,3;
+3 rows inserted/updated/deleted
+ij> create trigger tr1 after update on t1 for each row update t1 set i=i+1;
+0 rows inserted/updated/deleted
+ij> update t1 set i=i+1;
+ERROR 54038: Maximum depth of nested triggers was exceeded.
+ij> drop trigger tr1;
+0 rows inserted/updated/deleted
+ij> create trigger tr1 after update on t1 referencing old as oldt for each row update t1 set i=i+1 where oldt.i=2;
+0 rows inserted/updated/deleted
+ij> -- ok
+update t1 set i=i+1;
+3 rows inserted/updated/deleted
+ij> select * from t1;
+I          
+-----------
+4          
+5          
+6          
+ij> drop trigger tr1;
+0 rows inserted/updated/deleted
+ij> drop table t1;
+0 rows inserted/updated/deleted
 ij> 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerRecursion.sql
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerRecursion.sql?view=diff&rev=492741&r1=492740&r2=492741
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerRecursion.sql (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/triggerRecursion.sql Thu Jan  4 13:06:44 2007
@@ -64,10 +64,43 @@
 -- The following should work, but because of defect 5602, it raises NullPointerException.
 -- After the fix for 5602, we could enable the following part of the test.
 -- Reduce the recursion level to 16. It should pass now.
--- drop trigger tr17;
+drop trigger tr17;
 
--- insert  into t1 values 2;
+insert  into t1 values 2;
 
 -- prove it
--- select * from t1;
+select * from t1;
+
+-- clean up
+drop table t17;
+drop table t16;
+drop table t15;
+drop table t14;
+drop table t13;
+drop table t12;
+drop table t11;
+drop table t10;
+drop table t9;
+drop table t8;
+drop table t7;
+drop table t6;
+drop table t5;
+drop table t4;
+drop table t3;
+drop table t2;
+drop table t1;
+
+-- DERBY-2195
+-- Nested triggers not working properly after maximum trigger count exception is thrown
+create table t1 (i int);
+insert into t1 values 1,2,3;
+create trigger tr1 after update on t1 for each row update t1 set i=i+1;
+update t1 set i=i+1;
+drop trigger tr1;
+create trigger tr1 after update on t1 referencing old as oldt for each row update t1 set i=i+1 where oldt.i=2;
+-- ok
+update t1 set i=i+1;
+select * from t1;
+drop trigger tr1;
+drop table t1;