• SQL Server执行sp_changeobjectowner遇到"Msg 15001, Level 16,..."错误探究


    在SQL Server中使用sp_changeobjectowner存储过程修改对象所有者(Owner)时,可能会遇到下面错误信息,当然对象klb.[k3]这个表确实是存在的。如下所示:

     

    注意:个人测试环境为SQL Server 2014的标准版,如有不同情况,请以实际环境为准。

     

    USE AdventureWorks2014;
    GO
    EXEC sp_changeobjectowner 'klb.k3', 'dbo';
    GO

     

    Msg 15001, Level 16, State 1, Procedure sp_changeobjectowner, Line 81

    Object 'klb.[V_Test]' does not exist or is not a valid object for this operation.

     

     

    clip_image001

     

     

    当然你再次执行的话,可能会遇到同样的错误提示,但是Line的值有所变化,变成了99.  (这里是因为在脚本第二处抛出错误)

     

    Msg 15001, Level 16, State 1, Procedure sp_changeobjectowner, Line 99

    Object 'klb.[k3]' does not exist or is not a valid object for this operation.

     

     

    我们获取sp_changeobjectowner存储过程的定义如下:

     

    SET QUOTED_IDENTIFIER ON
    SET ANSI_NULLS ON
    GO
    create procedure sys.sp_changeobjectowner
        @objname    nvarchar(776),        -- may be "[owner].[object]"
        @newowner    sysname                -- must be entry from sysusers
    as
        Set nocount      on
        Set ansi_padding on
        declare    @objid        int,
                @newuid        int,
                @ret        int,
                @oldowner    sysname,
                @stmtS        nvarchar(4000)
     
        -- CHECK PERMISSIONS: Because changing owner changes both schema and
        --    permissions, the caller must be one of:
        -- (1) db_owner
        -- (2) db_ddladmin AND db_securityadmin
        if (is_member('db_owner') = 0) and
            (is_member('db_securityadmin') = 0 OR is_member('db_ddladmin') = 0)
        begin
            EXEC %%System().AuditEvent(ID = 1094864724, Success = 0, TargetLoginName = NULL, TargetUserName = @newowner, Role = NULL, Object = @objname, Provider = NULL, Server = NULL)
            raiserror(15247,-1,-1)
            return (1)
        end
        else
        begin
            EXEC %%System().AuditEvent(ID = 1094864724, Success = 1, TargetLoginName = NULL, TargetUserName = @newowner, Role = NULL, Object = @objname, Provider = NULL, Server = NULL)
        end
     
        if parsename(@objname, 1) is null
        begin
            raiserror(15253, -1, -1, @objname)
            return (1)
        end
     
        BEGIN TRANSACTION
     
        -- RESOLVE OBJECT NAME (CANNOT BE A CHILD OBJECT: TRIGGER/CONSTRAINT) --
        select @objid = object_id(@objname, 'local')
        if not (@objid is null)
        begin
            EXEC %%Object(MultiName = @objname).LockMatchID(ID = @objid, Exclusive = 1, BindInternal = 0)
            if (@@error <> 0)    -- lock failed
                select @objid = null
        end
        if (@objid is null) OR
            (select parent_obj from sysobjects where id = @objid) <> 0 OR
            ObjectProperty(@objid, 'IsSystemTable') = 1 OR
            parsename(@objname, 3) is not null OR
            parsename(@objname, 4) is not null OR
            exists (select * from sys.objects where object_id = @objid and schema_id in (3,4))  OR -- INFORMATION_SCHEMA, sys
            -- Check for Dependencies: No RENAME or CHANGEOWNER of OBJECT when exists:
            EXISTS (SELECT * FROM sysdepends d WHERE
                d.depid = @objid        -- A dependency on this object
                AND d.deptype > 0        -- that is enforced
                AND @objid <> d.id        -- that isn't a self-reference (self-references don't use object name)
                AND @objid <>            -- And isn't a reference from a child object (also don't use object name)
                    (SELECT o.parent_obj FROM sysobjects o WHERE o.id = d.id)
                )
        begin
            -- OBJECT NOT FOUND
            COMMIT TRANSACTION
            raiserror(15001,-1,-1,@objname)
            return 1
        end
     
        -- object's schema name must be the same as the schema owner's name
        if not exists (select so.name 
            from sys.objects so
            join sys.schemas ss on so.schema_id = ss.schema_id 
            join sys.database_principals su on ss.principal_id = su.principal_id
            where object_id = @objid and so.principal_id is null and ss.name = su.name)
        begin
            -- OBJECT NOT FOUND
            COMMIT TRANSACTION
            raiserror(15001,-1,-1,@objname)
            return 1
        end
        
        select @oldowner = ssch.name from sys.schemas ssch join sys.objects so on (so.schema_id = ssch.schema_id) where object_id = @objid
        -- SHARE LOCK OLD SCHEMA, PREVENT DROP OF THE OWNER WHILE TXN ACTIVE --
            -- (rollback could cause phantom owner) --
        EXEC %%ObjectSchema (Name = @oldowner).Lock(Exclusive = 0) -- should succeed due to object lock above
     
        -- SHARE LOCK NEW SCHEMA --
        EXEC %%ObjectSchema (Name = @newowner).Lock(Exclusive = 0) -- may fail, check below anyway
     
        -- RESOLVE NEW OWNER NAME (ATTEMPT ADDING IMPLICIT ROW FOR NT NAME) --
        --  Disallow aliases, and public cannot own objects --
        if @@error = 0 -- lock success, indicate new owner may exist, verify further
            select @newuid = schema_id from sys.schemas where name = @newowner
                                and schema_id not in (3,4) -- INFORMATION_SCHEMA, sys
     
        if @newuid is null -- indicate lock failed
        begin
            EXEC @ret = sys.sp_MSadduser_implicit_ntlogin @newowner
            if (@ret = 0) -- success
                select @newuid = schema_id from sys.schemas where name = @newowner
                -- Member locked by sp_MSadduser_implicit_ntlogin
        end
     
        if @newuid is null OR
            -- the schema name and its owner name must be the same
            not exists (select ss.name
                from sys.schemas ss
                join sys.database_principals su on ss.principal_id = su.principal_id
                where ss.name = @newowner and ss.name = su.name)
        begin
            -- Implicit login added above is not rolled back
            -- This is same as SQL 2000
            COMMIT TRANSACTION
            raiserror(15411, -1, -1, @newowner)
            return (1)
        end
     
        select @stmtS = 'ALTER SCHEMA '
        select @stmtS = @stmtS + quotename(@newowner)
        select @stmtS = @stmtS + ' TRANSFER '
        if parsename(@objname, 2) is not null
            select @stmtS = @stmtS + quotename(parsename(@objname, 2)) + '.'
        select @stmtS = @stmtS + quotename(parsename(@objname, 1))
     
        exec (@stmtS)
        IF @@ERROR <> 0
        BEGIN
            -- Nested transaction is used by alter schema statement
            COMMIT TRANSACTION
            return (1)
        END
     
        COMMIT TRANSACTION
        -- WARNING AFTER THE OWNER TRANSFER --
        raiserror(15477,-1,-1)
        return (0)    -- sp_changeobjectowner
     
    GO

    通过分析存储过程,我们发现在两个地方可能抛出Msg 15001的错误信息,如下所示

     

    if (@objid is null) OR
        (select parent_obj from sysobjects where id = @objid) <> 0 OR
        ObjectProperty(@objid, 'IsSystemTable') = 1 OR
        parsename(@objname, 3) is not null OR
        parsename(@objname, 4) is not null OR
        exists (select * from sys.objects where object_id = @objid and schema_id in (3,4))  OR -- INFORMATION_SCHEMA, sys
        -- Check for Dependencies: No RENAME or CHANGEOWNER of OBJECT when exists:
        EXISTS (SELECT * FROM sysdepends d WHERE
            d.depid = @objid        -- A dependency on this object
            AND d.deptype > 0        -- that is enforced
            AND @objid <> d.id        -- that isn't a self-reference (self-references don't use object name)
            AND @objid <>            -- And isn't a reference from a child object (also don't use object name)
                (SELECT o.parent_obj FROM sysobjects o WHERE o.id = d.id)
            )
    begin
        -- OBJECT NOT FOUND
        COMMIT TRANSACTION
        raiserror(15001,-1,-1,@objname)
        return 1
    end

     

     

    -- object's schema name must be the same as the schema owner's name
    if not exists (select so.name 
        from sys.objects so
        join sys.schemas ss on so.schema_id = ss.schema_id 
        join sys.database_principals su on ss.principal_id = su.principal_id
        where object_id = @objid and so.principal_id is null and ss.name = su.name)
    begin
        -- OBJECT NOT FOUND
        COMMIT TRANSACTION
        raiserror(15001,-1,-1,@objname)
        return 1
    end

     

    然后我们分析发现在第二个SQL会因为不满足条件,抛出错误信息,具体分析截图所示

     

    clip_image002

     

    其实从脚本的注释信息object's schema name must be the same as the schema owner's name我们已经知道,这个脚本有个逻辑,判断对象的schema name和schema owner's name是否一致,如果不一致的话,就会抛出错误信息。而这里遇到这个问题是因为我们下面脚本恰恰修改了klb这个schema的schema owner,所以才导致了这个错误出现。

     

    USE AdventureWorks2014;
    GO
    ALTER AUTHORIZATION ON SCHEMA::[klb]  TO [dbo];

     

     

    clip_image003

     

    这里将klb的schema owner修改回来,然后执行sp_changeobjectowner就会OK了。

     

    USE AdventureWorks2014;
    GO
    ALTER AUTHORIZATION ON SCHEMA::[klb]  TO [klb];
    GO
    USE AdventureWorks2014;
    GO
    EXEC sp_changeobjectowner 'klb.[k3]', 'dbo';
    GO
    扫描上面二维码关注我
    如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.
  • 相关阅读:
    NEERC 15 (10/12)
    uoj259 & 独立集问题的一些做法
    Berlekamp-Massey算法简单介绍
    树链剖分的一种用法
    长链剖分
    [黑科技]常数优化的一些技巧
    tarjan解决路径询问问题
    Comet OJ
    洛谷P3835 【模板】可持久化平衡树(FHQ Treap)
    LOJ#107. 维护全序集(FHQ Treap)
  • 原文地址:https://www.cnblogs.com/kerrycode/p/14446167.html
Copyright © 2020-2023  润新知