Estoy configurando un trabajo para recorrer una lista de servidores vinculados y ejecutar una consulta específica para cada uno. Estoy tratando de ejecutar la consulta dentro de un bloque TRY-CATCH, así que si hay un problema con un servidor en particular, puedo iniciar sesión pero luego continuar con los otros servidores.
La consulta que estoy ejecutando dentro del bucle se ve así:
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!';
Si hay un problema al conectarse al servidor, el código simplemente falla inmediatamente y no se transfiere al CATCH
bloque. Si el servidor se conecta pero hay un error en la consulta real, por ejemplo, dividir por cero, entonces el CATCH
bloque lo detecta como se esperaba .
Por ejemplo, creé un servidor vinculado a un nombre que sé que no existe. Al ejecutar lo anterior solo obtengo:
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].
He leído BOL TRY-CATCH
y sé que no detectará errores de nivel 20+ que rompan la conexión, pero este no parece ser el caso (este es solo el nivel 16).
¿Alguien sabe por qué estos errores no se detectan correctamente?
fuente
PRINT 'Start';
en la parte superior de la secuencia de comandos, esto se imprime en la salida, a pesar de que la conexión falla y la secuencia de comandos se cierra con el error. Entonces, esto indicaría un error de tiempo de ejecución, ¿no? ¿A menos que lo esté malentendiendo?PRINT
todavía tenía lasp_testlinkedserver
llamada en el guión. De hecho, no se imprime usando mi secuencia de comandos original (fallida). Entonces parece que esto es en realidad un error en tiempo de compilación , por lo que no queda atrapado.sp_testlinkedserver
llamada, pero dejé elSELECT
SQL dinámico. ElPRINT
no ocurre si hace referencia el nombre del servidor directamente, por lo que me había sugerido anteriormente,BEGIN TRY
no se introduce porque el error se planteó por primera vez.Después de la investigación, parece que este error no se detecta, ya que es un error en tiempo de compilación en lugar de un error en tiempo de ejecución. Para demostrar esto, intente lo siguiente:
La
PRINT
declaración inicial no obtiene salida, ni el error de división por cero se ejecuta / captura. El servidor inexistente hace que el script falle inmediatamente.fuente
Recientemente tuve un problema similar en el que llamé a un procedimiento remoto desde un TRY-CATCH y el procedimiento falló debido al intento de insertar una clave duplicada (error de tiempo de ejecución de nivel 16). El bloque CATCH no fue invocado. Encontré la razón en este artículo: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
La solución es SET XACT_ABORT ON en el procedimiento de llamada antes de invocar el procedimiento remoto. Cuando XACT_ABORT está en el bloque CATCH, se invoca como se esperaba. Debe tener en cuenta que la configuración XACT_ABORT se propaga al procedimiento remoto y eso puede afectar su comportamiento.
fuente
fuente