禁止包含游标的新 UDF

Wil*_*zen 7 sql-server-2008 sql-server ddl functions

有没有办法阻止开发人员创建使用游标的新用户定义函数?可以读取UDF代码的数据库触发器可以吗?

Aar*_*and 11

CREATE TRIGGER PreventCursorUDFs
    ON DATABASE 
    FOR CREATE_FUNCTION
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @EventData XML = EVENTDATA();

    IF LOWER(@EventData.value('(/EVENT_INSTANCE/TSQLCommand)[1]','NVARCHAR(MAX)'))
      LIKE N'%declare%cursor%fetch%'
    BEGIN
        RAISERROR('Yo, no cursors in functions!', 11, 1);
        ROLLBACK;
    END
END
GO
Run Code Online (Sandbox Code Playgroud)

需要注意的是,这也将禁止包含评论的触发器,例如:

/* we used to do this a dumb way, using DECLARE CURSOR and FETCH */
/* now we're a little smarter and use this table-valued function */
Run Code Online (Sandbox Code Playgroud)

...或者如果您有非常不方便的查询,例如:

SELECT [declare] = [cursor] * 10 FROM dbo.[fetch];
Run Code Online (Sandbox Code Playgroud)

...或者即使你调用你的函数:

CREATE FUNCTION dbo.ModeClarevoyantForCursoryFetching()
RETURNS TABLE
AS ...
Run Code Online (Sandbox Code Playgroud)

编辑

在这里解决尼克的问题而不是作为评论,因为它会变得有点啰嗦。

PBM 在某些方面非常有用,但在其他方面就不是那么好。此要求属于“其他东西”类别。主要问题是定义(例如OBJECT_DEFINITION())没有作为属性暴露给像用户定义函数这样的方面。这意味着您的条件不能简单地表达如下内容:

@ObjectDefinition NOT LIKE '%DECLARE%CURSOR%FETCH%'
Run Code Online (Sandbox Code Playgroud)

如果是这种情况,您可以创建此条件,围绕它制定策略,将其设置为“防止:更改”并去吃午饭。要将其作为一项政策来实施,需要做更多的工作。

由于@ObjectDefinition 不是这个方面的有效字段,我们需要使用ExecuteSql(). 所以你的条件必须是这样的:

ExecuteSql('Numeric', 'SELECT x = PATINDEX(''%declare%cursor%fetch'',
  LOWER(OBJECT_DEFINITION(OBJECT_ID(@@SchemaName + ''.'' + @@ObjectName))))')
Run Code Online (Sandbox Code Playgroud)

丑对不对?当它评估为 0 时,策略应该成功;当它 <> 0 时,策略应该失败。(请记住,策略应该根据您希望系统处于的状态来表达,而不是您不希望的状态。)

因此,首先您将通过打开对象资源管理器,展开管理 > 策略管理,右键单击条件,然后选择新建条件...来创建一个条件... 给它一个名称,选择用户定义的功能方面,然后单击高级编辑按钮. 在那里您可以输入ExecuteSql()上面的字符串,然后单击“确定”。

在此处输入图片说明

将运算符更改为 =,输入 0 作为值,然后单击确定。现在创建一个策略。右键单击 Policies,New Policy... 给它一个名字,选择你刚刚创建的条件,然后选择评估模式:

在此处输入图片说明

哦哦。为什么“预防”操作不可用?关于阻止:当然,更改将允许您阻止创建该功能。因为像 ID 和定义这样的属性不能通过 facet 获得,需要我们通过ExecuteSql(),所以我们受到限制,以防止带有条​​件 using 的策略ExecuteSql()被自动化。虽然这篇 2008 年的 PBM 博客文章表明此限制已取消,但我仍然发现它在应用了累积更新 #1 (11.0.2316) 的 SQL Server 2012 中得到了强制执行。

因此,目前,您可以使用策略来实现这一点,但您将无法阻止创建此类功能 - 您只能在事后调查违规行为(通过选择 On Demand 或 On Schedule)。请记住,即使您按需运行此策略,它也使用与 DDL 触发器完全相同的逻辑,因此受到相同的警告:如果您有评论或有效的非游标查询,包括相同的词序。

如果您希望 facet 可用的属性更灵活和更完整,这将允许在使用支持 DDL 触发器的策略时进行更多控制,请对这两个 Connect 项目投票和评论:

http://connect.microsoft.com/SQLServer/feedback/details/552345/pbm-add-objectid-as-a-parameter-for-executesql

http://connect.microsoft.com/SQLServer/feedback/details/649944/pbm-enable-the-ability-to-pass-more-parameters-to-executesql

我不知道有什么项目可以解决ExecuteSql()一般情况下放宽限制的问题。如果找不到,我会稍后查看并提交一份。我认为博客文章反映了这样一个事实:您现在可以按计划运行这些程序,但是如果您可以按计划运行它,为什么它不能在“预防”模式下运行?

结束循环:这是新的 Connect 项。请投票和/或添加描述您的用例/业务需求的评论(这通常比原始投票更有价值):

http://connect.microsoft.com/SQLServer/feedback/details/749317/allow-on-change-prevent-for-policies-with-executesql-conditions

  • +1 很好的答案和聪明的方法。更不用说令人敬畏的错误消息:) (2认同)