web-dev-qa-db-fra.com

SQL Server - TRY / CATCH ne fonctionne pas dans certains cas

Comment puis-je écrire du code protégé qui invoque le bloc de code CATCH dans tous les cas * attendus (sans faire de malice funky comme tout emballer en dynamique SQL)?

Par exemple, cela ne fonctionne pas:

  1. Définir un travail SQL Agent sans étapes
  2. Essayez de démarrer le travail dans un TRY/CATCH

    BEGIN TRY
        EXEC msdb.dbo.sp_start_job @job_name = 'my_empty_job'
    END TRY
    BEGIN CATCH
        SELECT [MyError] = 'Error caught: ' + ISNULL(ERROR_MESSAGE(), 'NULL')
    END CATCH
    

Msg 22022, niveau 16, état 1, ligne 0 Erreur SQLServerAgent: demande d'exécution du travail my_empty_job (de l'utilisateur xyz) refusée car le travail ne comporte aucune étape de travail.

Notez que sa gravité d'erreur est de 16, il ne devrait donc pas avoir contourné le bloc CATCH. wtf?!?

Il contourne également mon bloc CATCH si le travail est occupé à traiter une demande (je spammer les demandes d'arrêt et de démarrage dans mes tests).

Msg 22022, niveau 16, état 1, ligne 0 Erreur SQLServerAgent: demande d'exécution du travail my_simple_job (de l'utilisateur xyz) refusée car le travail a déjà une demande en attente de l'utilisateur xyz.

Cas connexe: référence de serveur lié non valide

P.S. Veuillez ne pas supposer que je veux juste une solution à portée limitée pour gérer l'appel de travail. Je recherche une solution générique que je pourrai réutiliser à l'avenir.

P.P.S. Je peux attraper le cas d'essayer de démarrer/arrêter un travail qui n'existe pas ("Le @job_name spécifié ('missing_job') n'existe pas."). Pourquoi cela se comporte-t-il différemment?

*Ce que TRY/CATCH ne gère pas (tl; gravité des erreurs dr en dehors de la plage (10, 20))

6
Elaskanator

Comment puis-je écrire du code protégé qui invoque le bloc de code CATCH dans tous les cas * attendus (sans faire de déchets géniaux comme tout en SQL dynamique)?

Vous ne pouvez malheureusement pas.

Le MVP SQL Server Erland Sommarskog a une série d'articles brefs * sur le sujet de la gestion des erreurs dans SQL Server qui commence ici: Gestion des erreurs et des transactions dans SQL Server

Le problème que vous rencontrez avec le travail de l'agent est qu'il appelle une procédure stockée étendue, ce qui provoque l'erreur. En particulier, cette erreur provient de master.dbo.xp_sqlagent_notify.

Erland couvre ce problème ici :

SQL Server est toujours livré avec un certain nombre de procédures stockées étendues, dont certaines sont documentées et d'autres ne sont destinées qu'aux outils fournis avec SQL Server. En ce qui concerne la gestion des erreurs, tous les paris sont ouverts avec ces gars-là. Il n'y a pas de comportement cohérent, et environ chaque XP a sa propre torsion.

Je sais que vous avez mentionné que vous n'êtes pas intéressé par des solutions sur mesure qui ne sont pas largement applicables, mais je pense qu'il convient de mentionner que, lorsque vous traitez avec des procédures stockées fournies par Microsoft, une solution à ce problème TRY/CATCH consiste à toujours capturer le code retour de la procédure. S'il est différent de zéro, vous pouvez déclencher manuellement une erreur pour déclencher le bloc CATCH (merci Dan Guzman ).

* bref, ha!

10
Josh Darnell