Usando TRY...CATCH na Transact-SQL
Os erros no código Transact-SQL podem ser processados com o uso da construção TRY…CATCH similar aos recursos de controle de exceções das linguagens Microsoft Visual C++ e Microsoft Visual C#. Uma construção TRY...CATCH consiste em duas partes: um bloco TRY e um bloco CATCH. Quando uma condição de erro for detectada em uma instrução Transact-SQL que está dentro de um bloco TRY, o controle é passado para um bloco CATCH, onde o erro pode ser processado.
Após o bloco CATCH controlar a exceção, o controle é transferido para a primeira instrução Transact-SQL que segue a instrução END CATCH. Se a instrução END CATCH for a última instrução de um procedimento ou gatilho, o controle retorna para o código que invocou o procedimento armazenado ou gatilho. As instruções Transact-SQL do bloco TRY que seguem a instrução que gera um erro não serão executadas.
Se não houver erros dentro do bloco TRY, o controle passa para a instrução imediatamente seguinte à instrução END CATCH associada. Se a instrução END CATCH for a última instrução de um procedimento armazenado ou gatilho, o controle é passado para a instrução que invocou o procedimento armazenado ou gatilho.
Um bloco TRY inicia com a instrução BEGIN TRY e termina com a instrução END TRY. Podem ser especificadas uma ou mais instruções Transact-SQL entre as instruções BEGIN TRY e END TRY.
Um bloco TRY deve ser seguido imediatamente por um bloco CATCH. Um bloco CATCH inicia com a instrução BEGIN CATCH e termina com a instrução END CATCH. Em Transact-SQL, cada bloco TRY é associado com só um bloco CATCH.
Trabalhando com TRY...CATCH
Ao usar a construção TRY.CATCH, considere as diretrizes e sugestões a seguir:
Cada construção TRY...CATCH deve estar dentro de um único lote, procedimento armazenado ou gatilho. Por exemplo, você não pode colocar um bloco TRY em um lote e o bloco CATCH associado, em outro lote. O script seguinte geraria um erro:
BEGIN TRY SELECT * FROM sys.messages WHERE message_id = 21; END TRY GO -- The previous GO breaks the script into two batches, -- generating syntax errors. The script runs if this GO -- is removed. BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber; END CATCH; GO
Um bloco TRY deve ser seguido imediatamente por um bloco CATCH.
As construções TRY...CATCH podem ser aninhadas. Isso significa que as construções TRY...CATCH podem ser colocadas dentro de outro bloco TRY e CATCH. Ao ocorrer um erro dentro de um bloco TRY aninhado, o controle de programas será transferido para o bloco CATCH associado ao bloco TRY aninhado.
Para controlar um erro dento de um determinado bloco CATCH, grave um bloco TRY…...CATCH no interior do bloco CATCH especificado.
Os erros com severidade 20 ou superior que levam o Mecanismo de Banco de Dados a encerrar a conexão não serão controlados pelo bloco TRY…CATCH. Porém, o TRY…CATCH controlará os erros com severidade igual ou superior a 20 contanto que a conexão seja mantida.
Os erros com severidade 10 ou inferior são considerados avisos ou mensagens informativas, e não serão controlados pelos blocos TRY…CATCH.
As atenções finalizarão um lote, mesmo ele estando dentro do escopo de uma construção TRY...CATCH. Isto inclui uma atenção enviada pelo MS DTC (Coordenador de Transações Distribuídas da Microsoft) quando uma transação distribuída falhar. O MS DTC gerencia as transações distribuídas.
Observação Se uma transação distribuída for executada dentro do escopo de um bloco TRY e ocorrer um erro , a execução será transferida para o bloco CATCH associado. A transação distribuída entra em um estado não confirmável. A execução dentro do bloco CATCH pode ser interrompida pelo Microsoft Coordenador de Transação Distribuída que administra as transações distribuídas. Quando o erro ocorrer, o MS DTC notifica, de forma assíncrona, todos os servidores que participam da transação distribuída, e finaliza todas as tarefas envolvidas na transação distribuída. Essa notificação é enviada na forma de atenção que não será controlada por uma construção TRY…CATCH, e o lote é finalizado. Quando um lote terminar de executar, o Mecanismo de Banco de Dados reverte qualquer transação ativa não confirmável. Se nenhuma mensagem de erro foi enviada quando a transação entrou em um estado não confirmável, quando o lote terminar, uma mensagem de erro será enviada ao aplicativo cliente que indica que uma transação não confirmável foi detectada e revertida. Para obter mais informações sobre transações distribuídas, consulteTransações distribuídas (Mecanismo de Banco de Dados).
Funções de erro
TRY…CATCH usa as seguintes funções de erro para capturar informações de erros:
ERROR_NUMBER () retorna o número do erro.
ERROR_MESSAGE () retorna o texto completo da mensagem de erro. O texto inclui os valores fornecidos para qualquer parâmetro substituível, como extensões, nomes de objetos ou horas.
ERROR_SEVERITY () retorna a severidade de erro.
ERROR_STATE() retorna o número do estado do erro.
ERROR_LINE () retorna o número de linha dentro da rotina que causou o erro.
ERROR_PROCEDURE() retorna o nome do procedimento armazenado ou do gatilho no qual ocorreu o erro.
As informações sobre o erro podem ser recuperadas usando-se essas funções de qualquer lugar dentro do escopo do bloco CATCH de uma construção TRY...CATCH. As funções de erro retornarão o NULL, se chamadas fora do escopo de um bloco CATCH. As funções de erro podem ser referenciadas dentro de um procedimento armazenado e usadas para recuperar as informações sobre erros, quando o procedimento armazenado for executado no bloco CATCH. Fazendo isto, você não precisa repetir o código de tratamento de erros em todo bloco CATCH. No exemplo de código a seguir, a instrução SELECT no bloco TRY gerará um erro do tipo dividir-por-zero. O erro será controlado pelo bloco CATCH, que usa um procedimento armazenado para retornar as informações de erro.
USE AdventureWorks;
GO
-- Verify that the stored procedure does not exist.
IF OBJECT_ID ('usp_GetErrorInfo', 'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create a 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 the error retrieval routine.
EXECUTE usp_GetErrorInfo;
END CATCH;
GO
Erros ao compilar e recompilar em nível de instrução
Existem dois tipos de erros que não serão controlados pelo TRY…CATCH, se o erro ocorrer no mesmo nível de execução da construção TRY…CATCH:
Erros de compilação, como erros de sintaxe que impedem um lote de executar.
Erros ocorridos ao se recompilar em nível de instrução, como os erros de resolução do nome do objeto que acontecem após a compilação devido à resolução do nome adiada.
Quando o lote, procedimento armazenado, ou gatilho que contém a construção TRY…CATCH gerar um desses erros, a construção TRY…CATCH não os controlará. Esses erros voltarão ao aplicativo ou lote que chamou a rotina de geração de erro. Para exemplificar, o exemplo de código a seguir mostra uma instrução SELECT que causa um erro de sintaxe. Se esse código for executado no Editor de Consultas do SQL Server Management Studio, a execução não será iniciada, pois a compilação do lote falhará. O erro retornará ao Editor de Consultas e não será pego por TRY…CATCH.
USE AdventureWorks;
GO
BEGIN TRY
-- This PRINT statement will not run because the batch
-- does not begin execution.
PRINT N'Starting execution';
-- This SELECT statement contains a syntax error that
-- stops the batch from compiling successfully.
SELECT ** FROM HumanResources.Employee;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
Diferente do erro de sintaxe do exemplo anterior, um erro que ocorre durante uma recompilação em nível de instrução não impedirá que o lote compile; mas, ela terminará o lote assim que a recompilação da instrução falhar. Por exemplo, se um lote possuir duas instruções e a segunda instrução fizer referência a uma tabela que não existe, a resolução adiada do nome faz o lote compilar com êxito, e iniciar a execução sem associar a tabela que falta ao plano de consulta até que essa instrução seja recompilada. O lote deixa de executar quando se deparar com a instrução, que fará referência à tabela perdida e retornará um erro. Esse tipo de erro não será controlado pela construção TRY…CATCH no mesmo nível de execução no qual o erro ocorreu. O exemplo a seguir demonstra esse comportamento.
USE AdventureWorks;
GO
BEGIN TRY
-- This PRINT statement will run because the error
-- occurs at the SELECT statement.
PRINT N'Starting execution';
-- This SELECT statement will generate an object name
-- resolution error because the table does not exist.
SELECT * FROM NonExistentTable;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
Você pode usar TRY…CATCH para controlar erros que ocorrem durante a compilação ou recompilação em nível de instrução, executando o código de geração de erro em um lote separado dentro do bloco TRY. Por exemplo, você pode fazer isso colocando o código em um procedimento armazenado ou executando uma instrução dinâmica Transact-SQL usando sp_executesql. Isso permitirá que TRY…CATCH capture o erro em um nível superior de execução em relação à ocorrência de erro. Por exemplo, o código a seguir mostra um procedimento armazenado que gera um erro de resolução de nome de objeto. O lote que contém a construção TRY…CATCH está executando em um nível superior ao do procedimento armazenado; e o erro, que ocorre em um nível inferior, é capturado.
USE AdventureWorks;
GO
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID ('usp_MyError', 'P') IS NOT NULL
DROP PROCEDURE usp_MyError;
GO
CREATE PROCEDURE usp_MyError
AS
-- This SELECT statement will generate
-- an object name resolution error.
SELECT * FROM NonExistentTable;
GO
BEGIN TRY
-- Run the stored procedure.
EXECUTE usp_MyError;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
Conjunto de resultados.
ErrorNumber ErrorMessage
----------- ---------------------------------------
208 Invalid object name 'NonExistentTable'.
Para obter mais informações, consulte Resolução e compilação de nome diferida e a seção "Recompilando Planos de Execução" em Reutilização e armazenamento em cache do plano de execução.
Transações não confirmáveis
Dentro de uma construção TRY...CATCH, as transações podem entrar em um estado em que a transação permanece aberta, mas não pode ser confirmada. A transação não poderá efetuar qualquer ação que gere uma gravação no log de transação, como a alteração de dados ou a tentativa de reversão a um ponto de salvamento. Contudo, nesse estado, são mantidos os bloqueios adquiridos pela transação e a conexão também permanece aberta. Os efeitos da transação não são revertidos até que uma instrução ROLLBACK seja emitida, ou até que o lote termine e a transação seja revertida automaticamente pelo Mecanismo de Banco de Dados. Se nenhuma mensagem de erro foi enviada quando a transação entrou em um estado não confirmável, quando o lote terminar, uma mensagem de erro será enviada ao aplicativo cliente, que indicará que uma transação não confirmável foi detectada e revertida.
Uma transação entra em um estado não confirmável dentro de um bloco TRY, quando ocorre um erro que, de outra forma, teria encerrado a transação. Por exemplo, a maioria dos erros de uma instrução DDL, linguagem de definição de dados (como CREATE TABLE), ou a maioria dos erros que ocorrem quando SET XACT_ABORT estiver definido em ON, encerram a transação fora de um bloco TRY; mas, tornam uma transação não confirmável dentro de um bloco TRY.
O código de um bloco CATCH deve testar o estado de uma transação usando a função XACT_STATE. O XACT_STATE retornará um -1 se a sessão tiver uma transação não confirmável. O bloco CATCH não deverá efetuar qualquer ação que gere gravações no log se a função XACT_STATE retornar um -1. O exemplo de código a seguir gera um erro de uma instrução DDL e usa XACT_STATE para testar o estado de uma transação, com objetivo de tomar a ação mais apropriada.
USE AdventureWorks;
GO
-- Verify that the table does not exist.
IF OBJECT_ID (N'my_books', N'U') IS NOT NULL
DROP TABLE my_books;
GO
-- Create table my_books.
CREATE TABLE my_books
(
Isbn int PRIMARY KEY,
Title NVARCHAR(100)
);
GO
BEGIN TRY
BEGIN TRANSACTION;
-- This statement will generate an error because the
-- column author does not exist in the table.
ALTER TABLE my_books
DROP COLUMN author;
-- If the DDL statement succeeds, commit the transaction.
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() as ErrorNumber,
ERROR_MESSAGE() as ErrorMessage;
-- Test XACT_STATE for 1 or -1.
-- XACT_STATE = 0 means 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 active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N'The transaction is committable. ' +
'Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH;
GO
Manipulando Deadlocks
É possível usar TRY.CATCH para controlar deadlocks. O erro 1205, vítima de deadlock, pode ser pego pelo bloco CATCH, e a transação poderá ser revertida até que os threads sejam desbloqueados. Para obter mais informações sobre deadlock, consulte Deadlock.
O exemplo a seguir mostra como TRY...CATCH pode ser usada para controlar deadlocks. A primeira seção cria uma tabela que será usada para demonstrar um estado deadlock e um procedimento armazenado que será usado para imprimir as informações de erros.
USE AdventureWorks;
GO
-- Verify that the table does not exist.
IF OBJECT_ID (N'my_sales',N'U') IS NOT NULL
DROP TABLE my_sales;
GO
-- Create and populate the table for deadlock simulation.
CREATE TABLE my_sales
(
Itemid INT PRIMARY KEY,
Sales INT not null
);
GO
INSERT my_sales (itemid, sales) VALUES (1, 1);
INSERT my_sales (itemid, sales) VALUES (2, 1);
GO
-- Verify that the stored procedure for error printing
-- does not exist.
IF OBJECT_ID (N'usp_MyErrorLog',N'P') IS NOT NULL
DROP PROCEDURE usp_MyErrorLog;
GO
-- Create a stored procedure for printing error information.
CREATE PROCEDURE usp_MyErrorLog
AS
PRINT
'Error ' + CONVERT(VARCHAR(50), ERROR_NUMBER()) +
', Severity ' + CONVERT(VARCHAR(5), ERROR_SEVERITY()) +
', State ' + CONVERT(VARCHAR(5), ERROR_STATE()) +
', Line ' + CONVERT(VARCHAR(5), ERROR_LINE());
PRINT
ERROR_MESSAGE();
GO
Os scripts de código, a seguir, para sessão 1 e sessão 2 executam simultaneamente em duas conexões separadas do SQL Server Management Studio. Ambas as sessões tentam atualizar as mesmas linhas na tabela. Uma das seções terá êxito na operação de atualização durante a primeira tentativa, e a outra sessão será selecionada como vítima de deadlock. O erro vítima de deadlock fará a execução pular para o bloco CATCH, e a transação entrará em um estado não confirmável. Dentro do bloco CATCH, a vítima de deadlock pode reverter a transação e tentar, novamente, atualizar a tabela até que a atualização tenha êxito, ou até que o limite de tentativas seja atingido, ou o que ocorrer primeiro.
Sessão 1 |
Sessão 2 |
---|---|
|
|
TRY…CATCH com RAISERROR
RAISERROR pode ser usado no bloco TRY ou CATCH de uma construção TRY...CATCH para afetar o comportamento do tratamento de erros.
RAISERROR com severidade de 11 a 19, executado dentro de um bloco TRY, transfere o controle para o bloco CATCH associado. O RAISERROR com severidade de 11 a 19, executado dentro de um bloco CATCH, retorna um erro para o aplicativo ou lote que chama. Desse modo, o RAISERROR pode ser usado para retornar informações para o chamador sobre o erro que fez o bloco CATCH executar. As informações de erro fornecidas pelas funções de erro TRY...CATCH podem ser capturadas na mensagem do RAISERROR, incluindo o número do erro original; no entanto, o número de erro do RAISERROR deve ser.>= 50000.
O RAISERROR com severidade igual ou inferior a 10 retorna uma mensagem informativa para o lote ou aplicativo de chamada, sem invocar o bloco CATCH.
O RAISERROR com severidade igual ou superior a 20 fecha a conexão de banco de dados sem invocar o bloco CAPTURA.
O exemplo de código a seguir mostra como o RAISERROR pode ser usado dentro de um bloco CATCH, para retornar as informações do erro original para o aplicativo ou lote de chamada. O procedimento armazenado usp_GenerateError executa uma instrução DELETE dentro de um bloco TRY, que gera um erro de violação de restrição. O erro faz a execução transferir para o bloco CATCH associado dentro do procedimento usp_GenerateError onde o procedimento armazenado usp_RethrowError é executado, para gerar as informações de erro de violação de restrição com o uso do RAISERROR. Esse erro gerado pelo RAISERROR retorna ao lote de chamada onde usp_GenerateError foi executado, e faz a execução transferir para o bloco CATCH associado no lote de chamada.
Observação |
---|
RAISERROR pode gerar erros somente com estado de 1 a 127. Como o Mecanismo de Banco de Dados pode gerar erros com o estado 0, recomendamos que você verifique o estado de erro retornado por ERROR_STATE antes de passá-lo como um valor ao parâmetro de estado de RAISERROR. |
USE AdventureWorks;
GO
-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL
DROP PROCEDURE usp_RethrowError;
GO
-- Create the stored procedure to generate an error using
-- RAISERROR. The original error information is used to
-- construct the msg_str for RAISERROR.
CREATE PROCEDURE usp_RethrowError AS
-- Return if there is no error information to retrieve.
IF ERROR_NUMBER() IS NULL
RETURN;
DECLARE
@ErrorMessage NVARCHAR(4000),
@ErrorNumber INT,
@ErrorSeverity INT,
@ErrorState INT,
@ErrorLine INT,
@ErrorProcedure NVARCHAR(200);
-- Assign variables to error-handling functions that
-- capture information for RAISERROR.
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
-- Build the message string that will contain original
-- error information.
SELECT @ErrorMessage =
N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' +
'Message: '+ ERROR_MESSAGE();
-- Raise an error: msg_str parameter of RAISERROR will contain
-- the original error information.
RAISERROR
(
@ErrorMessage,
@ErrorSeverity,
1,
@ErrorNumber, -- parameter: original error number.
@ErrorSeverity, -- parameter: original error severity.
@ErrorState, -- parameter: original error state.
@ErrorProcedure, -- parameter: original error procedure name.
@ErrorLine -- parameter: original error line number.
);
GO
-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_GenerateError',N'P') IS NOT NULL
DROP PROCEDURE usp_GenerateError;
GO
-- Create a stored procedure that generates a constraint violation
-- error. The error is caught by the CATCH block where it is
-- raised again by executing usp_RethrowError.
CREATE PROCEDURE usp_GenerateError
AS
BEGIN TRY
-- A FOREIGN KEY constraint exists on the table. This
-- statement will generate a constraint violation error.
DELETE FROM Production.Product
WHERE ProductID = 980;
END TRY
BEGIN CATCH
-- Call the procedure to raise the original error.
EXEC usp_RethrowError;
END CATCH;
GO
-- In the following batch, an error occurs inside
-- usp_GenerateError that invokes the CATCH block in
-- usp_GenerateError. RAISERROR inside this CATCH block
-- generates an error that invokes the outer CATCH
-- block in the calling batch.
BEGIN TRY -- outer TRY
-- Call the procedure to generate an error.
EXECUTE usp_GenerateError;
END TRY
BEGIN CATCH -- Outer CATCH
SELECT
ERROR_NUMBER() as ErrorNumber,
ERROR_MESSAGE() as ErrorMessage;
END CATCH;
GO
Alterando o fluxo de execução
Para alterar o fluxo de execução, o GOTO pode ser usado dentro de um bloco TRY ou um CATCH. O GOTO também pode ser usado para sair de um bloco TRY ou CATCH; no entanto, o GOTO não pode ser usado para inserir um bloco TRY ou CATCH.
Solução de tratamento de erros no banco de dados de exemplo AdventureWorks
O banco de dados de exemplo AdventureWorks inclui uma solução de tratamento de erros projetada para registrar informações sobre erros identificados pelo bloco CATCH de uma construção TRY…CATCH, que poderá ser consultada ou analisada posteriormente.
Tabela dbo.ErrorLog
A tabela ErrorLog registra as informações sobre o número do erro, severidade do erro, estado do erro, nome do procedimento armazenado ou gatilho onde o erro ocorreu, número de linha na qual o erro ocorreu, e o texto completo da mensagem de erro. Ela também registra a data e hora na qual o erro ocorreu, e o nome de usuário que executou a rotina que gerou o erro. Essa tabela é populada quando o procedimento armazenado uspLogError é executado no escopo do bloco CATCH de uma construção TRY...CATCH. Para obter mais informações, consulte Tabela ErrorLog (AdventureWorks).
dbo.uspLogError
O procedimento armazenado uspLogError registra informações na tabela ErrorLog sobre o erro que fez a execução transferir para o bloco CATCH de uma construção TRY... CATCH. Para o uspLogError inserir informações de erro na tabela ErrorLog, são exigidas as seguintes condições:
O uspLogError deve ser executado dentro do escopo de um bloco CATCH.
Se a transação atual estiver em um estado não confirmável, a transação será revertida antes de executar o uspLogError.
O parâmetro de saída @ ErrorLogID de uspLogError retorna o ErrorLogID da linha inserida por meio do uspLogError na tabela ErrorLog. O valor padrão de @ ErrorLogID é 0. O exemplo a seguir mostra o código para ouspLogError. Para obter mais informações, consulte Procedimentos armazenados na AdventureWorks.
CREATE PROCEDURE [dbo].[uspLogError]
@ErrorLogID [int] = 0 OUTPUT -- Contains the ErrorLogID of the row inserted
-- by uspLogError in the ErrorLog table.
AS
BEGIN
SET NOCOUNT ON;
-- Output parameter value of 0 indicates that error
-- information was not logged.
SET @ErrorLogID = 0;
BEGIN TRY
-- Return if there is no error information to log.
IF ERROR_NUMBER() IS NULL
RETURN;
-- Return if inside an uncommittable transaction.
-- Data insertion/modification is not allowed when
-- a transaction is in an uncommittable state.
IF XACT_STATE() = -1
BEGIN
PRINT 'Cannot log error since the current transaction is in an uncommittable state. '
+ 'Rollback the transaction before executing uspLogError in order to successfully log error information.';
RETURN;
END;
INSERT [dbo].[ErrorLog]
(
[UserName],
[ErrorNumber],
[ErrorSeverity],
[ErrorState],
[ErrorProcedure],
[ErrorLine],
[ErrorMessage]
)
VALUES
(
CONVERT(sysname, CURRENT_USER),
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
ERROR_PROCEDURE(),
ERROR_LINE(),
ERROR_MESSAGE()
);
-- Pass back the ErrorLogID of the row inserted
SELECT @ErrorLogID = @@IDENTITY;
END TRY
BEGIN CATCH
PRINT 'An error occurred in stored procedure uspLogError: ';
EXECUTE [dbo].[uspPrintError];
RETURN -1;
END CATCH
END;
dbo.uspPrintError
O procedimento armazenado uspPrintError imprime as informações sobre o erro que fez a execução se transferir para o bloco CATCH de uma construção TRY... CATCH. uspPrintError deve ser executado no escopo de um bloco CATCH; caso contrário, o procedimento retornará sem imprimir qualquer informação de erro. O exemplo a seguir mostra o código para o uspPrintError. Para obter mais informações, consulte Procedimentos armazenados na AdventureWorks.
CREATE PROCEDURE [dbo].[uspPrintError]
AS
BEGIN
SET NOCOUNT ON;
-- Print error information.
PRINT 'Error ' + CONVERT(varchar(50), ERROR_NUMBER()) +
', Severity ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
', State ' + CONVERT(varchar(5), ERROR_STATE()) +
', Procedure ' + ISNULL(ERROR_PROCEDURE(), '-') +
', Line ' + CONVERT(varchar(5), ERROR_LINE());
PRINT ERROR_MESSAGE();
END;
Exemplo de tratamento de erros
O exemplo a seguir demonstra a solução de tratamento de erros do AdventureWorks. O código dentro do bloco TRY tenta excluir o registro com ProductID 980, na tabela Production.Product. Uma restrição FOREIGN KEY da tabela não permite o êxito da instrução DELETE e um erro de violação de é gerado. Esse erro faz a execução transferir ao bloco CATCH. Dentro do bloco CATCH, ocorrem as seguintes ações:
O uspPrintError imprime as informações de erro.
Após a transação ser revertida, o uspLogError insere as informações de erro na tabela ErrorLog e retorna o ErrorLogID da linha inserida no parâmetro @ErrorLogID OUTPUT.
USE AdventureWorks;
GO
-- Variable to store ErrorLogID value of the row
-- inserted in the ErrorLog table by uspLogError
DECLARE @ErrorLogID INT;
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 operation succeeds, commit the transaction.
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Call procedure to print error information.
EXECUTE dbo.uspPrintError;
-- Roll back any active or uncommittable transactions before
-- inserting information in the ErrorLog.
IF XACT_STATE() <> 0
BEGIN
ROLLBACK TRANSACTION;
END
EXECUTE dbo.uspLogError @ErrorLogID = @ErrorLogID OUTPUT;
END CATCH;
-- Retrieve logged error information.
SELECT * FROM dbo.ErrorLog WHERE ErrorLogID = @ErrorLogID;
GO
Exemplo de manipulação de erro aninhado
O exemplo a seguir mostra o uso da construção aninhada TRY...CATCH.
BEGIN TRY
BEGIN TRY
SELECT CAST('invalid_date' AS datetime)
END TRY
BEGIN CATCH
PRINT 'Inner TRY error number: ' +
CONVERT(varchar,ERROR_NUMBER()) + ' on line: ' +
CONVERT(varchar, ERROR_LINE())
END CATCH
SELECT CAST('invalid_int' AS int)
END TRY
BEGIN CATCH
PRINT 'Outer TRY error mumber: ' + CONVERT(varchar,ERROR_NUMBER())+
' on line: ' + CONVERT(varchar, ERROR_LINE())
END CATCH
Conjunto de resultados.
Inner TRY error number: 241 on line: 3
Outer TRY error number: 245 on line: 9
Consulte também