¿Por qué las funciones de valor escalar necesitan permiso de ejecución en lugar de seleccionar?

15

Me pregunto por qué, para la función de valor escalar, tengo que otorgar al usuario la ejecución en lugar de solo una selección.

mientras tanto, una tabla con funciones valiosas funciona bien con solo seleccionar el permiso o la db_datareadermembresía.

para ser más claro, aquí está mi ejemplo: necesito un usuario que tenga permiso de solo lectura para la base de datos. así que creé un usuario llamado testUsery le doy db_datareadermembresía. luego creé una función con valores de tabla llamada fn_InlineTable. Y todo es genial. testUserejecuta este SQL todo el día

select * from dbo.fn_InlineTable

entonces necesito una función escalar, así que creé una función escalar llamada fn_ScalarTest. testUserno puede ejecutar este SQL

Select dbo.fn_ScalarTest(1) 

Bueno, comprensiblemente: es porque no he dado permiso a "testUser" para ejecutar fn_ScalarTest.

Mi pregunta es: en base a este enlace /programming/6150888/insert-update-delete-with-function-in-sql-server , que dice que FUNCTIONno se puede usar para realizar acciones que modifiquen el estado de la base de datos . Entonces, ¿por qué no dejar que se use una función escalar con el mismo permiso "SELECCIONAR" en lugar de ejecutar el permiso?

Espero que mi pregunta tenga sentido. Gracias.

BobNoobGuy
fuente

Respuestas:

15

Lo más probable es que la razón principal sea que las funciones con valores de tabla devuelven un conjunto de resultados, al igual que las tablas y vistas. Esto significa que se pueden utilizar en la FROMcláusula (incluyendo JOINs y APPLYs, etc.) de SELECT, UPDATEy DELETEconsultas. Sin embargo, no puede utilizar un UDF escalar en ninguno de esos contextos.

En segundo lugar, también puede EXECUTEun UDF escalar. Esta sintaxis es bastante útil cuando tiene valores predeterminados especificados para los parámetros de entrada. Tome el siguiente UDF, por ejemplo:

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

Si desea tratar cualquiera de los parámetros de entrada como "opcional", aún necesita pasar la DEFAULTpalabra clave al llamarla como una función ya que la firma es fija:

DECLARE @Bob1 INT;

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

SELECT @Bob1;
-- Returns: 102

Por otro lado, si utiliza EXECUTEla función, puede tratar cualquier parámetro con un valor predeterminado como realmente opcional, tal como puede hacerlo con los procedimientos almacenados. Puede pasar los primeros n parámetros sin especificar los nombres de los parámetros:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

Incluso puede omitir el primer parámetro especificando nombres de parámetros, nuevamente, al igual que con los Procedimientos almacenados:

DECLARE @Bob3 INT;

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

SELECT @Bob3;
-- Returns: 51

ACTUALIZAR

¿Por qué querrías usar la EXECsintaxis para llamar a un UDF escalar como un procedimiento almacenado? Ocasionalmente, hay UDF que es genial tener como UDF ya que se pueden agregar a una consulta y operar sobre el conjunto de filas devueltas, mientras que si el código estuviera en un Procedimiento almacenado, entonces debería colocarse en un cursor para iterar sobre un conjunto de filas. Pero luego hay veces que desea llamar a esa función con un solo valor, posiblemente desde otro UDF. Llamar a un UDF por un solo valor se puede hacer como:

SELECT dbo.UDF('some value');

en cuyo caso obtendrá un valor de retorno en un conjunto de resultados (un conjunto de resultados no funcionará). O podría hacerse de la siguiente manera:

DECLARE @Dummy INT;

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

en cuyo caso necesita declarar la @Dummyvariable;

SIN EMBARGO, con la EXECsintaxis, puede evitar ambas molestias:

EXEC dbo.UDF 'some value';

TAMBIÉN, los UDF escalares tienen sus planes de ejecución en caché. Esto significa que es posible encontrarse con problemas de detección de parámetros si hay consultas en el UDF que tienen planes de ejecución. Para escenarios donde es factible usar la EXECsintaxis, también es posible usar la WITH RECOMPILEopción de ignorar el valor compilado de los planes para esa ejecución . Por ejemplo:

PREPARAR:

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

PRUEBA:

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
fuente
4

Creo que la diferencia en los permisos se debe a que en realidad puede invocar funciones definidas por el usuario con valores escalares con EXEC al igual que los procedimientos almacenados (que no me había dado cuenta hasta que busqué en SQL Server 2000 Books Online, donde introdujeron funciones definidas por el usuario) , sin embargo, no puede seleccionarlos como fuente de tabla. Por ejemplo:

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

En este caso, dbo.first_day_of_month es una función definida por el usuario. No sé por qué invocaría una función de esa manera, pero especularía que requieren el permiso EJECUTAR en lugar de SELECCIONAR para mantener la coherencia. Hoy en día probablemente solo se mantenga como equipaje de compatibilidad.

db2
fuente