Eu apoio um aplicativo que usa modelos CodeSmith e NetTiers para gerar código C#. CodeSmith inspeciona o banco de dados e usa a SET FMTONLY ON
configuração para determinar as colunas para as quais o código deve ser gerado.
Infelizmente, ao mudar do SQL Server 2005 para 2012, há uma circunstância específica em que isso não está mais funcionando. Existe um procedimento armazenado que executa um procedimento armazenado em um servidor vinculado e o código que está sendo gerado para esse procedimento armazenado está incorreto.
Consegui isolar o problema da EXEC
declaração com SET FMTONLY ON
. O seguinte (somente exemplo) SELECT
funciona nas instâncias de 2005 e 2012:
SET FMTONLY ON
SELECT TOP(10) [MCMCU]
,[MCSTYL]
,[MCDC]
FROM [JDE].[JDE_CRP].[CRPDTA].[F0006]
SET FMTONLY OFF
Isso retorna apenas os títulos das colunas, conforme esperado. O seguinte funciona apenas na instância de 2005:
SET FMTONLY ON
EXEC('SELECT TOP(10) [MCMCU]
,[MCSTYL]
,[MCDC]
FROM [JDE_CRP].[CRPDTA].[F0006]') AT [JDE]
SET FMTONLY OFF
Quando executado na instância 2012, o SSMS mostra a mensagem "Comando(s) concluído(s) com êxito", mas não exibe os cabeçalhos das colunas.
Há alguma coisa que estou perdendo aqui? Talvez uma configuração que eu precise alterar? As definições do servidor vinculado são idênticas, incluindo a identidade usada para conectar. E sim, estou ciente de que FMTONLY
está obsoleto, mas não tenho nenhuma capacidade de alterar a maneira como o CodeSmith interroga o banco de dados.
Posso reproduzir o mesmo comportamento no SQL Server 2012. No entanto, consigo fazê-lo funcionar colocando o nome do Linked Server de volta na consulta. Existe uma razão para você ter colocado isso na
AT
cláusula?Tente o seguinte:
Bem, embora o acima funcione no SQL Server 2012, não foi um bom teste porque não funciona ao executar um procedimento armazenado. Pode ter algo a ver com o fato de ser um tipo diferente de chamada (ou seja, a chamada do procedimento armazenado é RPC e teve que ser configurada separadamente).
Eu até tentei adicionar
WITH RESULT SETS ((...))
e ainda não funcionou.Ok, então eu encontrei algo. É geralmente conhecido que
FMTONLY ON
na verdade não executa o código, apenas o verifica em busca deSELECT
instruções. Mas isso também significa que ele não sabe como lidar com código condicional. Portanto, ele retorna quaisquer conjuntos de resultados que possam ser retornados, mesmo que nenhum caminho de código retorne alguns deles.O exemplo 1 tem duas
SELECT
instruções, mas apenas uma pode ser retornada por vez. Ainda assim, ao executar comFMTONLY ON
, ambos são retornados:Resultados:
O exemplo 2 mostra outra consequência de não poder executar o código. Se o código produzir o conjunto de resultados dinamicamente, ele não poderá ser determinado por
FMTONLY ON
. Isso provavelmente explica por que não pode seguir a chamada EXEC quando o código é remoto. Suspeito que chamar procedimentos armazenados locais funcione apenas fazendo uma pesquisa na tabela de catálogo do sistema local para essa definição.Resultados:
Sabendo o que sabemos agora, podemos usar o fato de que
FMTONLY ON
encontrará todos os conjuntos de resultados sem realmente executar o código para, mesmo que não seja o ideal, falsificar um conjunto de resultados para fazer o CodeSmith (e outras ferramentas que ainda funcionam dessa maneira) funcionar novamente .O exemplo 3 mostra que podemos efetivamente ocultar um conjunto de resultados fictício em um bloco de código que não pode ser executado logicamente. Só
FMTONLY ON
será capaz de ver isso para não apresentar um problema para nenhum outro código (bem, eu tenteisys.dm_exec_describe_first_result_set
e não gostei muito, mas não acho que seja um problema neste caso).Resultados:
Para este teste, fiz com que o código retornasse um conjunto de resultados diferente para o
IF (1 = 0)
bloco para tornar a diferença de comportamento mais aparente. Mas, na prática, você gostaria de retornar exatamente a mesma estrutura do conjunto de resultadosSELECT
como retorna o procedimento armazenado remoto.A desvantagem óbvia aqui é que, se você alterar o conjunto de resultados desse procedimento remoto, precisará se lembrar de também alterar a definição no
IF (1 = 0)
bloco, mas pelo menos o CodeSmith funcionará.