USE [DD_SYS]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- [PRDD_GET_DB_DEADLOCKS]
-- =================================================================
-- Gets db deadlock victims
-- Minimum requirement: MS SQL Server 2016
-- 
-- Returns: table
-- =================================================================
-- Copyright (c) 2025 by Digital Data GmbH
--
-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim
-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works
-- =================================================================
-- Creation Date / Author:    26.03.2025 / MK
-- Version Date / Editor:     26.03.2025 / MK
-- Version Number:            1.0.0.0
-- =================================================================
-- History:
-- 26.03.2025 / MK - First Version

CREATE OR ALTER PROCEDURE [dbo].[PRDD_GET_DB_DEADLOCKS](
	pKILL_DEADLOCK_SESSIONS		BIT 	= NULL
)
AS
BEGIN

	SET NOCOUNT ON;
	
	-- declare new vars because of parameter sniffing
    DECLARE @KILL_DEADLOCK_SESSIONS 	BIT 			= ISNULL(@pKILL_DEADLOCK_SESSIONS,0);

	DECLARE @DEADLOCK_SESSIONS	TABLE  ([GUID]					[INT] IDENTITY(1,1) NOT NULL,
										[SessionID]				[INT])				NOT NULL,
										[blocking_session_id]	[INT]				NOT NULL,
										[database_id]			[INT]				NOT NULL,
										[blocking_statement]	[NVARCHAR](MAX)		NULL,
										[blocked_statement]		[NVARCHAR](MAX)		NULL);

	-- declare runtime vars
    DECLARE @MyProcedureName			NVARCHAR(128) 	= OBJECT_NAME(@@PROCID);
	DECLARE	@GUID						BIGINT,
			@SessionID					INT,
			@blocking_session_id		INT,
			@database_id				INT,
			@blocking_statement			NVARCHAR(MAX),
			@blocked_statement			NVARCHAR(MAX),
			@return_status				NVARCHAR(50)	= 0,
			@return_status_text			NVARCHAR(MAX)	= 'START ' + @MyProcedureName + ' @ ' + CONVERT(varchar(50),GETDATE(),120);

	PRINT '==============================='
	PRINT 'PROCEDURE  - ' + @return_status_text;
	PRINT 'PARAMETER01 - @KILL_DEADLOCK_SESSIONS: ' + CONVERT(VARCHAR(1),@KILL_DEADLOCK_SESSIONS);

	INSERT INTO @DEADLOCK_SESSIONS([SessionID],[blocking_session_id],[database_id],[blocking_statement],[blocked_statement])
	WITH XMLNAMESPACES ('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS sp)
	SELECT
		[requests].[session_id], 
		[requests].[blocking_session_id], 
		[requests].[database_id], 
		[sql_text1].[text] 			AS blocking_statement, 
		[sql_text2].[text] 			AS blocked_statement
	FROM [master].[sys].[dm_exec_requests] as [requests]
	CROSS APPLY [master].[sys].[dm_exec_sql_text]([requests].[sql_handle]) [sql_text1]
	JOIN [master].[sys].[dm_exec_connections] as [connections] ON [requests].[blocking_session_id] = [connections].[session_id]
	CROSS APPLY [master].[sys].[dm_exec_sql_text]([connections].[most_recent_sql_handle]) [sql_text2]
	ORDER BY [requests].[database_id] ASC;

	SELECT * FROM @DEADLOCK_SESSIONS ORDER BY [SessionID];
	
	SELECT	
		[database_id], 
		CONVERT(NVARCHAR(5),  [session_id]) as 'SessionID', 
		CONVERT(NVARCHAR(50), [login_name]) as 'LoginName', 
		CONVERT(NVARCHAR(50), [host_name])  as 'HostName'
	FROM  [master].[sys].[dm_exec_sessions] (NOLOCK)
	WHERE [is_user_process] = 1 
	  AND [database_id] IN (SELECT DISTINCT [SessionID] FROM @DEADLOCK_SESSIONS ORDER BY [SessionID]);
	
		--==========================================-- Create the main loop (cursor) --============================================--
	IF (SELECT COUNT(*) FROM @DEADLOCK_SESSIONS > 0) AND (@KILL_DEADLOCK_SESSIONS = 1) BEGIN

		DECLARE CURSOR_KILL_SESSIONS CURSOR STATIC LOCAL FOR  
			SELECT [SessionID] FROM @DEADLOCK_SESSIONS;
 
		OPEN CURSOR_KILL_SESSIONS   
		FETCH NEXT FROM CURSOR_KILL_SESSIONS INTO @SessionID   
		WHILE @@FETCH_STATUS = 0  BEGIN   
			BEGIN

				PRINT ' ';
				PRINT '-------------------------------';
				PRINT 'Now processing: ' + CONVERT(varchar(100),@SessionID);
	
				KILL @SessionID
				-----------------------------------------------------------------------------------------------------------------------------

			END;

			FETCH NEXT FROM CURSOR_KILL_SESSIONS INTO @SessionID;

		END;

		CLOSE CURSOR_KILL_SESSIONS;
		DEALLOCATE CURSOR_KILL_SESSIONS;

	END; ELSE BEGIN
		PRINT '';
		PRINT 'There are no deadlocks, or deadlock kill is disabled!';
	END;