0
votes

I am facing an issue with my stored procedure in SQL Azure, which has responsibility to create records on a table. When the same stored procedure is called more than once / or more than twice, it fails.

ALTER PROCEDURE [dbo].[usp_ActiveTouchPoints]
-- Add the parameters for the stored procedure here
@pAppOrgSyncId uniqueidentifier,
@pTouchPointId uniqueidentifier = null,
@pDoActive bit = 1,
@pRetValue BIT OUTPUT
AS BEGIN

SET NOCOUNT ON;

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--SET XACT_ABORT OFF

DECLARE @TransactionName varchar(20) = substring(CONVERT(NVARCHAR(50), NEWID()), 25,12);

BEGIN TRANSACTION @TransactionName
-- 2.  Copy Attribute mappings
BEGIN TRY

DECLARE @vTaskIds Table(TaskId uniqueidentifier)

DECLARE @vCreatedTasks VARCHAR(MAX)

print 'usp_ActiveInitialTouchPoints for OrgAPPSYNCID : ' + CAST(@pAppOrgSyncId as VARCHAR(100))

Exec usp_ActiveInitialTouchPoints @pAppOrgSyncId = @pAppOrgSyncId, 
            @pTouchPointId = @pTouchPointId, 
            @pDoActive = @pDoActive,
            @pTaskIds = @vCreatedTasks OUTPUT

DECLARE @vReverseOrgAppSyncId uniqueidentifier
DECLARE @vOrgId uniqueidentifier
DECLARE @vTemplateId uniqueidentifier
DECLARE @vRevTemplateId uniqueidentifier

SELECT @vTemplateId = TemplateId 
    From OrgAppSync
where OrgAppSyncId = @pAppOrgSyncId


SELECT @vReverseOrgAppSyncId = ReverseOrgAppSyncId,
       @vOrgId = OrgId,
       @vRevTemplateId = TemplateId
    From OrgAppSync 
where OrgAppSyncId = @pAppOrgSyncId

DECLARE @vRevCreatedTasks VARCHAR(MAX)

    print 'usp_ActiveInitialTouchPoints for OrgAPPSYNCID : ' + CAST(@vReverseOrgAppSyncId as VARCHAR(100))

Exec usp_ActiveInitialTouchPoints @pAppOrgSyncId = @vReverseOrgAppSyncId, 
            @pTouchPointId = @pTouchPointId, 
            @pDoActive = @pDoActive,
            @pTaskIds = @vRevCreatedTasks OUTPUT 

--INSERT INTO @vTaskIds 
--  Select * from FN_STRINGTOTABLE(@vCreatedTasks, ',')

--INSERT INTO @vTaskIds 
--  Select * from FN_STRINGTOTABLE(@vRevCreatedTasks, ',')

Insert into @vTaskIds 
    SELECT TaskId from Task
    Where OrgAppSyncId in (@pAppOrgSyncId, @vReverseOrgAppSyncId)

DECLARE @vTaskId uniqueidentifier
DECLARE @vParentTaskId uniqueidentifier
DECLARE @vTouchpointId uniqueidentifier
DECLARE @vTouchpointDependencyId uniqueidentifier
DECLARE @vEventId INT
DECLARE @vOrdering INT
DECLARE @vFlag INT

print 'usp_ActiveTouchPoints - CTD'

-- Create Dependent Task before creating the TaskDependencies
IF @pTouchpointId IS NOT NULL
BEGIN

    DECLARE @vReturnVal BIT
    Declare @vDTouchpointId uniqueidentifier
    Declare @vOrgAppSyncId uniqueidentifier

    DECLARE TPD CURSOR LOCAL
    FOR
        SELECT TouchpointId from TouchpointDependency
        where ParentTouchpointId =  @pTouchpointId
    OPEN TPD
    FETCH NEXT FROM TPD into @vDTouchpointId

    WHILE @@Fetch_status = 0
    BEGIN

        Select @vOrgAppSyncId = OrgAppSync.OrgAppSyncId 
        from 
            Touchpoint
        Inner join Template 
                    on Touchpoint.TemplateId = Template.Templateid
        Inner join OrgAppSync 
                    on OrgAppSync.TemplateId = Template.TemplateId
        where 
                OrgAppSync.OrgAppSyncId in (@pAppOrgSyncId, @vReverseOrgAppSyncId)
        And     Touchpoint.TouchpointId = @vDTouchpointId

        Exec [dbo].[usp_ActiveTouchPoints] @pAppOrgSyncId = @vOrgAppSyncId, @pTouchPointId = @vDTouchpointId, @pDoActive = @pDoActive, @pRetValue = @vReturnVal OUTPUT

        FETCH NEXT FROM TPD into @vDTouchpointId
    END

    CLOSE TPD;
    DEALLOCATE TPD;
END

DECLARE CTD CURSOR LOCAL
FOR
    SELECT TouchpointDependency.ParentTouchpointId
        , TouchpointDependency.TouchpointDependencyId
        , TouchpointDependency.EventId
        , TouchpointDependency.Ordering 
        , Task.TaskId
        , IsNull(TouchpointDependency.Flag, 0) from Task
    Inner join TouchpointDependency on Task.TouchpointId = TouchpointDependency.ParentTouchpointId 
    AND IsNull(TouchpointDependency.Active, 1) = 1
    where Task.TaskId in (select TaskId from @vTaskIds)


OPEN CTD
FETCH NEXT FROM CTD into @vTouchpointId, @vTouchpointDependencyId, @vEventId, @vOrdering, @vParentTaskId, @vFlag

WHILE @@Fetch_status = 0
BEGIN

    IF NOT EXISTS(SELECT * FROM TASKDEPENDENCY where TouchpointDependencyId = @vTouchpointDependencyId
                    And ParentTaskId = @vParentTaskId)
    BEGIN
    print 'usp_ActiveTouchPoints - TDD'
        Insert into TaskDependency
        (
            TaskDependencyId,
            ParentTaskId,
            TouchpointDependencyId,
            TaskId, 
            EventId, 
            Ordering,
            ACTIVE,
            Flag
        )
        SELECT  NEWID()
                , @vParentTaskId
                , @vTouchpointDependencyId
                , TaskId
                , @vEventId
                , @vOrdering
                , 1
                , @vFlag
        From Task 
        Inner join TouchpointDependency 
            on Task.TouchpointId = TouchpointDependency.TouchpointId 
        where TouchpointDependency.TouchpointDependencyId = @vTouchpointDependencyId
        AND Task.TaskId in (select TaskId from @vTaskIds)

    END

    FETCH NEXT FROM CTD into @vTouchpointId, @vTouchpointDependencyId, @vEventId, @vOrdering, @vParentTaskId, @vFlag
END
CLOSE CTD;
DEALLOCATE CTD;

    IF XACT_STATE() = 1
    BEGIN
        COMMIT TRANSACTION @TransactionName
    END

    SET @pRetValue = 1
END TRY

BEGIN CATCH 
    IF XACT_STATE() <> 0
    BEGIN
        ROLLBACK TRANSACTION @TransactionName
    END

    INSERT INTO ERRORLOG
    SELECT  
            ERROR_NUMBER(),
            ERROR_MESSAGE(),
            ERROR_SEVERITY(),
            ERROR_STATE(),
            ERROR_LINE(),
            ERROR_PROCEDURE(),
            NEWID()


    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_MESSAGE() AS ErrorMessage;


    SET @pRetValue = 0

END CATCH

END

There is lot of inserts happening in the Stored procedure. A number of Insert / Update. It also opens a Cursor but I marked it as local scope cursor.

Now this stored procedure is called using Entity Framework, and a website calls it using WebAPI.

Now the problem is when I am calling the same stored procedure multiple times, it says :

"Cannot roll back 76C80318BB6A. No transaction or savepoint of that name was found"

But the same works fine when I call it once and wait until I finish and then call it again. I have no idea hoe to fix the issue. Do you think there is an issue with code ?

1
Can you post your entire SQL BEGIN / END with the cursor - ta. - Tony Rogerson
@TonyRogerson I have updated the Stored proc with actual code. Can you please check. Sometimes, I am also getting : Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2 - abhishek
It looks like you are creating an additional transaction in one of the stored procedures you are calling, that then creates an error condition which gets caught. Stick some debug PRINT's in there - before and after each proc call check @@TRANCOUNT so you can identify which proc is causing the mismatch. - Tony Rogerson
Just to confirm doing PRINT @@TRANCOUNT; Exec usp_ActiveInitialTouchPoints {parameters}; PRINT @@TRANCOUNT over each EXEC call always produces 1 and 1? The error messages is saying you've an additional transaction on return from the proc call i.e. on entry @@TRANCOUNT is 1 and on completion 2. - Tony Rogerson
Also - at the start of your usp_ActiveTouchPoints proc add the code: IF @@TRANCOUNT > 0 then begin raiserror( 'existing transaction', 16, 1 ); return; end - that way if you have an existing transaction on entry to your base proc you will detect that. - Tony Rogerson

1 Answers

1
votes

Make sure SET IMPLICIT_TRASACTIONS is OFF when calling the initial stored procedure otherwise code with an outstanding transaction from the stored proc call in mind.