I'm having an SQL related problem which is just pissing me off now :p. Here is my setup:
I have 2 Stored Procedures:
Parent Stored Procedure is called GenerateAnnualPenalty
.
GenerateAnnualPenalty
has a SELECT CURSOR in it, which iterates over a series of objects called Properties
, and for each Property
, it determines if a Penalty
needs to be applied. This is stored in a boolean variable named @ApplyPenalty
, and its either 0
or 1
. Also, there are no SQL Transactions being used in GenerateAnnualPenalty
.
Secondly, For each Property
that GenerateAnnualPenalty
iterates over, it calls a child Stored Procedure named GenerateAnnualPenaltyForProperty
. @ApplyPenalty
is passed as an input to GenerateAnnualPenaltyForProperty
. GenerateAnnualPenaltyForProperty
does use SQL Transactions (commit/rollback).
I make entries into a table named DebugLog
, to mark if a specific point has been reached in code or not.
Here is the skeleton for the child GenerateAnnualPenaltyForProperty
:
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
DECLARE @TRANSACTION_NAME varchar(50)
SET @TRANSACTION_NAME = 'GenerateAnnualPenaltyForProperty'
BEGIN TRANSACTION @TRANSACTION_NAME
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
COMMIT TRANSACTION @TRANSACTION_NAME
RETURN 0
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION @TRANSACTION_NAME
RETURN -1
END CATCH
The Problem (Intro):
Suppose GenerateAnnualPenalty
iterates over 4 Properties
, in this specific order (which exploits the problem):
First property to iterate over: @PROPERTY_ID = 1
Second property to iterate over: @PROPERTY_ID = 2
Third property to iterate over: @PROPERTY_ID = 3
Fourth property to iterate over: @PROPERTY_ID = 4
Suppose that for Properties 1, 3 and 4, ApplyPenalty = 1
, while for Property 2, ApplyPenalty = 0
The Problem (Main Crux):
When GenerateAnnualPenaltyForProperty
is called for Property 1, everything is fine: I see both Checkpoint 1 and Checkpoint 2 entries in the DebugLog
table.
When GenerateAnnualPenaltyForProperty
is called for Property 2, everything is fine again: I see both Checkpoint 1 and Checkpoint 2 entries in the DebugLog
table.
When GenerateAnnualPenaltyForProperty
is called for Property 3, the incorrect scenario occurs: I see only the Checkpoint 1 entry in the DebugLog
table, whereas the 'Checkpoint 2` entry should also have been visible !
When GenerateAnnualPenaltyForProperty
is called for Property 4, its again correct: I again see both Checkpoint 1 and Checkpoint 2 entries in the DebugLog
table.
So the problem only occurs for a Property for which ApplyPenalty = 1
, provided that in the previous iteration, ApplyPenalty = 0
. In such a case, the property with ApplyPenalty = 1
gets treated as if it was ApplyPenalty = 0
Disabling SQL Transaction code fixes the problem, but why ?:
If I disable all code in GenerateAnnualPenaltyForProperty
which relates to SQL Transactions, everything works fine ! The problematic case described above is corrected. Here is a skeleton for GenerateAnnualPenaltyForProperty
, in which SQL Transaction code has been taken out, for which it works:
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
RETURN 0
END TRY
BEGIN CATCH
RETURN -1
END CATCH
The Question (???):
Why does this behavior occur ? Why is it that when I use SQL Transaction commit/rollback into GenerateAnnualPenaltyForProperty
, the Stored Procedure doesn't work for the problematic case ?
Actual Code:
If anyone wishes to see the full code for the child Stored Procedure, then its available here: https://gist.github.com/anonymous/5214236