Is there any way to get a list of open/allocated cursors in SQL server?
-
06-07-2019 - |
Question
I have a stored procedure that creates and opens some cursors. It closes them at the end, but if it hits an error those cursors are left open! Then subsequent runs fail when it tries to create cursors since a cursor with the name already exists.
Is there a way I can query which cursors exists and if they are open or not so I can close and deallocate them? I feel like this is better than blindly trying to close and swallow errors.
Solution 3
This seems to work for me:
CREATE PROCEDURE dbo.p_cleanUpCursor @cursorName varchar(255) AS
BEGIN
DECLARE @cursorStatus int
SET @cursorStatus = (SELECT cursor_status('global',@cursorName))
DECLARE @sql varchar(255)
SET @sql = ''
IF @cursorStatus > 0
SET @sql = 'CLOSE '+@cursorName
IF @cursorStatus > -3
SET @sql = @sql+' DEALLOCATE '+@cursorName
IF @sql <> ''
exec(@sql)
END
OTHER TIPS
Look here for info on how to find cursors. I have never used any of them because I could figure out a way to get it done without going Row By Agonizing Row.
You should rebuild the sp to either
not use cursors ( we can help - there is almost always a way to avoid RBAR)
build it in a transaction and roll it back if there is a failure or if you detect an error. Here are some excellent articles on this. part 1 and part 2
If you have SQL2005, you can also use try catch
EDIT (in response to your post):Ideally, data generation is best handled at the application level as they are better suited for non set based operations.
Red Gate has a SQL Data generator that I have used before (its great for single tables, but takes some configuring if you have lots of FK or a wide [normalized] database).
This works on 2008R2, haven't tested on anything earlier than that:
USE MASTER
GO
select s.session_id, s.host_name, s.program_name, s.client_interface_name, s.login_name
, c.cursor_id, c.properties, c.creation_time, c.is_open, con.text,
l.resource_type, d.name, l.request_type, l.request_Status, l.request_reference_count, l.request_lifetime, l.request_owner_type
from sys.dm_exec_cursors(0) c
left outer join (select * from sys.dm_exec_connections c cross apply sys.dm_exec_sql_text(c.most_recent_sql_handle) mr) con on c.session_id = con.session_id
left outer join sys.dm_exec_sessions s on s.session_id = c.session_id
left outer join sys.dm_tran_locks l on l.request_session_id = c.session_id
left outer join sys.databases d on d.database_id = l.resource_database_id
You can use the sp_cursor_list system stored procedure to get a list of cursors visible to the current connection, and sp_describe_cursor, sp_describe_cursor_columns, and sp_describe_cursor_tables to determine the characteristics of a cursor.
(from http://msdn.microsoft.com/it-it/library/aa172595(v=sql.80).aspx )
You can use
sys.dm_exec_cursors
as described here
Basically you can run this sample query and get information about the cursors that are open in various databases
sys.dm_exec_cursors(0)