2017-07-28 102 views
2
程序

让我们假设我们有一个SQL服务器重新启动时自动运行简单的日志记录步骤:如果我们试图用参数过程中,我们会得到错误相同SQL服务器 - sp_procoption标记与参数

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'; 

Msg 15399, Level 11, State 1, Procedure sp_procoption,

Could not change startup option because this option is restricted to objects that have no parameters.

但是我们仍然能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'; 

Msg 15399, Level 11, State 1, Procedure sp_procoption Could not change startup option because this option is restricted to objects that have no parameters.


当然,如果我用预期DROP-CREATE一切都将正常工作。

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

但用CREATE-ALTER的路径是:

  • CREATE PROCEDURE不带参数
  • EXEC sp_procoption(程序将开始启动)
  • ALTER PROCEDURE使用默认参数
  • 程序将被解雇

有什么具体原因这项工作呀?具体而言,为什么在修改对象属性(如ExecAtStartup)未验证时?

+0

因为设计师没有预料到像你这样的邪恶人士?你在寻找什么样的答案?你为什么不直接从一个包装程序中调用你的过程,该过程足够坚持“无参数”规则? –

+0

@JeroenMostert我搜索了一些关于验证元数据的注释(MSDN,BOL)。这仅仅是一个例子。像查看'WITH SCHEMABINDING'基础对象不能改变。这个问题更多的是关于内部。 – lad2025

+0

对我来说,作为一名程序员,很明显'sp_procoption'是后来为标记启动而添加的一个新功能,它可以验证您以这种方式标记的过程(无论是“开”还是“关”)。 'ALTER'是引擎的核心命令,不知道或不关心这个程序是否在启动时使用,并且会很高兴地让你在脚下自拍。这仅仅是来自不同层面的机制的紧急行为;如果有人撰写关于此行为的官方文档,我会非常惊讶。 (可能是无聊MVP的博客文章。) –

回答

1

sp_procoption后运行正常明确检查该程序是有效的:

    由DBO 在主
  • 没有参数资

之前,它做任何事情。

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

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

如果此功能于今日实施,可能会得到自己的语法(ALTER PROCEDURE Foo SET STARTUP = ON)而不是内部的存储过程,其中微软正在远离运动(对比sp_dbcmptlevelALTER DATABASE SET COMPATIBILITY_LEVELsp_attach_dbCREATE DATABASE FOR ATTACH)。如果它是ALTER正确的一部分,那么如果程序被标记为STARTUP,那么ALTER PROCEDURE也可以检查参数。尽管如此,这是其中任何一项关于功能改进的优先列表中可能都不高的事情之一。

解决方法当然很简单:如果您必须使用(默认)参数作为启动过程调用过程,请从包含真正没有参数的包装存储过程中转发此调用。因为启动过程可能会严重破坏服务器,如果它们没有经过仔细的编写,实际上它是一个非常好的主意,它只用于启动(并给它们起名为startup),并且不会让它们在通过参数设置,可以很容易地无意中改变它们。

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