SQL Server 2008 R2 : Creating and Managing Triggers – Using Nested Triggers, Using Recursive Triggers

1. Using Nested Triggers

Triggers can be nested up to 32 levels. If a trigger changes a table on which another trigger exists, the second trigger is fired and can then fire a third trigger, and so on. If the nesting level is exceeded, the trigger is canceled, and the transaction is rolled back.

The following error message is returned if the nesting level is exceeded:

Server: Msg 217, Level 16, State 1, Procedure ttt2, Line 2
Maximum stored procedure nesting level exceeded (limit 32).

 

You can disable nested triggers by setting the nested triggers option of sp_configure to 0 (off):

EXEC sp_configure 'nested triggers', 0
GO
RECONFIGURE WITH OVERRIDE
GO

 

After the nested triggers option is turned off, the only triggers to fire are those that are part of the original data modification: the top-level triggers. If updates to other tables are made via the top-level triggers, those updates are completed, but the triggers on those tables do not fire. For example, say you have an UPDATE trigger on the jobs table in the BigPubs2008 database and an UPDATE trigger on the employee table as well. The trigger on the jobs table updates the employee table. If an update is made to the jobs table, the jobs trigger fires and completes the updates on the employee table. However, the trigger on the employee table does not fire.

The default configuration is to allow nested triggers, but there are reasons for turning off the nested triggers option. For example, you might want triggers to fire on direct data modifications but not on modifications that are made by another trigger. Say you have a trigger on every table that updates the audit time. You might want the audit time for a table to be updated by a trigger when that table is being updated directly, but you might not want the audit date updated on any of the other tables that are part of the nested trigger executions. This can be accomplished by turning off the nested triggers option.

2. Using Recursive Triggers

Recursive triggers were introduced in SQL Server 7.0. If a trigger modifies the same table where the trigger was created, the trigger does not fire again unless the recursive triggers option is turned on. recursive triggers is a database option turned off by default.

The first command in the following example checks the setting of recursive triggers for the BigPubs2008 database, and the second sets recursive triggers to TRUE:

EXEC sp_dboption BigPubs2008, 'recursive triggers'


EXEC sp_dboption BigPubs2008, 'recursive triggers', TRUE

 

If you turn off nested triggers, recursive triggers are automatically disabled, regardless of how the database option is set. The maximum nesting level for recursive triggers is the same as for nested triggers: 32 levels.

You should use recursive triggers with care. It is easy to create an endless loop, as shown in Listing 1, which creates a recursive trigger on a new test table in the BigPubs2008 database.

Listing 1. The Error Message Returned for an Endless Loop with Recursive Triggers
--The first statement is used to disable the previously created
--DDL trigger which would prevent any changes.
DISABLE TRIGGER ALL ON DATABASE
EXEC sp_configure 'nested triggers', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_dboption BigPubs2008, 'recursive triggers', TRUE
CREATE TABLE rk_tr_test (id int IDENTITY)
GO
CREATE TRIGGER rk_tr ON rk_tr_test FOR INSERT
AS INSERT rk_tr_test DEFAULT VALUES
GO
INSERT rk_tr_test DEFAULT VALUES

Server: Msg 217, Level 16, State 1, Procedure rk_tr, Line 2
Maximum stored procedure nesting level exceeded (limit 32).


The recursion described thus far is known as direct recursion. Another type of recursion exists as well: indirect recursion. With indirect recursion, a table that has a trigger fires an update to another table, and that table, in turn, causes an update to happen to the original table on which the trigger fired. This action causes the trigger on the original table to fire again.

With indirect recursion, setting the recursive triggers database setting to FALSE does not prevent the recursion from happening. The only way to prevent this type of recursion is to set the nested triggers setting to FALSE, which, in turn, prevents all recursion.