Reputation: 499
Within a stored procedure I have a try catch block with a transaction which will commit if control never passes to the catch otherwise will rollback if there's an error and control does pass to the catch block.
I'm running this stored procedure from within a transaction, as per the below example:
CREATE PROCEDURE sp_test
AS
BEGIN
BEGIN TRY
BEGIN TRAN
DECLARE @var INT = 1
IF @var <> 2
BEGIN
RAISERROR('error', 16,1)
END
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT 'Rolled back'
END CATCH
END
BEGIN TRAN
EXEC sp_test
When I run this, I'm seeing the error
Msg 266, Level 16, State 2, Procedure sp_test, Line 0 [Batch Start Line 7]
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
But I don't understand why.
I'm starting a transaction outside of the stored procedure. I'm then going into the SP and beginning another transaction. Once control passes to the catch block, both transactions should be rolled back so transaction count should be 0.
Obviously there's a gap in my understanding here.
Upvotes: 0
Views: 969
Reputation: 2766
This behaviour is by design. Whenever a transaction is started, the @@TRANCOUNT session variable will increase one, and when a transaction is committed, it decreases one. However, when a transaction rolls back, it rolls back the all nested transactions. So in your case, the rollback in your catch will roll back the 2 nested transactions and @@TRANCOUNT will become 0. This will cause the caller throw the mismatch transaction count exception.
To avoid this issue, you can check @@TRANCOUNT in your SP and only start a new transaction when it is 0 and set a flag (a local variable) to indicate that, e.g. @new_tarn=1. Then you commit or rollback only when @new_tran=1.
Upvotes: 2