Dlaczego funkcje o wartościach skalarnych wymagają uprawnień do wykonywania, a nie wyboru?

15

Zastanawiam się, dlaczego w przypadku funkcji o wartości skalarnej muszę przyznać użytkownikowi wykonanie, a nie tylko wybór?

tymczasem funkcje cenione w tabeli działają dobrze, tylko z uprawnieniami do wyboru lub db_datareaderczłonkostwem.

dla lepszego wyjaśnienia oto mój przykład: potrzebuję użytkownika, który ma uprawnienia tylko do odczytu do bazy danych. więc utworzyłem użytkownika o nazwie testUseri nadałem mu db_datareaderczłonkostwo. następnie utworzyłem funkcję o wartości tabeli fn_InlineTable. I wszystko jest świetnie. testUseruruchamia ten SQL przez cały dzień

select * from dbo.fn_InlineTable

następnie potrzebuję funkcji skalarnej, więc utworzyłem funkcję skalarną o nazwie fn_ScalarTest. testUsernie można uruchomić tego SQL

Select dbo.fn_ScalarTest(1) 

Zrozumiałe: dzieje się tak, ponieważ nie dałem uprawnienia „testUser” do wykonania fn_ScalarTest.

Moje pytanie brzmi: w oparciu o ten link /programming/6150888/insert-update-delete-with-function-in-sql-server , który mówi, że FUNCTIONnie można użyć do wykonania akcji zmieniających stan bazy danych . Dlaczego więc nie pozwolić, aby funkcja skalarna była używana z tym samym uprawnieniem „WYBIERZ”, a nie wykonywać uprawnienia?

Mam nadzieję, że moje pytanie ma sens. Dziękuję Ci.

BobNoobGuy
źródło

Odpowiedzi:

15

Najprawdopodobniej głównym powodem jest to, że funkcje wyceniane w tabeli zwracają zestaw wyników, podobnie jak tabele i widoki. Oznacza to, że mogą one być stosowane w FROMklauzuli (włączając JOINs i APPLYs, etc.) z SELECT, UPDATEi DELETEzapytań. Nie można jednak użyć Skalarnego UDF w żadnym z tych kontekstów.

Po drugie, możesz także EXECUTESkalarny UDF. Ta składnia jest bardzo przydatna, gdy określono wartości domyślne parametrów wejściowych. Weźmy na przykład następujący UDF:

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

Jeśli chcesz traktować którykolwiek z parametrów wejściowych jako „opcjonalny”, nadal musisz podać DEFAULTsłowo kluczowe, nazywając go jak funkcję, ponieważ podpis jest stały:

DECLARE @Bob1 INT;

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

SELECT @Bob1;
-- Returns: 102

Z drugiej strony, jeśli masz EXECUTEtę funkcję, możesz traktować dowolne parametry o wartości domyślnej jako naprawdę opcjonalne, tak jak możesz to zrobić za pomocą procedur przechowywanych. Możesz przekazać pierwsze n parametrów bez określania nazw parametrów:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

Możesz nawet pominąć pierwszy parametr, ponownie określając nazwy parametrów, podobnie jak w przypadku procedur przechowywanych:

DECLARE @Bob3 INT;

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

SELECT @Bob3;
-- Returns: 51

AKTUALIZACJA

Dlaczego możesz chcieć użyć EXECskładni do wywołania skalarnego UDF, tak jak procedura przechowywana? Czasami istnieją UDF, które świetnie nadają się jako UDF, ponieważ można je dodawać do zapytania i operować na zestawie zwróconych wierszy, natomiast jeśli kod był w procedurze przechowywanej, należy go umieścić w kursorze, aby iterować po zestawie wierszy. Ale są chwile, kiedy chcesz wywołać tę funkcję na jednej wartości, być może z innego UDF. Wywołanie UDF dla pojedynczej wartości można wykonać jako:

SELECT dbo.UDF('some value');

w takim przypadku otrzymasz wartość zwracaną w zestawie wyników (zestaw wyników nie będzie działać). Lub można to zrobić w następujący sposób:

DECLARE @Dummy INT;

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

w takim przypadku musisz zadeklarować @Dummyzmienną;

JEDNAK dzięki EXECskładni możesz uniknąć obu tych niedogodności:

EXEC dbo.UDF 'some value';

TAKŻE, skalarne UDF mają buforowane swoje plany wykonania. Oznacza to, że można napotkać problemy z wąchaniem parametrów, jeśli w UDF są zapytania zawierające plany wykonania. W przypadku scenariuszy, w których możliwe jest użycie EXECskładni, można również użyć WITH RECOMPILEopcji zignorowania wartości skompilowanej planu dla tego wykonania . Na przykład:

USTAWIAĆ:

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

TEST:

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
źródło
4

Myślę, że różnica w uprawnieniach polega na tym, że za pomocą EXEC można wywoływać funkcje zdefiniowane przez użytkownika o wartości skalarnej, podobnie jak procedury składowane (czego nie zdałem sobie sprawy, dopóki nie zagłębiłem się w SQL Server 2000 Books Online, gdzie wprowadzono funkcje zdefiniowane przez użytkownika) , ale tak naprawdę nie możesz wybrać z nich źródła tabeli. Na przykład:

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

W tym przypadku dbo. pierwszy dzień_miesiąca jest funkcją zdefiniowaną przez użytkownika. Nie wiem, dlaczego miałbyś kiedykolwiek wywoływać funkcję w ten sposób, ale spekulowałbym, że wymagały one uprawnień WYKONAJ, a nie WYBIERZ, aby zachować spójność. Obecnie prawdopodobnie jest to tylko bagaż kompatybilności.

db2
źródło