Ho una procedura memorizzata che viene chiamata in un blocco insert-exec:
insert into @t
exec('test')
Come posso gestire le eccezioni generate nella procedura memorizzata e continuare comunque l'elaborazione?
Il seguente codice illustra il problema. Quello che voglio fare è restituire 0 o -1 a seconda dell'esito positivo o negativo della exec()
chiamata interna :
alter procedure test -- or create
as
begin try
declare @retval int;
-- This code assumes that PrintMax exists already so this generates an error
exec('create procedure PrintMax as begin print ''hello world'' end;')
set @retval = 0;
select @retval;
return(@retval);
end try
begin catch
-- if @@TRANCOUNT > 0 commit;
print ERROR_MESSAGE();
set @retval = -1;
select @retval;
return(@retval);
end catch;
go
declare @t table (i int);
insert into @t
exec('test');
select *
from @t;
Il mio problema è il return(-1)
. La strada del successo va bene.
Se tralascio il blocco try / catch nella procedura memorizzata, l'errore viene generato e l'inserimento non riesce. Tuttavia, ciò che voglio fare è gestire l'errore e restituire un buon valore.
Il codice così com'è restituisce il messaggio:
Msg 3930, Level 16, State 1, Line 6
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
Questo è forse il peggior messaggio di errore che ho riscontrato. Sembra davvero significare "Non hai gestito un errore in una transazione nidificata".
Se inserisco il if @@TRANCOUNT > 0
, allora ricevo il messaggio:
Msg 3916, Level 16, State 0, Procedure gordontest, Line 7
Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.
Ho provato a giocare con le dichiarazioni di transazione start / commit, ma nulla sembra funzionare.
Quindi, come posso fare in modo che la mia procedura memorizzata gestisca gli errori senza interrompere la transazione complessiva?
Modifica in risposta a Martin:
Il codice chiamante effettivo è:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
dichiarare @retval int; exec @retval = '+ @ query +'; seleziona @retval ');
select @retval = retval from @RetvalTable;
Dov'è @query
la chiamata della procedura memorizzata. L'obiettivo è ottenere il valore restituito dalla procedura memorizzata. Se ciò è possibile senza un insert
(o, più specificamente, senza avviare una transazione), sarebbe fantastico.
Non riesco a modificare le procedure memorizzate in generale per memorizzare il valore in una tabella, perché ce ne sono troppe. Uno di questi sta fallendo e posso modificarlo. La mia migliore soluzione attuale è qualcosa del tipo:
if (@StoredProcedure = 'sp_rep__post') -- causing me a problem
begin
exec @retval = sp_rep__post;
end;
else
begin
-- the code I'm using now
end;
select @retval; return @retval
alla fine. Se conosci un altro modo per ottenere il valore restituito da una chiamata di procedura memorizzata dinamica, mi piacerebbe saperlo.
DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
funziona bene.