Download - Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Transcript
Page 1: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

SQL Real World Error Handling

Weird SQL Server Error Handling Behavior

Page 2: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Bio - Niels Berglund

Software Specialist - Derivco Software Specialist - lots of production dev. plus figuring out

ways to "use and abuse" existing and new technologies

Author - "First Look at SQL Server 2005 for Developers" Researcher / Instructor - DevelopMentor Speaker - TechEd, DevWeek, SQL Pass, etc. Longtime user of SQL Server

www.derivco.com [email protected] @nielsberglund

9/7/2013 | Footer Goes Here2 |

Page 3: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Derivco

World's leading development house for online gaming software; Casino, Poker, Bingo etc.

Technology company One of the world's largest install base of SQL Server's

(~300 SQL Server servers, multiple instances & db's). SQL Server 2008 / 2012, research into 2014 Hadoop, Windows Azure .NET 4.5, SignalR, WebSockets, mobile (Android, iOS)

Offices in Durban, Cape Town, Pretoria (soon) Estonia, Hong Kong, Sweden, UK

WE ARE HIRING!!

Page 4: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Background

Once upon a time … Pre SQL 2005, arcane error handling Checking @@ERROR after each statement

execution does not halt at an error

SELECT 1 / 0 AS ResultSET @err = @@ERRORIF(@err <> 0)BEGIN --handle the errorEND

Page 5: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Background II (a.k.a Ivory Tower)

SQL 2005 introduced the concept of TRY … CATCH Instead of checking @@ERROR for every statement,

the code is enveloped in a TRY block, followed by a CATCH block.

It is neat, simple and all code should use this method or should it???

BEGIN TRY SET @x = 1 / 0 PRINT 'Hello World';END TRYBEGIN CATCH SET @errMsg = ERROR_MESSAGE(); --code to handle the errorEND CATCH

Page 6: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Real world

Derivco: ~300 SQL Server Servers, multiple instances. Main production db.; ~1,500 tables, ~5,000 procedures

In a live environment, you cannot change all code to use the new features!

New code; yes most definitely - you have full control of the call chain.

Editing existing procedures; be careful, be very careful there are subtle and not so subtle differences when

using try…catch blocks.

Page 7: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

RETURN and @@ERROR

A proc always returns an integer as return value.

The return value can be implicit, or set explicitly by the RETURN xxx statement.

If a proc encounters an error and no return value is defined, it returns -6 (undocumented…)

Page 8: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

TRY blocks

Code executing inside a TRY block executes in a specific error related context.

When an error occurs you are immediately transferred to the CATCH block.

Downstream, if no TRY CATCH block exist - you end up in the calling code's CATCH block what if you handle errors the "old" way

downstream? that will not happen, ouch!

Page 9: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

CATCH blocks

The error happening in the TRY block is handled in the CATCH block.

Even if an error occurs and is handled in a CATCH, the default return value of the proc indicates a failure (-6). if an explicit return value has been set, that value

will be returned.

To (re - ) raise an error in a CATCH block, can have strange side effects.

Page 10: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

CATCH and RAISERROR

You can (re)raise errors in a CATCH block Those errors will be caught in calling procs TRY … CATCH blocks. However, in order for "old"-style error handling to catch those errors,

there MUST be a RETURN immediately following the RAISERROR not RETURN variable but RETURN

BEGIN CATCH SET @errMsg = ERROR_MESSAGE(); PRINT 'We are in the catch block in the error proc' --re-raise the error, this will not make @@ERROR to catch the error upstrram RAISERROR('Something went wrong: %s', 16, -1, @errMsg);END CATCH

BEGIN CATCH SET @errMsg = ERROR_MESSAGE(); PRINT 'We are in the catch block in the error proc' --re-raise the error, this will make @@ERROR to catch the error upstrram RAISERROR('Something went wrong: %s', 16, -1, @errMsg); RETURNEND CATCH

Page 11: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

THROW

Pre SQL 2012 no easy way to re-throw an error you captured the error message and then did a RAISERROR

with the message. SQL 2012 introduces THROW THROW can be used in-place of RAISERROR

it does not support substitution parameters though you can however raise a specific error without that error number

existing in sys.messages The THROW statement has to be used in conjunction with

TRY CATCH. If no TRY CATCH is available for a THROW statement, the session is ended!

In a CATCH block THROW can be used to re-throw an error

Page 12: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

THROW examples

--syntaxTHROW [ { error_number | @local_variable }, { message | @local_variable }, { state | @local_variable } ] [ ; ]

--do some stuffTHROW 52000, 'Something weird happened', 1

BEGIN CATCH SET @errMsg = ERROR_MESSAGE(); PRINT 'We are in the catch block in the error proc'; --tis requires the calling proc, to have a try catch block THROW;END CATCH

Page 13: Sql Server Error-handling: Gotcha's when doing error-handling in SQL Server

Summary

TRY CATCH blocks ARE good! However, be carful when mixing new TRY CATCH with

"old" @@ERROR You need to check all nested procedures called inside the

Try block and: Make sure your error handling is correct (to the n level) Potentially handle Transactions started in nested

procedures If raising an error in a CATCH block, ALWAYS follow the

RAISERROR with a RETURN (no value). Unless you can guarantee that your code will always use

TRY CATCH, stay away from THROW.