Monday, November 16, 2009

Getting the SQL (and other goodness) from a running transaction

I had run a bunch of SQL scripts against a SQL Server database during a deployment. All tests after the updates checked out. I went to close SSMS and got the message, "There are uncommitted transactions. Do you wish to commit these transactions before closing the window"?

WTF? How could I have failed to commit a transaction yet testing all checked out? Well that's a mystery I haven't yet figured out, but I did find a good query (that I had to alter somewhat to make work) for getting the text of the command that had not yet been committed:


SELECT
  st.Session_id, req.Blocking_Session_ID [Blocker], req.Wait_Type,
  req.Wait_Time [WaitTimeMS], req.Wait_Resource, req.open_transaction_count,
  req.percent_complete, dt.transaction_id, dt.database_transaction_begin_time,
  case when dt.database_transaction_type = 1 then 'RW'
    when dt.database_transaction_type = 2 then 'R'
    when dt.database_transaction_type = 3 then 'Sys'
    else 'Unknown'
end [TranType],
  case when dt.database_transaction_state = 1 then 'Not Initialized'
    when dt.database_transaction_state = 3 then 'Initialized, but no logs'
    when dt.database_transaction_state = 4 then 'Generated logs'
  when dt.database_transaction_state = 5 then 'Prepared'
    when dt.database_transaction_state = 10 then 'Committed'
    when dt.database_transaction_state = 11 then 'Rolled Back'
    when dt.database_transaction_state = 12 then 'In process of committing'
  else 'Unknown'
end [TranState],
  req.Status, req.Command, stxt.objectid [ExecObjID],
(SUBSTRING(stxt.text, req.statement_start_offset/2,( CASE WHEN req.statement_end_offset = -1 then LEN(CONVERT(nvarchar(max), stxt. text)) * 2
        ELSE req.statement_end_offset
      end -req.statement_start_offset)/2)) [SubText],
  stxt.text, req.statement_start_offset
FROM
  sys.dm_tran_database_transactions dt (nolock)
  inner join sys.dm_tran_session_transactions st (nolock) on dt.transaction_id = st.transaction_id
  inner join sys.dm_exec_requests req (nolock) on st.transaction_id = req.transaction_id
  CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) [stxt]
where
  dt.database_id = db_id() and st.is_user_transaction = 1


This query wouldn't work in my situation (would barf "Incorrect syntax near '.'" at the second to last dot), but it will work on a database with compatibility level 90 or better.

No comments: