TRY...CATCH (Transact-SQL)

Implémente la gestion des erreurs pour Transact-SQL, similaire à la gestion des exceptions dans les langages Microsoft Visual C# et Microsoft Visual C++. Un groupe d'instructions Transact-SQL peut être contenu dans un bloc TRY. Si une erreur survient dans le bloc TRY, le contrôle est passé à un autre groupe d'instructions contenues dans un bloc CATCH.

Icône Lien de rubriqueConventions de syntaxe de Transact-SQL

Syntaxe

BEGIN TRY
     { sql_statement | statement_block }
END TRY
BEGIN CATCH
          [ { sql_statement | statement_block } ]
END CATCH
[ ; ]

Arguments

  • sql_statement
    Toute instruction Transact-SQL.

  • statement_block
    Tout groupe d'instructions Transact-SQL dans un lot ou contenues dans un bloc BEGIN…END.

Notes

La construction TRY…CATCH intercepte toutes les erreurs d'exécution dont la gravité est supérieure à 10 et qui ne ferment pas la connexion de la base de données.

Un bloc TRY doit être suivi immédiatement d'un bloc CATCH associé. L'inclusion d'une autre instruction entre les instructions END TRY et BEGIN CATCH génère une erreur de syntaxe.

Une construction TRY…CATCH ne peut pas s'étendre sur plusieurs lots. Une construction TRY…CATCH ne peut pas s'étendre sur plusieurs blocs d'instructions Transact-SQL. Par exemple, une construction TRY…CATCH ne peut pas s'étendre sur deux blocs BEGIN…END d'instructions Transact-SQL et ne peut pas s'étendre sur une construction IF…ELSE.

Si le code inclus dans un bloc TRY ne contient aucune erreur, lorsque l'exécution de la dernière instruction du bloc TRY est terminée, le contrôle est passé à l'instruction qui se trouve immédiatement après l'instruction END CATCH associée. S'il existe une erreur dans le code inclus dans le bloc TRY, le contrôle est passé à la première instruction du bloc CATCH associé. Si l'instruction END CATCH se trouve dans la dernière instruction d'une procédure stockée ou d'un déclencheur, le contrôle revient à l'instruction qui a appelé la procédure stockée ou activé le déclencheur.

Lorsque le code du bloc CATCH est terminé, le contrôle est passé à l'instruction qui se trouve immédiatement après l'instruction END CATCH. Les erreurs interceptées par un bloc CATCH ne sont pas renvoyées à l'application appelante. Si une partie des informations sur les erreurs doivent être renvoyées à l'application, le code dans le bloc CATCH doit pour ce faire utiliser des mécanismes tels que les jeux de résultats SELECT ou les instructions RAISERROR et PRINT. Pour plus d'informations sur l'utilisation de RAISERROR avec TRY…CATCH, consultez Utilisation de TRY...CATCH dans Transact-SQL.

Les constructions TRY…CATCH peuvent être imbriquées. Un bloc TRY ou CATCH peut contenir des constructions imbriquées TRY…CATCH. Par exemple, un bloc CATCH peut contenir une construction TRY…CATCH imbriquée pour gérer les erreurs rencontrées par le code CATCH.

Les erreurs rencontrées dans un bloc CATCH sont traitées comme les erreurs générées à n'importe quel autre emplacement. Lorsqu'un bloc CATCH contient une construction TRY…CATCH imbriquée, toute erreur dans le bloc imbriqué TRY fera passer le contrôle au bloc CATCH imbriqué. S'il n'existe pas de construction TRY…CATCH imbriquée, l'erreur est renvoyée à l'appelant.

Les constructions TRY…CATCH interceptent des erreurs non gérées provenant de procédures stockées ou de déclencheurs exécutés par le code dans le bloc TRY. Les procédures stockées ou les déclencheurs peuvent également contenir leurs propres constructions TRY…CATCH pour gérer les erreurs générées par leur code. Par exemple, lorsqu'un bloc TRY exécute une procédure stockée et qu'une erreur survient dans la procédure stockée, l'erreur peut être gérée des manières suivantes :

  • Si la procédure stockée ne contient pas sa propre construction TRY…CATCH, l'erreur renvoie le contrôle au bloc CATCH associé au bloc TRY qui contient l'instruction EXECUTE.

  • Si la procédure stockée contient une construction TRY…CATCH, l'erreur transfère le contrôle au bloc CATCH dans la procédure stockée. Lorsque le code du bloc CATCH est terminé, le contrôle est renvoyé à l'instruction qui se trouve immédiatement après l'instruction EXECUTE qui a appelé la procédure stockée.

Les instructions GOTO ne peuvent pas être utilisées pour entrer un bloc TRY ou CATCH. Les instructions GOTO peuvent être utilisées pour accéder directement à une étiquette dans le même bloc TRY ou CATCH ou pour quitter un bloc TRY ou CATCH.

La construction TRY...CATCH ne peut pas être utilisée dans une fonction définie par l'utilisateur.

Extraction des informations d'erreur

Dans la portée d'un bloc CATCH, les fonctions système suivantes peuvent être utilisées pour obtenir des informations sur l'erreur qui a entraîné l'exécution du bloc CATCH :

  • ERROR_NUMBER() renvoie le numéro de l'erreur.

  • ERROR_SEVERITY() renvoie la gravité de l'erreur.

  • ERROR_STATE() renvoie le numéro d'état de l'erreur.

  • ERROR_PROCEDURE() renvoie le nom de la procédure stockée ou du déclencheur dans lequel s'est produit l'erreur.

  • ERROR_LINE() renvoie le numéro de ligne au sein de la routine qui a entraîné l'erreur.

  • ERROR_MESSAGE() renvoie le texte complet du message d'erreur. Ce texte comprend les valeurs fournies pour tous les paramètres substituables, tels que les longueurs, les noms d'objet ou les heures.

Ces fonctions renvoient la valeur NULL si elles sont appelées en dehors de l'étendue du bloc CATCH. Les informations sur les erreurs peuvent être récupérées à l'aide de ces fonctions à partir de n'importe quel emplacement dans l'étendue du bloc CATCH. Par exemple, le script suivant montre une procédure stockée contenant des fonctions de gestion des erreurs : dans le bloc CATCH d'une construction TRY…CATCH, la procédure stockée est appelée et les informations sur l'erreur sont retournées.

USE AdventureWorks2008R2;
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;

Erreurs non affectées par une construction TRY…CATCH

Les constructions TRY…CATCH n'interceptent pas les conditions suivantes :

  • Les avertissements ou messages d'information dont la gravité est inférieure ou égale à 10.

  • Les erreurs dont le niveau de gravité est supérieur ou égal à 20 interrompent le traitement des tâches du moteur de base de données SQL Server pour la session. Si une erreur dont le niveau de gravité est supérieur ou égal à 20 survient et que la connexion à la base de données n'est pas interrompue, TRY…CATCH gère l'erreur.

  • Un événement d'avertissement, tel qu'une requête d'interruption par le client ou une rupture de connexion avec le client, se produit.

  • Cela survient lorsque la session est terminée par un administrateur système utilisant l'instruction KILL.

Les types d'erreur suivants ne sont pas gérés par un bloc CATCH lorsqu'ils surviennent au même niveau d'exécution que la construction TRY…CATCH :

  • Les erreurs de compilation, telles que les erreurs de syntaxe, qui empêchent un traitement de s'exécuter.

  • Les erreurs qui se produisent pendant une recompilation de niveau instruction, telles que les erreurs de résolution de nom d'objet qui surviennent après la compilation en raison d'une résolution de nom différée.

Ces erreurs sont renvoyées au niveau qui a exécuté le traitement, la procédure stockée ou le déclencheur.

Si une erreur survient pendant la compilation ou la recompilation au niveau de l'instruction à un niveau d'exécution inférieur (par exemple, lors de l'exécution de sp_executesql ou d'une procédure stockée définie par l'utilisateur) à l'intérieur du bloc TRY, l'erreur survient à un niveau inférieur à la construction TRY…CATCH et sera gérée par le bloc CATCH associé. Pour plus d'informations, consultez Utilisation de TRY...CATCH dans Transact-SQL.

L'exemple suivant montre comment une erreur de résolution de noms d'objets générée par une instruction SELECT n'est pas interceptée par la construction TRY…CATCH, mais par le bloc CATCH lorsque la même instruction SELECT est exécutée au sein d'une procédure stockée.

USE AdventureWorks2008R2;
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

L'erreur n'est pas interceptée et le contrôle est passé de la construction TRY…CATCH au niveau supérieur suivant.

L'exécution de l'instruction SELECT au sein d'une procédure stockée entraîne l'occurrence de l'erreur à un niveau inférieur à celui du bloc TRY. L'erreur sera gérée par la construction TRY…CATCH.

-- 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;
  • Pour plus d'informations sur les traitements, consultez Traitements.

Transactions non validables et XACT_STATE

Si une erreur générée dans un bloc TRY entraîne l'invalidation de la transaction actuelle, elle est classifiée comme transaction non validable. Une erreur qui termine normalement une transaction en dehors d'un bloc TRY fait entrer la transaction dans un état non validable lorsqu'elle survient au sein d'un bloc TRY. Une transaction non validable ne peut effectuer que des opérations de lecture ou ROLLBACK TRANSACTION. La transaction ne peut exécuter aucune instruction Transact-SQL qui générerait une opération d'écriture ou COMMIT TRANSACTION. La fonction XACT_STATE renvoie une valeur de -1 si une transaction a été classifiée comme non validable. Lorsqu'un traitement est terminé, le moteur de base de données restaure automatiquement toutes les transactions non validables actives. Si aucun message d'erreur n'a été envoyé lorsque la transaction est passée dans un état non validable, une erreur est envoyée à l'application cliente lorsque le traitement se termine. Cela indique qu'une transaction non validable a été détectée et annulée.

Pour plus d'informations sur les transactions non validables et la fonction XACT_STATE, consultez Utilisation de TRY...CATCH dans Transact-SQL et XACT_STATE (Transact-SQL).

Exemples

A. Utilisation de TRY…CATCH

L'exemple suivant illustre une instruction SELECT qui génère une erreur de division par zéro. L'erreur entraîne le saut de l'exécution vers le bloc CATCH associé.

USE AdventureWorks2008R2;
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. Utilisation de TRY…CATCH dans une transaction

L'exemple suivant montre comment un bloc TRY…CATCH fonctionne dans une transaction. L'instruction dans le bloc TRY génère une erreur de violation de contrainte.

USE AdventureWorks2008R2;
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. Utilisation de TRY…CATCH avec XACT_STATE

L'exemple suivant montre comment utiliser la construction TRY…CATCH pour gérer les erreurs qui surviennent dans une transaction. La fonction XACT_STATE détermine si la transaction doit être validée ou annulée. Dans cet exemple, SET XACT_ABORT est ON. Cela rend la transaction non validable lorsque l'erreur de violation de contrainte se produit.

USE AdventureWorks2008R2;
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