使用 ALTER SCHEMA TRANSFER 时,对象上的权限消失

问题描述 投票:0回答:1

我们通过添加“_V1”、“_V2”等后缀来根据任何 ALTER 请求创建一个新的存储过程。 这样我们就可以保持应用程序和数据库之间的向后兼容性。

该标准使我们保留了许多旧版本的代码。 我们开始使用 ALTER SCHEMA [CanDel] TRANSFER 来仅保留存储过程的最后 4 个版本。 其他进程(作业)充当垃圾收集器 - 如果对象在“CanDel”模式中保留 3 个月,它将被删除。

但是,有时我们需要进行回滚并将其中一个存储过程传输回原始模式。

我们注意到旧的权限消失了。 我很想知道这个功能是设计使然还是被改变了。

我们使用 SQL Server 2022。

我添加了一个示例代码来重现。

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
SET NOCOUNT ON;
GO
USE tempdb;
GO
/* Cleanup */
IF OBJECT_ID('dbo.USP_PermissionsTest') IS NOT NULL
BEGIN
    DROP PROCEDURE dbo.USP_PermissionsTest;
END;
IF OBJECT_ID('CanDel.USP_PermissionsTest') IS NOT NULL
BEGIN
    DROP PROCEDURE CanDel.USP_PermissionsTest;
END;
GO
/* Create test role */
IF USER_ID('UDR_Test') IS NULL
    CREATE ROLE [UDR_Test];
GO
/* Create dummy stored procedure */
IF OBJECT_ID('dbo.USP_PermissionsTest') IS NULL
BEGIN
    EXEC('CREATE PROCEDURE dbo.USP_PermissionsTest AS');
END;
GO
/* grant permission to the stored procedure */
GRANT EXECUTE ON dbo.USP_PermissionsTest TO [UDR_Test];
GO
/* check permissions */
SELECT      USER_NAME(p.grantee_principal_id) AS principal_name,
            dp.principal_id,
            dp.type_desc                      AS principal_type_desc,
            p.class_desc,
            CASE p.class_desc
                WHEN 'DATABASE' THEN DB_NAME()
                WHEN 'SCHEMA' THEN SCHEMA_NAME(p.major_id)
                WHEN 'OBJECT_OR_COLUMN' THEN OBJECT_NAME(p.major_id)
                ELSE NULL
            END                               AS object_name,
            p.permission_name,
            p.state_desc                      AS permission_state_desc
FROM        sys.database_permissions           p
            INNER JOIN sys.database_principals dp ON p.grantee_principal_id = dp.principal_id
            LEFT OUTER JOIN sys.all_objects    o ON p.major_id = o.object_id
WHERE       p.grantee_principal_id = USER_ID('UDR_Test')
            AND o.object_id = OBJECT_ID('dbo.USP_PermissionsTest')
ORDER BY    o.name;
GO
/* Create different schema to a destination */
IF SCHEMA_ID('CanDel') IS NULL
BEGIN
    EXEC('CREATE SCHEMA [CanDel];');
END
GO 
/* Transfer stored procedure to other schema */
ALTER SCHEMA [CanDel] TRANSFER dbo.USP_PermissionsTest;
GO 
/* check permissions */
SELECT      USER_NAME(p.grantee_principal_id) AS principal_name,
            dp.principal_id,
            dp.type_desc                      AS principal_type_desc,
            p.class_desc,
            CASE p.class_desc
                WHEN 'DATABASE' THEN DB_NAME()
                WHEN 'SCHEMA' THEN SCHEMA_NAME(p.major_id)
                WHEN 'OBJECT_OR_COLUMN' THEN OBJECT_NAME(p.major_id)
                ELSE NULL
            END                               AS object_name,
            p.permission_name,
            p.state_desc                      AS permission_state_desc
FROM        sys.database_permissions           p
            INNER JOIN sys.database_principals dp ON p.grantee_principal_id = dp.principal_id
            LEFT OUTER JOIN sys.all_objects    o ON p.major_id = o.object_id
WHERE       p.grantee_principal_id = USER_ID('UDR_Test')
            AND o.object_id = OBJECT_ID('CanDel.USP_PermissionsTest')
ORDER BY    o.name;
GO
/* Cleanup */
IF OBJECT_ID('dbo.USP_PermissionsTest') IS NOT NULL
BEGIN
    DROP PROCEDURE dbo.USP_PermissionsTest;
END;
IF OBJECT_ID('CanDel.USP_PermissionsTest') IS NOT NULL
BEGIN
    DROP PROCEDURE CanDel.USP_PermissionsTest;
END;
GO
IF SCHEMA_ID('CanDel') IS NOT NULL
BEGIN
    EXEC('DROP SCHEMA [CanDel];');
END
GO 
sql-server t-sql
1个回答
0
投票

我编写了一个带有权限的传输包装器

CREATE OR ALTER PROCEDURE dbo.USP_TransferToSchemaWithPermissions
        @I_SourceSchema sysname = 'dbo',
        @I_SourceObject sysname = 'USP_PermissionsTest',
        @I_TargetSchema sysname = 'CanDel'
WITH EXECUTE AS OWNER
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @cmd NVARCHAR(MAX);
    DECLARE @crlf VARCHAR(2) = CHAR(13) + CHAR(10);
    SELECT @I_TargetSchema = REPLACE(REPLACE(@I_TargetSchema,']',''),'[','');
    SELECT @cmd = CONCAT(N'USE [',ORIGINAL_DB_NAME(),'];',@crlf,
    N'IF OBJECT_ID(@I_TargetSchema + ''.'' + @I_SourceObject) IS NULL',@crlf,
    N'BEGIN',@crlf,
    N'  DECLARE @icmd NVARCHAR(MAX) = N'''';',@crlf,
    N'  IF SCHEMA_ID(''',@I_TargetSchema,''') IS NULL EXEC(''CREATE SCHEMA [',@I_TargetSchema,'];'');',@crlf,
    N'  SELECT   @icmd += CONCAT(IIF(dp.class IN (1,3,6,24,25),''IF '' + CASE dp.class',@crlf,
    N'              WHEN 0 THEN ''''',@crlf,
    N'              WHEN 1 THEN',@crlf, --table or column subset on the table
    N'                  CASE WHEN dp.major_id < 0 THEN ''OBJECT_ID(''''sys.'' + OBJECT_NAME(dp.major_id) + '''''')''',@crlf,
    N'                  ELSE  ''OBJECT_ID('''''' + (SELECT @I_TargetSchema + ''.'' + name FROM sys.objects WHERE object_id = dp.major_id)+ '''''')'' END',@crlf,
    N'              WHEN 3 THEN ''SCHEMA_ID('''''' + @I_TargetSchema + '''''')''',@crlf,
    N'              WHEN 6 THEN ''TYPE_ID('''''' + (SELECT name FROM sys.types WHERE user_type_id = dp.major_id) + '''''')''',@crlf,
    N'              WHEN 24 THEN ''KEY_ID('''''' + (SELECT name FROM sys.symmetric_keys WHERE symmetric_key_id = dp.major_id) + '''''')''',@crlf,
    N'              WHEN 25 THEN ''CERT_ID('''''' + (SELECT name FROM sys.certificates WHERE certificate_id = dp.major_id) + '''''')''',@crlf,
    N'           END COLLATE DATABASE_DEFAULT + '' IS NOT NULL '',''''),',@crlf,
    N'          CASE dp.state',@crlf,
    N'              WHEN ''D'' THEN ''DENY ''',@crlf,
    N'              WHEN ''G'' THEN ''GRANT ''',@crlf,
    N'              WHEN ''R'' THEN ''REVOKE ''',@crlf,
    N'              WHEN ''W'' THEN ''GRANT ''',@crlf,
    N'          END,dp.permission_name,'' '',',@crlf,
    N'          CASE dp.class',@crlf,
    N'              WHEN 0 THEN ''''',@crlf,
    N'              WHEN 1 THEN',@crlf, --table or column subset on the table
    N'                  CASE WHEN dp.major_id < 0 THEN',@crlf,
    N'                      + ''ON [sys].['' + OBJECT_NAME(dp.major_id) + ''] ''',@crlf,
    N'                  ELSE',@crlf,
    N'                      + ''ON ['' +',@crlf,
    N'                      (SELECT @I_TargetSchema + ''].['' + name FROM sys.objects WHERE object_id = dp.major_id)',@crlf,
    N'                          +',@crlf, -- optionally concatenate column names
    N'                      CASE WHEN MAX(dp.minor_id) > 0 ',@crlf,
    N'                           THEN ''] (['' + REPLACE(',@crlf,
    N'                                          (SELECT name + ''], ['' ',@crlf,
    N'                                           FROM sys.columns ',@crlf,
    N'                                           WHERE object_id = dp.major_id ',@crlf,
    N'                                              AND column_id IN (SELECT minor_id ',@crlf,
    N'                                                                FROM sys.database_permissions ',@crlf,
    N'                                                                WHERE major_id = dp.major_id',@crlf,
    N'                                                                  AND USER_NAME(grantee_principal_id) IN (USER_NAME(dp.grantee_principal_id))',@crlf,
    N'                                                               )',@crlf,
    N'                                           FOR XML PATH('''')',@crlf,
    N'                                          )',@crlf, --replace final square bracket pair
    N'                                      + ''])'', '', []'', '''')',@crlf,
    N'                           ELSE '']''',@crlf,
    N'                      END + '' ''',@crlf,
    N'                  END',@crlf);
    SELECT @cmd += CONCAT(
    N'           END COLLATE DATABASE_DEFAULT,''TO ['',USER_NAME(dp.grantee_principal_id),'']'',',@crlf,
    N'           CASE dp.state WHEN ''W'' THEN '' WITH GRANT OPTION'' ELSE '''' END,'';'',@crlf)',@crlf,
    N'  FROM    sys.database_permissions dp',@crlf,
    N'  WHERE   dp.major_id = OBJECT_ID(@I_SourceSchema + ''.'' + @I_SourceObject)',@crlf,
    N'  GROUP BY dp.state, dp.major_id, dp.permission_name, dp.class,dp.grantee_principal_id;',@crlf,
    N'  ',@crlf,
    N'  ALTER SCHEMA [',@I_TargetSchema,'] TRANSFER [',@I_SourceSchema,'].[',@I_SourceObject,'];',@crlf,
    N'  EXEC sys.sp_executesql @icmd, N''@crlf VARCHAR(2),@I_SourceSchema sysname,@I_SourceObject sysname,@I_TargetSchema sysname'',',@crlf,
    N'      @crlf = @crlf,@I_SourceSchema = @I_SourceSchema, @I_SourceObject= @I_SourceObject, @I_TargetSchema = @I_TargetSchema;',@crlf,
    N'END',@crlf);

    EXEC sys.sp_executesql @cmd, N'@crlf VARCHAR(2),@I_SourceSchema sysname,@I_SourceObject sysname,@I_TargetSchema sysname',
        @crlf = @crlf,@I_SourceSchema = @I_SourceSchema, @I_SourceObject= @I_SourceObject, @I_TargetSchema = @I_TargetSchema;
END
GO
© www.soinside.com 2019 - 2024. All rights reserved.