0

Good afternoon,

I'm creating a trigger to be present on 3 databases, one of which is on a linkedserver. When inserting data in one of the databases, the objective is to replicate the information in the remaining databases.

Whenever I do an insert, I get the error 'Transaction context in use by another session.'

Anyone knows why this is happening? And is there a way to surprass this?

DROP TRIGGER Insertdata 
USE A
GO
SET ANSI_NULLS ON
SET ANSI_WARNINGS ON
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER Insertdata ON DATA WITH ENCRYPTION FOR INSERT  AS 
SET NOCOUNT ON
    

    if(Upper((SELECT DB_NAME()))=UPPER('A')) Begin

----------------------------------------------------------------------------------------------
        --------------------------------------------- Insert Data ------------------------------------
        ----------------------------------------------------------------------------------------------

        --Create variable for database name and query variable
        DECLARE @DB_Name VARCHAR(100) -- database name
        DECLARE @Local VARCHAR(1) -- database name
        DECLARE @query VARCHAR(4000) -- query variable

        --Declare the cursor 
        DECLARE db_cursor CURSOR LOCAL FOR
        -- Populate the cursor with the selected database name
        select t.name,t.islocal from (
        Select name, '1' as islocal from master.sys.databases WHERE name in ('A','B','C')
        union all
        select name, '0' as islocal from LinkedServer.master.sys.databases WHERE name in ('A','B','C')
        )t

        OPEN db_cursor
        --Moves the cursor to the first point and put that in variable name
        FETCH NEXT FROM db_cursor INTO @DB_Name,@Local;
        -- while loop to go through all the DB selected
        WHILE @@FETCH_STATUS = 0
            BEGIN
                    if(@Local ='0') begin
                        Set @DB_Name = 'LinkedServer.' + @DB_Name
                    end


                    -- Check if received data exists
                    SET @query = N'Select id from ' + @DB_Name +'.dbo.data where data.id='''+(Select inserted.id from inserted)+''''
                    EXEC(@query)

                    --If doesnt exists, then insert data
                    if @@ROWCOUNT < 1 begin
                        SET @query = N'INSERT INTO ' + @DB_Name +'.dbo.data(id,name,surname) 
                                values('+''''+(select inserted.id from inserted)+''''
                                +','+''''+(select convert(varchar,inserted.name) from inserted)+''''
                                +','+''''+(select convert(varchar,inserted.surname) from inserted)+''''
                                +')'
                        EXEC (@query)
                        --Fetch the next record from the cursor
                    end
                FETCH NEXT FROM db_cursor INTO @DB_Name,@Local
            END
        --Close and deallocate cursor
        CLOSE db_cursor
        DEALLOCATE db_cursor
    End
GO

SET ANSI_NULLS OFF
SET ANSI_WARNINGS OFF
SET QUOTED_IDENTIFIER OFF
GO

EDIT: I think the problem here is the fact, that my trigger is being executed on different databases. For example, the current database is A, so the trigger should execute on B and C, but I realized that when A calls B, B executes the trigger aswell. C doesn't executes because gives the error on B. Thought db_name() would fix this, but guess it doesn't

CodeOnce
  • 79
  • 1
  • 9
  • possible dupe https://stackoverflow.com/questions/10704553/transaction-context-in-use-by-another-session – Doug Coats Aug 30 '21 at 15:50
  • I have read that article and others, before posting my problem ... – CodeOnce Aug 30 '21 at 15:55
  • 2
    Linked servers are tricky enough, they get trickier when combined with transactions (and all triggers implicitly execute in a transaction) and if you then throw dynamic SQL on top of it, you've got a truly lovely mix. Any reason you can't use the feature specifically designed for data replication, that being, replication? – Jeroen Mostert Aug 30 '21 at 16:00
  • Also, you've got SQL injection all over this. And you've also made the usual mistake of assuming that `inserted` has exactly one row, it may in fact have multiple or zero rows. That doesn't answer your question, but needs fixing – Charlieface Aug 30 '21 at 16:10
  • @JeroenMostert I cannot use replication, because the value of certain fields in the this table will vary from database to database. There are other tables that are connected to this one, affecting fields of this table. – CodeOnce Aug 30 '21 at 16:10
  • @Charlieface, I know what your talking about xD, but there will be always one row – CodeOnce Aug 30 '21 at 16:12
  • Varying values can be solved by combining replication with custom stored procedures to handle the DML, and/or excluding those fields from replication. If all else fails the data proper can be replicated with "regular" replication, and then triggers on the table itself can be used to further process the data into local tables (although this requires some care so as to not slow things down unreasonably; a periodic job is another option). This may sound involved, but it's probably still not as involved as trying to get your own custom linked server triggers to work under all circumstances. – Jeroen Mostert Aug 30 '21 at 16:14
  • I think the problem here is the fact, that my trigger is being executed on different databases. For example, the current database is A, so the trigger should execute on B and C, but I realized that when A calls B, B executes the trigger aswell. C doesn't executes because gives the error on B. Thought db_name() would fix this, but guess it doesn't – CodeOnce Aug 30 '21 at 17:15
  • 1
    Please don't use linked servers in a trigger. If you must roll your own solution, the triggers should only write to staging tables or service broker queues, and the data movement and inserts should be done asynchronously. – David Browne - Microsoft Aug 30 '21 at 17:41
  • This looks to be a horrid solution and many other cleaner solutions exist such as CDC. However, instead if inserting directly to the linked server table in the trigger, you might consider passing values to a procedure on the target server; this can then have control over whether the trigger does or does not fire on the inserted table. – Stu Aug 30 '21 at 18:38

0 Answers0