TABLE 23-2 Catch Functions Error_Message The text of the error message Error_Number The number of the error Error_Procedure The name of the stored procedure or trigger in which the error
Trang 1the case, I recommend rolling back the transaction as the first action so that any locks the transaction might be holding are released
For more details on transactions and error handling, including a discussion on doomed transactions and the xact_state() function, please refer to Chapter 66, ‘‘Managing Transactions, Locking, and Blocking.’’
2 If the error is one that the stored procedure logic detects, and it’s not a SQL Server error, then
raise the error message so that the user or front-end application is informed
3 Optionally, log the error to an error table.
4 Terminate the batch If it’s a stored procedure, user-defined function, or trigger, then terminate
it with aRETURNcommand
When an error occurs in theTRYblock and execution is passed to theCATCHblock, the error
infor-mation is also passed to theCATCHblock The information may be examined using the error functions
listed in Table 23-2 These functions are designed specifically for theCATCHblock Outside aCATCH
block, they will always return anullvalue
TABLE 23-2
Catch Functions
Error_Message() The text of the error message
Error_Number() The number of the error
Error_Procedure() The name of the stored procedure or trigger in which the error occurred
Error_Severity() The severity of the error
Error_State() The state of the error
Error_Line() The line number within the batch or stored procedure that generated
the error Xact_State() Whether the transaction can be committed (see Chapter 66)
TheseCATCHfunctions retain the error information of the error that fired theCATCHblock They may
be called multiple times and still retain the error information
The following sample demonstrates aCATCHblock using theCATCHfunctions and aRAISERRORto
report the error to the client The contents of the error functions are being passed to variables so a
custom error string can be assembled for theRAISERROR:
BEGIN CATCH DECLARE
Trang 2T-SQL Error Handling 23
@Error_Severity INT,
@Error_State INT,
@Error_Number INT,
@Error_Line INT,
@Error_Message VARCHAR(245);
SELECT
@Error_Severity = ERROR_SEVERITY(),
@Error_State = ERROR_STATE(),
@Error_Number = ERROR_NUMBER(),
@Error_Line = ERROR_LINE(),
@Error_Message = ERROR_MESSAGE();
RAISERROR (’Msg %d, Line %d: %s’,
@Error_Severity,
@Error_State,
@Error_Number,
@Error_Line,
@Error_Message);
RETURN @Error_Number;
END CATCH;
Nested try/catch and rethrown errors
Any error (orRAISERRORevent) will bubble up through every layer of stored procedures until it’s
caught by a try/catch block or it reaches the client Visualizing the call stack — the stack of procedures
that have executed or called other stored procedures — it’s possible for lower level, or nested, stored
procedures to use this principle to send, or rethrow, errors to higher-level stored procedures in the
call stack
Try/catch blocks can easily be nested even if the nesting is unintentional If one stored procedure calls
another stored procedure and both procedures are well written, with try/catch blocks, then not only are
the stored procedures nested, but the try/catch blocks are nested too
In the following example, theTopProcwill execute, or call, theCalledProc A divide by zero
error inCalledProccauses the code to jump to theCATCHblock Thecatchblock will issue a
RAISERROR
TheTopProcwill receive the error that was raised by theCalledProc It sees the error as any other
type of error and therefore jumps down to itsCATCHblock TheRAISERRORin theTopProcis
exe-cuted, and it too raises an error This time the raised error is seen by the client, in this case
Manage-ment Studio:
CREATE PROC TopProc
AS
BEGIN TRY
EXEC CalledProc
Trang 3END TRY BEGIN CATCH RAISERROR (’TopProc Raiserror’,16,1) END CATCH
GO CREATE PROC CalledProc AS
BEGIN TRY SELECT 3/0 END TRY BEGIN CATCH RAISERROR (’CalledProc Raiserror’,16,1) END CATCH
Go EXEC TopProc Result:
Msg 50000, Level 16, State 1, Procedure TopProc, Line 7 TopProc Raiserror
T-SQL Fatal Errors
If T-SQL encounters a fatal error, then the batch will immediately abort without giving you the
opportu-nity to test@@Error, handle the error, or correct the situation
Fatal errors are rare enough that they shouldn’t pose much of a problem Generally, if the code works
once, then it should continue to work unless the schema is changed or SQL Server is reconfigured The
most common fatal errors are those caused by the following:
■ Data-type incompatibilities
■ Unavailable SQL Server resources
■ SQL Server advanced settings that are incompatible with certain tasks
■ Missing objects or misspelled object names For a list of most of the fatal error messages, run the following query:
SELECT message_id, severity, language_id, text FROM master.sys.messages
WHERE language_id = 1033 US English AND severity >= 19
ORDER BY severity, message_id;
Trang 4T-SQL Error Handling 23
Try Catchdoes a good job of handling typical day-to-day user errors, such as constraint-violation
errors Nevertheless, to be safe, front-end application developers should also include error-handling code
in their programs
Summary
Error handling — perhaps it’s the developer’s equivalent of the DBA’s backup command, yet it adds
a sense of polish and finish to any stored procedure Any production T-SQL code should have error
handling, no question about it It’s easy
Key points about T-SQL error handling:
■ Legacy error handling uses@@errorand@@rowcountto determine whether an error
occurred in the previous statement The values must be checked after every DML statement by
saving them to local variables
■ RAISERRORcan send errors toward the client and log errors
■ Try/catch blocks are the right way to handle errors On any error in theTRYblock, execution
jumps to theCATCHblock
■ Error functions in theCATCHblock return information about the last error
Next on the agenda: All the T-SQL query and programming pieces finally come together as stored
procedures
Trang 6Developing Stored
Procedures
IN THIS CHAPTER Creating and managing stored procedures
Passing data to and from stored procedures Using stored procedures within
ad hoc queries Executing stored procedures on linked SQL servers
Of all the possible SQL Server bad practices, I believe the worst is ad hoc
SQL The solution: stored procedures Here’s why
Chapter 2, ‘‘Data Architecture,’’ presented six databases objectives and the notion
that with careful design and development, all six could be achieved Architecting
the database with stored procedures is critical to achieving five of the six
objec-tives (all but availability):
■ Extensibility: Using stored procedures is the best means of abstracting,
or decoupling, the database A stored procedure API contract will
encapsulate the database and provide it with long-term extensibility
■ Performance: A well-written stored procedure is the fastest possible
SQL Server code, it keeps the execution of data-centric code close to the
data, and it’s easier to index tune a database with stored procedures
■ Usability: It’s easier for application programmers to make a stored
procedure call and consume the result than it is to write ad hoc SQL
■ Data Integrity: A stored procedure developed by the database
devel-oper is less likely to contain data integrity errors, and easier to unit test,
than ad hoc SQL code
■ Security: Locking down the tables and providing access only through
stored procedures is a standard best practice for database development
Of these five, extensibility is the most compelling reason to use stored procedures
I’ve personally witnessed too many IT shops and ISVs that have a nightmare
database they wish they could fix, but without an abstraction layer, it seems too
scary to manage As a result, they spend 10 times more building out additional
code, adding extra databases, or losing business because they can’t adapt
Trang 7Stored procedures aren’t mysterious All the features of T-SQL queries and batches are in full force In
the same way that a view is a SQL query saved under a view name, a stored procedure is a batch that
has been stored with a name so it can be easily called, and its query execution plan saved in memory
(see Figure 24-1)
FIGURE 24-1
Stored procedures keep the code inside the box, protecting the abstraction layer and keeping the data
execution close to the data
SQL Server
Processing Continuum
Data
Improved
integrity and
performance
Data Type Constraint TriggerStored Procedure View Submitted Batch Front-End Application
User
To write an efficient stored procedure, don’t start with this chapter A well-written stored procedure is
based on a well-written batch (see Chapter 23) consisting of well-written, set-oriented SQL queries (see
Chapters 8 through 21) This chapter explains how to pull together the batch and wrap it as a stored
procedure
What’s New with Stored Procedures?
SQL Server 2008 adds user-defined table types and table-valued parameters (my number two favorite new
feature) to T-SQL These radically improve how a client application can pass a complex transaction to
SQL Server Previously, the only options were to pass in a comma-delimited list using a varchar(max)
parameter, pass in an XML variable, or make multiple calls to stored procedures
Stored procedures are highly dependent on the objects they call SQL Server 2008 provides enhanced ways
to view these dependencies
Managing Stored Procedures
The actual management of stored procedures is simple compared to the logic within them Once you
know the basic facts and syntax, managing stored procedures shouldn’t present any problems
Trang 8Developing Stored Procedures 24
Create, alter, and drop
Stored procedures are managed by means of the data definition language (DDL) commands:CREATE,
ALTER, andDROP
CREATEmust be the first command in a batch; the termination of the batch ends the creation of the
stored procedure The following example creates a very simple stored procedure that retrieves data from
theProductCategorytable in theOBXKitesdatabase:
USE OBXKites;
go
CREATE PROCEDURE dbo.CategoryList
AS
SELECT ProductCategoryName, ProductCategoryDescription
FROM dbo.ProductCategory;
go
As this chapter progresses, more features will be added to theCategoryListexample stored
procedure
Dropping a stored procedure removes it from the database Altering a stored procedure replaces the
entire existing stored procedure with new code When modifying a stored procedure, altering it is
preferable to dropping and recreating it, because the latter method removes any permissions
Of course, stored procedures may be created, altered, or dropped using Object Explorer, but I strongly
suggest that stored procedures be managed using scripts (.sqlfiles) that may be checked into a version
control system
Executing a stored procedure
When calling a stored procedure within a SQL batch, theEXECUTEcommand executes the stored
pro-cedure with a few special rules.EXECUTEis typically coded asEXEC
If the stored-procedure call is the first line of a batch (and if it’s the only line, then it’s also the first
line), the stored-procedure call doesn’t require theEXECcommand However, including it anyway won’t
cause any problems and it prevents an error if the code is cut and pasted later
The following two-system stored procedure calls demonstrate the use of theEXECcommand within
a batch:
sp_help;
EXEC sp_help;
This section covers the batch aspects of EXEC You can find more details about using the
EXECUTE command in Chapter 29, ‘‘Dynamic SQL and Code Generation.’’
Trang 9Returning a record set
If a stored procedure is a saved batch, then whatever a batch can do, a stored procedure can do Just
as a batch returns a record set from a SQLSELECTquery, a stored procedure also returns a record set
from a query
Referring back to the stored procedure that was created in the preceding section, when the
CategoryListstored procedure is executed, the query within the stored procedure returns all
rows from theproductcategorytable:
EXEC dbo.CategoryList;
Result (abridged):
ProductCategoryName ProductCategoryDescription - -Accessory kite flying accessories
Clothing OBX t-shirts, hats, jackets
Compiling stored procedures
Compiling a stored procedure is an automatic process Stored procedures compile and are stored in
memory the first time they are executed Rather more accurately, SQL Server develops query execution
plans for the queries and code within the stored procedures, and these query execution plans are stored
in memory
For more details about query execution plans and how they’re stored in memory, refer to Chapter 65, ‘‘Query Plan Reuse.’’
Stored procedure encryption
When the stored procedure is created, its text is saved in a system table The text is not stored for the
execution of the stored procedure, but only so that it may be retrieved later if it needs to be modified
Thesp_helptextsystem stored procedure will extract the original text of the stored procedure:
EXEC sp_helptext ‘dbo.CategoryList’;
Result:
Text -CREATE PROCEDURE CategoryList
AS SELECT ProductCategoryName, ProductCategoryDescription FROM dbo.ProductCategory;
If the stored procedure is created with theWITH ENCRYPTIONoption, the stored procedure text is not
directly readable It’s common practice for third-party vendors to encrypt their stored procedures The
Trang 10Developing Stored Procedures 24
followingALTERcommand stores theCategoryListprocedure withWITH ENCRYPTIONand then
attempts to read the code:
ALTER PROCEDURE dbo.CategoryList
WITH ENCRYPTION
AS
SELECT ProductCategoryName, ProductCategoryDescription
FROM dbo.ProductCategory;
go
EXEC sp_helptext ‘dbo.CategoryList’;
Result:
The text for object ‘dbo.CategoryList’ is encrypted
System stored procedures
The basic SQL syntax includes only DML, DDL, and DCL commands For other admin tasks, Microsoft
adds system stored procedures stored in themasterdatabase But with every version of SQL Server,
Microsoft moves more of these tasks from system stored procedures into standard SQL Specifically, the
ALTERcommand is becoming more powerful with every version
To make these procedures available to all databases, special rules govern the scope of system stored
procedures Any procedures beginning withsp_in themasterdatabase can be executed from any
database If a name conflict exists between a system stored procedure and a stored procedure in the
local user database, the system stored procedure in the local database is executed
Best Practice
When creating stored procedures, use a consistent naming convention other than sp_ to name your
stored procedures Using sp_ can only cause name conflicts and confusion I sometimes add the
pprefix to the names of stored procedures, but even no prefix is better than sp_
Using stored procedures within queries
Stored procedures are typically executed with theEXECcommand or submitted by the client
applica-tion, but a stored procedure can be used within theFROMportion of a query if the stored procedure is
called from within anopenquery()function
Openquery()is a distributed query function that sends a pass-through query to an external data
source for remote execution When theopenquery()function includes a stored procedure, it simply
submits the stored procedure to the local server
The openquery() function is explained in more detail in Chapter 31, ‘‘Executing Distributed Queries.’’