是否可以检测INSERT-EXEC
语句是否正在调用当前存储过程?
是的,我知道我们可能不想再使用INSERT-EXEC
声明......这不是我要问的问题。
我使用INSERT-EXEC
的原因是因为我希望能够促进存储过程的重用,而不是一直重写相同的SQL。
这就是我关心的原因:
在INSERT-EXEC
方案下,一旦请求ROLLBACK
,原始错误消息就会丢失。因此,任何创建的记录现在都将成为孤儿。
示例:
ALTER PROCEDURE [dbo].[spa_DoSomething]
(
@SomeKey INT,
@CreatedBy NVARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION
-- SQL runs and throws an error of some kind.
COMMIT TRAN
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRAN
-- If this procedure is called using an INSERT-EXEC
-- then the original error will be lost at this point because
-- "Cannot use the ROLLBACK statement within an INSERT-EXEC statement."
-- will come-up instead of the original error.
SET @ErrorMessage = ERROR_MESSAGE();
SET @ErrorSeverity = ERROR_SEVERITY();
SET @ErrorState = ERROR_STATE();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
RETURN @@Error
END
答案 0 :(得分:1)
基于你不能拥有嵌套的INSERT--EXECUTE
...语句的事实,我想出了一些kludge(好吧,它是一个很大的kludge)。基本上,如果您的“问题”过程是INSERT--EXECUTE
的目标,并且其本身包含INSERT--EXECUTE
,则会引发错误。为了使这项工作,您必须在过程中进行(很可能毫无意义的)INSERT--EXECUTE
调用,并将其包装在TRY--CATCH
块中,并进行适当的处理。尴尬和迟钝,但如果没有其他事情出现,可能值得一试。
使用以下方法进行测试。这将创建三个过程:
IF objectproperty(object_id('dbo.Foo1'), 'isProcedure') = 1
DROP PROCEDURE dbo.Foo1
IF objectproperty(object_id('dbo.Foo2'), 'isProcedure') = 1
DROP PROCEDURE dbo.Foo2
IF objectproperty(object_id('dbo.Foo3'), 'isProcedure') = 1
DROP PROCEDURE dbo.Foo3
GO
-- Returns a simple data set
CREATE PROCEDURE Foo1
AS
SET NOCOUNT on
SELECT name
from sys.databases
GO
-- Calls Foo1, loads data into a local temp table, then returns those contents
CREATE PROCEDURE Foo2
AS
SET NOCOUNT on
CREATE TABLE #Temp (DBName sysname not null)
BEGIN TRY
INSERT #Temp (DBName)
EXECUTE Foo1
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 8164
PRINT 'Nested INSERT EXECUTE'
ELSE
PRINT 'Unanticipated err: ' + cast(ERROR_NUMBER() as varchar(10))
END CATCH
SELECT *
from #Temp
GO
-- Calls Foo2, loads data into a local temp table, then returns those contents
CREATE PROCEDURE Foo3
AS
SET NOCOUNT on
CREATE TABLE #Temp2 (DBName sysname not null)
INSERT #Temp2 (DBName)
EXECUTE Foo2
SELECT *
from #Temp2
GO
EXECUTE Foo1
将返回“基础”数据集。
EXECUTE Foo2
将调用Foo1,将数据加载到临时表中,然后返回该表的内容。
EXECUTE Foo3
尝试做与Foo2相同的事情,但它调用Foo2。这会导致嵌套INSERT--EXECUTE
错误,由Foo2的TRY--CATCH
检测并处理。
答案 1 :(得分:0)
也许@@ NESTLEVEL可以提供帮助: