![]() |
|
|
By: Arshad Ali | Read Comments | Print Arshad is a SQL and BI Developer focusing on Data Warehousing projects @ Microsoft India R&D Pvt Ltd. Related Tips: 1 | 2 | 3 | More |
|
Prior to SQL Server 2005, writing code for exception handling was painful for T-SQL developers. SQL Server 2005 introduced structured exception handling with BEGIN TRY...BEGIN CATCH blocks. Though this inclusion made managing exceptions in T-SQL programming quite easier, it has some limitations. In this tip I am going to talk about some of these challenges and limitations, then show how a new command THROW in SQL Server Denali overcomes those items.
While writing T-SQL code we use the RAISERROR command to raise an exception. We normally use the RAISERROR command inside of a BEGIN TRY...END TRY block to raise an exception and handle it in the BEGIN CATCH...END CATCH block. Sometimes we need to raise the exception or re-raise the same exception from the BEGIN CATCH...END CATCH block to send it to an outer block or calling application and hence we use RAISERROR command inside the BEGIN CATCH...END CATCH block.
Generally speaking, there are two different ways we can use the RAISERROR command to raise an exception. First, we can pass the error message string as an argument to this command (in this case the error number will be 50000). The second, way is to pass the error number. When we use error number as a parameter to the RAISERROR command, the entry for that error number must exist in the sys.messages system table or the RAISERROR command itself will fail. Although this second approach sounds easy at first, it becomes a little difficult if you are calling procedures across instances (where you need to add error messages on all instances) or you are migrating you code from one instance to another and you forget to migrate the messages from the sys.messages system object. Let's see step by step how we can use RAISERROR command as well as new THROW command.
In Script #1, I am simply creating a table in the tempdb database for the our examples.
|
Script #1 - Setup environment for testing |
USE tempdb; GO CREATE TABLE dbo.Sample_Table ( column_1 int NOT NULL PRIMARY KEY, column_2 int NULL ); |
In Script #2, my intent is to show how you can use the BEGIN TRY...END TRY and BEGIN CATCH...END CATCH blocks for structured exception handling. Inside the BEGIN TRY...END TRY block I am trying to insert duplicate records. In this circumstance, SQL Server throws an error (error number 2627). As a result of this error, control and execution will jump to the BEGIN CATCH...END CATCH block. Here we can gracefully handle the exception and continue with further processing or re-raise the exception.
|
Script #2 - Structured Exception Handling |
BEGIN TRY TRUNCATE TABLE dbo.Sample_Table; INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After First Insert'; -- Msg 2627, Level 14, State 1 - Violation of PRIMARY KEY constraint INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After Second Insert'; END TRY BEGIN CATCH PRINT 'In Catch Block.'; END CATCH; |
In Script #3, I have the same example as above, but this time I am re-raising the exception (to send it to the outer block or caller application). You can notice here the RAISERROR command itself fails. The reason is we are raising the exception by passing the system generated error number, which is not allowed to be used explicitly by the users (you can add your own user defined messages to the sys.messages table and then use the user defined message while raising an exception). Please note, when you raise an exception by passing the error number as an argument to RAISERROR command, that error number must exist in the sys.messages table (user defined messages can be added with the sp_addmessage system stored procedure).
|
Script #3 - Re-raising exception with Error Number |
BEGIN TRY TRUNCATE TABLE dbo.Sample_Table; INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After First Insert'; -- Msg 2627, Level 14, State 1 - Violation of PRIMARY KEY constraint INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After Second Insert'; END TRY BEGIN CATCH DECLARE @ErrorNumber INT = ERROR_NUMBER(); RAISERROR(@ErrorNumber, 16, 1) END CATCH; |
In Script #4, I have the same example as above, but this time instead of passing the error number I am passing the error message (I have concatenated the error number and error message in one string) and it works fine. Please note, even though it works fine, the indicated line number is Line 12 of the RAISERROR command instead of Line 6 of the actual command which failed.
|
Script #4 - Re-raising exception with Error Message |
BEGIN TRY
TRUNCATE TABLE dbo.Sample_Table;
INSERT dbo.Sample_Table VALUES(1, 1);
PRINT 'After First Insert';
-- Msg 2627, Level 14, State 1 - Violation of PRIMARY KEY constraint
INSERT dbo.Sample_Table VALUES(1, 1);
PRINT 'After Second Insert';
END TRY
BEGIN CATCH
DECLARE @ErrorNumber INT = ERROR_NUMBER();
DECLARE @ErrorMessage NVARCHAR(1000) = ERROR_MESSAGE()
RAISERROR('Error Number-%d : Error Message-%s', 16, 1,
@ErrorNumber, @ErrorMessage)
END CATCH;![]() |
In Script #5, I have the same example as above, but this time instead of using RAISERROR command to re-raise the exception I am using new THROW command. As you can see, this time it reports the exact error number (i.e. 2627) which caused the exception as well as the exact line number where the exception occurred.
|
Script #5 - Re-raising exception with the new THROW command |
BEGIN TRY TRUNCATE TABLE dbo.Sample_Table; INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After First Insert'; -- Msg 2627, Level 14, State 1 - Violation of PRIMARY KEY constraint INSERT dbo.Sample_Table VALUES(1, 1); PRINT 'After Second Insert'; END TRY BEGIN CATCH PRINT 'Handle Exception here if required and re-throw'; THROW; END CATCH; ![]() |
Here are a few observations:
| Share: | Share | Tweet |
|
![]() |
![]() |
Free SQL Server Learning |
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |