Error 266
Severity Level 16
Message Text
Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = %ld, current count = %ld.
Explanation
If a stored procedure exits with the @@TRANCOUNT value that is not the same as when the stored procedure was entered, Microsoft® SQL Server™ returns error 266.
Note This error can be ignored because it only sends a message to the client and does not affect execution.
This example reproduces the problem:
CREATE PROCEDURE test
AS
SELECT @@TRANCOUNT
ROLLBACK TRANSACTION
SELECT @@TRANCOUNT
GO
BEGIN TRANSACTION
EXECUTE test
GO
Because @@TRANCOUNT is not the same in both SELECT statements, error 266 is generated on return from the stored procedure.
This is expected behavior, but it does not mean that transactions cannot be started, completed, or terminated in a stored procedure. Instead, care must be taken so that the @@TRANSACTION function matches on both the entry and exit of the stored procedure. For more information, see ROLLBACK TRANSACTION.
This problem is more likely to occur when writing nested stored procedures.
Action
There is a solution so that the stored procedure works without the error. The following is a list of solutions, with sample code for each:
- Perform final COMMIT TRANSACTION or ROLLBACK TRANSACTION statements from the same stored procedure nesting level where the transaction began, as shown by the following examples:
-- Example 1.a CREATE PROCEDURE test1a AS SELECT @@TRANCOUNT GO BEGIN TRANSACTION EXECUTE test1a ROLLBACK TRANSACTION GO -- Example 1.b CREATE PROCEDURE test1c AS SELECT @@TRANCOUNT GO CREATE PROCEDURE test1b AS BEGIN TRANSACTION EXEC test1c COMMIT TRANSACTION GO EXECUTE test1b GO
- If nested transactions are used in a stored procedure, perform matching commits.
Note The transaction is not committed until @@TRANCOUNT is equal to 0 (zero).
-- Example 2 CREATE PROCEDURE test2b AS SELECT @@TRANCOUNT BEGIN TRANSACTION SELECT @@TRANCOUNT COMMIT TRANSACTION SELECT @@TRANCOUNT GO CREATE PROCEDURE test2a AS BEGIN TRANSACTION EXECUTE test2b COMMIT TRANSACTION GO EXECUTE test2a GO
- If a rollback is needed and the stored procedure nesting level is different than where the transaction began, use RAISERROR, with a valid user-defined error, and check the @@ERROR function after the EXECUTE statement.
-- Example 3 USE master EXECUTE sp_addmessage 50001, 16, 'Rollback of transaction in test3' GO CREATE PROCEDURE test3 AS RAISERROR (50001,16,1) GO BEGIN TRANSACTION EXEC test3 IF @@error <> 50001 BEGIN PRINT 'Commit' COMMIT TRANSACTION END ELSE BEGIN PRINT 'Rollback' ROLLBACK TRANSACTION END GO
- The exception to this rule is that if a trigger performs a rollback, @@TRANCOUNT need not match its starting value, because the batch is terminated. However, a stored procedure called by a trigger may cause the problem if it terminated the transaction.
-- Example 4 CREATE TABLE x (col1 int) GO CREATE TRIGGER xins ON x FOR INSERT AS ROLLBACK TRANSACTION GO CREATE PROCEDURE sp_xinsert AS SELECT @@TRANCOUNT INSERT x (col1) VALUES (1) SELECT @@TRANCOUNT GO BEGIN TRANSACTION EXECUTE sp_xinsert IF @@error <> 0 BEGIN PRINT 'Commit' COMMIT TRANSACTION END ELSE BEGIN PRINT 'Rollback' ROLLBACK TRANSACTION END GO SELECT * FROM x