Para procedimentos armazenados T-SQL com o prefixo sp_, o SQL Server procurará e usará um procedimento no banco de dados mestre antes do atual. Este não parece ser o caso de um procedimento armazenado SQLCLR que criei com o SQL Server 2010 usando a implantação integrada do Visual Studios. O servidor de banco de dados é o SQL Server 2008 R2 (SP1).
Eu executo este script:
SELECT name
from master.sys.procedures
WHERE type_desc='CLR_STORED_PROCEDURE' and schema_id = 1
USE tempdb
PRINT 'USING tempDb'
EXEC sp_RAISERROR_CaughtDemo;
GO
USE master
PRINT 'USING master'
EXEC sp_RAISERROR_CaughtDemo
GO
--SELECT * from sys.assembly_modules
E o procedimento armazenado será executado apenas com um nome não qualificado do banco de dados mestre:
name
----------------------------------
sp_RAISERROR_CaughtDemo
sp_RAISERROR_UncaughtDemo
(2 row(s) affected)
USING tempDb
Msg 2812, Level 16, State 62, Line 5
Could not find stored procedure 'sp_RAISERROR_CaughtDemo'.
USING master
RAISERROR() Caught Severity 0
RAISERROR() Caught Severity 1
Msg 50000, Level 1, State 1
RAISERROR() Caught Severity 2
Msg 50000, Level 2, State 1
RAISERROR() Caught Severity 3
Msg 50000, Level 3, State 1
RAISERROR() Caught Severity 4
Msg 50000, Level 4, State 1
RAISERROR() Caught Severity 5
Msg 50000, Level 5, State 1
RAISERROR() Caught Severity 6
Msg 50000, Level 6, State 1
RAISERROR() Caught Severity 7
Msg 50000, Level 7, State 1
RAISERROR() Caught Severity 8
Msg 50000, Level 8, State 1
RAISERROR() Caught Severity 9
Msg 50000, Level 9, State 1
RAISERROR() Caught Severity 10
Msg 50000, Level 11, State 1, Line 1
RAISERROR() Caught Severity 11
O código para esses procedimentos é o seguinte:
[SqlProcedure(Name = "sp_RAISERROR_UncaughtDemo")]
public static void RaiserrorUncaught()
{
short i = 0;
using (var cn = new SqlConnection("context connection=true"))
using (var cmd = cn.CreateCommand())
{
cn.Open();
cmd.CommandText = "RAISERROR('RAISERROR() Uncaught Severity %d', @i, 1, @i)";
cmd.Parameters.Add("@i", SqlDbType.SmallInt);
while (true)
{
cmd.Parameters["@i"].Value = i++;
SqlContext.Pipe.ExecuteAndSend(cmd);
}
cn.Close();
}
}
[SqlProcedure(Name = "sp_RAISERROR_CaughtDemo")]
public static void RaiserrorCaught()
{
try
{
short i = 0;
using (var cn = new SqlConnection("context connection=true"))
using (var cmd = cn.CreateCommand())
{
cn.Open();
cmd.CommandText = "RAISERROR('RAISERROR() Caught Severity %d', @i, 1, @i)";
cmd.Parameters.Add("@i", SqlDbType.SmallInt);
while (true)
{
cmd.Parameters["@i"].Value = i++;
SqlContext.Pipe.ExecuteAndSend(cmd);
}
cn.Close();
}
}
catch(SqlException) {}
}
Existe algo que eu possa fazer para fazer a pesquisa do SQL Server no banco de dados mestre para encontrar esse procedimento armazenado? Eu tentei sys.sp_MS_marksystemobject
sem sucesso.
Não conheço uma solução (e não sei se o andaime CLR já foi projetado para imitar a funcionalidade da qual você está falando), mas uma solução alternativa poderia ser criar um procedimento armazenado T-SQL no mestre que serve como um wrapper para retransmitir a chamada para a versão CLR. Não deve ser necessário marcá-lo como um objeto do sistema, desde que não exista um procedimento armazenado com o mesmo nome no banco de dados do usuário.
EDIT - acabei de provar que isso funciona bem, tanto para mim quanto para qualquer outra coisa. Primeiro criei sua montagem e adicionei o procedimento necessário para repro (não vou incluir todos os bits aqui para abreviar):
Em seguida, criei um procedimento armazenado wrapper, certificando-me de qualificar totalmente o procedimento CLR:
Em seguida, ajustei seu código repro para chamar o wrapper do tempdb:
Resultados:
Portanto, isso mostra que você deve ser capaz de usar um wrapper como este para poder chamar procedimentos CLR, sem referência, de outros bancos de dados.
(No entanto, vou sugerir que, em geral, isso não deve ser um objetivo - você deve definir referências adequadamente com nomes de três partes, quando aplicável).
Confesso que fiz uma alteração em seu procedimento armazenado, para evitar que o Visual Studio reclamasse de mim. Eu mudei:
Para:
Mas é claro que essa mudança não teve nada a ver com a questão do escopo.