簡體   English   中英

如何返回在另一個數據庫中調用存儲過程的遠程數據庫名稱?

[英]How to return the remote database name which is calling a stored proc in a different database?

我在單個SQL Server 2008 R2上有許多不同的數據庫。 為了論證,讓我們稱它們為DB_A,DB_B和DB_C。 我被要求開發為存儲過程,它將存在於DB_A上。 此存儲過程將用於刪除和創建索引,並在DB_A上的表中存儲有關索引的一些額外信息。 當從DB_C或DB_C調用此存儲過程時,它將能夠在調用數據庫上刪除並創建索引,但在DB_A上的表中存儲有關索引的額外信息。

這就是我想要做的事情:我希望存儲過程能夠獲取調用數據庫的名稱,而不必請求數據庫名稱作為參數。

這是一個簡單的例子:

USE [DB_A]

CREATE PROC sp_WhatDatabaseAmICallingFrom
AS 
BEGIN
      DECLARE @calling_db NVARCHAR(128)
      SET @calling_db = DB_NAME()
      PRINT 'calling database: ' + @calling_db
END

當我在DB_A中執行存儲過程時...

EXEC sp_WhatDatabaseAmICallingFrom

...它返回:“ 調用數據庫:DB_A

當我在DB_B中執行存儲過程時...

USE DB_B
GO

EXEC DB_A.dbo.sp_WhatDatabaseAmICallingFrom

...它返回:“ 調用數據庫:DB_A ”。

在閱讀了各種SQL Server元數據函數之后,這正是它應該做的。 但我想要的是更改代碼,以便它將@calling_db設置為調用數據庫的名稱,以便我的示例存儲過程將打印:“ 調用數據庫:DB_B ”。

不幸的是,我找不到任何能夠做到這一點的元數據功能。 關於如何做到這一點的任何想法?

要使SP在當前連接的上下文中運行,您需要在master數據庫上創建SP 使其成為系統對象。

USE MASTER 
GO 

CREATE PROC sp_WhatDatabaseAmICallingFrom
AS 
BEGIN
      DECLARE @calling_db NVARCHAR(128)
      SET @calling_db = DB_NAME()
      PRINT 'calling database: ' + @calling_db
END
GO

EXEC sp_ms_marksystemobject 'sp_WhatDatabaseAmICallingFrom'
GO

檢查它是如何工作的:

USE [DB_A]
GO

EXEC sp_WhatDatabaseAmICallingFrom
GO

我知道這個帖子很老了,但我發現了一些至少幫助我的東西。

如果您正在使用DB_A並在DB_B中調用存儲過程,如:

USE DB_A
EXEC db_b.dbo.sproc

我發現獲取“調用數據庫”id的唯一方法是在存儲過程內對sys.dm_tran_locks運行select。 request_session_id應該是你的spid,resource_type應該是DATABASE,request_owner_type應該是SHARED_TRANSACTION_WORKSPACE。 對於每個連接的會話,這種共享鎖始終存在於數據庫中。 查詢將是這樣的:

SELECT resource_database_id FROM sys.dm_tran_locks WHERE request_session_id = @@SPID and resource_type = 'DATABASE' and request_owner_type = 'SHARED_TRANSACTION_WORKSPACE'

雖然這要求執行用戶至少擁有服務器上的VIEW SERVER STATE權限。 在我的情況下,這不是一個問題,但..

基於邁克的答案,這是一個在Sql2012中運行的解決方案的示例。

您必須以具有足夠權限的用戶(“VIEW SERVER STATE”)登錄時創建該功能,但使用該功能的用戶只需要獲得執行該功能的權限。

USE [DB_A];
GO

CREATE FUNCTION dbo.GetCallingDbCatName()
RETURNS nvarchar(128) 
WITH EXECUTE AS SELF
AS
BEGIN
    DECLARE @result nvarchar(128);
    SELECT TOP 1 @result = DB_NAME(resource_database_id) 
        FROM sys.dm_tran_locks 
        WHERE request_session_id = @@SPID 
            AND resource_type = 'DATABASE' 
            AND request_owner_type = 'SHARED_TRANSACTION_WORKSPACE' 
        ORDER BY IIF(resource_database_id != DB_ID(), 0, 1);
    RETURN @result;
END
GO

USE [DB_A];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_A"
USE [DB_B];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_B"
USE [DB_C];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_C"

從那里,您應該能夠構建所需的實際功能,而無需污染 dbcat。

編輯2019-07-26 - 僅供參考:這是有效的,因為除了mastertempdb之外的每個與(或使用)dbcat的連接都將具有SHARED_TRANSACTION_WORKSPACE鎖。 以下說明來自此頁面另一頁同樣解釋

SHARED_TRANSACTION_WORKSPACE鎖所有者的目的是防止SQL Server獲取EXCLUSIVE_TRANSACTION_WORKSPACE鎖,即防止進程在數據庫正在使用時丟棄,恢復或更改數據庫的可讀性狀態。 SQL Server沒有為master和tempdb數據庫獲取這些鎖的原因是這些數據庫無法刪除,或者其可讀性狀態已更改。 此外,我們永遠不會恢復tempdb,並且要恢復master數據庫,我們必須以單用戶模式啟動整個服務器,因此,再次不需要SHARED_TRANSACTION_WORKSPACE鎖。

因此,當您從DB_B調用DB_A中的函數時,該查詢返回2行; 一個用於運行查詢的DB_B,另一個用於運行/生存函數的DB_A。 這也意味着上面的查詢不適用於更復雜的調用堆棧(DB_A調用DB_B中的func,然后在DB_C中調用func,嘗試確定調用者的dbcat; ORDER BY將無法在DB_A和DB_A之間正確選擇DB_B。)

最后,該解決方案也適用於CLR方法。 您必須記住執行具有足夠權限的“wrapper”Sql函數以使用db_tran_locks ,並且SqlFunction屬性必須具有“SystemDataAccess = SystemDataAccessKind.Read”。 “上下文連接”使用與調用者相同的SPID,它位於程序集所在的dbcat中(因此,包裝函數/ sproc的生命周期暴露了CLR方法。)

作為參考,這是我的測試CLR方法:

[SqlFunction(IsDeterministic = false, DataAccess = DataAccessKind.Read, SystemDataAccess = SystemDataAccessKind.Read), SqlMethod(OnNullCall = true)]
public static SqlString GetCallingDbcatName()
{
    string sqlResult = "";
    using (var connection = new System.Data.SqlClient.SqlConnection("context connection=true"))
    {
        connection.Open();
        var sqlCmd = connection.CreateCommand();
        sqlCmd.CommandText = @"
SELECT TOP 1 DB_NAME(resource_database_id) 
  FROM sys.dm_tran_locks
  WHERE request_session_id = @@SPID
    AND resource_type = 'DATABASE'
    AND request_owner_type = 'SHARED_TRANSACTION_WORKSPACE'
  ORDER BY IIF(resource_database_id != DB_ID(), 0, 1); ";
        sqlResult = sqlCmd.ExecuteScalar().ToString();
    }
    return sqlResult;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM