Why doesn’t this ROLLBACK TRANSACTION statement work?
BEGIN TRANSACTION; DECLARE @foo INT EXECUTE [database].[dbo].[get_counter] @CounterID='inventory_records', @nextValue=@foo OUTPUT; ROLLBACK TRANSACTION;
Background
I’m inserting records into a customer’s ERP system built on SQL Server 19. The ERP database doesn’t have auto-incrementing primary keys. It instead uses a table called counters where each row has a counterID field and an integer value field.
To insert a new row into a table like inventory_record, I first need to call a stored procedure like this:
EXECUTE get_counter @counterID='inventory_record'
This procedure returns an OUT parameter called @nextValue which I then INSERT into the inventory_record table as its uid.
I need to ROLLBACK this stored procedure’s behavior if my insert fails. That way the counter doesn’t increase boundlessly on failed INSERT attempts.
Contents of get_counter stored procedure
It’s dirt simple but also subject to copyright. I’ve summarized and truncated here. The counters are stored as sequences in the DB. So get_counter calls sp_sequence_get_range after checking that the requested counter is legitimate.
ALTER PROCEDURE get_counter
@strCounterID varchar(64),
@iIncrementValue integer = 1,
@LastValue BIGINT = NULL OUTPUT
AS
SET NOCOUNT ON
BEGIN
DECLARE
@nextSeqVar SQL_VARIANT
, @lastSeqVar SQL_VARIANT
-- code that confirms valid counter name
BEGIN TRY
-- code that calls [sp_sequence_get_range]
END TRY
BEGIN CATCH
THROW
END CATCH
RETURN(@LastValue)
END
The Problem
The inventory_record counter always increments. I can’t roll it back.
If I run the SQL at the top of this question from SSMS, then SELECT value FROM counters WHERE counterID = 'inventory_record', the counter increments each time I execute.
I’m new to transaction handling in SQL Server. Any ideas what I’m missing?
Advertisement
Answer
re-post comments as answer for better readability.
The get_counter is using Sequence Numbers (sp_sequence_get_range). Please refer to documentation on Limitation section.
Sequence numbers are generated outside the scope of the current transaction. They are consumed whether the transaction using the sequence number is committed or rolled back
You may see a simple demo here