基于 Mike 的回答,这是一个适用于 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 - 仅供参考:这是有效的,因为除了master或tempdb之外的每个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_B。)
最后,此解决方案也适用于 CLR 方法。一定要记得执行“包装器”Sql函数有足够的使用权限db_tran_locks
,SqlFunction
属性必须有“SystemDataAccess = SystemDataAccessKind.Read”。“上下文连接”使用与调用者相同的 SPID,它位于程序集所在的 dbcat 中(因此,包装函数/存储过程所在的位置暴露了 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;
}