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 de sélection ou db_datareader
adhésion.
pour être plus clair, voici mon exemple: j'ai besoin d'un utilisateur qui dispose d'une autorisation en lecture seule sur la base de données. j'ai donc créé un utilisateur appelé testUser
et je lui ai donné db_datareader
adhésion. puis j'ai créé une fonction de valeur de table appelée fn_InlineTable
. Et tout va bien. testUser
exé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
. testUser
ne peut pas exécuter ce SQL
Select dbo.fn_ScalarTest(1)
Bien entendu: c'est parce que je n'ai pas donné à "testUser" la permission d'exécuter fn_ScalarTest
.
Ma question est: basée sur ce lien https://stackoverflow.com/questions/6150888/insert-update-delete-with-function-in-sql-server , qui dit un FUNCTION
ne 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.
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 clause FROM
(y compris JOIN
s et APPLY
s, etc.) de SELECT
, UPDATE
, et DELETE
requêtes. Cependant, vous ne pouvez pas utiliser une FDU Scalar dans aucun de ces contextes.
Secondairement, vous pouvez également EXECUTE
une 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 passer le mot clé DEFAULT
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 EXECUTE
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 premiers n 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ètre, à 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 syntaxe EXEC
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');
auquel cas vous devez déclarer le @Dummy
variable;
TOUTEFOIS, avec la syntaxe EXEC
, 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 syntaxe EXEC
, il est possible d'utiliser également la WITH RECOMPILE
option 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;
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é.