SQL Server - 带参数的sp_procoption标记过程

时间:2017-07-28 14:19:22

标签: sql sql-server tsql stored-procedures

假设我们在SQL Server重启期间有自动运行的简单日志记录过程:

USE master
GO

CREATE TABLE dbo.silly_logging(id INT IDENTITY(1,1) PRIMARY KEY
                               ,created_date DATETIME DEFAULT GETDATE()
                               ,comment VARCHAR(100));
GO

-- no parametrs
CREATE PROCEDURE dbo.my_procedure 
AS
INSERT INTO dbo.silly_logging(comment)
VALUES ('SQL Server Startup');
GO

-- mark procedure to start at SQL Server instance startup
EXEC sp_procoption @ProcName = 'dbo.my_procedure'
    , @OptionName = 'startup'   
    , @OptionValue = 'on';

SELECT name, is_auto_executed
FROM master.sys.procedures
WHERE is_auto_executed = 1;
-- my_procedure 1

-- restart instance
SELECT *
FROM dbo.silly_logging;
--id    created_date    comment
--1 2017-07-28 07:01:24.650 SQL Server Startup

如果我们尝试使用带参数的程序,我们会收到错误:

CREATE PROCEDURE dbo.my_procedure2 @i INT = 10
AS
SELECT @i;
GO

-- mark procedure to start at SQL Server instance startup
EXEC sp_procoption @ProcName = 'dbo.my_procedure2'
    , @OptionName = 'startup'   
    , @OptionValue = 'on';
  

消息15399,级别11,状态1,过程sp_procoption,

     

无法更改启动选项,因为此选项仅限于没有参数的对象。

但我们仍然可以ALTER现有程序:

ALTER PROCEDURE dbo.my_procedure @text NVARCHAR(100) = 'Default value'
AS
INSERT INTO dbo.silly_logging(comment)
VALUES (@text);
GO

-- restart instance
SELECT *
FROM dbo.silly_logging;
--id    created_date    comment
--1 2017-07-28 07:01:24.650 SQL Server Startup
--2 2017-07-28 07:03:50.510 Default value

现在我们最终得到了带有参数(默认值)的存储过程。

缺点:无法关闭。

EXEC sp_procoption @ProcName = 'dbo.my_procedure'
    , @OptionName = 'startup'   
    , @OptionValue = 'off';
  

消息15399,级别11,状态1,过程sp_procoption   无法更改启动选项,因为此选项仅限于没有参数的对象。

当然,如果我使用DROP-CREATE,一切都会按预期工作。

  • DROP PROCEDURE - 删除对象,同时删除ExecAtStartup属性
  • 使用默认参数
  • 创建过程
  • EXEC sp_procoption - 将返回错误
  • 程序不会被解雇

但是CREATE-ALTER的路径是:

  • 不带参数的创建程序
  • EXEC sp_procoption(程序将在启动时启动)
  • 使用默认参数
  • 的ALTER PROCEDURE
  • 程序将被解雇

这种工作有什么具体原因吗?具体来说,为什么在更改对象属性(如ExecAtStartup)时未验证?

2 个答案:

答案 0 :(得分:1)

该检查仅在sp_procoption,因此仅在sp_procoption执行时进行检查。

ALTER

后仍然运行正常
CREATE PROCEDURE dbo.my_procedure 
AS
RAISERROR ('fff', 10, 1) WITH LOG
GO
EXEC sp_procoption @ProcName = 'dbo.my_procedure'
    , @OptionName = 'startup'   
    , @OptionValue = 'on';
GO

-- SQL restarted. Check logs
-- Error: 50000 Severity: 10 State: 1 fff
GO
ALTER PROCEDURE dbo.my_procedure 
    @dummy int = 0
AS
RAISERROR ('ggg', 10, 1) WITH LOG
GO

-- SQL restarted. Check logs
-- Error: 50000 Severity: 10 State: 1 ggg
GO
DROP PROCEDURE dbo.my_procedure 

答案 1 :(得分:1)

sp_procoption显式检查过程是否有效:

  • 拥有dbo
  • in master
  • 没有参数

在它做任何事之前。

传递这些检查后sp_procoption 'proc', 'startup', 'on'的唯一影响是将对象属性ExecIsStartup设置为1(而off将其设置为0 )。您可以使用OBJECTPROPERTY验证这一点。

没有特别原因ALTER PROCEDURE无法检查此属性并验证过程没有参数并拒绝ALTER,否则它只是没有。因此,您可以标记启动过程,将其更改为具有参数,然后再遇到sp_procoption拒绝处理它,即使只是关闭该选项。

如果今天实现了此功能,它可能会获得自己的语法(ALTER PROCEDURE Foo SET STARTUP = ON)而不是内部存储过程,而Microsoft正在逐渐退出(比较sp_dbcmptlevelALTER DATABASE SET COMPATIBILITY_LEVELsp_attach_dbCREATE DATABASE FOR ATTACH)。如果它是ALTER正确的一部分,那么如果程序标记为ALTER PROCEDURE,那么STARTUP也可以检查参数。然而,这是任何人在功能改进的优先级列表中可能并不高的事情之一。

当然,解决方法很简单:如果必须使用(默认)参数作为启动过程调用过程,请从实际上没有参数的包装器存储过程执行此操作并转发调用。因为如果不仔细编写服务器,启动程序可能会使您的服务器崩溃,实际上使用进行启动是一个非常好的主意(并使用{{1}给它们命名并且没有让他们在一个带有参数的设置中拉双重任务,因为它很容易在不经意间改变它们。