Pourquoi les fonctions à valeur scalaire ont-elles besoin d'une autorisation d'exécution plutôt que d'une sélection?

15

Je me demande pourquoi, pour une fonction à valeur scalaire, je dois autoriser l'utilisateur à exécuter plutôt qu'une simple sélection?

Pendant ce temps, une fonction de valeur de table fonctionne très bien avec seulement une autorisation ou une db_datareaderappartenance sélectionnée .

pour être plus clair, voici mon exemple: j'ai besoin d'un utilisateur qui dispose d'une autorisation de lecture seule sur la base de données. J'ai donc créé un utilisateur appelé testUseret lui ai donné l' db_datareaderadhésion. puis j'ai créé une fonction de valeur de table appelée fn_InlineTable. Et tout va bien. testUserexécute ce SQL toute la journée

select * from dbo.fn_InlineTable

alors j'ai besoin d'une fonction scalaire, j'ai donc créé une fonction scalaire appelée fn_ScalarTest. testUserne peut pas exécuter ce SQL

Select dbo.fn_ScalarTest(1) 

Bien entendu: c'est parce que je n'ai pas donné la permission à "testUser" de s'exécuter fn_ScalarTest.

Ma question est: sur la base de ce lien /programming/6150888/insert-update-delete-with-function-in-sql-server , qui dit qu'un FUNCTIONne peut pas être utilisé pour effectuer des actions qui modifient l'état de la base de données . Alors pourquoi ne pas laisser une fonction scalaire être utilisée avec la même permission "SELECT" plutôt que d'exécuter la permission ??

J'espère que ma question a un sens. Je vous remercie.

BobNoobGuy
la source

Réponses:

15

La raison principale est probablement que les fonctions table renvoient un ensemble de résultats, tout comme les tables et les vues. Cela signifie qu'ils peuvent être utilisés dans la FROMclause (y compris JOINs et APPLYs, etc.) de SELECT, UPDATEet les DELETErequêtes. Cependant, vous ne pouvez pas utiliser une FDU Scalar dans aucun de ces contextes.

Secondairement, vous pouvez également EXECUTEun UDF Scalaire. Cette syntaxe est très pratique lorsque des valeurs par défaut sont spécifiées pour les paramètres d'entrée. Prenez par exemple l'UDF suivant:

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

Si vous souhaitez traiter l'un des paramètres d'entrée comme "facultatif", vous devez toujours saisir le DEFAULTmot - clé lorsque vous l'appelez comme une fonction car la signature est fixe:

DECLARE @Bob1 INT;

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

SELECT @Bob1;
-- Returns: 102

D'un autre côté, si vous EXECUTEutilisez la fonction, vous pouvez traiter tous les paramètres avec une valeur par défaut comme vraiment optionnels, tout comme vous le pouvez avec les procédures stockées. Vous pouvez passer les n premiers paramètres sans spécifier de noms de paramètres:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

Vous pouvez même ignorer le premier paramètre en spécifiant des noms de paramètres, à nouveau, comme avec les procédures stockées:

DECLARE @Bob3 INT;

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

SELECT @Bob3;
-- Returns: 51

MISE À JOUR

Pourquoi voudriez-vous utiliser la EXECsyntaxe pour appeler une UDF scalaire comme une procédure stockée? Parfois, il y a des UDF qui sont géniaux d'avoir comme UDF car ils peuvent être ajoutés à une requête et opérer sur l'ensemble des lignes retournées, alors que si le code était dans une procédure stockée, il devrait être placé dans un curseur afin de itérer sur un ensemble de lignes. Mais il y a des moments où vous voulez appeler cette fonction sur une seule valeur, peut-être à partir d'un autre UDF. L'appel d'un UDF pour une valeur unique peut se faire comme suit:

SELECT dbo.UDF('some value');

dans ce cas, vous obtenez une valeur de retour dans un jeu de résultats (un jeu de résultats ne fonctionnera pas). Ou cela pourrait être fait comme suit:

DECLARE @Dummy INT;

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

dans ce cas, vous devez déclarer la @Dummyvariable;

CEPENDANT, avec la EXECsyntaxe, vous pouvez éviter ces deux désagréments:

EXEC dbo.UDF 'some value';

AUSSI, les FDU scalaires ont leurs plans d'exécution mis en cache. Cela signifie qu'il est possible de rencontrer des problèmes de détection de paramètres s'il existe des requêtes dans l'UDF qui ont des plans d'exécution. Pour les scénarios où il est possible d'utiliser la EXECsyntaxe, il est également possible d'utiliser l' WITH RECOMPILEoption pour ignorer la valeur compilée des plans pour cette exécution . Par exemple:

INSTALLER:

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

TESTER:

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
la source
4

Je pense que la différence dans les autorisations est parce que vous pouvez réellement invoquer des fonctions définies par l'utilisateur à valeur scalaire avec EXEC, tout comme les procédures stockées (ce que je n'avais pas réalisé avant de creuser dans la documentation en ligne de SQL Server 2000, où ils ont introduit des fonctions définies par l'utilisateur) , mais vous ne pouvez pas réellement les sélectionner comme source de table. Par exemple:

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

Dans ce cas, dbo.first_day_of_month est une fonction définie par l'utilisateur. Je ne sais pas pourquoi vous invoqueriez une fonction de cette façon, mais je suppose qu'ils avaient besoin de l'autorisation EXECUTE plutôt que SELECT pour maintenir la cohérence. De nos jours, il s'agit probablement d'un bagage de compatibilité.

db2
la source