Tải bản đầy đủ (.pdf) (10 trang)

Microsoft SQL Server 2008 R2 Unleashed- P105 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (349.23 KB, 10 trang )

ptg
984
CHAPTER 30 Creating and Managing Triggers
This type of trigger is useful for controlling development and production database envi-
ronments. It goes beyond the normal security measures and helps manage unwanted
change. For development environments, this type of trigger enables the database adminis-
trator to lock down an environment and focus all changes through that person.
The previous examples include events scoped at the database level. Let’s look at an
example that applies to server-level events. The script in Listing 30.15 creates a trigger
scoped at the server level. It prevents changes to the server logins. When this trigger is
installed, it displays a message and rolls back any login changes that are attempted.
LISTING 30.15 A Server-Scoped DDL Trigger for Logins
CREATE TRIGGER tr_LoginAudit
ON ALL SERVER
FOR CREATE_LOGIN, ALTER_LOGIN, DROP_LOGIN
AS
PRINT ‘You must disable the tr_LoginAudit trigger before making login changes’
ROLLBACK
The DDL trigger examples we have looked at thus far have targeted specific events listed
in Table 30.2. These individual events can also be referenced via an event group. Event
groups are hierarchical in nature and can be referenced in DDL triggers instead of the indi-
vidual events. For example, the table-level trigger from Listing 30.14 can be changed as
shown in Listing 30.16 to accomplish the same result. In Listing 30.16, the
DDL_TABLE_EVENTS group reference replaces the individual event references to
CREATE_TABLE, ALTER_TABLE, and DROP_TABLE.
LISTING 30.16 An Example of a DDL Trigger Referencing an Event Group
USE [BigPubs2008]
IF EXISTS (SELECT * FROM sys.triggers
WHERE name = N’tr_TableAudit’ AND parent_class=0)
DROP TRIGGER [tr_TableAudit] ON DATABASE
go


CREATE TRIGGER tr_TableAudit
ON DATABASE
FOR DDL_TABLE_EVENTS
AS
PRINT ‘You must disable the TableAudit trigger in
order to change any table in this database’
ROLLBACK
GO
Download from www.wowebook.com
ptg
985
Using DDL Triggers
30
SQL Server Books Online has an excellent diagram listing all the event groups that can be
used to fire DDL triggers. Refer to the “DDL Event Groups” topic in Books Online, which
shows the event groups and related DDL events they contain. Event groups simplify
administration and allow for auditing at a high level.
The DDL trigger examples we have looked at thus far have executed simple print state-
ments. To further extend the functionality of DDL triggers, you can code them to capture
event information related to the DDL trigger execution. You do this by using the
EVENTDATA function. The EVENTDATA function returns an XML string that includes the time
of the event, server process ID (SPID), and type of event that fired the trigger. For some
events, additional information, such as the object name or T-SQL statement, is included in
the XML string as well.
The
EVENTDATA function is essentially the replacement for the inserted and deleted tables
available with DML triggers but not available with DDL triggers. It gives you information
you can use to implement an auditing solution that captures changes to a data definition.
This function is particularly useful in situations in which you do not want to prevent
changes to your definition, but you want a record of the changes that occur.

Listing 30.17 shows an auditing solution with a DDL trigger that utilizes the
EVENTDATA
function to capture any changes to indexes in the BigPubs2008 database. Several event
data elements are selected from the EVENTDATA XML string and displayed whenever a
change is made to an index.
LISTING 30.17 An Example of a DDL Trigger That References an Event Group
CREATE TRIGGER tr_ddl_IndexAudit
ON DATABASE
FOR CREATE_INDEX, ALTER_INDEX, DROP_INDEX
AS
DECLARE @EventData XML
Capture event data from the EVENTDATA function
SET @EventData = EVENTDATA()
Select the auditing info from the XML stream
SELECT @EventData.query (‘’data(/EVENT_INSTANCE/PostTime)’’)
AS [Event Time],
@EventData.query (‘’data(/EVENT_INSTANCE/EventType)’’)
AS [Event Type],
@EventData.query (‘’data(/EVENT_INSTANCE/ServerName)’’)
AS [Server Name],
@EventData.query (‘’data(/EVENT_INSTANCE/TSQLCommand/CommandText)’’)
AS [Command Text]
GO
To test the DDL trigger in Listing 30.17, you can run the following statement to create an
index on the titles table in the BigPubs2008 database:
Download from www.wowebook.com
ptg
986
CHAPTER 30 Creating and Managing Triggers
CREATE NONCLUSTERED INDEX [nc_titles_type] ON [dbo].[titles] ( [type] ASC )

The INDEX CREATE statement completes successfully, and the event-specific information
appears in the Results pane.
You can further extend the auditing capabilities of this type of DDL trigger by writing the
results to an audit table. This would give you a quick way of tracking changes to database
objects. This type of approach dramatically improves change control and reporting on
database changes.
NOTE
DDL triggers can also execute managed code based on the CLR. This topic is dis-
cussed in the section “Using CLR Triggers,” later in this chapter.
Managing DDL Triggers
The administration of DDL triggers is similar to the administration of DML triggers, but
DDL triggers are located in a different part of the Object Explorer tree. The reason is that
DDL triggers are scoped at the server or database level, not at the table level. Figure 30.3
shows the Object Explorer tree and the nodes related to DDL triggers at both the server
and database levels. The
tr_TableAudit trigger you created earlier in this chapter is shown
under the Database Triggers node. Figure 30.3 shows the options available when you
right-click a database trigger in the Object Explorer tree.
FIGURE 30.3 Using SSMS to manage DDL triggers.
Download from www.wowebook.com
ptg
987
Using DDL Triggers
30
The DDL triggers scoped at the server level are found in the Triggers node under the
Server Objects node of the Object Explorer tree. (The Server Objects node is near the
bottom of Figure 30.3.)
You can obtain information about DDL triggers by using catalog views. These views
provide a convenient and flexible means for querying database objects, including DDL
triggers. Table 30.3 lists the catalog views that relate to triggers. The table includes the

scope of the trigger that the view reports on and a brief description of what it returns.
Listing 30.18 shows sample
SELECT statements that utilize the catalog views. These state-
ments use the sys.triggers and sys.server_triggers views. The SELECT against the
sys.triggers table uses a WHERE clause condition that checks the parent_class column to
retrieve only DDL triggers. The SELECT from sys.server_triggers does not need a WHERE
clause because it inherently returns only DDL triggers. The results of each statement are
shown below each SELECT in the listing.
LISTING 30.18 Viewing DDL Triggers with Catalog Views
DATABASE SCOPED DDL TRIGGERS
select left(name,20) ‘Name’, create_date, modify_date, is_disabled
from sys.triggers
where parent_class = 0
TABLE 30.3 Catalog Views for DDL Triggers
Catalog View Description
Statements with Database-Level Scope
sys.triggers
All triggers, including DDL database-scoped triggers
sys.trigger_events
All trigger events, including those that fire DDL database-
scoped triggers
sys.sql_modules
All SQL-defined modules, including trigger definitions
sys.assembly_modules
All CLR-defined modules, including database-scoped triggers
Statements with Server-Level Scope
sys.server_triggers
Server-scoped DDL triggers
sys.server_trigger_events
Events that fire server-scoped triggers

sys.sql_modules
DDL trigger definitions for server-scoped triggers
sys.server_assembly_modules
CLR trigger definitions for server-scoped triggers
Download from www.wowebook.com
ptg
988
CHAPTER 30 Creating and Managing Triggers
Name create_date modify_date is_disabled

tr_TableAudit 2009-06-18 12:48:43.140 2009-06-18 12:48:43.140 0
tr_ddl_IndexAudit 2009-06-22 06:35:10.233 2009-06-22 06:35:10.233 0
SERVER SCOPED DDL TRIGGERS
select left(name,20) ‘Name’, create_date, modify_date, is_disabled
from sys.server_triggers
Name create_date modify_date is_disabled

tr_LoginAudit 2009-06-18 12:13:46.077 2005-06-18 12:13:46.077 0
Using CLR Triggers
CLR triggers are triggers based on the CLR. CLR integration, which was added with SQL
Server 2008, allows for database objects (such as triggers) to be coded in one of the
supported .NET languages, including Visual Basic .NET and C#.
The decision to code triggers and other database objects by using the CLR depends on the
type of operations in the trigger. Typically, objects that have heavy computations or
require references to objects outside SQL are coded in the CLR. Triggers strictly geared
toward database access should continue to be coded in T-SQL.
You can code both DDL and DML triggers by using a supported CLR language. Generally
speaking, it is much easier to code a CLR trigger in the Visual Studio .NET Integrated
Development Environment (IDE), but you can create them outside the IDE as well. Visual
Studio .NET provides a development environment that offers IntelliSense, debugging facil-

ities, and other user-friendly capabilities that come with a robust IDE. The .NET
Framework and development environment are discussed in more detail in Chapter 4, “SQL
Server and the .NET Framework.”
The following basic steps are required to create a CLR trigger:
1. Create the CLR class. You code the CLR class module with references to the name-
spaces required to compile CLR database objects.
2. Compile the CLR class into an assembly or a DDL file, using the appropriate
language compiler.
3. Load the CLR assembly into SQL Server so that it can be referenced.
4. Create the CLR trigger that references the loaded assembly.
The following listings provide examples of each of these steps.
Download from www.wowebook.com
ptg
989
Using CLR Triggers
30
NOTE
The CLR must be enabled on your server before you can add CLR components. The
CLR option is disabled by default. To enable the CLR, you use the sp_configure ‘clr
enabled’, 1 T-SQL command followed by the RECONFIGURE command. You can also
enable CLR integration by using SQL Server 2008 Surface Area Configuration and then
choosing the Surface Area Configuration for Features and selecting the Enable CLR
Integration option.
Listing 30.19 contains C# code that can be used for the first step: creating the CLR class.
This simple example selects rows from the inserted table.
LISTING 30.19 A CLR Trigger Class Created with C#
using System;
using System.Data;
using System.Data.Sql;
using Microsoft.SqlServer.Server;

using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
using System.Text.RegularExpressions;
public class clrtriggertest
{
public static void showinserted()
{
SqlTriggerContext triggContext = SqlContext.TriggerContext;
SqlConnection conn = new SqlConnection (“context connection = true”);
conn.Open();
SqlCommand sqlComm = conn.CreateCommand();
SqlPipe sqlP = SqlContext.Pipe;
SqlDataReader dr;
sqlComm.CommandText = “SELECT pub_id, pub_name from inserted”;
dr = sqlComm.ExecuteReader();
while (dr.Read())
sqlP.Send((string)dr[0] + “, “ + (string)dr[1]);
}
}
The CLR class in Listing 30.19 needs to be compiled so that SQL Server can use it. The
compiler for C# is located in the .NET Framework path, which is
Download from www.wowebook.com
ptg
990
CHAPTER 30 Creating and Managing Triggers
C:\WINDOWS\Microsoft.NET\Framework\version by default. The last part of the path,
version, is the number of the latest version installed on your machine. For simplicity’s
sake, you can add the full .NET Framework path to your path variable in the Advanced tab
of your System Properties dialog. If you add the .NET Framework path to your path vari-

able, you can run the executable for the compiler without navigating to that location.
You can save the code from Listing 30.19 in a text file named
clrtriggertesting.cs.
Then you can open a command prompt window and navigate to the folder where you
saved the
clrtriggertesting.cs file. The command shown in Listing 30.20 compiles the
clrtriggertesting.cs file into clrtriggertesting.dll. This command can be run from
any directory if you have added the .NET Framework path (for example,
C:\WINDOWS\Microsoft.NET\Framework\v3.5) to your path variable. Without the addi-
tional path entry, you need to navigate to the .NET Framework path prior to executing
the command.
LISTING 30.20 A CLR Trigger Class Compilation
csc /target:library clrtriggertesting.cs
After compiling clrtriggertesting.dll, you need to load the assembly into SQL Server.
Listing 30.21 shows the T-SQL command you can execute to create the assembly for
clrtriggertesting.dll.
LISTING 30.21 Using CREATE ASSEMBLY in SQL Server
CREATE ASSEMBLY triggertesting
from ‘c:\clrtrigger\clrtriggertesting.dll’
WITH PERMISSION_SET = SAFE
The final step is to create the trigger that references the assembly. Listing 30.22 shows the
T-SQL commands to add a trigger on the publishers table in the BigPubs2008 database.
LISTING 30.22 Creating a CLR Trigger
CREATE TRIGGER tri_publishers_clr
ON publishers
FOR INSERT
AS
EXTERNAL NAME triggertesting.clrtriggertest.showinserted
Listing 30.23 contains an INSERT statement to the publishers table that fires the newly
created CLR trigger.

Download from www.wowebook.com
ptg
991
Using Nested Triggers
30
LISTING 30.23 Using an INSERT Statement to Fire a CLR Trigger
INSERT publishers
(pub_id, pub_name)
values (‘9922’,’Sams Publishing’)
The trigger simply echoes the contents of the inserted table. The output from the trigger
based on the insertion in Listing 30.23 is as follows:
9922, Sams Publishing
The tri_publishers trigger demonstrates the basic steps for creating a CLR trigger. The
true power of CLR triggers lies in performing more complex calculations, string manipula-
tions and things of this nature that the can be done much more efficiently with CLR
programming languages than they can in T-SQL.
NOTE
For more detailed information and examples of CLR triggers, see Chapter 45.
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.
Download from www.wowebook.com
ptg
992
CHAPTER 30 Creating and Managing Triggers
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.
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 trig-
gers 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 30.24, which creates a recursive trigger on a new test table in the
BigPubs2008
database.
LISTING 30.24 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).
Download from www.wowebook.com
ptg
993
Summary
30
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 origi-

nal 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.
Summary
Triggers are among the most powerful tools for ensuring the quality of data in a database.
The range of commands that can be executed from within triggers and their capability to
automatically fire give them a distinct role in defining sound database solutions.
Chapter 31, “Transaction Management and the Transaction Log,” looks at the methods for
defining and managing transactions within SQL Server 2008.
Download from www.wowebook.com

×