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?
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?
Antworten:
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.
Ä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:
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:
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):