Warum müssen skalarwertige Funktionen die Berechtigung ausführen, anstatt auszuwählen?

15

Ich frage mich, warum ich dem Benutzer für eine skalarwertige Funktion die Berechtigung erteilen muss, anstatt nur eine Auswahl auszuführen.

In der Zwischenzeit funktionieren Tabellenfunktionen einwandfrei, wenn nur die Berechtigung select oder die db_datareaderMitgliedschaft ausgewählt wird.

Zur Verdeutlichung hier mein Beispiel: Ich benötige einen Benutzer, der nur Leserechte für die Datenbank hat. Also habe ich einen Benutzer namens erstellt testUserund ihm die db_datareaderMitgliedschaft verliehen. dann habe ich eine Tabellenwertfunktion namens erstellt fn_InlineTable. Und alles ist großartig. testUserLäuft diese SQL den ganzen Tag

select * from dbo.fn_InlineTable

dann brauche ich eine Skalarfunktion, also habe ich eine Skalarfunktion namens erstellt fn_ScalarTest. testUserkann dieses SQL nicht ausführen

Select dbo.fn_ScalarTest(1) 

Gut verständlich: es liegt daran, dass ich "testUser" nicht die Berechtigung zur Ausführung gegeben habe fn_ScalarTest.

Meine Frage ist: basierend auf diesen Link /programming/6150888/insert-update-delete-with-function-in-sql-server , die besagt , dass eine FUNCTIONkann nicht verwendet werden , um Aktionen auszuführen, der die Datenbank - Status ändern . Warum also nicht eine Skalarfunktion mit der gleichen "SELECT" -Berechtigung verwenden lassen, anstatt die Berechtigung auszuführen?

Ich hoffe meine Frage macht Sinn. Vielen Dank.

BobNoobGuy
quelle

Antworten:

14

Der Hauptgrund ist wahrscheinlich, dass Tabellenfunktionen eine Ergebnismenge zurückgeben, genau wie Tabellen und Ansichten. Dies bedeutet , dass sie in der verwendet werden FROMKlausel (einschließlich JOINs und APPLYs, usw.) von SELECT, UPDATEund DELETEAbfragen. Sie können jedoch in keinem dieser Kontexte eine skalare UDF verwenden.

Zweitens können Sie auch EXECUTEeine Skalar-UDF. Diese Syntax ist sehr praktisch, wenn Sie Standardwerte für Eingabeparameter angegeben haben. Nehmen Sie zum Beispiel die folgende UDF:

CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
    RETURN @Param1 + @Param2;
END;

Wenn Sie einen der Eingabeparameter als "optional" behandeln möchten, müssen Sie das DEFAULTSchlüsselwort dennoch übergeben, wenn Sie es wie eine Funktion aufrufen, da die Signatur festgelegt ist:

DECLARE @Bob1 INT;

SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);

SELECT @Bob1;
-- Returns: 102

Wenn Sie dagegen EXECUTEdie Funktion verwenden, können Sie alle Parameter mit einem Standardwert wie bei gespeicherten Prozeduren als wirklich optional behandeln. Sie können die ersten n Parameter ohne Angabe von Parameternamen übergeben:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

Sie können den ersten Parameter sogar überspringen, indem Sie erneut Parameternamen angeben, genau wie bei gespeicherten Prozeduren:

DECLARE @Bob3 INT;

EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;

SELECT @Bob3;
-- Returns: 51

AKTUALISIEREN

Warum möchten Sie möglicherweise die EXECSyntax verwenden, um eine skalare UDF wie eine gespeicherte Prozedur aufzurufen? Gelegentlich gibt es UDFs, die sich hervorragend als UDFs eignen, da sie zu einer Abfrage hinzugefügt und über die zurückgegebenen Zeilen ausgeführt werden können. Wenn der Code in einer gespeicherten Prozedur enthalten wäre, müsste er dazu in einen Cursor eingefügt werden Iterieren Sie über eine Reihe von Zeilen. Aber dann gibt es Zeiten, in denen Sie diese Funktion für einen einzelnen Wert aufrufen möchten, möglicherweise innerhalb einer anderen UDF. Das Aufrufen einer UDF für einen einzelnen Wert kann folgendermaßen erfolgen:

SELECT dbo.UDF('some value');

In diesem Fall erhalten Sie einen Rückgabewert in einer Ergebnismenge (eine Ergebnismenge funktioniert nicht). Oder es könnte wie folgt gemacht werden:

DECLARE @Dummy INT;

SET @Dummy = dbo.UDF('some value');

In diesem Fall müssen Sie die @DummyVariable deklarieren .

Mit der EXECSyntax können Sie jedoch diese beiden Belästigungen vermeiden:

EXEC dbo.UDF 'some value';

AUCH bei skalaren UDFs werden die Ausführungspläne zwischengespeichert. Dies bedeutet, dass Parameter-Sniffing-Probleme auftreten können, wenn in der UDF Abfragen mit Ausführungsplänen vorhanden sind. In Szenarien, in denen die EXECSyntax verwendet werden kann, können Sie auch die WITH RECOMPILEOption verwenden, um den für diese Ausführung kompilierten Planwert zu ignorieren . Beispielsweise:

INSTALLIEREN:

GO
CREATE FUNCTION dbo.TestUDF (@Something INT)
RETURNS INT
AS 
BEGIN
   DECLARE @Ret INT;
   SELECT @Ret = COUNT(*)
   FROM   sys.indexes si
   WHERE  si.[index_id] = @Something;

   RETURN @Ret;
END;
GO

PRÜFUNG:

DECLARE @Val INT;

SET @Val = dbo.TestUDF(1);
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 -- uses compiled value of (1)
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 WITH RECOMPILE; -- uses compiled value of (0)
SELECT @Val;

EXEC @Val = dbo.TestUDF 3 -- uses compiled value of (1)
SELECT @Val;
Solomon Rutzky
quelle
4

Ich denke, der Unterschied bei den Berechtigungen liegt darin, dass Sie mit EXEC tatsächlich benutzerdefinierte Funktionen mit skalaren Werten aufrufen können, genau wie gespeicherte Prozeduren (die ich erst in der SQL Server 2000-Onlinedokumentation erkannt hatte, als sie benutzerdefinierte Funktionen einführten). Sie können sie jedoch nicht als Tabellenquelle auswählen. Beispielsweise:

DECLARE @date datetime
EXEC @date = dbo.first_day_of_month '8/14/2015'
SELECT @date

In diesem Fall ist dbo.first_day_of_month eine benutzerdefinierte Funktion. Ich weiß nicht, warum Sie jemals eine Funktion auf diese Weise aufrufen würden, aber ich würde spekulieren, dass sie EXECUTE-Berechtigung anstelle von SELECT benötigten, um die Konsistenz aufrechtzuerhalten. Heutzutage hält es sich wahrscheinlich nur noch als Kompatibilitätsgepäck fest.

db2
quelle