programming4us
programming4us
DATABASE

SQL Server 2012 : Exploring SQL CLR - CLR Triggers

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
11/25/2013 8:28:54 PM
T-SQL triggers are really just stored procedures that are called by SQL Server at specific times and that can query values in the DELETED and INSERTEDSQL CLR triggers are similar to SQL CLR stored procedures, and they can be created for all data manipulation language (DML) actions that modify data (that is, updates, inserts, and deletes). pseudo-tables (which expose “before and after” snapshots of data changed by the statement that fired the trigger).

SQL Server 2005 introduced the concept of data definition language (DDL) triggers, which can intercept and handle actions such as CREATE TABLE and ALTER PROCEDURE. Like DML triggers, DDL triggers can be implemented in T-SQL or SQL CLR code. We will cover both SQL CLR DML and DDL triggers in this section.

SQL CLR DML triggers, like their T-SQL counterparts, have access to the DELETED and INSERTED pseudo-tables and must be declared as handling one or more specific events for a specific table or, under certain circumstances, a specific view. Also, they can make use of the SqlTriggerContext object (through the SqlContext object’s TriggerContext property) to determine which particular event (update, insert, or delete) caused them to fire and which columns were updated.

Once you understand these concepts, writing SQL CLR DML triggers is really quite simple. Example 1, which shows the code for the trgUpdatePerson function from trgTest.cs in the SQLCLRDemo sample project, shows the SQL CLR code for the trgUpdatePerson DML trigger, which is designed to function as a FOR UPDATE trigger on the Person.Person table in the AdventureWorks2012 database.

Example 1. trgUpdatePerson from trgTest.cs.

[SqlTrigger(Target="Person.Person", Event="for UPDATE")]
public static void trgUpdatePerson()
{
SqlTriggerContext context = SqlContext.TriggerContext;
string oldName = string.Empty;
string newName = string.Empty;
SqlConnection conn = new SqlConnection("context connection=true");
SqlCommand cmOld = new SqlCommand(
"SELECT FirstName FROM DELETED", conn);
SqlCommand cmNew = new SqlCommand(
"SELECT FirstName FROM INSERTED", conn);
conn.Open();
SqlDataReader drOld = cmOld.ExecuteReader();
if (drOld.Read())
{
oldName = (string)drOld[0];
}
drOld.Close();
SqlDataReader drNew = cmNew.ExecuteReader();
if (drNew.Read())
{

newName = (string)drNew[0];
}
drNew.Close();
conn.Close();
SqlContext.Pipe.Send("Old Value of FirstName:" + oldName);
SqlContext.Pipe.Send("New Value of FirstName:" + newName);
for (int i = 0; i <= context.ColumnCount - 1; i++)
{
SqlContext.Pipe.Send("Column " + i.ToString() + ": " +
context.IsUpdatedColumn(i).ToString());
}
}

This CLR DML trigger queries the DELETED and INSERTED pseudo-tables and echoes back the “before and after” values (respectively) for the FirstNameSqlDataReader objects but by fetching values from the pseudo-tables and echoing back the values as text using the SqlPipe object’s Send method. The trigger code also uses the TriggerContext.IsUpdatedColumn method to return a list of all columns in the Person.Person table and whether each was updated. column when a row is updated. It does so not by piping back

To deploy the trigger automatically, you apply a SqlTrigger attribute to the .NET function that implements the trigger. Because DML triggers are tied to a target object (a table or a view) and an event (for example, “for update” or “instead of insert”), the SqlTrigger attribute has parameters for each of these pieces of information and you must supply values for both. The SqlTrigger attribute deploys only a single copy of the trigger, but you can use T-SQL to deploy the same code as a separate trigger for a different event and table. Each separate deployment of the same code is assigned a unique trigger name.

Although Example 1 does not demonstrate it, you can create a single piece of code that functions as both the update and the insert trigger for a given table. You can then use the TriggerContext object’s TriggerAction property to determine exactly what event caused the trigger to fire, and you can execute slightly different code accordingly. Should you want to deploy such a CLR trigger using the SqlTrigger attribute, you would set its Event parameter to FOR UPDATE, INSERT.

The T-SQL command to register a .NET function as a SQL CLR trigger (for the update event only) is as follows:

CREATE TRIGGER trgUpdatePerson
ON Person.Person
FOR UPDATE
AS EXTERNAL NAME SQLCLRDemo.Triggers.trgUpdatePerson

You can use the following query to test the trigger. (This T-SQL code can be found in the TestTriggers.sql script file in the SSMS project.)

UPDATE Person.Person
SET FirstName = 'Gustavo'
WHERE BusinessEntityId = 1

If you place the TriggerContext object’s TriggerAction property in a comparison statement, Visual Studio’s IntelliSense will show you that there is a wide array of enumerated constants that the property can be equal to, and that a majority of these values correspond to DDL triggers. This demonstrates clearly that SQL CLR code can be used for DDL and DML triggers alike.

In the case of DDL triggers, a wide array of environmental information might be desirable to determine exactly what event caused the trigger to fire, what system process ID (SPID) invoked it, what time the event fired, and other information specific to the event type such as the T-SQL command that caused the event. The SqlTriggerContext object’s EventData property can be queried to fetch this information. The EventData property is of type SqlXml; therefore it, in turn, has a CreateReader method and a Value property that you can use to fetch the XML-formatted event data as an XmlReader object or text, respectively.

The code in Example 2, taken from function trgCreateTable in trgTest.cs in the SQLCLRDemo sample project, shows the SQL CLR code for the DDL trigger trgCreateTable, registered to fire for any CREATE TABLE statement executed on the AdventureWorks2012 database.

Example 2. trgCreateTable from trgTest.cs.

[SqlTrigger(Target = "DATABASE", Event = "FOR CREATE_TABLE")]
public static void trgCreateTable()
{
SqlTriggerContext context = SqlContext.TriggerContext;
if (!(context.EventData == null))
{
SqlContext.Pipe.Send("Event Data: " + context.EventData.Value.ToString());
}
}

The code interrogates the Value property of SqlContext.TriggerContext.EventData, converts it to a string, and pipes that string back to the client. To deploy this trigger, you can use attribute-based deployment in the SQL Server Database Project or the following command for the Class Library version:

CREATE TRIGGER trgCreateTable
ON DATABASE
FOR CREATE_TABLE
AS EXTERNAL NAME SQLCLRDemo.Triggers.trgCreateTable

Use the following T-SQL DDL command to test the DDL trigger. (You can find this code in the TestTriggers.sql script file in the sample SSMS project.)

CREATE TABLE Test (low int, high int)
DROP TABLE Test

Your result should contain the message “Event Data:” followed by text similar to the following:

<EVENT_INSTANCE>
<EventType>CREATE_TABLE</EventType>
<PostTime>2012-04-27T16:16:05.150</PostTime>
<SPID>66</SPID>
<ServerName>KIWI</ServerName>
<LoginName>CONTOSO\Administrator</LoginName>
<UserName>dbo</UserName>
<DatabaseName>AdventureWorks2012</DatabaseName>
<SchemaName>dbo</SchemaName>
<ObjectName>Test</ObjectName>
<ObjectType>TABLE</ObjectType>
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON"
QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
<CommandText>CREATE TABLE Test (low int, high int)</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>

Note

The actual output would consist of continuous, unformatted text. Line breaks and indentation have been added here to make the EventData XML easier to read.

Other  
  •  My SQL : Replication for High Availability - Procedures (part 8) - Circular Replication
  •  My SQL : Replication for High Availability - Procedures (part 7) - Slave Promotion - Slave promotion in Python
  •  My SQL : Replication for High Availability - Procedures (part 6) - Slave Promotion - A revised method for promoting a slave
  •  My SQL : Replication for High Availability - Procedures (part 5) - Semisynchronous Replication - Configuring semisynchronous replication
  •  My SQL : Replication for High Availability - Procedures (part 4) - Dual Masters - Replicated disks using DRBD , Bidirectional replication
  •  My SQL : Replication for High Availability - Procedures (part 3) - Dual Masters - Shared disks
  •  My SQL : Replication for High Availability - Procedures (part 2) - Hot Standby
  •  My SQL : Replication for High Availability - Procedures (part 1) - The mysql.com Outage
  •  My SQL : Replication for High Availability - Redundancy, Planning
  •  SQL Server 2012 : Exploring SQL CLR - Deployment (part 2) - Deploying Your Stored Procedures, Testing Your Stored Procedures
  •  
    Top 10
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
    - Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
    - Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    programming4us programming4us
    programming4us
     
     
    programming4us