英文:
SQL Server Service Broker DSQL operation on another database causing Broker failure
问题
我已根据Eitan Blumin的优秀示例建立了一个基于Service Broker的配置。
链接:https://eitanblumin.com/2018/10/31/advanced-service-broker-sample-asynchronous-triggers/
我已编写了自己的存储过程。当我在同一数据库内执行操作时,示例可以正常工作。但如果我尝试在当前数据库之外操作,则会出现错误。
这段代码有效:
DELETE FROM CurrentDB.dbo.[gis_pt_im_map_auth_label]
WHERE plotnumber IN (@ids)
这段代码失败:
DELETE FROM OtherDB.OtherSchema.[gis_pt_im_map_auth_label]
WHERE plotnumber IN (@ids)
以下是涉及的存储过程。我怀疑这是某种用户权限问题,但我已尝试了一些基于用户的更改,例如将执行用户设置为两个数据库的DBO,但没有结果。
为了澄清,如果我手动执行存储过程,它将正常运行。但是Service Broker会改变执行的方式。
欢迎任何想法或意见。
CREATE PROCEDURE [dbo].[sp_Location_UPDATE_TEST3]
@inserted XML,
@deleted XML = NULL
AS
SET NOCOUNT ON;
BEGIN TRY
DECLARE @SQL NVARCHAR(max)
DECLARE @ids NVARCHAR(max)
IF EXISTS (SELECT NULL FROM @inserted.nodes('inserted/row') AS T(X))
BEGIN
INSERT INTO [dbo].[LocationViewLog] ([lo_location], [lo_Location_Code])
SELECT
inserted.[lo_location],
inserted.lo_location_Code
FROM
(SELECT
X.query('.').value('(row/lo_location)[1]', 'int') AS lo_location,
X.query('.').value('(row/lo_Location_Code)[1]', 'nvarchar(100)') AS lo_location_Code
FROM
@inserted.nodes('inserted/row') AS T(X)) AS inserted
SELECT @ids = String_agg(inserted.lo_location, ',')
FROM
(SELECT
X.query('.').value('(row/lo_location)[1]', 'int') AS lo_location
FROM @inserted.nodes('inserted/row') AS T(X)
) AS inserted
--以下块是有问题的部分。
--如果我尝试在另一个数据库中执行此删除操作,Service Broker会因错误而中断。
--如果我创建相同的命令以在当前数据库中运行,就不会有问题
SET @SQL = 'DELETE FROM Test.dbo.[gis_pt_im_map_auth_label] WHERE plotnumber IN ('+@ids+')';
INSERT INTO [dbo].[LocationViewLog]
(lo_Location_Code) VALUES (@SQL);
EXEC(@SQL)
--结束问题块
END
END TRY
BEGIN CATCH
--由于我们在异步触发器中,回滚更新操作比常规触发器要复杂得多。
--目前,对于这种情况,我们将冒有部分数据丢失的风险。
EXECUTE [dbo].[uspLogError];
END CATCH;
英文:
I have established a Service Broker configuration based on Eitan Blumin's excellent example.
https://eitanblumin.com/2018/10/31/advanced-service-broker-sample-asynchronous-triggers/
I have crafted my own stored procedure. I can get the example to work when I'm performing activities within the same database. If I try to operate outside the current database, I get errors.
I'm new to Service Brokers and I'm having trouble capturing the error but I suspect this is all part of the same problem.
This works
DELETE FROM CurrentDB.dbo.[gis_pt_im_map_auth_label]
WHERE plotnumber IN (' + @ids + ')
This fails
DELETE FROM OtherDB.OtherSchema.[gis_pt_im_map_auth_label]
WHERE plotnumber IN (' + @ids + ')
Below is the stored procedure in question. I suspect it is some kind of user permission but I have tried a couple of user based changes like making the executing user the DBO of both databases and no result.
For clarity if I execute the stored procedure manually, this will run. However Service Brokers changes the nature of the execution.
Any thoughts or inputs appreciated.
CREATE PROCEDURE [dbo].[sp_Location_UPDATE_TEST3]
@inserted XML,
@deleted XML = NULL
AS
SET NOCOUNT ON;
BEGIN TRY
DECLARE @SQL NVARCHAR(max)
DECLARE @ids NVARCHAR(max)
IF EXISTS (SELECT NULL FROM @inserted.nodes('inserted/row') AS T(X))
BEGIN
INSERT INTO [dbo].[LocationViewLog] ([lo_location], [lo_Location_Code])
SELECT
inserted.[lo_location],
inserted.lo_location_Code
FROM
(SELECT
--X.query('.').value('(row/PurchaseOrderID)[1]', 'int') AS PurchaseOrderID
X.query('.').value('(row/lo_Location)[1]', 'int') AS lo_location,
X.query('.').value('(row/lo_Location_Code)[1]', 'nvarchar(100)') AS lo_location_Code
FROM
@inserted.nodes('inserted/row') AS T(X)) AS inserted
SELECT @ids = String_agg(inserted.lo_location, ',')
FROM
(SELECT
X.query('.').value('(row/lo_Location)[1]', 'int') AS lo_location
FROM @inserted.nodes('inserted/row') AS T(X)
) AS inserted
--The following block is what is problematic.
--if I try to execute this delete in another database the Service Broker breaks as a result of an error.
--If I craft this same command to operate in the current database there's no problem
SET @SQL = 'DELETE FROM Test.dbo.[gis_pt_im_map_auth_label] WHERE plotnumber IN ('+@ids+')';
INSERT INTO [dbo].[LocationViewLog]
(lo_Location_Code) VALUES (@SQL);
EXEC(@SQL)
--END Problem Block
END
END TRY
BEGIN CATCH
-- Since we're in an Asynchronous Trigger, rolling back an update operation
-- is a lot more complicated than in a regular trigger.
-- For now, for this scenario we'll take the risk of having partial data.
EXECUTE [dbo].[uspLogError];
END CATCH;
**EDIT. The answer provided by David Browne was indeed the issue. I found the follwo=ing two links to be exactly what I needed and demonstrated the implementation of Module Signing I needed.
https://sqlundercover.com/2018/05/02/digitally-signing-a-stored-procedure-to-allow-it-to-run-with-elevated-permissions/
https://sqlundercover.com/2018/10/30/signing-stored-procedures-that-access-multiple-databases/
答案1
得分: 3
Service Broker Internal Activation 使用 SQL Server 身份模拟来运行您的激活过程。而 SQL Server 身份模拟仅限于当前数据库。
> 问题的简要解释是,激活执行上下文仅在数据库中受信任,而不在整个服务器中受信任。
> 与整个服务器相关的任何内容,如服务器级别视图、动态管理视图或链接服务器,都会被视为您以 [Public] 身份登录。
> 解决此问题的推荐方法是使用具有所需操作权限的服务器级别证书对存储过程进行签名。
Why does feature … not work under activation?
要对存储过程进行签名,请按照此处的说明操作:
Tutorial: Signing Stored Procedures with a Certificate
英文:
Service Broker Internal Activation runs your activation procedure using SQL Server impersonation. And SQL Server impersonation is limited to the current database.
> A short explanation of the problem is that the activation execution
> context is trusted only in the database, not in the whole server.
> Anything related to the whole server, like a server level view or a
> dynamic management view or a linked server, acts as if you logged in
> as [Public].
>
> The recommended way to solve the issue is to sign the procedure with a
> server level certificate that has the proper rights needed for the
> operation in question
Why does feature … not work under activation?
To sign the stored procedure, follow the instructions here:
Tutorial: Signing Stored Procedures with a Certificate
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论