Vous êtes sur la page 1sur 22

Top 10 advanced features of SQL Server

2005
Takeaway: SQL Server 2005 offers new features that enhance productivity,
efficiency, availability, and administrative ease. Tim Chapman discusses 10 of the more
advanced new features of the SQL Server 2005 Database Engine.

SQL Server 2005 offers a plethora of new features and enhancements that improve
productivity, efficiency, availability, and administrative ease. In this article, I discuss 10
of the more advanced features of the SQL Server 2005 Database Engine.

1. Database mirroring
Database mirroring is a new high-availability feature in SQL Server 2005. It's similar to
server clustering in that failover is achieved by the use of a stand-by server; the difference
is that the failover is at the database level rather than the server level. The primary
database continuously sends transaction logs to the backup database on a separate SQL
Server instance. A third SQL Server instance is then used as a witness database to
monitor the interaction between the primary and the mirror databases.

2. Database snapshots
A database snapshot is essentially an instant read-only copy of a database, and it is a great
candidate for any type of reporting solution for your company. In addition to being a
great reporting tool, you can revert control from your primary database to your snapshot
database in the event of an error. The only data loss would be from the point of creation
of the database snapshot to the event of failure.

3. CLR integration
With SQL Server 2005, you now have the ability to create custom .NET objects with the
database engine. For example, stored procedures, triggers, and functions can now be
created using familiar .NET languages such as VB and C#. Exposing this functionality
gives you tools that you never had access to before such as regular expressions.

Weekly SQL tips in your inbox


TechRepublic's free SQL Server newsletter, delivered each Tuesday, contains hands-on tips that will help you
become more adept with this powerful relational database management system.

4. Service Broker
This feature gives you the ability to create asynchronous, message-based applications in
the database entirely through TSQL. The database engine guarantees message delivery,
message order consistency, and handles message grouping. In addition, Service Broker
gives you the ability to send messages between different SQL Server instances. Server
Broker is also used in several other features in SQL Server 2005. For example, you can
define Event Nonfictions in the database to send a message to a Queue in the database
when someone attempts to alter a table structure, of if there is a string of login failures.

5. DDL triggers
In previous articles, I outlined how you can use data definition language (DDL) triggers
in SQL Server 2005 to implement custom database and server auditing solutions for
Sarbanes-Oxley compliance (here are part one and part two of my SOX articles). DDL
triggers are defined at the server or database level and fire when DDL statements occur.
This gives you the ability to audit when new tables, stored procedures, or logins are
created.

6. Ranking functions

SQL Server 2005 provides you with the ability to rank result sets returned from the
database engine. This allows you to customize the manner in which result sets are
returned, such as creating customized paging functions for Web site data.

7. Row versioning-based isolation levels


This new database engine feature improves database read concurrency by reducing the
amount of locks being used in your database. There are two versions of this feature (both
of which must be enabled at the database level):

• Read Committed Isolation Using Row Versioning is used at the individual


statement level, and guarantees that the data is consistent for the duration of the
statement.
• Snapshot Isolation is used at the transaction level, and guarantees that the data is
consistent for the duration of the transaction.

The database engine is able to guarantee the consistency through row versions stored in
the tempdb database. When a statement or transaction is issued with their respective
isolation levels, read operations accessing the same data that is being involved in a
transaction will read from the previous version of the data that is stored in tempdb. Using
these techniques in the appropriate situations can significantly decrease your database
locking issues.

8. XML integration
SQL Server 2005 introduces the new XML data-type. You can store full XML documents
in this new data-type, and you can place validations on the well-formed documents in the
database. Additional enhancements include the ability to query the XML documents and
create indexes on the XML data-type.

9. TRY...CATCH
In a previous article, I outlined how you can use the new TRY...CATCH constructs in
SQL Server 2005 to catch and handle deadlocks when they occur in the database. This
long-awaited feature simplifies error handling in the database.

10. Database Mail


Database Mail, the eventual successor to SQL Mail, is a greatly enhanced e-mail solution
available in the database engine. With Database Mail, there is no longer a dependency on
Microsoft Outlook or MAPI e-mail clients. Database Mail uses standard SMTP to send e-
mail messages. These messages may contain query results, attachments (which can be
governed by the DBA), and is fully cluster aware. In addition, the e-mail process runs
outside of the database engine space, which means that messages can continue to be
queued even when the database engine has stopped.

What are your favorite features?


If you are using SQL Server 2005, I would love to hear about your favorite features.
Please post your comments in the article discussion.

Understanding the new Try/Catch


statement in SQL Server 2005
Versions prior to SQL Server 2005 offered little in the way of error handling—Raiserror()
was about it. SQL Server 2005 adds the Try/Catch statement, which is modeled on the
similar construct in Java and other development languages.

Try/Catch consists of two blocks—Try and Catch—each of which can contain multiple
statements. Listing A contains a simple example in pseudo-code.

If either the insert or the update fails, the implicit transaction is rolled back. The insert
statement cannot succeed (i.e., it is committed) while the update statement fails. Both
succeed or both fail.

(Note: Any error that is caught by the Catch block is not returned to the caller.)
With SQL Server 2000, any fatal error (i.e., an error with a severity level greater than 17)
immediately terminates execution and breaks the connection. With SQL Server 2005, the
engine will attempt to handle the error and continue execution. Listing B illustrates this
point.

When you paste the code from Listing B into a new query window in Management
Studio and execute it, the results look like this:

Begin Try

Begin Catch

Variable @int = 0

Code Completed

The Try block attempts to divide by zero, which immediately invokes the Catch block;
this prints its message and then assigns zero to the variable. Code execution continues,
printing the final two statements.

Using built-in functions in the Catch block


Six new functions are available in SQL Server 2005 for use within the Catch block. Here
are brief descriptions of each of the functions:

• Error_Message(): returns the error message that would typically be sent to the
caller.
• Error_Number(): returns the integer assigned to the error.
• Error_Severity(): returns the integer corresponding to the severity.
• Error_State(): returns the state.
• Error_Procedure(): returns the name of the procedure or function where the
error occurred.
• Error_Line(): returns the line number where the error occurred.

To demonstrate the functions' use, I revised the code, which you can see in Listing C.

I fancied up the custom error message so it displays on multiple lines for clarity. (You
might want to keep this code for use as a template Catch block in the future.) This results
in the following display:

Begin Try

Begin Catch
Msg 50000, Level 16, State 2, Line 20
Error(8134): Divide by zero error encountered.
Severity: 16
State: 1
Procedure: None.
Line #: 4

Variable @int = 0

Code Completed

Note: Application code would typically be using transactions. The mere existence of a
Catch block won't automatically perform a rollback—you must do it yourself. In this
case, your procedure would resemble this generic version:

BEGIN TRY
BEGIN TRANSACTION
[Do some stuff here]
COMMIT TRANSACTION

END TRY

BEGIN CATCH
Print 'Begin Catch'
ROLLBACK TRANSACTION
[Do some stuff here]

END CATCH

Error handling has come a long way in SQL Server 2005. If you're still handling errors
the old way, with nothing more than Raiserror() in your toolkit, it's time to wake up and
smell the coffee!

Miss a tip?
Check out the SQL Server archive, and catch up on the most recent editions of Arthur
Fuller's column.

TechRepublic's free SQL Server newsletter, delivered each Tuesday, contains hands-on
tips that will help you become more adept with this powerful relational database
management system. Automatically subscribe today!

Understanding error handling in SQL Server 2000

Most iterative language compilers have built-in error handling routines (e.g., TRY…
CATCH statements) that developers can leverage when designing their code. Although
SQL Server 2000 developers don't enjoy the luxury that iterative language developers do
when it comes to built-in tools, they can use the @@ERROR system variable to design
their own effective error-handling tools.

Introducing transactions
In order to grasp how error handling works in SQL Server 2000, you must first
understand the concept of a database transaction. In database terms, a transaction is a
series of statements that occur as a single unit of work. To illustrate, suppose you have
three statements that you need to execute. The transaction can be designed in such a way
so that all three statements occur successfully, or none of them occur at all.

When data manipulation operations are performed in SQL Server, the operation takes
place in buffer memory and not immediately to the physical table. Later, when the
CHECKPOINT process is run by SQL Server, the committed changes are written to disk.
This means that when transactions are occurring, the changes are not made to disk during
the transaction, and are never written to disk until committed. Long-running transactions
require more processing memory and require that the database hold locks for a longer
period of time. Thus, you must be careful when designing long running transactions in a
production environment.

Here's a good example of how using transactions is useful. Withdrawing money from an
ATM requires a series of steps which include entering a PIN number, selecting an account
type, and entering the amount of funds you wish to withdraw. If you try to withdraw $50
from the ATM and the machine fails thereafter, you do not want to be charged the $50
without receiving the money. Transactions can be used to ensure this consistency.

The @@ERROR variable

Successful error handling in SQL Server 2000 requires consistently checking the value of
the @@ERROR system variable. @@ERROR is a variable updated by the SQL Server
database engine after each statement is executed on the server for the given connection.
This variable contains the corresponding error number, if applicable. You can find a
listing of these error numbers in the sysmessages table in the master database. The details
of this table are listed on Microsoft's site.

Here's an example of how the @@ERROR variable works:

PRINT 'Taking a look at @@ERROR'

PRINT @@ERROR

In these instructions, we are printing out a string to the screen and printing the value of
the @@ERROR variable. Because no error is returned from printing out to the screen,
the value @@ERROR contains is 0.

PRINT 1/0

PRINT @@ERROR
In this example, we generate a division by zero error, which means that the @@ERROR
variable will contain 8134, which is the error number that Microsoft assigns for this type
of error. For most error handling purposes, you will only be concerned if the value of
@@ERROR is non-zero, which will indicate that an error occurred. It is a good idea to
keep track of the error numbers when recording the errors as they will come in handy
during the debugging process.

Error handling at work


Here's a good example of how you can use error handling in stored procedures. The goal
of the sample script is to execute a stored procedure that will declare a transaction and
insert a record into a table. Because this is for explanation purposes only, we will design
the procedure in such a way as to let us tell it whether to commit or roll back the
transaction.

Execute the following statement to create the table that we will use for our example:

CREATE TABLE Transactions

(
TranID SMALLINT IDENTITY(1,1) PRIMARY KEY,
EntryDate SMALLDATETIME DEFAULT(GETDATE()),
ParamValue CHAR(1),
ThrowError BIT

The two fields of value in the script are ParamValue and ThrowError. These fields will
correspond to the input parameters of the procedure we will create, and we will use them
in our logic for committing transactions.

Once our table is in place to keep track of our transactions, we are ready to create our
procedure. The procedure will have a parameter used simply to record a character value
and a parameter, which will give us the ability to throw an error in the procedure. Run the
statement in Listing A to create the procedure.

This simple stored procedure exhibits the characteristics we need for effective error
handling. First, a transaction is explicitly declared. After a record is inserted into the
Transaction table, we check the value of the @ThrowError parameter. This parameter
indicates whether to throw an error, and uses the RAISERROR function to throw the
custom error. When the RAISERROR function is called, the value of the @@ERROR
variable is populated with the error number that we provide.

If an error occurs in the stored procedure, we will roll back the transaction. Rolling back
the transactions means that the record we attempted to insert into the Transactions table
will be removed as if it never occurred. The state of the database will be exactly how it
was before the transaction began.
In this example, you will also notice the use of the GOTO statement and the label
ErrorHandler. GOTO statements are typically considered a bad programming practice in
iterative programming languages, but they are very useful when handling errors in SQL
Server 2000. Don't be afraid to use the GOTO statement to handle errors.

This procedure call will throw an error and the record will not be inserted in the
Transactions table:

DECLARE @ReturnCode INT

EXECUTE @ReturnCode = usp_TestTransaction @ParamValue = 'E',


@ThrowError = 1

PRINT @ReturnCode

This procedure call will not throw an error, and the inserted record will be committed to
the Transactions table:

DECLARE @ReturnCode INT

EXECUTE @ReturnCode = usp_TestTransaction @ParamValue = 'S',


@ThrowError = 0

PRINT @ReturnCode

These procedure calls make use of a Return parameter, which indicates the success or
failure of a stored procedure. It is a good programming practice to explicitly set the
Return parameter in your code to indicate success or failure of the procedure; this allows
you to know when your stored procedure has failed so you can take the necessary steps to
handle the failure. For example, you can nest procedure calls and transactions. Your
application could potentially declare a transaction, call a stored procedure, and
(depending on the success or failure of the stored procedure) commit or roll back the
outside transaction.

Looking to the future


• Careful transaction design and consistently checking the value of the @@ERROR
variable is the key to effective error handling in SQL Server 2000. In a future
article, I'll show you how to use the new error handling capabilities in SQL Server
2005, which

T-SQL error handling with Try…Catch


blocks
SQL Server error handling, or exception handling, has always been a tricky part of T-SQL
development. It used to be that you had to manually check for errors after running each
statement and handle them on a case-by-case basis. SQL Server transaction management
was also a chore because you had to figure out the state of your transactions and roll them
back or commit them as appropriate.

With SQL Server 2005, Microsoft gives us newer, more robust error handling capabilities
by adding Try...Catch blocks to T-SQL. In this tip, we will look at how Try...Catch blocks
work and how you can put them to use in your code. We will also look at some
comparisons between the old ways and the new ways so you'll have a better
understanding of how using Try...Catch can bring your error handling into the 21st
century.

Try...Catch defined

In order to understand Try…Catch blocks, you have to understand exception handling.


Exception handling is simple really: When something unplanned occurs during

the execution of your code, an exception, you need to


More on T-SQL and SQL have a routine that can handle that exception. How you
Server performance tuning: handle the exception is up to you as the developer.
Top 10 T-SQL tips for
improved SQL Server In order to add exception handling to your T-SQL code,
development you use Try…Catch blocks. If you have used Visual
Guide: SQL Server 2005 Studio recently, you are probably familiar with the
performance tuning tools A-Z concept of Try…Catch blocks. Their implementation in
T-SQL is similar but actually has fewer options than the
full-blown implementation you would encounter in
Visual Studio. To use Try…Catch, put the T-SQL code you want to run inside of a Try
block. If an error with a severity of 10 or higher occurs during the execution of the Try
code, execution is passed to exception handling code in a Catch block. The basic
construct is shown below:

BEGIN TRY
[T-SQL Code Goes Here]
END TRY
BEGIN CATCH
[Exception Handling Code Goes Here]
END CATCH

When using Try…Catch in T-SQL, here are a few crucial points to keep in mind:

Try blocks must be followed directly by a Catch block, anything else will cause an
error.
Try…Catch cannot span batches.
If the Try code runs without fail, execution passes to the first line following the end of
the Catch block.
When Catch code completes, execution passes to the first line following the end of the
Catch block.

Handling errors

When an error occurs, you as the developer need to decide how to deal with it. Since you
cannot pass control back to code that caused the error, like you can in .NET languages,
you will likely log the problem and roll back any transactions that may be in-flight. To
help with logging, there are several system functions that can provide more information
about an error. The available system functions are detailed below:

ERROR_NUMBER() - Returns the error number.


ERROR_SEVERITY() - Returns the error's severity.
ERROR_STATE() - Returns the error's state.
ERROR_PROCEDURE() - Returns the name of the stored procedure or trigger in
which the error occurred.
ERROR_LINE() - Returns the line number on which the error occurred.
ERROR_MESSAGE() returns the actual text of the error message.

Using these functions, you can record the details of the error and return that information
to the caller of the procedure or log it for troubleshooting purposes. The functions will
only work when called inside a Catch block; trying to call them otherwise would return
NULL. They will, however, work within the scope of the code running in the Catch
block. This means that you can call a stored procedure to handle the error and that stored
procedure can access the error functions. Here is an example of just such a stored
procedure:

CREATE PROCEDURE spLogError


AS

--Return error details to calling application


SELECT
ERROR_NUMBER() AS ErrNum,
ERROR_SEVERITY() AS ErrSev,
ERROR_STATE() as ErrState,
ERROR_PROCEDURE() as ErrProc,
ERROR_LINE() as ErrLine,
ERROR_MESSAGE() as ErrMsg

--Log error to error databases


INSERT INTO SQLErrors.dbo.ErrorLog
VALUES(ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_STATE(),
ERROR_PROCEDURE(), ERROR_LINE(),ERROR_MESSAGE())

This procedure can then be called in your Catch block to return and log the error details.

BEGIN TRY
--INSERT CODE HERE: When an error occurs, control will be passed
to the Catch block
END TRY
BEGIN CATCH
--This proc will log the error and send the details back to the
calling application
EXEC spLogError
END CATCH
Using the XACT_STATE() function

There is one more error function that we have not discussed, the XACT_STATE()
function. This function can be called in your Catch blocks to return the exact transaction
state of your procedure. The return code from XACT_STATE() will have one of the
following values:

1 : There is an active transaction that could be either committed or rolled back.


0 : There is no active transaction.
-1 : There is an active transaction, but errors have occurred and the transaction cannot
be committed.

Based on the return of this function, you can handle your in-flight transaction. If you
receive a 1, you can roll back or commit as normal. If you receive a 0, there are no open
transactions, and attempting a commit would generate an error. The special case is -1.
That means there was a transaction, but it is not committable. You are also unable to roll
back to a save point when you receive a -1 code; the entire transaction must be rolled
back.

Error and exception handling is crucial to any good coding standards. Now with SQL
Server 2005 you can implement advanced error handling using Try…Catch blocks.

TRY...CATCH (Transact-SQL)

Updated: 14 April 2006

Implements error handling for Transact-SQL that is similar to the exception handling in the Microsoft
Visual C# and Microsoft Visual C++ languages. A group of Transact-SQL statements can be enclosed
in a TRY block. If an error occurs in the TRY block, control is passed to another group of statements
that is enclosed in a CATCH block.

Syntax

BEGIN TRY

{ sql_statement | statement_block }

END TRY

BEGIN CATCH
[ { sql_statement | statement_block } ]

END CATCH

[ ; ]

Arguments

sql_statement
Is any Transact-SQL statement.

statement_block
Any group of Transact-SQL statements in a batch or enclosed in a BEGIN…END block.

Remarks

A TRY…CATCH construct catches all execution errors that have a severity higher than 10 that do not
close the database connection.

A TRY block must be immediately followed by an associated CATCH block. Including any other
statements between the END TRY and BEGIN CATCH statements generates a syntax error.

A TRY…CATCH construct cannot span multiple batches. A TRY…CATCH construct cannot span multiple
blocks of Transact-SQL statements. For example, a TRY…CATCH construct cannot span two BEGIN…
END blocks of Transact-SQL statements and cannot span an IF…ELSE construct.

If there are no errors in the code that is enclosed in a TRY block, when the last statement in the TRY
block has finished running, control passes to the statement immediately after the associated END
CATCH statement. If there is an error in the code that is enclosed in a TRY block, control passes to
the first statement in the associated CATCH block. If the END CATCH statement is the last statement
in a stored procedure or trigger, control is passed back to the statement that called the stored
procedure or fired the trigger.

When the code in the CATCH block finishes, control passes to the statement immediately after the
END CATCH statement. Errors trapped by a CATCH block are not returned to the calling application.
If any part of the error information must be returned to the application, the code in the CATCH block
must do so by using mechanisms such as SELECT result sets or the RAISERROR and PRINT
statements. For more information about how to use RAISERROR with TRY…CATCH, see Using
TRY...CATCH in Transact-SQL.

TRY…CATCH constructs can be nested. Either a TRY block or a CATCH block can contain nested TRY…
CATCH constructs. For example, a CATCH block can contain an embedded TRY…CATCH construct to
handle errors encountered by the CATCH code.

Errors encountered in a CATCH block are treated like errors generated anywhere else. If the CATCH
block contains a nested TRY…CATCH construct, any error in the nested TRY block will pass control to
the nested CATCH block. If there is no nested TRY…CATCH construct, the error is passed back to the
caller.
TRY…CATCH constructs catch unhandled errors from stored procedures or triggers executed by the
code in the TRY block. Alternatively, the stored procedures or triggers can contain their own TRY…
CATCH constructs to handle errors generated by their code. For example, when a TRY block
executes a stored procedure and an error occurs in the stored procedure, the error can be handled
in the following ways:

• If the stored procedure does not contain its own TRY…CATCH construct, the error returns

control to the CATCH block associated with the TRY block that contains the EXECUTE
statement.

• If the stored procedure contains a TRY…CATCH construct, the error transfers control to the

CATCH block in the stored procedure. When the CATCH block code finishes, control is
passed back to the statement immediately after the EXECUTE statement that called the
stored procedure.

GOTO statements cannot be used to enter a TRY or CATCH block. GOTO statements can be used to
jump to a label inside the same TRY or CATCH block or to leave a TRY or CATCH block.

The TRY…CATCH construct cannot be used in a user-defined function.

Retrieving Error Information

In the scope of a CATCH block, the following system functions can be used to obtain information
about the error that caused the CATCH block to be executed:

• ERROR_NUMBER() returns the number of the error.

• ERROR_SEVERITY() returns the severity.

• ERROR_STATE() returns the error state number.

• ERROR_PROCEDURE() returns the name of the stored procedure or trigger where the error

occurred.

• ERROR_LINE() returns the line number inside the routine that caused the error.

• ERROR_MESSAGE() returns the complete text of the error message. The text includes the

values supplied for any substitutable parameters, such as lengths, object names, or times.

These functions return NULL if they are called outside the scope of the CATCH block. Error
information can be retrieved by using these functions from anywhere within the scope of the CATCH
block. For example, the following script shows a stored procedure that contains error-handling
functions. In the CATCH block of a TRY…CATCH construct, the stored procedure is called and
information about the error is returned.

Copy Code

USE AdventureWorks;
GO

-- Verify that the stored procedure does not already exist.

IF OBJECT_ID ( 'usp_GetErrorInfo', 'P' ) IS NOT NULL

DROP PROCEDURE usp_GetErrorInfo;

GO

-- Create procedure to retrieve error information.

CREATE PROCEDURE usp_GetErrorInfo

AS

SELECT

ERROR_NUMBER() AS ErrorNumber,

ERROR_SEVERITY() AS ErrorSeverity,

ERROR_STATE() AS ErrorState,

ERROR_PROCEDURE() AS ErrorProcedure,

ERROR_LINE() AS ErrorLine,

ERROR_MESSAGE() AS ErrorMessage;

GO

BEGIN TRY

-- Generate divide-by-zero error.

SELECT 1/0;

END TRY

BEGIN CATCH

-- Execute error retrieval routine.

EXECUTE usp_GetErrorInfo;

END CATCH;

Errors Unaffected by a TRY…CATCH Construct

TRY…CATCH constructs do not trap the following conditions:

• Warnings or informational messages that have a severity of 10 or lower.


• Errors that have a severity of 20 or higher that stop the SQL Server Database Engine task

processing for the session. If an error occurs that has severity of 20 or higher and the
database connection is not disrupted, TRY…CATCH will handle the error.

• Attentions, such as client-interrupt requests or broken client connections.

• When the session is ended by a system administrator by using the KILL statement.

The following types of errors are not handled by a CATCH block when they occur at the same level
of execution as the TRY…CATCH construct:

• Compile errors, such as syntax errors, that prevent a batch from running.

• Errors that occur during statement-level recompilation, such as object name resolution

errors that occur after compilation because of deferred name resolution.

These errors are returned to the level that ran the batch, stored procedure, or trigger.

If an error occurs during compilation or statement-level recompilation at a lower execution level (for
example, when executing sp_executesql or a user-defined stored procedure) inside the TRY block,
the error occurs at a lower level than the TRY…CATCH construct and will be handled by the
associated CATCH block. For more information, see Using TRY...CATCH in Transact-SQL.

The following example shows how an object name resolution error generated by a SELECT
statement is not caught by the TRY…CATCH construct, but is caught by the CATCH block when the
same SELECT statement is executed inside a stored procedure.

Copy Code

USE AdventureWorks;

GO

BEGIN TRY

-- Table does not exist; object name resolution

-- error not caught.

SELECT * FROM NonexistentTable;

END TRY

BEGIN CATCH

SELECT

ERROR_NUMBER() as ErrorNumber,

ERROR_MESSAGE() as ErrorMessage;
END CATCH

The error is not caught and control passes out of the TRY…CATCH construct to the next higher level.

Running the SELECT statement inside a stored procedure will cause the error to occur at a level
lower than the TRY block. The error will be handled by the TRY…CATCH construct.

Copy Code

-- Verify that the stored procedure does not exist.

IF OBJECT_ID ( N'usp_ExampleProc', N'P' ) IS NOT NULL

DROP PROCEDURE usp_ExampleProc;

GO

-- Create a stored procedure that will cause an

-- object resolution error.

CREATE PROCEDURE usp_ExampleProc

AS

SELECT * FROM NonexistentTable;

GO

BEGIN TRY

EXECUTE usp_ExampleProc

END TRY

BEGIN CATCH

SELECT

ERROR_NUMBER() as ErrorNumber,

ERROR_MESSAGE() as ErrorMessage;

END CATCH;

• For more information about batches, see Batches.


Uncommittable Transactions and XACT_STATE

If an error generated in a TRY block causes the state of the current transaction to be invalidated,
the transaction is classified as an uncommittable transaction. An error that ordinarily ends a
transaction outside a TRY block causes a transaction to enter an uncommittable state when the
error occurs inside a TRY block. An uncommittable transaction can only perform read operations or a
ROLLBACK TRANSACTION. The transaction cannot execute any Transact-SQL statements that would
generate a write operation or a COMMIT TRANSACTION. The XACT_STATE function returns a value
of -1 if a transaction has been classified as an uncommittable transaction. When a batch finishes,
the Database Engine rolls back any active uncommittable transactions. If no error message was
sent when the transaction entered an uncommittable state, when the batch finishes, an error
message will be sent to the client application. This indicates that an uncommittable transaction was
detected and rolled back.

For more information about uncommittable transactions and the XACT_STATE function, see Using
TRY...CATCH in Transact-SQL and XACT_STATE (Transact-SQL).

Examples

A. Using TRY…CATCH

The following example shows a SELECT statement that will generate a divide-by-zero error. The
error causes execution to jump to the associated CATCH block.

Copy Code

USE AdventureWorks;

GO

BEGIN TRY

-- Generate a divide-by-zero error.

SELECT 1/0;

END TRY

BEGIN CATCH

SELECT

ERROR_NUMBER() AS ErrorNumber,

ERROR_SEVERITY() AS ErrorSeverity,

ERROR_STATE() AS ErrorState,

ERROR_PROCEDURE() AS ErrorProcedure,

ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;

END CATCH;

GO

B. Using TRY…CATCH in a transaction

The following example shows how a TRY…CATCH block works inside a transaction. The statement
inside the TRY block generates a constraint violation error.

Copy Code

USE AdventureWorks;

GO

BEGIN TRANSACTION;

BEGIN TRY

-- Generate a constraint violation error.

DELETE FROM Production.Product

WHERE ProductID = 980;

END TRY

BEGIN CATCH

SELECT

ERROR_NUMBER() AS ErrorNumber,

ERROR_SEVERITY() AS ErrorSeverity,

ERROR_STATE() as ErrorState,

ERROR_PROCEDURE() as ErrorProcedure,

ERROR_LINE() as ErrorLine,

ERROR_MESSAGE() as ErrorMessage;

IF @@TRANCOUNT > 0

ROLLBACK TRANSACTION;

END CATCH;
IF @@TRANCOUNT > 0

COMMIT TRANSACTION;

GO

C. Using TRY…CATCH with XACT_STATE

The following example shows how to use the TRY…CATCH construct to handle errors that occur
inside a transaction. The XACT_STATE function determines whether the transaction should be
committed or rolled back. In this example, SET XACT_ABORT is ON. This makes the transaction
uncommittable when the constraint violation error occurs.

Copy Code

USE AdventureWorks;

GO

-- Check to see whether this stored procedure exists.

IF OBJECT_ID (N'usp_GetErrorInfo', N'P') IS NOT NULL

DROP PROCEDURE usp_GetErrorInfo;

GO

-- Create procedure to retrieve error information.

CREATE PROCEDURE usp_GetErrorInfo

AS

SELECT

ERROR_NUMBER() AS ErrorNumber,

ERROR_SEVERITY() AS ErrorSeverity,

ERROR_STATE() as ErrorState,

ERROR_LINE () as ErrorLine,

ERROR_PROCEDURE() as ErrorProcedure,

ERROR_MESSAGE() as ErrorMessage;

GO

-- SET XACT_ABORT ON will cause the transaction to be uncommittable


-- when the constraint violation occurs.

SET XACT_ABORT ON;

BEGIN TRY

BEGIN TRANSACTION;

-- A FOREIGN KEY constraint exists on this table. This

-- statement will generate a constraint violation error.

DELETE FROM Production.Product

WHERE ProductID = 980;

-- If the DELETE statement succeeds, commit the transaction.

COMMIT TRANSACTION;

END TRY

BEGIN CATCH

-- Execute error retrieval routine.

EXECUTE usp_GetErrorInfo;

-- Test XACT_STATE:

-- If 1, the transaction is committable.

-- If -1, the transaction is uncommittable and should

-- be rolled back.

-- XACT_STATE = 0 means that there is no transaction and

-- a commit or rollback operation would generate an error.

-- Test whether the transaction is uncommittable.

IF (XACT_STATE()) = -1

BEGIN

PRINT

N'The transaction is in an uncommittable state.' +

'Rolling back transaction.'


ROLLBACK TRANSACTION;

END;

-- Test whether the transaction is committable.

IF (XACT_STATE()) = 1

BEGIN

PRINT

N'The transaction is committable.' +

'Committing transaction.'

COMMIT TRANSACTION;

END;

END CATCH;

GO

SQL Server 2005 Books Online (September 2007)

GOTO (Transact-SQL)
Alters the flow of execution to a label. The Transact-SQL statement or statements that follow GOTO
are skipped and processing continues at the label. GOTO statements and labels can be used
anywhere within a procedure, batch, or statement block. GOTO statements can be nested.

Transact-SQL Syntax Conventions

Syntax

Define the label:

label :

Alter the execution:

GOTO label

Arguments

label
Is the point after which processing starts if a GOTO is targeted to that label. Labels must
follow the rules for identifiers. A label can be used as a commenting method whether GOTO is
used.

Remarks
GOTO can exist within conditional control-of-flow statements, statement blocks, or procedures, but
it cannot go to a label outside the batch. GOTO branching can go to a label defined before or after
GOTO.

Permissions

GOTO permissions default to any valid user.

Examples

The following example shows how to use GOTO as a branch mechanism.

DECLARE @Counter int;

SET @Counter = 1;

WHILE @Counter < 10

BEGIN

SELECT @Counter

SET @Counter = @Counter + 1

IF @Counter = 4 GOTO Branch_One --Jumps to the first branch.

IF @Counter = 5 GOTO Branch_Two --This will never execute.

END

Branch_One:

SELECT 'Jumping To Branch One.'

GOTO Branch_Three; --This will prevent Branch_Two from executing.

Branch_Two:

SELECT 'Jumping To Branch Two.'

Branch_Three:

SELECT 'Jumping To Branch Three.'

Vous aimerez peut-être aussi