web-dev-qa-db-fra.com

Comportement de RaisError dans un essai / attrape dans une boucle

Je viens de rencontrer une section de SQL qui se comporte pas comme on pouvait s'y attendre (voir ci-dessous une version distillée de la SQL en question qui démontre le modèle de problèmes).

(Ceci est sur SQL Server 2008 R2 SP2 64BIT)

La partie "Faites du travail ici" soulève une erreur et déclenche la manipulation des erreurs dans le bloc de capture. Le numéro d'erreur est 515 (tentative d'insérer une null dans une colonne non nullable), donc RAISError signale l'erreur, mais la boucle continue, tente de nouveau le travail, jette une erreur, etc. dans une boucle infinie.

Je m'attendrais à ce que RaisError provoque l'exécution de quitter la boucle. Qu'est-ce qui se passe ici?

Merci

WHILE (@Applied <> 1)
BEGIN

    BEGIN TRY

        -- === Do some work here ===

        -- Successfully applied
        SET @Applied = 1;

    END TRY
    BEGIN CATCH

        -- Save the error details
        SELECT
            @ErrorNumber = ERROR_NUMBER(),
            @ErrorMessage = ERROR_MESSAGE(), 
            @ErrorSeverity = ERROR_SEVERITY(), 
            @ErrorState = ERROR_STATE();

        -- Test for a deadlock or uncommittable transaction
        IF (@ErrorNumber = 1205 OR @ErrorNumber = 3930)
            -- Sleep for 5 seconds
            WAITFOR DELAY '00:00:05';
        ELSE
            RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);

    END CATCH
END
1
redcalx

RAISERROR _ n'arrête généralement pas l'exécution. [~ # ~] jeter [~ # ~ ~] Le fait, mais qui a été introduit dans SQL 2012.

Mettre un RETURN; ou alors RETURN -1; après le RAISERROR.

Ce qui suit est extrait de la section "remarques" de la page MSDN pour RAISERROR :

Lorsque RAISError est exécuté avec une gravité de 11 ou plus dans un bloc d'essai, il transfère le contrôle du bloc de capture associé. L'erreur est renvoyée à l'appelant si Raiserror est exécuté:

  • En dehors de la portée de tout bloc d'essai.
  • Avec une gravité de 10 ou moins dans un bloc d'essai.
  • Avec une gravité de 20 ou plus qui termine la connexion de la base de données.

Vous trouverez ci-dessous un test simple du comportement. Si vous utilisez une version de SQL Server avant 2012, commencez ou supprimez la ligne avec THROW.

RAISERROR(N'This is from RAISERROR - Severity 16', 16, 1);
PRINT N'----- 1';

;THROW 50505, N'This is from THROW', 1;
PRINT N'----- 2';

GO

PRINT N'----- 3';

-- WITH LOG needed for severity > 18
RAISERROR(N'This is from RAISERROR - Severity 20', 20, 1) WITH LOG;
PRINT N'----- 4';

GO

PRINT N'----- 5';

Le test ci-dessus renvoie ce qui suit dans l'onglet "Messages":

MSG 50000, niveau 16, état 1, ligne 2
[.____] C'est de Raiserror - Gravité 16
----- 1
[.____] MSG 50505, niveau 16, état 1, ligne 5
[.____] c'est de lancer
[.____] ----- 3
[.____] MSG 2745, niveau 16, état 2, ligne 4
ID de processus 54 a soulevé l'erreur utilisateur 50000, la gravité 20. SQL Server met fin à ce processus.
[.____] MSG 50000, niveau 20, état 1, ligne 4
[.____] C'est de Raiserror - Gravité 20
[.____] Msg 0, niveau 20, état 0, ligne 0
Une erreur grave s'est produite sur la commande actuelle. Les résultats, le cas échéant, doivent être jetés.

Et dans le fond, le coin gauche de SSMS indiquera "déconnecté".

5
Solomon Rutzky