Estou configurando um trabalho para percorrer uma lista de servidores vinculados e executar uma consulta específica em cada um. Estou tentando executar a consulta dentro de um bloco TRY-CATCH, portanto, se houver um problema com um servidor específico, eu posso registrá-lo, mas depois continuar com os outros servidores.
A consulta que estou executando dentro do loop é mais ou menos assim:
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!';
Se houver um problema na conexão com o servidor, o código falhará imediatamente e não será transferido para o servidor. CATCH
bloco. Se o servidor se conectar, mas houver um erro na consulta real, por exemplo, dividir por zero, isso será capturado conforme o esperado pelo CATCH
bloco.
Por exemplo, criei um servidor vinculado a um nome que sei que não existe. Ao executar o acima, eu apenas recebo:
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].
Eu li BOL em TRY-CATCH
e sei que ele não detectará erros de nível 20+ que interrompem a conexão, mas isso não parece ser o caso (este é apenas o nível 16).
Alguém sabe por que esses erros não foram detectados corretamente?
fonte
PRINT 'Start';
na parte superior do script, isso será impresso na saída, mesmo que a conexão falhe e o script saia com o erro. Então isso indicaria um erro de tempo de execução, não é? A menos que eu esteja entendendo errado?PRINT
, ainda tinha asp_testlinkedserver
chamada no script. Na verdade, ele não é impresso usando meu script original (com falha). Portanto, parece que esse é realmente um erro em tempo de compilação, e é por isso que não é pego.sp_testlinkedserver
ligação, mas deixei oSELECT
SQL como dinâmico. APRINT
não ocorre se você faz referência o nome do servidor diretamente, assim como eu tinha sugerido anteriormente,BEGIN TRY
nunca é introduzido porque o erro é gerado pela primeira vez.Após a investigação, parece que esse erro não está sendo capturado, pois é um erro em tempo de compilação e não um erro de tempo de execução. Para demonstrar isso, tente o seguinte:
A
PRINT
instrução inicial não obtém saída, nem o erro de divisão por zero é executado / capturado. O servidor inexistente faz com que o script falhe imediatamente.fonte
Recentemente, tive um problema semelhante ao chamar um procedimento remoto de dentro de um TRY-CATCH e o procedimento falhou devido à tentativa de inserir chave duplicada (erro de tempo de execução no nível 16). O bloco CATCH não foi chamado. Encontrei o motivo neste artigo: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
A solução é SET XACT_ABORT ON no procedimento de chamada antes de chamar o procedimento remoto. Quando XACT_ABORT está no bloco CATCH, é invocado conforme o esperado. Você precisa estar ciente de que a configuração XACT_ABORT é propagada para o procedimento remoto e isso pode afetar seu comportamento.
fonte
fonte