Neue UDFs, die einen Cursor enthalten, nicht zulassen


7

Gibt es eine Möglichkeit, Entwickler daran zu hindern, neue benutzerdefinierte Funktionen zu erstellen, die einen Cursor verwenden? Würde ein Datenbank-Trigger, der den Code einer UDF lesen kann, dies tun?


2
Der neue Weg, dies zu tun, ist mit Richtlinien .
Nick Chammas

4
Und der alte Weg, dies zu tun, ist mit der Codeüberprüfung!
HLGEM

Antworten:


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

Mit einer Einschränkung wird auch ein Auslöser, der einen Kommentar enthält, nicht zugelassen, wie z.

/* 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 */

... oder wenn Sie wirklich unbequeme Fragen haben wie:

SELECT [declare] = [cursor] * 10 FROM dbo.[fetch];

... oder auch wenn Sie Ihre Funktion aufrufen:

CREATE FUNCTION dbo.ModeClarevoyantForCursoryFetching()
RETURNS TABLE
AS ...

BEARBEITEN

Nicks Frage hier anstatt als Kommentar anzusprechen, weil es ein wenig langwierig werden wird.

PBM ist großartig für einige Sachen, aber nicht so toll für andere Sachen. Diese Anforderung fällt unter die Kategorie "Sonstiges". Das Hauptproblem besteht darin, dass die Definition (z. B. OBJECT_DEFINITION()) nicht als Eigenschaft Facetten wie benutzerdefinierten Funktionen ausgesetzt ist. Dies bedeutet, dass Ihr Zustand nicht einfach Folgendes ausdrücken kann:

@ObjectDefinition NOT LIKE '%DECLARE%CURSOR%FETCH%'

Wenn dies der Fall wäre, könnten Sie diese Bedingung erstellen, eine Richtlinie darum wickeln, sie auf "Verhindern: Ändern" setzen und zum Mittagessen gehen. Um dies als Richtlinie umzusetzen, ist etwas mehr Arbeit erforderlich.

Da @ObjectDefinition kein gültiges Feld für diese Facette ist, müssen wir es mithilfe von erhalten ExecuteSql(). Ihr Zustand müsste also ungefähr so ​​aussehen:

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

Hässlich, richtig? Wenn dies 0 ergibt, sollte die Richtlinie erfolgreich sein. Wenn es <> 0 ist, sollte die Richtlinie fehlschlagen. (Denken Sie daran, dass eine Richtlinie in Bezug auf den Status ausgedrückt werden soll, in dem sich das System befinden soll, nicht in dem Status, in dem Sie dies nicht tun.)

Zu Beginn erstellen Sie eine Bedingung, indem Sie den Objekt-Explorer öffnen, Verwaltung> Richtlinienverwaltung erweitern, mit der rechten Maustaste auf Bedingungen klicken und Neue Bedingung auswählen ... Geben Sie einen Namen ein, wählen Sie die Facette Benutzerdefinierte Funktion und klicken Sie auf die Schaltfläche Erweiterte Bearbeitung . Dort können Sie die ExecuteSql()obige Zeichenfolge eingeben und auf OK klicken.

Geben Sie hier die Bildbeschreibung ein

Ändern Sie den Operator in =, geben Sie 0 als Wert ein und klicken Sie auf OK. Erstellen Sie nun eine Richtlinie. Klicken Sie mit der rechten Maustaste auf Richtlinien, Neue Richtlinie ... Geben Sie einen Namen ein, wählen Sie die gerade erstellte Bedingung aus und wählen Sie dann den Bewertungsmodus:

Geben Sie hier die Bildbeschreibung ein

Oh oh. Warum sind keine "On Prevent" -Aktionen verfügbar? Bei Verhindern: Wenn Sie den Kurs ändern, können Sie verhindern, dass die Funktion erstellt wird. Da Eigenschaften wie ID und Definition nicht über die Facette verfügbar sind und wir diese durchlaufen müssen ExecuteSql(), unterliegen wir einer Einschränkung, die verhindert, dass Richtlinien mit Bedingungen ExecuteSql()automatisiert werden. Obwohl dieser PBM-Blogbeitrag aus dem Jahr 2008 darauf hinweist, dass diese Einschränkung aufgehoben wurde, stelle ich immer noch fest, dass sie in SQL Server 2012 mit dem angewendeten kumulativen Update Nr. 1 (11.0.2316) erzwungen wird.

Im Moment können Sie dies mithilfe einer Richtlinie implementieren, aber Sie können nicht verhindern, dass eine solche Funktion erstellt wird. Sie können Verstöße erst nachträglich untersuchen (indem Sie entweder On Demand oder On Schedule auswählen). Beachten Sie, dass diese Richtlinie, selbst wenn Sie sie bei Bedarf ausführen, genau dieselbe Logik wie der DDL-Trigger verwendet und daher denselben Einschränkungen unterliegt: Wenn Sie Kommentare oder gültige Nicht-Cursor-Abfragen haben, die Folgendes enthalten, kann dies zu Fehlalarmen führen gleiche Folge von Wörtern.

Wenn Sie möchten, dass die für Facetten verfügbaren Eigenschaften flexibler und vollständiger sind, was eine bessere Kontrolle bei der Verwendung von Richtlinien zugunsten von DDL-Triggern ermöglicht, stimmen Sie für diese beiden Connect-Elemente ab und kommentieren Sie sie:

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

Ich kenne keinen Punkt, der sich mit der Lockerung der Beschränkung ExecuteSql()im Allgemeinen befasst. Ich werde später nachsehen und eine einreichen, wenn ich keine finde. Ich denke, der Blog-Beitrag spiegelt die Tatsache wider, dass Sie diese jetzt nach einem Zeitplan ausführen können. Wenn Sie ihn jedoch nach einem Zeitplan ausführen können, warum kann er dann nicht im Modus "Verhindern" ausgeführt werden?

Schließen der Schleife: Hier ist das neue Connect-Element. Bitte stimmen Sie ab und / oder fügen Sie Kommentare hinzu, die Ihren Anwendungsfall / Geschäftsbedarf beschreiben (dies ist oft viel wertvoller als nur rohe Stimmen):

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


2
+1 Tolle Antwort und kluger Ansatz. Ganz zu schweigen von der tollen Fehlermeldung :)
Thomas Stringer

Sie sind offensichtlich mit richtlinienbasiertem Management vertraut . Kann diese Art der Einschränkung mit PBM besser durchgesetzt werden?
Nick Chammas

1
Ich mag auch die Rückmeldung. Ich könnte sogar den Namen des einzigen Mannes hier hart codieren, der Cursor verwendet. Verlockend. Nein, nein.
William Meitzen

Leider wurde das von mir angesprochene Connect-Element geschlossen, da "nicht behoben werden kann".
Aaron Bertrand
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.