Je configure un travail pour parcourir une liste de serveurs liés et exécuter une requête spécifique sur chacun d'eux. J'essaie d'exécuter la requête à l'intérieur d'un bloc TRY-CATCH, donc s'il y a un problème avec un serveur particulier, je peux le journaliser mais continuer avec les autres serveurs.
La requête que j'exécute à l'intérieur de la boucle ressemble à ceci:
BEGIN TRY
SELECT *
FROM OPENQUERY([server1], 'SELECT 1 AS c;');
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;
PRINT 'We got past the Catch block!';
En cas de problème de connexion au serveur, le code échoue immédiatement et n'est pas transféré vers le CATCH
bloc. Si le serveur se connecte mais qu'il y a une erreur dans la requête réelle, par exemple diviser par zéro, cela est détecté comme prévu par le CATCH
bloc.
Par exemple, j'ai créé un serveur lié avec un nom dont je sais qu'il n'existe pas. Lors de l'exécution de ce qui précède, je reçois simplement:
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"Login timeout expired".
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"An error has occurred while establishing a connection to the server.
When connecting to SQL Server 2005, this failure may be caused by the
fact that under the default settings SQL Server does not allow remote
connections.".
Msg 53, Level 16, State 1, Line 0
Named Pipes Provider: Could not open a connection to SQL Server [53].
J'ai lu BOL sur TRY-CATCH
et je sais qu'il ne détectera pas les erreurs de niveau 20+ qui interrompent la connexion, mais cela ne semble pas être le cas (ce n'est que le niveau 16).
Est-ce que quelqu'un sait pourquoi ces erreurs ne sont pas détectées correctement?
la source
PRINT 'Start';
tout en haut du script, cela est imprimé dans la sortie, même si la connexion échoue et que le script se termine avec l'erreur. Cela indiquerait donc une erreur d' exécution , n'est-ce pas? A moins que je ne le comprenne mal?PRINT
j'avais toujours l'sp_testlinkedserver
appel dans le script. En fait, il n'est pas imprimé à l'aide de mon script d'origine (défaillant). Il semble donc que ce soit en fait une erreur au moment de la compilation , c'est pourquoi il n'est pas détecté.sp_testlinkedserver
appel, mais j'ai laissé leSELECT
SQL aussi dynamique. LePRINT
ne se produit pas si vous faites directement référence au nom du serveur, de sorte que, comme je l'avais suggéré précédemment, ilBEGIN TRY
n'est jamais entré car l'erreur est déclenchée en premier.Après enquête, il semble que cette erreur ne soit pas détectée car il s'agit d'une erreur de compilation plutôt que d'une erreur d'exécution. Pour illustrer cela, essayez ce qui suit:
L'
PRINT
instruction initiale n'obtient pas de sortie, et l'erreur de division par zéro n'est pas exécutée / capturée. Le serveur inexistant provoque l'échec immédiat du script.la source
J'ai récemment eu un problème similaire où j'ai appelé une procédure distante à partir d'un TRY-CATCH et la procédure a échoué en raison de la tentative d'insertion d'une clé en double (erreur d'exécution de niveau 16). Le bloc CATCH n'a pas été appelé. J'ai trouvé la raison dans cet article: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
La solution consiste à SET XACT_ABORT ON dans la procédure d'appel avant d'appeler la procédure distante. Lorsque XACT_ABORT est sur le bloc CATCH est appelé comme prévu. Vous devez savoir que le paramètre XACT_ABORT est propagé à la procédure distante, ce qui peut affecter son comportement.
la source
la source