繁体   English   中英

SQL Server 2019跨库function调用权限

[英]SQL Server 2019 cross-database function call permission

我在 SQL Server 2019 中遇到了一些有趣的行为——它似乎在早期版本中没有发生。

If, in database1, I call a function in the same database, which calls a function in database2, which SELECTS a table in database2, I get "The SELECT permission was denied on the object '{TableName}', database '{DbName} ',模式'dbo'。”

相反,如果我直接在 database2 中调用 function(在 database1 中不使用 function),则查询将成功执行。

架构图

我的问题是:这背后的逻辑是什么? I don't understand why I am allowed to read a table in another database, without the SELECT permission, through a function, but not when I call that function using a function in my current database? 是不是因为 function 阻止了权限的传递。 我目前假设这是一个有意的改变——但我不明白它背后的逻辑。

下面是一些以简单方式演示该行为的代码。

/*******************************************
SET UP
*******************************************/
CREATE DATABASE TestDb1
GO
CREATE DATABASE TestDb2
GO

CREATE LOGIN [TestLogin] WITH PASSWORD = '123456a.'
GO

--Create users in each database and add to roles.
USE TestDb1
CREATE USER [TestUser] FOR LOGIN [TestLogin]
CREATE ROLE Db1Role
ALTER ROLE Db1Role ADD MEMBER [TestUser]

USE TestDb2
CREATE USER [TestUser] FOR LOGIN [TestLogin]
CREATE ROLE Db2Role
ALTER ROLE Db2Role ADD MEMBER [TestUser]

--Create table in db1, but do no GRANTs on it.
USE TestDb1
CREATE TABLE dbo._testDb1Table (Col1 INT)
GO

--Create a function in db1, and GRANT EXECUTE.
CREATE FUNCTION dbo._TestDb1Function()
RETURNS INT
AS
BEGIN
    DECLARE @Result INT = (SELECT TOP (1) Col1 FROM dbo._testDb1Table)
    RETURN @Result
END
GO
GRANT EXECUTE ON dbo._TestDb1Function TO Db1Role
GO

--Create a function in db2, and GRANT EXECUTE.
USE TestDb2
GO
CREATE FUNCTION dbo._TestDb2Function()
RETURNS INT
AS
BEGIN
    DECLARE @Result INT = (SELECT TestDb1.dbo._TestDb1Function())
    RETURN @Result
END
GO
GRANT EXECUTE ON dbo._TestDb2Function TO Db2Role
GO

/*******************************************
TESTS
*******************************************/
USE TestDb2

--Querying TestDb1 by calling the TestDb2 function directly works.
EXECUTE AS LOGIN = 'TestLogin'
SELECT TestDb1.dbo._TestDb1Function()
REVERT
GO

--Querying TestDb2 through a scalar function in db2 doesn't work.
--The SELECT permission was denied on the object '_testDb1Table', database 'TestDb1', schema 'dbo'.
EXECUTE AS LOGIN = 'TestLogin'
SELECT dbo._TestDb2Function()
REVERT
GO

/*******************************************
TIDY UP
*******************************************/
USE [master]
DROP LOGIN [TestLogin]
DROP DATABASE TestDb1
DROP DATABASE TestDb2

根据 GSerg 和 Larnu 的有用评论,此行为似乎是由 SQL Server 2019 中添加的标量 UDF 内联功能引起的。

它可以通过在数据库级别禁用标量 UDF 内联、在 function 定义中或使用查询提示来修复。

编辑:根据 Razvan Socol 的回答,这已在 SQL Sever 2019 CU9 中修复。

这是与原始问题中给出的代码相同的代码,但将这 3 个可能的解决方案插入到适当的位置(已注释掉)。 取消注释这 3 个解决方案中的任何一个都允许脚本在 SQL Server 2019 中无错误地运行。

/*******************************************
SET UP
*******************************************/
CREATE DATABASE TestDb1
CREATE DATABASE TestDb2
GO
--SOLUTION 1: Turn off scalar UDF inlining at the database level.
--USE TestDb2
--ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = OFF;
GO

CREATE LOGIN [TestLogin] WITH PASSWORD = '123456a.'
GO

--Create users in each database and add to roles.
USE TestDb1
CREATE USER [TestUser] FOR LOGIN [TestLogin]
CREATE ROLE Db1Role
ALTER ROLE Db1Role ADD MEMBER [TestUser]

USE TestDb2
CREATE USER [TestUser] FOR LOGIN [TestLogin]
CREATE ROLE Db2Role
ALTER ROLE Db2Role ADD MEMBER [TestUser]

--Create table in db1, but do no GRANTs on it.
USE TestDb1
CREATE TABLE dbo._testDb1Table (Col1 INT)
GO

--Create a function in db1, and GRANT EXECUTE.
CREATE FUNCTION dbo._TestDb1Function()
RETURNS INT
AS
BEGIN
    DECLARE @Result INT = (SELECT TOP (1) Col1 FROM dbo._testDb1Table)
    RETURN @Result
END
GO
GRANT EXECUTE ON dbo._TestDb1Function TO Db1Role
GO

--Create a function in db2, and GRANT EXECUTE.
USE TestDb2
GO
CREATE FUNCTION dbo._TestDb2Function()
RETURNS INT
--SOLUTION 2: Turn off scalar UDF inlining for the function.
--WITH INLINE = OFF
AS
BEGIN
    DECLARE @Result INT = (SELECT TestDb1.dbo._TestDb1Function())
    RETURN @Result
END
GO
GRANT EXECUTE ON dbo._TestDb2Function TO Db2Role
GO

/*******************************************
TESTS
*******************************************/
USE TestDb2

--Querying TestDb1 by calling the TestDb2 function directly works.
EXECUTE AS LOGIN = 'TestLogin'
SELECT TestDb1.dbo._TestDb1Function()
REVERT
GO

--Querying TestDb2 through a scalar function in db2 doesn't work.
--The SELECT permission was denied on the object '_testDb1Table', database 'TestDb1', schema 'dbo'.
EXECUTE AS LOGIN = 'TestLogin'
SELECT dbo._TestDb2Function()
--SOLUTION 3: Turn off scalar UDF inlining for the query which calls the function.
--OPTION (USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING')); --Added line
REVERT
GO

/*******************************************
TIDY UP
*******************************************/
USE [master]
DROP LOGIN [TestLogin]
DROP DATABASE TestDb1
DROP DATABASE TestDb2

这是 SQL Server 2019 中的一个错误,由scalar UDF inlining 引起。 它已在SQL Server 2019 CU9 (2021 年 2 月发布)中修复。 有关更多详细信息,请参阅KB4538581

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM