handling errors in t sql code (1)
DESCRIPTION
Errores en sql server 2008TRANSCRIPT
Handling Errors in T-SQL Code 12-1
Module 12
Handling Errors in T-SQL Code Contents:
Lesson 1: Understanding T-SQL Error Handling 12-3
Lesson 2: Implementing T-SQL Error Handling 12-13
Lesson 3: Implementing Structured Exception Handling 12-23
Lab 12: Handling Errors in T-SQL Code 12-31
12-2 Implementing a Microsoft® SQL Server® 2008 R2 Database
Module Overview
When creating applications for SQL Server using the T-SQL language, appropriate handling of errors is
critically important. A large number of myths surround how error handling in T-SQL works. In this module,
you will explore T-SQL error handling; look at how it has traditionally been implemented and how
structured exception handling can be used.
Objectives
After completing this lesson, you will be able to:
Design T-SQL error handling
Implement T-SQL error handling
Implement structured exception handling
Handling Errors in T-SQL Code 12-3
Lesson 1
Understanding T-SQL Error Handling
Before delving into the coding that deals with error handling in T-SQL, it is important to gain an
understanding of the nature of errors, of where they can occur when T-SQL is being executed, the data
that is returned by errors and the severities that errors can exhibit.
Objectives
After completing this lesson, you will be able to:
Explain where T-SQL errors occur
Describe types of errors
Explain what values are returned by an error
Describe different levels of error severities
12-4 Implementing a Microsoft® SQL Server® 2008 R2 Database
Where T-SQL Errors Occur
Key Points
T-SQL statements go through multiple phases during their execution. Errors can occur at each phase.
Some errors could potentially be handled by the database engine. Other errors will need to be passed
back to the calling application.
Syntax Check
In the first phase of execution, the syntax of a statement is checked. At this phase errors occur if the
statements do not conform to the rules of the language. During the syntax checking phase that the
objects referred to may not actually exist yet still no errors would be returned. For example, imagine the
execution of a statement where the word "Customer" was misspelled:
SELECT * FROM Custommer;
There is nothing incorrect about this from a syntax point of view. The rules of the T-SQL language have
been followed. During the syntax checking phase, no error would be returned.
Object Resolution
In the second phase of execution, the objects referenced by name in the T-SQL statements are resolved to
underlying object IDs. Errors occur at this phase if the objects do not exist. Single part names are resolved
to specific objects at this point. To avoid ambiguity at this point, multi-part names should be used for
objects except in rare circumstances.
In the example above, SQL Server would first look for an table named "Custommer" in the default schema
of the user executing the code. If no such table exists, SQL Server would then look for the table
"dbo.Custommer" ie: it would next look in the dbo schema. If no such table existed in the dbo schema, an
error would then be returned.
Handling Errors in T-SQL Code 12-5
Statement Execution
In the third phase of execution, the statement is executed. At this phase, runtime errors can occur. For
example, the user may not have permission to SELECT from the table specified or an INSERT statement
might fail because a constraint was going to be violated. You could also have more basic errors occurring
at this point such as an attempt to divide by a zero value.
Some errors can be handled in the database engine but other errors will need to be handled by client
applications. Client applications always need to be written with error handling in mind.
Question: Can you suggest a reason why you might want to catch errors in a client application rather
than allowing the errors to be seen by the end users?
12-6 Implementing a Microsoft® SQL Server® 2008 R2 Database
Types of Errors
Key Points
A number of different categories of error can occur. Mostly they differ by the scope of the termination
that occurs when the error is not handled.
Syntax Errors
Syntax errors occur when the rules of the language are not followed. For example, consider the following
statement:
SELECT TOP(10) FROM Production.Product;
If you try to execute the statement, you receive the following message:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'FROM'.
Note that the syntax of the entire batch of statements being executed is checked before the execution of
any statement within the batch is attempted. Syntax errors are batch terminating errors.
Object Resolution Errors
In the last topic, you saw an example of an object resolution error. These errors occur when the object
name specified cannot be resolved to an object ID, such as in the following statement:
SELECT * FROM SomeNonexistentTable;
The same issue would occur if the schema for the object was not specified and the object did not exist in
the user's default schema or in the dbo schema. Note that if a syntax error occurs, no attempt at object
name resolution will be made.
Handling Errors in T-SQL Code 12-7
Statement Terminating Errors
With a statement terminating error, execution resumes at the next statement following the statement that
was in error. Consider the following batch executed against the AdventureWorks2008R2 database:
DELETE FROM Production.Product WHERE ProductID = 1;
PRINT 'Hello';
When this batch is executed, the following is returned:
Msg 547, Level 16, State 0, Line 3
The DELETE statement conflicted with the REFERENCE constraint
"FK_BillOfMaterials_Product_ComponentID". The conflict occurred in database
"AdventureWorks2008R2", table "Production.BillOfMaterials", column 'ComponentID'.
The statement has been terminated.
Hello
Note that the PRINT statement was still executed even though the DELETE statement failed because of a
constraint violation.
Batch, Scope, Session and Server Terminating Errors
More serious errors can cause the batch, the scope (eg: the current stored procedure) or the session to be
terminated.
The most serious errors would terminate SQL Server itself. Errors of this nature usually indicate particularly
serious hardware errors. Fortunately such errors are rare!
12-8 Implementing a Microsoft® SQL Server® 2008 R2 Database
What's in an Error?
Key Points
An error is itself an object and has properties as shown in the table.
What's in an Error
It might not be immediately obvious that a SQL Server error (or sometimes called an exception) is itself an
object. Errors return a number of useful properties.
Error numbers are helpful when trying to locate information about the specific error, particularly when
searching online for information about the error.
You can view the list of system-supplied error messages by querying the sys.messages catalog view:
SELECT * FROM sys.messages
ORDER BY message_id, language_id;
When executed, this command returns the following:
Note that there are multiple messages with the same message_id. Error messages are localizable and can
be returned in a number of languages. A language_id of 1033 is the English version of the message. You
can see an English message in the third line of the output above.
Severity indicates how serious the error is. It is described further in the next topic.
Handling Errors in T-SQL Code 12-9
State is defined by the author of the code that raised the error. For example, if you were writing a stored
procedure that could raise an error for a missing customer and there were five places in the code that this
message could occur, you could assign a different state to each of the places where the message was
raised. This would help later to troubleshoot the error.
Procedure name is the name of the stored procedure that that error occurred in and Line Number is the
location within that procedure. In practice, line numbers are not very helpful and not always applicable.
Question: Why is it useful to be able to localize error messages?
12-10 Implementing a Microsoft® SQL Server® 2008 R2 Database
Error Severity
Key Points
The severity of an error indicates the type of problem encountered by SQL Server. Low severity values are
informational messages and do not indicate true errors. Error severities occur in ranges:
Values from 0 to 10
Values from 0 to 9 are purely informational messages. When queries that raise these are executed in SQL
Server Management Studio, the information is returned but no error status information is provided. For
example, consider the following code executed against the AdventureWorks2008R2 database:
SELECT COUNT(Color) FROM Production.Product;
When executed, it returns a count as expected. However, if you look on the Messages tab in SQL Server
Management Studio, you will see the following:
Warning: Null value is eliminated by an aggregate or other SET operation.
(1 row(s) affected)
Note that no error really occurred but SQL Server is warning you that it ignored NULL values when
counting the rows. Note that no status information is returned.
Severity 10 is the top of the informational messages.
Values from 11 to 16
Values from 11 to 16 are considered errors that the user can correct. Typically they are used for errors
where SQL Server assumes that the statement being executed was in error.
Here are a few examples of these errors:
Handling Errors in T-SQL Code 12-11
Error Severity Example
11 indicates that an object does not exist
13 indicates a transaction deadlock
14 indicates errors such as permission denied
15 indicates syntax errors
17 indicates that SQL Server has run out of resources (memory, disk space, locks, etc.)
Values from 17 to 19
Values from 17 to 19 are considered serious software errors that the user cannot correct.
Values above 19
Values above 19 tend to be very serious errors that normally involve errors with either the hardware or
SQL Server itself. It is common to ensure that all errors above 19 are logged and alerts generated on
them.
12-12 Implementing a Microsoft® SQL Server® 2008 R2 Database
Demonstration 1A: Error Types and Severity
Key Points
In this demonstration you will see how to:
See how different types of errors are returned from T-SQL statements
See the types of messages that are related to severe errors
Query the sys.messages view and note which errors are logged automatically
Demonstration Setup
1. Revert the 623XB-MIA-SQL virtual machine using Hyper-V Manager on the host system.
2. In the virtual machine, click Start, click All Programs, click Microsoft SQL Server 2008 R2, click
SQL Server Management Studio. In the Connect to Server window, type Proseware in the Server
name text box and click Connect. From the File menu, click Open, click Project/Solution, navigate
to D:\6232B_Labs\6232B_12_PRJ\6232B_12_PRJ.ssmssln and click Open.
3. Open and execute the 00 – Setup.sql script file from within Solution Explorer.
4. Open the 11 – Demonstration 1A.sql script file.
5. Follow the instructions contained within the comments of the script file.
Question: What do you imagine the "is_event_logged" column relates to?
Handling Errors in T-SQL Code 12-13
Lesson 2
Implementing T-SQL Error Handling
Now that you understand the nature of errors, it is time to consider how they can be handled or reported
in T-SQL. The T-SQL language offers a variety of error handling capabilities. It is important to understand
these and how they relate to transactions. This lesson covers basic T-SQL error handling, including how
you can raise errors intentionally and how you can set up alerts to fire when errors occur. In the next
lesson, you will see how to implement a more advanced form of error handling known as structured
exception handling.
Objectives
After completing this lesson, you will be able to:
Raise errors
Use the @@ERROR system variable
Explain the role of errors and transactions
Explain transaction nesting errors
Raise custom errors
Create alerts that fire when errors occur
12-14 Implementing a Microsoft® SQL Server® 2008 R2 Database
Raising Errors
Key Points
Both PRINT and RAISERROR can be used to return information or warning messages to applications.
RAISERROR allows applications to raise an error that could then be caught by the calling process.
RAISERROR
The ability to raise errors in T-SQL makes error handling in the application easier as it is sent like any other
system error. RAISERROR is used to:
Help troubleshoot T-SQL code
Check the values of data
Return messages that contain variable text
Note that using a PRINT statement is similar to raising an error of severity 10, as shown in the sample on
the slide.
Substitution Placeholders and Message Number
Note that in the message shown in the example on the slide, that %d is a placeholder for a number and
%s is a placeholder for a string. Note also that a message number was not mentioned. When errors with
message strings are raised using this syntax, the errors raised always have error number 50000.
Question: Why might you want to intentionally raise an error in your code?
Handling Errors in T-SQL Code 12-15
Using @@Error
Key Points
Most traditional error handling code in SQL Server applications has been created using @@ERROR. Note
that structured exception handling was introduced in SQL Server 2005 and provides a strong alternative
to using @@ERROR. It will be discussed in the next lesson. A large amount of existing SQL Server error
handling code is based on @@ERROR so it is important to understand how to work with it.
@@ERROR
@@ERROR is a system variable that holds the error number of the last error that has occurred. One
significant challenge with @@ERROR is that the value it holds is quickly reset as each additional statement
is executed.
For example, consider the following code:
RAISERROR(N'Message', 16, 1);
IF @@ERROR <> 0
PRINT 'Error=' + CAST(@@ERROR AS VARCHAR(8));
GO
You might expect that when it is executed, it would return the error number in a printed string. However,
when the code is executed, it returns:
Msg 50000, Level 16, State 1, Line 1
Message
Error=0
Note that the error was raised but that the message printed was "Error=0". You can see in the first line of
the output that the error was actually 50000 as expected with a message passed to RAISERROR. This is
because the IF statement that follows the RAISERROR statement was executed successfully and caused the
@@ERROR value to be reset.
12-16 Implementing a Microsoft® SQL Server® 2008 R2 Database
Capturing @@ERROR into a Variable
For this reason, when working with @@ERROR, it is important to capture the error number into a variable
as soon as it is raised and to then continue processing with the variable.
Look at the following code that demonstrates this:
DECLARE @ErrorValue int;
RAISERROR(N'Message', 16, 1);
SET @ErrorValue = @@ERROR;
IF @ErrorValue <> 0
PRINT 'Error=' + CAST(@ErrorValue AS VARCHAR(8));
When this code is executed, it returns the following output:
Msg 50000, Level 16, State 1, Line 2
Message
Error=50000
Note that the error number is correctly reported now.
Centralizing Error Handling
One other significant issue with using @@ERROR for error handling is that it is difficult to centralize error
handling within your T-SQL code. Error handling tends to end up scattered throughout the code. It would
be possible to somewhat centralized error handling using @@ERROR by using labels and GOTO
statements but this would be frowned upon by most developers today as a poor coding practice.
Handling Errors in T-SQL Code 12-17
Errors and Transactions
Key Points
Many new developers are surprised to find out that a statement that fails even when enclosed in a
transaction does not automatically rolled the transaction back, only the statement itself. The SET
XACT_ABORT statement can be used to control this behavior.
Statement Terminating Errors vs Batch/Scope Terminating Errors
Most common errors that occur when processing T-SQL are statement terminating errors not batch or
scope terminating errors. This means that the statement in error is rolled back and execution then
continues with the next statement following the statement in error. Note that this happens even when
working within a transaction.
For example, consider the following code:
BEGIN TRAN;
DELETE Production.Product WHERE ProductID = 1;
PRINT 'Hello';
COMMIT;
PRINT 'Hello again';
Note that when it is executed, the following output is generated:
Msg 547, Level 16, State 0, Line 3
The DELETE statement conflicted with the REFERENCE constraint
"FK_BillOfMaterials_Product_ComponentID". The conflict occurred in database
"AdventureWorks2008R2", table "Production.BillOfMaterials", column 'ComponentID'.
The statement has been terminated.
Hello
Hello again
12-18 Implementing a Microsoft® SQL Server® 2008 R2 Database
Note that both PRINT statements still execute even though the DELETE statement failed.
SET XACT_ABORT ON
The SET XACT_ABORT ON statement is used to tell SQL Server that statement terminating errors should
become batch terminating errors.
Now consider the same code with SET XACT_ABORT ON present:
SET XACT_ABORT ON;
BEGIN TRAN;
DELETE Production.Product WHERE ProductID = 1;
PRINT 'Hello';
COMMIT;
PRINT 'Hello again';
When executed, it returns:
Msg 547, Level 16, State 0, Line 5
The DELETE statement conflicted with the REFERENCE constraint
"FK_BillOfMaterials_Product_ComponentID". The conflict occurred in database
"AdventureWorks2008R2", table "Production.BillOfMaterials", column 'ComponentID'.
Note that when the DELETE statement failed, the entire batch was terminated, including the transaction
that had begun. The transaction would have been rolled back.
Handling Errors in T-SQL Code 12-19
Transaction Nesting Errors
Key Points
Any ROLLBACK causes all levels of transactions to be rolled back, not just the current nesting level.
Transaction Nesting Errors
SQL Server does not support nested transactions. The syntax of the language might appear to support
them but they do not operate in a nested fashion.
No matter how deeply you nest transactions, a ROLLBACK rolls back all levels of transaction.
SQL Server does not support autonomous transactions. Autonomous transactions are nested transactions
that are in a different transaction scope. Typically this limitation arises when trying to construct auditing
or logging code. Code that is written to log that a user attempted an action is rolled back as well when
the action is rolled back.
Nesting Levels
You can determine the current transaction nesting level by querying the @@TRANCOUNT system
variable.
Another rule to be aware of is that SQL Server requires that the transaction nesting level of a stored
procedure is the same on entry to the stored procedure and on exit from it. If the transaction nesting level
differs, error 286 is raised. This is commonly seen when users are attempting to nest transaction rollback.
12-20 Implementing a Microsoft® SQL Server® 2008 R2 Database
Raising Custom Errors
Key Points
Rather than raising system errors, SQL Server allows users to define custom error messages that have
meaning to their applications. The error numbers supplied must be 50000 or above and the user adding
them must be a member of the sysadmin or serveradmin fixed server roles.
Raising Custom Errors
As well as being able to define custom error messages, members of the sysadmin server role can also use
an additional parameter @with_log. When set to TRUE, the error will also be recorded in the Windows
Application log. Any message written to the Windows Application log is also written to the SQL Server
error log. Be judicious with the use of the @with_log option as network and system administrators tend to
dislike applications that are "chatty" in the system logs.
Note that raising system errors is not supported.
sys.messages System View
The messages that are added are visible within the sys.messages system view along with the system-
supplied error messages. Messages can be replaced without the need to delete them first by using the
@replace = 'replace' option.
The messages are customizable and different messages can be added for the same error number for
multiple languages, based on a language_id value. (Note: English messages are language_id 1033).
Question: What do the DB_ID and DB_NAME functions return?
Handling Errors in T-SQL Code 12-21
Creating Alerts When Errors Occur
Key Points
For certain categories of errors, administrators might wish to be notified as soon as these errors occur.
This can even apply to user-defined error messages. For example, you may wish to raise an alert whenever
a customer is deleted. More commonly, alerting is used to bring high-severity errors (such as severity 19
or above) to the attention of administrators.
Raising Alerts
Alerts can be created for specific error messages. The alerting service works by registering itself as a
callback service with the event logging service. This means that alerts only work on errors that are logged.
There are two ways to make messages be alert-raising. You can use the WITH LOG option when raising
the error or the message can be altered to make it logged by executing sp_altermessage. Modifying
system errors via sp_altermessage is only possible from SQL Server 2005 SP3 or SQL Server 2008 SP1
onwards.
Question: Can you suggest an example of an error that would require immediate attention from an
administrator?
12-22 Implementing a Microsoft® SQL Server® 2008 R2 Database
Demonstration 2A: T-SQL Error Handling
Key Points
In this demonstration you will see:
How to raise errors
How severity affects errors
How to add a custom error message
How to raise a custom error message
That custom error messages are instance-wide
How to use @@ERROR
That system error messages cannot be raised
Demonstration Steps
1. If Demonstration 1A was not performed:
Revert the 623XB-MIA-SQL virtual machine using Hyper-V Manager on the host system.
In the virtual machine, click Start, click All Programs, click Microsoft SQL Server 2008 R2,
click SQL Server Management Studio. In the Connect to Server window, type Proseware in
the Server name text box and click Connect. From the File menu, click Open, click
Project/Solution, navigate to D:\6232B_Labs\6232B_12_PRJ\6232B_12_PRJ.ssmssln and click
Open.
Open and execute the 00 – Setup.sql script file from within Solution Explorer.
2. Open the 21 – Demonstration 2A.sql script file.
3. Open the 22 – Demonstration 2A 2nd Window.sql script file.
4. Follow the instructions contained within the comments of the script file.
Question: Why is the ability to substitute values in error messages useful?
Handling Errors in T-SQL Code 12-23
Lesson 3
Implementing Structured Exception Handling
Now that you have an understanding of the nature of errors and of basic error handling in T-SQL, it is
time to look at a more advanced form of error handling. Structured exception handling was introduced in
SQL Server 2005. You will see how to use it and evaluate its benefits and limitations.
Objectives
After completing this lesson, you will be able to:
Explain TRY CATCH block programming
Describe the role of error handling functions
Describe catchable vs non-catchable errors
Explain how TRY CATCH relates to transactions
Explain how errors in managed code are surfaced
12-24 Implementing a Microsoft® SQL Server® 2008 R2 Database
TRY CATCH Block Programming
Key Points
Structured exception handling has been part of high level languages for some time. SQL Server 2005
introduced structured exception handling to the T-SQL language.
TRY CATCH Block Programming
Structured exception handling is more powerful than error handling based on the @@ERROR system
variable. It allows you to prevent code from being littered with error handling code and to centralize that
error handling code.
Centralization of error handling code also allows you to focus more on the purpose of the code rather
than on the error handling in the code.
TRY Block and CATCH Block
When using structured exception handling, code that might raise an error is placed within a TRY block.
TRY blocks are enclosed by BEGIN TRY and END TRY statements.
Should a catchable error occur (most errors can be caught), execution control moves to the CATCH block.
The CATCH block is a series of T-SQL statements enclosed by BEGIN CATCH and END CATCH statements.
Note that while BEGIN CATCH and END TRY are separate statements, the BEGIN CATCH statement must
immediately follow the END TRY statement.
Current Limitations
High level languages often offer a try/catch/finally construct. There is no equivalent FINALLY block in T-
SQL.
There is currently no mechanism for rethrowing errors and only errors above 50000 can be thrown
manually. This means that you cannot raise a system error within a CATCH block.
Question: In what situation might it have been useful to be able to raise a system error?
Handling Errors in T-SQL Code 12-25
Error Handling Functions
Key Points
CATCH blocks make the error related information available throughout the duration of the CATCH block,
including in sub-scopes such as stored procedures run from within the CATCH block.
Error Handling Functions
Recall that when programming with @@ERROR, the value held by the @@ERROR system variable was
reset as soon as the next statement was executed.
Another key advantage of structured exception handling in T-SQL is that a series of error handling
functions have been provided and these functions retain their values throughout the CATCH block.
Separate functions are provided to provide each of the properties of an error that has been raised.
This means that you can write generic error handling stored procedures and they can still access the error
related information.
12-26 Implementing a Microsoft® SQL Server® 2008 R2 Database
Catchable vs. Non-catchable Errors
Key Points
It is important to realize that while TRY…CATCH blocks allow you to catch a much wider range of errors
than you could catch with @@ERROR, you cannot catch all types of errors.
Catchable vs Non-catchable Errors
Not all errors can be caught by TRY/CATCH blocks within the same scope that the TRY/CATCH block exists
in. Often the errors that cannot be caught in the same scope can be caught in a surrounding scope. For
example, you might not be able to catch an error within the stored procedure that contains the
TRY/CATCH block, however you are likely to be able to catch that error in a TRY/CATCH block in the code
that called the stored procedure where the error occurred.
Common Non-catchable Errors
Common examples of non-catchable errors are:
Compile errors can occur such as syntax errors that prevent a batch from compiling.
Statement level recompilation issues which usually relate to deferred name resolution. For example,
you could create a stored procedure that refers to an unknown table. An error is only thrown when
the procedure actually tries to resolve the name of the table to an objectid.
Question: Given the earlier discussion on the phases of execution of T-SQL statements, how could a
syntax error occur once a batch has already started executing?
Handling Errors in T-SQL Code 12-27
TRY CATCH and Transactions
Key Points
If a transaction is current at the time an error occurs, the statement that caused the error is rolled back. If
XACT_ABORT is ON, the execution jumps to the CATCH block, instead of terminating the batch as usual.
TRY/CATCH and Transactions
New SQL Server developers are often surprised that a statement terminating error that occurs within a
transaction does not automatically roll that transaction back. You saw how SET XACT_ABORT ON was used
to deal with that issue.
When TRY/CATCH blocks are used in conjunction with transactions and SET XACT_ABORT is on, a
statement terminating error will cause the code in the CATCH block to be executed. However, the
transaction is not automatically rolled back.
Note that at this point, no further work that would need to be committed is permitted until a rollback has
been performed. The transaction is considered to be "doomed". After the rollback however, updates may
be made to the database, such as logging the error.
XACT_STATE()
Look at the code in the slide example. It is important to consider that when the CATCH block is entered,
the transaction may or may not have actually started. In this example, @@TRANCOUNT is being used to
determine if there is a transaction in progress and to roll back if there is one.
Another option is to use the XACT_STATE() function which provides more detailed information in this
situation. The XACT_STATE() function can be used to determine the state of the transaction:
A value of 1 indicates that there is an active transaction.
A value of 0 indicates that there is no active transaction.
12-28 Implementing a Microsoft® SQL Server® 2008 R2 Database
A value of -1 indicates that there is a current transaction but that it is doomed. The only action permitted
within the transaction is to roll it back.
Handling Errors in T-SQL Code 12-29
Errors in Managed Code
Key Points
SQL CLR Integration allows for the execution of managed code within SQL Server. High level .NET
languages such as C# and VB have detailed exception handling available to them. Errors can be caught
using standard .NET try/catch/finally blocks.
Errors in Managed Code
In general, you may wish to catch errors as much as possible within managed code. (Managed code is
discussed in Module 16).
It is important to realize though that any errors that are not handled in the managed code are passed
back to the calling T-SQL code. Whenever any error that occurs in managed code is returned to SQL
Server, it will appear to be a 6522 error. Errors can be nested and that error will be wrapping the real
cause of the error.
Another rare but possible cause of errors in managed code would be that the code could execute a
RAISERROR T-SQL statement via a SqlCommand object.