use master
go

dump tran master with no_log
go

exec dbo.sp_configure 'allow updates',1
go
reconfigure with override
go

set ANSI_NULLS off

exec sp_MS_upd_sysobj_category 1
go

--------------------------------------------------------------------------------
--.	System objects (replsys.sql)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--. sp_MSispulldistributionjobnamegenerated
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSispulldistributionjobnamegenerated')
drop procedure sp_MSispulldistributionjobnamegenerated
go

raiserror('Creating procedure sp_MSispulldistributionjobnamegenerated', 0,1) with nowait
go
--
-- Name: sp_MSispulldistributionjobnamegenerated
--
-- Descriptions: This procedure checks whether a given job id corresponds to
--               a pull distribution agent job with a name generated by replication. 
--               If so, a return value of zero will be returned, otherwise
--               a value of one will be returned to the caller.
-- 
-- Notes: 1) For this procedure to be effective, it must match the current
--           pull distribution agent name generation algorithm. Note that the 
--           algorithm used for matching auto-generated job name is not 
--           exact. (See sp_addpullsubscription_agent replsys.sql)
--        2) This procedure is supposed to be executed at the subscriber
--           database. The subscriber server name and subscriber database
--           name for contructing the generated job name are obtained via
--           the serverproperty('ServerName') and the db_name() functions. 
--
-- Parameters: @publisher     sysname
--             @publisher_db  sysname
--             @publication   sysname (This can be null for shared agent)
--             @job_id        uniqueidentifier
--
-- Returns: 0 - If the specified jobid corresponds to a snapshot job with
--              a generated name.
--          1 - Otherwise
--
-- Security: This is an internal system procedure.
--
create procedure dbo.sp_MSispulldistributionjobnamegenerated (
    @publisher     sysname,
    @publisher_db  sysname,
    @publication   sysname,
    @job_id        uniqueidentifier
    )
as
begin
    set nocount on

    declare @generated_job_name nvarchar(4000)
    declare @generated_job_name_length int
    declare @job_name sysname

    select @job_name = null
    select @job_name = name
      from msdb.dbo.sysjobs_view 
     where job_id = @job_id

    if @job_name is null
    begin
        goto MISMATCH
    end

    -- First of all, make sure that the job is indeed a distribution agent
    -- job (there should be a step with Distribution as the subsystem in the 
    -- job)
    if not exists (select * 
                     from msdb.dbo.sysjobsteps
                    where job_id = @job_id
                      and upper(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DISTRIBUTION')
    begin
        goto MISMATCH
    end
                    
    -- Pull distribution agent names are always generated with a guid
    select @generated_job_name = left(@publisher, 21) + N'-'
                               + left(@publisher_db, 21) + N'-'
                               + left(@publication, 21) + N'-'
                               + left(convert(nvarchar(4000),serverproperty('ServerName')), 21) + N'-'
                               + left(db_name(), 21) + N'-'

    select @generated_job_name_length = len(@generated_job_name)

    -- Try matching the prefix of the job name
    if left(@job_name, @generated_job_name_length) = @generated_job_name
    begin
        -- Checks if the tail end of the job name matches a hexadecimal guid 
        -- with embedded dashes
        if upper(right(@job_name, len(@job_name) - @generated_job_name_length) collate SQL_Latin1_General_CP1_CS_AS)
            like N'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]'
        begin
            return 0
        end
        else
        begin
            goto MISMATCH
        end
    end

MISMATCH:
    if @job_name is not null
    begin
        raiserror(21695, -1, -1, @job_name)
    end
    return 1
end
go
exec sp_MS_marksystemobject 'dbo.sp_MSispulldistributionjobnamegenerated'

--------------------------------------------------------------------------------
--. sp_MSispullmergejobnmaegenerated
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSispullmergejobnamegenerated')
drop procedure sp_MSispullmergejobnamegenerated
go

raiserror('Creating procedure sp_MSispullmergejobnamegenerated', 0,1) with nowait
go
--
-- Name: sp_MSispullmergejobnamegenerated
--
-- Descriptions: This procedure checks whether a given job id corresponds to
--               a pull merge agent job with a name generated by replication. 
--               If so, a return value of zero will be returned, otherwise
--               a value of one will be returned to the caller.
-- 
-- Notes: 1) For this procedure to be effective, it must match the current
--           pull merge agent name generation algorithm. Note that the 
--           algorithm used for matching auto-generated job name is not 
--           exact. (See sp_addmergepullsubscription_agent replsys.sql)
--        2) This procedure is supposed to be executed at the subscriber
--           database. The subscriber server name and subscriber database
--           name for contructing the generated job name are obtained via
--           the serverproperty('ServerName') and the db_name() functions. 
--
-- Parameters: @publisher     sysname
--             @publisher_db  sysname
--             @publication   sysname (This can be null for shared agent)
--             @job_id        uniqueidentifier
--
-- Returns: 0 - If the specified jobid corresponds to a snapshot job with
--              a generated name.
--          1 - Otherwise
--
-- Security: This is an internal system procedure.
--
create procedure dbo.sp_MSispullmergejobnamegenerated (
    @publisher    sysname,
    @publisher_db sysname,
    @publication  sysname,
    @job_id       uniqueidentifier
    )
as
begin
    set nocount on
    
    declare @generated_job_name nvarchar(4000)
    declare @generated_job_name_length int
    declare @job_name sysname

    select @job_name = null
    select @job_name = name
      from msdb.dbo.sysjobs_view
     where job_id = @job_id

    if @job_name = null
    begin
        goto MISMATCH
    end
    
    -- First of all, make sure that the given job is indeed a merge agent
    -- job (There should be a step with Distribution as the subsystem in the 
    -- job)
    if not exists (select * 
                     from msdb.dbo.sysjobsteps
                    where job_id = @job_id
                      and upper(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'MERGE')
    begin
        goto MISMATCH
    end
    
    -- Pull merge agent names are always generated with a - 0 extension
    select @generated_job_name = left(@publisher, 23) + N'-'
                               + left(@publisher_db, 23) + N'-'
                               + left(@publication, 23) + N'-'
                               + left(convert(nvarchar(4000),serverproperty('ServerName')), 23) + N'-'
                               + left(db_name(), 23) + N'- 0'

    if @job_name = @generated_job_name
    begin
        return 0
    end    

MISMATCH:
    if @job_name is not null
    begin
        raiserror(21695, -1, -1, @job_name)
    end
    return 1
end
go
exec sp_MS_marksystemobject 'dbo.sp_MSispullmergejobnamegenerated'

--------------------------------------------------------------------------------
--. sp_droppullsubscription
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_droppullsubscription')
drop procedure sp_droppullsubscription
go

raiserror('Creating procedure sp_droppullsubscription', 0,1)
go

CREATE PROCEDURE sp_droppullsubscription (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,   /* publication name */
    @reserved bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */


    DECLARE @name nvarchar(255)
    DECLARE @retcode int
    DECLARE @agent_id binary(16)
    DECLARE @publisher_ex sysname          /* Expression used in the cursor */
    DECLARE @publisher_db_ex sysname     /* Expression used in the cursor */
    DECLARE @publication_ex sysname      /* Expression used in the cursor */
    DECLARE @expanded bit
    DECLARE @subscription_type_id int
    DECLARE @count_sub int
    DECLARE @drop_null_pub bit
    DECLARE @drop_push_bit bit
    DECLARE @push int
    DECLARE @implicit_transaction int
    DECLARE @close_cursor_at_commit int
    DECLARE @owner_sid varbinary(85)
    DECLARE @owner_name sysname
    DECLARE @qualified_publication_name nvarchar(512)
    
    /* 
    ** Initialization
    */
    SELECT @expanded = 0
    SELECT @drop_null_pub = 0
    SELECT @push = 0

    /*
    ** Get the original set value off IMPLICIT_TRANSACTIONS and CURSOR_CLOSE_ON_COMMIT
    **      before set these two to off
    */
    select @implicit_transaction = 0
    select @close_cursor_at_commit = 0
    IF (@reserved = 0)
    BEGIN
        SELECT @implicit_transaction = @@options & 2
        SELECT @close_cursor_at_commit = @@options & 4
        SET IMPLICIT_TRANSACTIONS OFF
        SET CURSOR_CLOSE_ON_COMMIT OFF
    END

    /*
    ** Security Check
    */

    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
    IF @@ERROR <> 0 or @retcode <> 0
        RETURN(1)

    SELECT @drop_push_bit = 0   
    
    /*
    ** Check parameter and set expressions used by cursor
    */
    
    /* Publisher */
    IF @publisher IS NULL
    BEGIN
        RAISERROR (14043, 16, -1, '@publisher')
        RETURN (1)
    END

    IF @publisher = 'all'
    BEGIN
        SELECT @publisher_ex = '%'
        SELECT @expanded = 1
    END
    ELSE
    BEGIN
        EXECUTE @retcode = dbo.sp_validname @publisher
        IF @retcode <> 0
        RETURN (1)
        SELECT @publisher_ex = @publisher
    END


    /* Publisher_db */
    IF @publisher_db IS NULL
    BEGIN
            RAISERROR (14043, 16, -1, '@publisher_db')
            RETURN (1)
    END

    IF @publisher_db = 'all'
    BEGIN
        SELECT @publisher_db_ex = '%'
        select @expanded = 1
    END
    ELSE
    BEGIN
        /*
        EXECUTE @retcode = dbo.sp_validname @publisher_db
        IF @retcode <> 0
        RETURN (1)
        */
        SELECT @publisher_db_ex = @publisher_db
    END

    /* 
    ** Publication
    ** '' is not a valid name but it may be in the publication name in the table. 
    */
    IF @publication IS NULL OR @publication = ''
    BEGIN
        SELECT @drop_null_pub = 1
    END
    ELSE IF @publication = 'all'
    BEGIN
        SELECT @publication_ex = '%'
        SELECT @expanded = 1
        SELECT @drop_null_pub = 1
    END
    ELSE
    BEGIN
        EXECUTE @retcode = dbo.sp_validname @publication
        IF @retcode <> 0
        RETURN (1)
        SELECT @publication_ex = @publication
    END

    /*
    ** Check to see if the  subscription table exists
    */
    IF NOT EXISTS (SELECT * FROM sysobjects 
                WHERE type = 'U' AND
                      name = 'MSreplication_subscriptions')
    BEGIN
        IF @expanded = 0
        BEGIN
            RAISERROR(14135, 11, -1,  @publisher, 
                @publisher_db, @publication)
            RETURN(1)
        END
        ELSE
            RETURN(0)
    END

    IF @expanded = 0 
    BEGIN 
        /*
        **
        ** Check to see if the subscription entry exists
        */
        IF  NOT EXISTS (SELECT * FROM  MSreplication_subscriptions 
                    WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db = @publisher_db AND
                      publication = @publication)     
        BEGIN
            RAISERROR(14135, 11, -1, @publisher, @publisher_db, @publication)
            RETURN(1)
        END

        /* 
        ** Make sure the subscription is not push type if @drop_push_bit = 0
        */
        IF @drop_push_bit = 0
        BEGIN
            IF EXISTS (SELECT * FROM MSreplication_subscriptions 
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                  publisher_db = @publisher_db AND
                  publication = @publication AND
                  subscription_type = @push AND
                  @drop_push_bit = 0)
            BEGIN
                RAISERROR(20017, 16, -1)
                RETURN(1)
            END
        END

    END
    ELSE
    /* 
    ** Open a cursor and call recursively if
    ** parameters are expanded.
    */
    BEGIN

        /*      
        **  Note: Any expression check on null value is false
        ** @subscription_type_id is NULL <==> push
        ** @subscription_type_id is NOT NULL <==> non push
        */
        -- Have to use static cursor option because 
        DECLARE hCdroppullsubscription CURSOR STATIC LOCAL FORWARD_ONLY FOR
            SELECT DISTINCT publisher, publisher_db, publication    
                FROM MSreplication_subscriptions
                WHERE ((@publisher_ex = N'%') OR (UPPER(publisher) = UPPER(@publisher_ex))) AND
                                          ((@publisher_db_ex = N'%') OR ( publisher_db = @publisher_db_ex)) AND
                      (publication LIKE @publication_ex OR
                      (@drop_null_pub = 1 AND
                      publication IS NULL)) AND
                      ((@drop_push_bit =0 AND
                      subscription_type <> @push) OR
                      @drop_push_bit = 1)
        FOR READ ONLY
        OPEN hCdroppullsubscription

        FETCH hCdroppullsubscription INTO @publisher, 
            @publisher_db, @publication
        WHILE (@@fetch_status <> -1)
        BEGIN
            EXECUTE @retcode  = dbo.sp_droppullsubscription @publisher = @publisher, 
                @publisher_db = @publisher_db, @publication = @publication, 
                @reserved = 1

            FETCH hCdroppullsubscription INTO @publisher, 
                @publisher_db, @publication
        END

        CLOSE hCdroppullsubscription
        DEALLOCATE hCdroppullsubscription
        RETURN (0)
    END
    
    /*
    ** Only members of the sysadmin group and the creator of the distribution
    ** agent can drop a pull subscription successfully. This behavior matches 
    ** the behavior of the sysjobs_view. DBO of the subscriber database, 
    ** sysadmins (owner is undefined) can drop a subscription if the owner_sid 
    ** is null.
    */

    EXEC sp_MSget_pullsubsagent_owner @publisher = @publisher,
                                      @publisher_db = @publisher_db,
                                      @publication = @publication,
                                      @owner_sid = @owner_sid OUTPUT

    IF (@owner_sid is not null AND
        (SUSER_SID() <> @owner_sid) AND
        (ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) = 0))
    BEGIN
        SELECT @owner_name = SUSER_SNAME(@owner_sid)
        SELECT @qualified_publication_name = @publisher + N':' + 
                                             @publisher_db + N':' +
                                             @publication
        RAISERROR(21121,16,-1,@owner_name, @qualified_publication_name) 
        RETURN (1)
    END

    /* 
    ** Get the agent name, it may be dropped later.
    */
    SELECT @agent_id = agent_id FROM MSreplication_subscriptions
                    WHERE UPPER(publisher) = UPPER(@publisher) AND
                          publisher_db  = @publisher_db AND
                          publication = @publication 

    -- If the agent is used by other subscription, don't drop it.
    if (select count(*) from MSreplication_subscriptions where
        agent_id = @agent_id) > 1
        select @agent_id = NULL

    begin tran
    save TRAN droppullsubscription

    /*
    ** Drop the subscription entry and the distribution agent if it exists 
    */


    /* 
    ** If the distribution agent is not used anymore,
    ** drop the agent if it exists
    */

    IF @agent_id IS NOT NULL
    BEGIN
        IF (EXISTS (SELECT * FROM msdb..sysjobs_view WHERE job_id = @agent_id))
        BEGIN
            -- Checks if the job name matches one that is generated
            -- by replication
            EXEC @retcode = dbo.sp_MSispulldistributionjobnamegenerated
                               @publisher = @publisher,
                               @publisher_db = @publisher_db,
                               @publication = @publication,
                               @job_id = @agent_id
            IF @@ERROR <> 0
                GOTO UNDO

            -- Only drop jobs if the name was generated
            IF @retcode = 0
            BEGIN
                EXEC @retcode = msdb.dbo.sp_delete_job @job_id = @agent_id
                IF @@ERROR <> 0 or @retcode <> 0
                    GOTO UNDO

                -- Delete MSreplication_subsciptions table after dropping 
                -- the distribution agent and delay one second
                -- to avoid deadlock with it.
                WAITFOR DELAY '00:00:01'
            END
        END

    END

    /* Call sp_MSunregistersubscription so that the reg entries get deleted */
    declare @subscriber_db sysname
    set @subscriber_db = DB_NAME()
    exec @retcode = dbo.sp_MSunregistersubscription @publisher = @publisher,
                                @publisher_db = @publisher_db,
                                @publication = @publication,
                                @subscriber = @@SERVERNAME,
                                @subscriber_db = @subscriber_db

    IF @retcode<>0 or @@ERROR<>0
        GOTO UNDO
    /*
    -- Delete MSreplication_subsciptions table after dropping the distribution agent\
    -- To avoid deadlock with it.
    --DELETE MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher) AND
        --publisher_db  = @publisher_db AND
        --publication = @publication 
    
    --IF @@ERROR <> 0 
    --  GOTO UNDO

    */
    
    IF EXISTS(select * from sysobjects where type='U' and name = 'MSsubscription_properties')
    BEGIN
        DELETE FROM MSsubscription_properties 
        WHERE UPPER(publisher) = UPPER(@publisher)  AND
        publisher_db  = @publisher_db AND
        publication = @publication 

        IF @@ERROR <> 0 
            GOTO UNDO

        IF NOT EXISTS (SELECT * FROM MSsubscription_properties)
        BEGIN
            exec @retcode = dbo.sp_MSsub_cleanup_prop_table
            IF @@ERROR <> 0 or @retcode <> 0
                GOTO UNDO
        END
    END
    
    /*
    ** Clean up metadata at subscriber side
    */
    -- Note: sp_subscription_cleanup should be called after deleting the row
    -- in MSreplication_subscriptions.
    exec @retcode = dbo.sp_subscription_cleanup @publisher = @publisher,
                                            @publisher_db  = @publisher_db,
                                            @publication = @publication
    IF @retcode<>0 or @@ERROR<>0
        GOTO UNDO

    --
    -- drop table MSreplication_subscriptions if empty and
    -- not in recursive call
    --
    IF EXISTS (SELECT * 
                 FROM sysobjects 
                WHERE name = 'MSreplication_subscriptions' 
                  AND type = 'U')
    BEGIN
        IF (@reserved = 0 AND 
            NOT EXISTS (SELECT * FROM MSreplication_subscriptions))
        BEGIN
            DROP TABLE MSreplication_subscriptions
            IF @@ERROR <> 0 
                GOTO UNDO
        END
    END

    COMMIT TRAN
    /*
    ** set back the two settings if needed 
    */
    if @reserved = 0
    BEGIN
        IF @implicit_transaction <>0 
            SET IMPLICIT_TRANSACTIONS ON
        IF @close_cursor_at_commit <>0 
            SET CURSOR_CLOSE_ON_COMMIT ON
    END
    RETURN (0)

UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN droppullsubscription
        COMMIT TRAN   
    end
    /*
    ** set back the two settings if needed
    */
    if @reserved = 0
    BEGIN
        IF @implicit_transaction <>0 
            SET IMPLICIT_TRANSACTIONS ON
        IF @close_cursor_at_commit <>0 
            SET CURSOR_CLOSE_ON_COMMIT ON
    END

    return 1
go
exec sp_MS_marksystemobject 'dbo.sp_droppullsubscription'
grant execute on dbo.sp_droppullsubscription to public
--------------------------------------------------------------------------------
--. sp_dropmergepullsubscription
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_dropmergepullsubscription')
drop procedure sp_dropmergepullsubscription
go
raiserror('Creating procedure sp_dropmergepullsubscription', 0,1)
GO
CREATE PROCEDURE sp_dropmergepullsubscription(
    @publication        sysname = NULL,             /* Publication name */
    @publisher          sysname = NULL,             /* Publisher server */
    @publisher_db       sysname = NULL,             /* Publication database */
    @reserved           bit = 0
    )AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    declare @retcode                int
    declare @subscriber_srvid       int
    declare @publisher_srvid        int
    declare @pubid                  uniqueidentifier
    declare @subid                  uniqueidentifier
    declare @partnerid              uniqueidentifier 
    declare @local_server           sysname
    declare @local_db               sysname
    declare @merge_jobid            binary(16)
    declare @cmd                    nvarchar(255)
    declare @pubidstr               nvarchar(38)
    declare @subscriber             sysname
    declare @subscriber_db          sysname
    declare @subscriber_type        int
    declare @local_job              bit
    declare @implicit_transaction   int
    declare @close_cursor_at_commit int
    declare @owner_sid              varbinary(85)
    declare @owner_name             sysname
    declare @qualified_publication_name nvarchar(512)


    select @close_cursor_at_commit = 0
    select @implicit_transaction = 0

    /*
    ** Get original setting values before setting them to false for recursive calling
    */
    IF (@reserved = 0)
    BEGIN
        SELECT @implicit_transaction = @@options & 2
        SELECT @close_cursor_at_commit = @@options & 4
        SET IMPLICIT_TRANSACTIONS OFF
        SET CURSOR_CLOSE_ON_COMMIT OFF
    END

    /* 
    ** Security Check.
    */
    exec @retcode = dbo.sp_MSreplcheck_subscribe
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

     /*
    ** Initializations.
    */              
    set @local_db = DB_NAME()
    set @local_server = @@SERVERNAME
    set @subscriber = @@SERVERNAME   
    set @subscriber_db = DB_NAME()

   /*
    ** Assign parameter values appropriately
    */
            
    select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
    IF @subscriber_srvid IS NULL
        BEGIN
           RAISERROR (14010, 16, -1)
           RETURN (1)     
        END
        
    IF not exists (select name from sysobjects where name='sysmergesubscriptions')
        BEGIN
            RAISERROR (14055, 16, -1)
            RETURN (1)
        END     

    /*
    ** Parameter Check: @publisher
    ** Check to make sure that the publisher is defined
    */
            IF @publisher IS NULL
            BEGIN
                RAISERROR (14043, 16, -1, '@publisher')
                RETURN (1)
            END

            EXECUTE @retcode = dbo.sp_validname @publisher
            IF @@ERROR <> 0 OR @retcode <> 0
               RETURN (1)

    /*
    ** Parameter Check: @publisher_db
    */
            IF @publisher_db IS NULL
            BEGIN
                RAISERROR (14043, 16, -1, '@publisher_db')
                RETURN (1)
            END    

    /*
    ** Parameter Check:  @publication.
    ** If the publication name is specified, check to make sure that it
    ** conforms to the rules for identifiers and that the publication
    ** actually exists.  Disallow NULL.
    */
    if @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END

    IF LOWER(@publication) = 'all'
        BEGIN
            declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications FOR READ ONLY
            
            OPEN hC1
            FETCH hC1 INTO @publication
            if @@fetch_status = -1 
                begin
                    CLOSE hC1
                    DEALLOCATE hC1
                    RETURN (0) --- It's OK to have no publication when 'ALL'
                end
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication,
                                      @publisher = @publisher,
                                      @publisher_db = @publisher_db,
                                      @reserved = 1
                    FETCH hC1 INTO @publication
                END
            CLOSE hC1
            DEALLOCATE hC1
            RETURN (0)
        END
        
    IF LOWER(@publisher) = 'all'
        BEGIN
            declare hC4 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT srvname FROM master..sysservers FOR READ ONLY
            
            OPEN hC4
            FETCH hC4 INTO @publisher
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication,
                                                @publisher = @publisher,
                                                @publisher_db = @publisher_db,
                                                @reserved = 1
                    FETCH hC4 INTO @publisher
                END
            CLOSE hC4
            DEALLOCATE hC4
            RETURN (0)
        END

    /*
    ** Validate that the publisher is a valid server
    */
    select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
    IF @publisher_srvid IS NULL
        BEGIN
            --RAISERROR (14010, 16, -1)
            RETURN (1)
        END


    /* Previously the condition is set as 'AND subid<>pubid' which is fatally errorous */

    IF LOWER(@publisher_db) = 'all'
        BEGIN
            declare hC5 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT db_name FROM sysmergesubscriptions 
                    WHERE subid = pubid and pubid in (select pubid from sysmergepublications 
                            where UPPER(publisher)=UPPER(@publisher) 
                                and name=@publication)
                                
                        FOR READ ONLY
            
            OPEN hC5
            FETCH hC5 INTO @publisher_db
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergepullsubscription @publication = @publication,
                                      @publisher = @publisher,
                                      @publisher_db = @publisher_db,
                                      @reserved = 1
                    FETCH hC5 INTO @publisher_db
                END
            CLOSE hC5
            DEALLOCATE hC5
            RETURN (0)
        END

    /*
    ** return error if only there is no 'ALL'. Same is true for the rest of error handling.
    */
    if NOT EXISTS (select * FROM sysmergepublications 
    WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db) 
    BEGIN
        if @reserved = 0
            RAISERROR (20026, 16, -1, @publication)
        RETURN (1)
    END
        
    select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
    set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
    if @pubid is null  
        BEGIN
            if @reserved = 0
                RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END

    /*
    ** Only members of the sysadmin group and the creator of the distribution
    ** agent can drop a pull subscription successfully. This behavior matches 
    ** the behavior of the sysjobs_view. DBO of the subscriber database, 
    ** sysadmins (owner is undefined) can drop a subscription if the owner_sid 
    ** is null.
    */
    
    EXEC sp_MSget_mergepullsubsagent_owner @publisher = @publisher,
                                           @publisher_db = @publisher_db,
                                           @publication = @publication,
                                           @owner_sid = @owner_sid OUTPUT 
    
    IF (@owner_sid is not null AND
        (SUSER_SID() <> @owner_sid) AND
        (ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) = 0))
    BEGIN
        SELECT @owner_name = SUSER_SNAME(@owner_sid)
        SELECT @qualified_publication_name = @publisher + N':' + 
                                             @publisher_db + N':' +
                                             @publication
        RAISERROR(21121,16,-1,@owner_name, @qualified_publication_name) 
        RETURN (1)
    END

    /*
    ** Get subscriptions from either local replicas or global replicas
    */
    select @subid = subs1.subid, @subscriber_type = subs1.subscriber_type, @partnerid = subs2.subid from
        sysmergesubscriptions   subs1,
        sysmergesubscriptions   subs2,
        sysmergepublications        pubs
        where subs1.srvid = @subscriber_srvid
            and subs1.db_name = @subscriber_db
            and subs2.srvid = @publisher_srvid
            and subs2.db_name = @publisher_db
            and subs1.pubid = subs2.subid
            and subs2.pubid = pubs.pubid
            and pubs.name = @publication
            and UPPER(pubs.publisher)=UPPER(@publisher)
            and pubs.publisher_db=@publisher_db

    if @subid IS NULL 
        begin
            if @reserved = 0 
                raiserror (14050, 16, -1)
            RETURN (0)
        end                 

    begin tran
    save TRAN dropmergepullsubscription
    
        /*  
        ** Drop the local merge task
        */
        select @merge_jobid = merge_jobid from MSmerge_replinfo WHERE repid = @subid
        if (@merge_jobid IS NOT NULL)
        BEGIN
            IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE job_id = @merge_jobid)
            BEGIN

                -- Checks if the job name matches one that is generated
                -- by replication
                EXEC @retcode = dbo.sp_MSispullmergejobnamegenerated
                                    @publisher = @publisher,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @job_id = @merge_jobid
                IF @@ERROR <> 0
                    GOTO FAILURE

                -- Only drop the job if the name was generated
                IF @retcode = 0
                BEGIN
                    EXEC @retcode = msdb.dbo.sp_delete_job @job_id = @merge_jobid
                    IF @@ERROR <> 0 or @retcode <> 0
                        GOTO FAILURE
                END
            END
        END                                 

        if @subid <> @partnerid
        BEGIN
            DELETE MSmerge_replinfo WHERE repid = @subid 
            IF @@ERROR <> 0
                GOTO FAILURE
            delete from sysmergesubscriptions where subid = @subid
            if @@ERROR <> 0
                GOTO FAILURE

            /* Call sp_MSunregistersubscription so that the reg entries get deleted */
            exec @retcode = dbo.sp_MSunregistersubscription @publisher = @publisher,
                                        @publisher_db = @publisher_db,
                                        @publication = @publication,
                                        @subscriber = @@SERVERNAME,
                                        @subscriber_db = @subscriber_db
            IF @retcode<>0 or @@ERROR<>0
                GOTO FAILURE

            exec dbo.sp_MSpublicationcleanup @publisher=@publisher, 
                                            @publisher_db = @publisher_db,
                                            @publication = @publication
            IF @@ERROR <> 0 
                BEGIN
                    RAISERROR (20025, 16, -1, @publication)
                    GOTO FAILURE
                END
        END
        
        IF EXISTS(select * from sysobjects where type='U' and name = 'MSsubscription_properties')
        BEGIN
            DELETE FROM MSsubscription_properties 
            WHERE UPPER(publisher) = UPPER(@publisher)  AND
            publisher_db  = @publisher_db AND
            publication = @publication 
    
            IF @@ERROR <> 0 
                GOTO FAILURE
    
            IF NOT EXISTS (SELECT * FROM MSsubscription_properties)
            BEGIN
                exec @retcode = dbo.sp_MSsub_cleanup_prop_table
                IF @@ERROR <> 0 or @retcode <> 0
                    GOTO FAILURE
            END
        END

    COMMIT TRAN

    /*
    ** Set back original settings
    */
    IF @reserved = 0
    BEGIN
        /* 
        ** If last subscription is dropped and the DB is not enabled for publishing,
        ** then remove the merge system tables
        */
        IF (not exists (select * from sysmergesubscriptions )) 
            AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME())=0
        BEGIN
                execute @retcode = dbo.sp_MSdrop_mergesystables
                if @@ERROR <> 0 or @retcode <> 0
                    begin
                        return (1)
                    end
        END 

        IF @implicit_transaction <>0 
            SET IMPLICIT_TRANSACTIONS ON
        IF @close_cursor_at_commit <>0 
            SET CURSOR_CLOSE_ON_COMMIT ON
    END

    RETURN(0)       

FAILURE:
    RAISERROR (14056, 16, -1)
    if @@trancount > 0
    begin
        ROLLBACK TRANSACTION dropmergepullsubscription
        COMMIT TRANSACTION
    end
    /*
    ** Set back original settings
    */  
    IF @reserved = 0
    BEGIN
        IF @implicit_transaction <>0 
            SET IMPLICIT_TRANSACTIONS ON
        IF @close_cursor_at_commit <>0 
            SET CURSOR_CLOSE_ON_COMMIT ON
    END
    return 1
go
exec sp_MS_marksystemobject 'dbo.sp_dropmergepullsubscription'
grant execute on dbo.sp_dropmergepullsubscription to public
--------------------------------------------------------------------------------
--. sp_MSenum_replsqlqueues
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenum_replsqlqueues')
drop procedure sp_MSenum_replsqlqueues
go
raiserror('Creating procedure sp_MSenum_replsqlqueues', 0,1)
go
create procedure sp_MSenum_replsqlqueues
(
	@curdistdb	sysname = NULL
)
as
begin
	declare @distbit int
	declare @db_name sysname
	declare @cmd nvarchar(1024)

	select @distbit = 16
	--
	-- security check
	--
	if (is_srvrolemember('sysadmin') != 1)
	begin
		--
		-- non SA user
		-- @curdistdb cannot be null for NON-SA user
		--
		if (@curdistdb is null)
		begin
			raiserror (14043, 16, -1, '@curdistdb')
			return 1
		end
		else
		begin
			--
			-- The user has to be DBO of the specified distribution db
			--
			declare @fisdbo bit
					,@securitycmd nvarchar(300)

			select @securitycmd = quotename(@curdistdb) + '.dbo.sp_executesql'
			exec @securitycmd
				N'if is_member(N''db_owner'') = 1 set @fisdbo = 1'
				,N'@fisdbo bit output'
				,@fisdbo output 
			if (@fisdbo != 1)
			begin
				raiserror (21050, 14, 3)
				return 1
			end
		end
	end
	--
	-- create the temp table to store the relevant information
	--
	create table #replqueue (
		publisher sysname collate database_default not null,
		publisher_db sysname collate database_default not null,
		subscriber sysname collate database_default not null,
		subscriber_db sysname collate database_default not null,
		publication sysname collate database_default not null,
		dist_db sysname collate database_default not null
	)
	create unique index ucreplqueue ON #replqueue (subscriber, subscriber_db, publication)

	--
	-- Has the user specified a distribution database
	--
	if (@curdistdb is NULL)
	begin
		--
		-- Go through all the distribution databases
		--
		declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR 
			select name from master.dbo.sysdatabases 
			where
				category & @distbit <> 0 and
				has_dbaccess(name) = 1
			for read only
	end
	else
	begin
		--
		-- User specified Distribution Database
		-- Validate the user specified name
		--
		if exists (select name from master.dbo.sysdatabases 
		where
			name = @curdistdb and
			category & @distbit <> 0 and
			has_dbaccess(name) = 1)
		begin
			declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR
			select @curdistdb
			for read only
		end
		else
		begin
			--
			-- Error : Invalid distribution db specified
			--
			raiserror(20587, 16, 3, N'@curdistdb', N'sp_MSenum_replsqlqueues')
			return 1
		end
	end
	
	--
	-- Enumerate
	--
	open hCdatabase
	fetch next from hCdatabase into @db_name
	while (@@fetch_status <> -1)
	begin
		select @cmd =
		'SET NOCOUNT ON ' +
		'INSERT INTO #replqueue (publisher, publisher_db, subscriber, subscriber_db, publication, dist_db) ' +
		'SELECT c.srvname, a.publisher_db, b.srvname, a.subscriber_db, a.publication, N''' + @db_name + ''' ' +
		'FROM ' + QUOTENAME(@db_name) + '.dbo.MSdistribution_agents as a ' +
			'JOIN master.dbo.sysservers as b ' +
			'ON a.subscriber_id = b.srvid ' +
			'JOIN master.dbo.sysservers as c ' + 
			'ON a.publisher_id = c.srvid ' + 
			'WHERE queue_id = N''mssqlqueue'' '
			
		exec (@cmd)
		fetch next from hCdatabase into @db_name
	end
	close hCdatabase
	deallocate hCdatabase

	--
	-- select the contents of the temp table
	--
	select * from #replqueue

	--
	-- cleanup
	--
	drop table #replqueue
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSenum_replsqlqueues
go
grant execute on dbo.sp_MSenum_replsqlqueues to public
go

--------------------------------------------------------------------------------
--. sp_MSenum_replqueues
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenum_replqueues')
drop procedure sp_MSenum_replqueues
go
raiserror('Creating procedure sp_MSenum_replqueues', 0,1)
go
create procedure sp_MSenum_replqueues
(
	@curdistdb	sysname = NULL
)
as
begin
	declare @distbit int
	declare @db_name sysname
	declare @cmd nvarchar(1024)

	select @distbit = 16
	--
	-- security check
	--
	if (is_srvrolemember('sysadmin') != 1)
	begin
		--
		-- non SA user
		-- @curdistdb cannot be null for NON-SA user
		--
		if (@curdistdb is null)
		begin
			raiserror (14043, 16, -1, '@curdistdb')
			return 1
		end
		else
		begin
			--
			-- The user has to be DBO of the specified distribution db
			--
			declare @fisdbo bit
					,@securitycmd nvarchar(300)

			select @securitycmd = quotename(@curdistdb) + '.dbo.sp_executesql'
			exec @securitycmd
				N'if is_member(N''db_owner'') = 1 set @fisdbo = 1'
				,N'@fisdbo bit output'
				,@fisdbo output 
			if (@fisdbo != 1)
			begin
				raiserror (21050, 14, 3)
				return 1
			end
		end
	end
	--
	-- create the temp table to store the relevant information
	--
	create table #replqueue (
		queue_server sysname collate database_default not null,
		queue_id sysname collate database_default not null,
		dist_db sysname collate database_default not null
	)
	create unique clustered index ucreplqueue ON #replqueue (queue_id)

	--
	-- Has the user specified a distribution database
	--
	if (@curdistdb is NULL)
	begin
		--
		-- Go through all the distribution databases
		--
		declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR 
			select name from master.dbo.sysdatabases 
			where
				category & @distbit <> 0 and
				has_dbaccess(name) = 1
			for read only
	end
	else
	begin
		--
		-- User specified Distribution Database
		-- Validate the user specified name
		--
		if exists (select name from master.dbo.sysdatabases 
		where
			name = @curdistdb and
			category & @distbit <> 0 and
			has_dbaccess(name) = 1)
		begin
			declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR
			select @curdistdb
			for read only
		end
		else
		begin
			--
			-- Error : Invalid distribution db specified
			--
			raiserror(20587, 16, 4, N'@curdistdb', N'sp_MSenum_replqueues')
			return 1
		end
	end

	--
	-- Enumerate
	--
	open hCdatabase
	fetch next from hCdatabase into @db_name
	while (@@fetch_status <> -1)
	begin
		select @cmd =
		'SET NOCOUNT ON ' +
		'INSERT INTO #replqueue (queue_server, queue_id, dist_db) ' +
		'SELECT queue_server, queue_id, ' +
				'N''' + replace(@db_name, '''', '''''') + ''' ' +
		'FROM ' +
				QUOTENAME(@db_name) + '.dbo.MSdistribution_agents ' +
		'WHERE ' +
				'queue_id IS NOT NULL and queue_id != N''mssqlqueue'''
			
		exec (@cmd)
		fetch next from hCdatabase into @db_name
	end
	close hCdatabase
	deallocate hCdatabase

	--
	-- select the contents of the temp table to present
	-- the formatted queue name
	--
	select 	N'DIRECT=OS:' + queue_server + N'\PRIVATE$\' + queue_id AS 'queue_format'
			,dist_db
	from #replqueue
	
	--
	-- cleanup
	--
	drop table #replqueue
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSenum_replqueues
go
grant execute on dbo.sp_MSenum_replqueues to public
go

--------------------------------------------------------------------------------
--. sp_vupgrade_publisherdb
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_vupgrade_publisherdb')
drop procedure sp_vupgrade_publisherdb
go
raiserror('Creating procedure sp_vupgrade_publisherdb', 0,1)
go
create procedure sp_vupgrade_publisherdb @ver_old int, @ver_retention int
as
begin
/* 
 * Process schema and metadata changes specific to a publishing database. Transactional replication 
 * system tables at the publisher are updated by sp_vupgrade_publisherdb; merge tables are not.
 * Most merge system tables exist in both the publishing and subscribing databases; merge schema 
 * and metadata changes are processed by a separate pass over all databases in sp_vupgrade_mergetables.
 *
 * Match column order of newly created table when adding columns.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_publisher -> sp_vupgrade_publisherdb
*/

	set nocount on 

	declare @default_name sysname 

	-- raiserror('sp_vupgrade_publisherdb', 0,1) with nowait

	-- sysarticles 
	if exists( select name from sysobjects where name = 'sysarticles' )
	begin
		
		if exists( select * from syscolumns where id = object_id('dbo.sysarticles') and name = 'schema_option' )
		begin
			-- The following two-phase upgrade operation has to be atomic
			begin transaction
			save transaction sysarticles_upgrade 
    
				-- For table articles which used to have the 
				-- SQLDMOCreationScript_DRI_Primary (0x00000080) schema option enabled,
				-- turn on the SQLDMOCreationScript_PKFKAsConstraints (0x00008000)
				-- option
				update sysarticles 
				   set schema_option = convert(int, schema_option) | convert(int, 0x00008000)
				  from sysobjects so
				where (convert(int, schema_option) & 0x00000080) <> 0x00000000
				  and so.id = sysarticles.objid
				  and so.xtype = 'U'
        
				if @@error <> 0
					goto SYSARTICLE_ERROR

				-- Enable both the SQLDMOCreationScript_DRI_PrimaryKey and
				-- SQLDMOCreationScript_UniqueKeys options (0x00004000) if at least 
				-- one of SQLDMOCreationScript_NonClusteredIndexes (0x00000010) and 
				-- SQLDMOCreationScript_ClusteredIndexes (0x00000040) was enabled
				-- or the table article belongs to a transactional publication  
				update sysarticles 
				   set schema_option = convert(int, schema_option) |
										convert(int, 0x00004080)
				  from sysobjects so,
					   syspublications sp
				where ((sysarticles.pubid = sp.pubid and sp.repl_freq = 0) 
					  or (convert(int, schema_option) & convert(int, 0x00000050) <> 
						  0x00000000)) 
				  and so.id = sysarticles.objid
				  and so.xtype = 'U'

				if @@error <> 0
					goto SYSARTICLE_ERROR

				-- Skip over the error handling code
				goto SYSARTICLE_END
		SYSARTICLE_ERROR:
			rollback transaction sysarticles_upgrade
			commit transaction
			return 1    
		SYSARTICLE_END:
			commit transaction 
		end
	end -- end of sysarticles upgrade

	-- syssubscriptions
	if exists (select name from sysobjects where name='syssubscriptions')
	begin
		if not exists (select * from syscolumns where id = object_id('syssubscriptions') and 
			name = 'queued_reinit')
		begin
			alter table syssubscriptions add queued_reinit bit default 0 not null
		end

	end -- end of syssubscriptions upgrade

	-- syspublications
	if exists (select name from sysobjects where name='syspublications')
	begin

		-- default_access column no longer used
		if exists (select * from syscolumns where id = object_id('syspublications') and
			name = 'default_access')
		begin
			alter table syspublications drop column default_access
		end 

		/*
		 * Queued updating subscriptions option; conflict management settings added later in this proc
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'allow_queued_tran')
		begin
			alter table syspublications add allow_queued_tran bit default 0 not null
		end

		/*
		 * Portable snapshot
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'snapshot_in_defaultfolder')
		begin
			alter table syspublications add snapshot_in_defaultfolder bit default 1 not null
		end
    
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'alt_snapshot_folder')
		begin
			alter table syspublications add alt_snapshot_folder nvarchar(255) null
		end

		/*
		 * Snapshot pre/post commands
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'pre_snapshot_script')
		begin
			alter table syspublications add pre_snapshot_script nvarchar(255) null
		end
       
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'post_snapshot_script')
		begin
			alter table syspublications add post_snapshot_script nvarchar(255) null
		end

		/*
		 * Snapshot compression
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'compress_snapshot')
		begin
			alter table syspublications add compress_snapshot bit default 0 not null
		end

		/*
		 * Post SQL7.0 FTP configuration stored at publisher
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_address')
		begin
			alter table syspublications add ftp_address sysname null
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_port')
		begin
			alter table syspublications add ftp_port int not null default 21
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_subdirectory')
		begin
			alter table syspublications add ftp_subdirectory nvarchar(255) null
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_login')
		begin
			alter table syspublications add ftp_login sysname null default N'anonymous'
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and name = 'ftp_password')
		begin
			alter table syspublications add ftp_password nvarchar(524) null
		end

		-- Since the ftp_address is now required to enable a publication for 
		-- internet, publications that were enabled for internet can not
		-- be upgraded automatically. So the enabled for internet option 
		-- is reset in the upgrade process. 
		if exists (select * from syscolumns where id = object_id('syspublications') and 
		   name = 'enabled_for_internet')
		begin
			update dbo.syspublications 
			   set enabled_for_internet = 0 
		end

		/*
		 * Transformable subscriptions
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'allow_dts')
		begin
			alter table syspublications add allow_dts bit default 0 not null
		end

		/*
		 * Attach & Go 
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'allow_subscription_copy')
		begin
			alter table syspublications add allow_subscription_copy bit default 0 not null
		end

		/*
		 * Transactional conflict management
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'centralized_conflicts')
		begin
			alter table syspublications add centralized_conflicts bit NULL
		end
    
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'conflict_retention')
		begin
			alter table syspublications add conflict_retention int NULL
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'conflict_policy')
		begin
			alter table syspublications add conflict_policy int NULL
		end

		/*
		 * Attach & Go 
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'queue_type')
		begin
			alter table syspublications add queue_type int NULL
		end

		/*
		 * Active Directory
		*/
		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'ad_guidname')
		begin
			alter table syspublications add ad_guidname sysname null
		end

		if not exists (select * from syscolumns where id = object_id('syspublications') and 
			name = 'backward_comp_level')
		begin
			alter table syspublications add backward_comp_level int default 10 not null
		end
		
		/*
		 * Schema only articles (views, procs, udfs)
		*/
		if not exists (select * from sysobjects where name = 'sysschemaarticles')
		begin
			create table dbo.sysschemaarticles
			(
				artid               int                 NOT NULL,
				creation_script     nvarchar(255)       NULL,
				description         nvarchar(255)       NULL,
				dest_object         sysname             NOT NULL,
				name                sysname             NOT NULL,
				objid               int                 NOT NULL,
				pubid               int                 NOT NULL,
				pre_creation_cmd    tinyint             NOT NULL,
				status              int                 NOT NULL,
				type                tinyint             NOT NULL,
				schema_option       binary(8)           NULL,
				dest_owner          sysname             NULL
			)
			exec dbo.sp_MS_marksystemobject sysschemaarticles

			if not exists (select * from sysindexes where name = 'unc1sysschemaarticles')
			begin
				create unique nonclustered index unc1sysschemaarticles
					on sysschemaarticles(artid, pubid)
			end  

		end

		if exists (select * from sysobjects where name = 'sysextendedarticlesview')
		begin
            drop view dbo.sysextendedarticlesview
		end
		-- cannot create view directly in stored procedure			
		exec ( 'create view dbo.sysextendedarticlesview
				   as
				   select artid, columns, creation_script, del_cmd, description,
				   dest_table, filter, filter_clause, ins_cmd, name, objid, pubid, pre_creation_cmd,
				   status, sync_objid, type, upd_cmd, schema_option, dest_owner	
				   from sysarticles
				   union all
				   select artid, NULL, creation_script, NULL, description,
				   dest_object, NULL, NULL, NULL, name, objid, pubid, 
				   pre_creation_cmd, status, NULL, type, NULL, 
				   schema_option, dest_owner 
				   from sysschemaarticles' )

		exec dbo.sp_MS_marksystemobject 'sysextendedarticlesview'

		exec sp_vupgrade_syscol_status

	end

	-- sysarticleupdates
	if exists (select name from sysobjects where name='sysarticleupdates')
	begin
		if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and 
			name = 'sync_upd_trig')
		begin
			alter table sysarticleupdates add sync_upd_trig int default 0 NOT NULL
		end

		if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and 
			name = 'conflict_tableid')
		begin
			alter table sysarticleupdates add conflict_tableid int NULL
		end

		if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and 
			name = 'ins_conflict_proc')
		begin
			alter table sysarticleupdates add ins_conflict_proc int NULL
		end

		if not exists (select * from syscolumns where id = object_id('sysarticleupdates') and 
			name = 'identity_support')
		begin
			alter table sysarticleupdates add identity_support bit default 0 NOT NULL
		end

	end

	-- Upgrade dbt->distbackuplsn
	-- Make sure the upgrade is done for 8.0 Beta 2 customers.
	if exists (select * from sysobjects where name = 'sysarticles') and
		not exists (select * from sysobjects where name = 'systranschemas')
	begin
		-- Force to get in even if the logreader is running.
		exec sp_replflush 
		exec sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0,
		    @time = 0, @reset = 0, @code = 1
		-- Unmark the connection as the logreader.
		exec sp_replflush
	end

	-- Create new tran tables if the db is enabled for tran publishing.
	if exists (select name from sysobjects where name='syspublications')
	begin
		exec dbo.sp_MScreate_pub_tables
	end

	/*
	 * syspublications
	*/
	if exists (select name from sysobjects where name='syspublications')
	begin
		if not exists (select * from syscolumns where id = Object_Id('syspublications') and name = 'ftp_password' and length = '1048')
		begin
			/*
			 * syspublications ftp_password
			 * no need to upgrade passwords since this column is new in 8.0.
			*/
			declare @dbname sysname
			declare @cmptlevel tinyint
			set @dbname = db_name()
			select @cmptlevel = cmptlevel from master..sysdatabases where name = @dbname collate database_default
			if @cmptlevel < 70
			begin
                                raiserror (15048, -1, -1, 70, 70, 70, 80)
			end
			else
			begin
				exec( 'alter table syspublications alter column ftp_password nvarchar(524)' )
			end
		end

		-- change non-clustered index on syspublications.pubid to clustered 
		-- index
		if exists( select * from sysindexes where name = 'unc1syspublications' and id = object_id('dbo.syspublications') )
		begin
		   drop index dbo.syspublications.unc1syspublications 
		end
		if not exists ( select * from sysindexes where name = 'uc1syspublications' and id = object_id('dbo.syspublications') )
		begin
			create unique clustered index uc1syspublications
				on syspublications (pubid)
		end
	end
end
go
exec dbo.sp_MS_marksystemobject sp_vupgrade_publisherdb
go

--------------------------------------------------------------------------------
--. sp_MSreset_queue
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSreset_queue')
revoke execute on dbo.sp_MSreset_queue from public

--------------------------------------------------------------------------------
--. sp_MSscript_begintrig1
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_begintrig1')
revoke execute on dbo.sp_MSscript_begintrig1 from public

--------------------------------------------------------------------------------
--. sp_MSscript_begintrig2
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_begintrig2')
revoke execute on dbo.sp_MSscript_begintrig2 from public

--------------------------------------------------------------------------------
--. sp_MSscript_endtrig
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_endtrig')
revoke execute on dbo.sp_MSscript_endtrig from public

--------------------------------------------------------------------------------
--. sp_MSscript_multirow_trigger
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_multirow_trigger')
revoke execute on dbo.sp_MSscript_multirow_trigger from public

--------------------------------------------------------------------------------
--. sp_MSscript_params
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_params')
revoke execute on dbo.sp_MSscript_params from public

--------------------------------------------------------------------------------
--. sp_MSscript_pkvar_assignment
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_pkvar_assignment')
revoke execute on dbo.sp_MSscript_pkvar_assignment from public

--------------------------------------------------------------------------------
--. sp_MSscript_procbodystart
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_procbodystart')
revoke execute on dbo.sp_MSscript_procbodystart from public

--------------------------------------------------------------------------------
--. sp_MSscript_singlerow_trigger
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_singlerow_trigger')
revoke execute on dbo.sp_MSscript_singlerow_trigger from public 

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_assignment
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_assignment')
revoke execute on dbo.sp_MSscript_trigger_assignment from public

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_exec_rpc
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_exec_rpc')
revoke execute on dbo.sp_MSscript_trigger_exec_rpc  from public

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_fetch_statement
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_fetch_statement')
revoke execute on dbo.sp_MSscript_trigger_fetch_statement from public

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_update_checks
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_update_checks')
revoke execute on dbo.sp_MSscript_trigger_update_checks from public

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_updates
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_updates')
revoke execute on dbo.sp_MSscript_trigger_updates from public

--------------------------------------------------------------------------------
--. sp_MSclearcolumnbit
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSclearcolumnbit')
revoke execute on dbo.sp_MSclearcolumnbit from public

--------------------------------------------------------------------------------
--. sp_MSget_subtypedatasrc
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSget_subtypedatasrc')
revoke execute on dbo.sp_MSget_subtypedatasrc from public

--------------------------------------------------------------------------------
--. sp_MSCheckmergereplication
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSCheckmergereplication')
revoke execute on dbo.sp_MSCheckmergereplication from public

--------------------------------------------------------------------------------
--. sp_MSremove_userscript
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSremove_userscript')
revoke execute on dbo.sp_MSremove_userscript from public

--------------------------------------------------------------------------------
--. sp_MSscript_trigger_variables
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_trigger_variables')
revoke execute on dbo.sp_MSscript_trigger_variables from public

--------------------------------------------------------------------------------
--. sp_MSscript_where_clause
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_where_clause')
revoke execute on dbo.sp_MSscript_where_clause from public

--------------------------------------------------------------------------------
--. sp_MSupdate_mqserver_subdb
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSupdate_mqserver_subdb')
revoke exec on dbo.sp_MSupdate_mqserver_subdb from public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_del_trig
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_del_trig')
drop procedure sp_MSscript_sync_del_trig
go
create procedure sp_MSscript_sync_del_trig (
	@objid        int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname, 
	@trigname     sysname,
	@procname     sysname,
	@proc_owner	  sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000)
)
as
BEGIN
	declare @colname sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

	set nocount on
	--
	-- security check
	--
	exec @rc = sp_MSreplcheck_subscribe
	if @@error <> 0 or @rc <> 0
	begin
		return (1)
	end

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	if (LOWER(@cftproc) = N'null')
	begin
		select @fisqueued =  0
				,@cftproc = NULL
	end
	else 
		select @fisqueued =  1

	if @ts_col in ('null','NULL')
		select @ts_col = null

	if @identity_col in ('null','NULL')
		select @identity_col = null

	-- Create temp table
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	-- 1st preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'del', @fisqueued

	-- 2nd preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'del', @agent_id, @fisqueued

	-- script single row handling
	exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, 
	@cftproc, @identity_col, @ts_col, 'del', @primary_key_bitmap

	-- script multi-row handling
	exec @rc = dbo.sp_MSscript_multirow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, 
	@cftproc, @identity_col, @ts_col, 'del', @primary_key_bitmap

	-- script end of trigger
	exec dbo.sp_MSscript_endtrig 

	-- send fragments to client
	select procedure_text from #proctext order by c1 asc
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_sync_del_trig
go
grant execute on dbo.sp_MSscript_sync_del_trig to public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_ins_trig
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_ins_trig')
drop procedure sp_MSscript_sync_ins_trig
go
raiserror('Creating procedure sp_MSscript_sync_ins_trig', 0,1)
go
create procedure sp_MSscript_sync_ins_trig (
	@objid		  int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname,
	@trigname     sysname,
	@procname     sysname,
	@proc_owner   sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000)
)
as
BEGIN
	declare @colname      sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

    set nocount on
    --
    -- security check
    --
    exec @rc = sp_MSreplcheck_subscribe
    if @@error <> 0 or @rc <> 0
    begin
        return (1)
    end
    exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	if (LOWER(@cftproc) = N'null')
	begin
		select @fisqueued =  0
				,@cftproc = NULL
	end
	else 
		select @fisqueued =  1

	if @ts_col in ('null','NULL')
		select @ts_col = null

	if @identity_col in ('null','NULL')
		select @identity_col = null

    -- Create temp table
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	-- 1st preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'ins', @fisqueued
				
	-- 2nd preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'ins',@agent_id, @fisqueued

	-- script single row handling
	exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, 
		@cftproc, @identity_col, @ts_col, 'ins', @primary_key_bitmap

	-- script multi-row handling
	exec @rc = dbo.sp_MSscript_multirow_trigger @objid, @publisher, @publisher_db, @publication, @procname, @proc_owner, 
		@cftproc, @identity_col, @ts_col, 'ins', @primary_key_bitmap

    -- script end of trigger
	exec dbo.sp_MSscript_endtrig 

	-- send fragments to client
	select procedure_text from #proctext order by c1 asc
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_trig
go
grant execute on dbo.sp_MSscript_sync_ins_trig to public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_upd_trig
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_upd_trig')
drop procedure sp_MSscript_sync_upd_trig
go
raiserror('Creating procedure sp_MSscript_sync_upd_trig', 0,1)
go
create procedure sp_MSscript_sync_upd_trig (
	@objid        int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname, 
	@trigname     sysname,
	@procname     sysname,
	@proc_owner   sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000) )
as
BEGIN
	declare @colname      sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

    set nocount on
    --
    -- security check
    --
    exec @rc = sp_MSreplcheck_subscribe
    if @@error <> 0 or @rc <> 0
    begin
        return (1)
    end
    exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	if (LOWER(@cftproc) = N'null')
	begin
		select @fisqueued =  0
				,@cftproc = NULL
	end
	else 
		select @fisqueued =  1

	if @ts_col in ('null','NULL')
		select @ts_col = null

	if @identity_col in ('null','NULL')
		select @identity_col = null

    -- Create temp table
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	-- 1st preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig1 @trigname, @objid, @procname, @filter_clause, 'upd', @fisqueued
					
	-- prevent updating of unique index when 'row compare' conflict detection, since it would trickle
    -- back as a del/insert, and fail
/*
	if @ts_col is null
	begin
		insert into #proctext(procedure_text) values(N' 
')
--		exec dbo.sp_MSscript_trigger_update_checks @objid, null, null, 'pk', 0
	end
*/

	-- 2nd preamble common to all synctran procs
	exec dbo.sp_MSscript_begintrig2 @publisher, @publisher_db, @publication, @objid, 'upd',@agent_id, @fisqueued

	-- script single row handling
	exec @rc = dbo.sp_MSscript_singlerow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, 
		@cftproc, @identity_col, @ts_col, 'upd', @primary_key_bitmap

	-- script multi-row handling
	exec @rc = dbo.sp_MSscript_multirow_trigger @objid,@publisher, @publisher_db, @publication, @procname, @proc_owner, 
		@cftproc, @identity_col, @ts_col, 'upd', @primary_key_bitmap
    -- script end of trigger
	exec dbo.sp_MSscript_endtrig 

	-- send fragments to client
	select procedure_text from #proctext order by c1 asc
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_trig
go
grant execute on dbo.sp_MSscript_sync_upd_trig to public
go

--------------------------------------------------------------------------------
--. sp_check_sync_trigger
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_check_sync_trigger')
revoke exec on dbo.sp_check_sync_trigger from public
go
--------------------------------------------------------------------------------
--. sp_check_for_sync_trigger
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_check_for_sync_trigger')
drop procedure sp_check_for_sync_trigger
go
raiserror('Creating procedure sp_check_for_sync_trigger', 0,1)
go
create proc sp_check_for_sync_trigger 
(
    @tabid int, 
    @trigger_op char(10) = NULL OUTPUT
)
as
begin
    declare @ins_trigid int
    declare @upd_trigid int
    declare @del_trigid int
    declare @retcode int

    --
    -- security check
    --
    exec @retcode = sp_MSreplcheck_subscribe
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end

    select @trigger_op = NULL
    
    select @ins_trigid = id from sysobjects where
        type = N'TR' and name like N'trg_MSsync_ins_%' and parent_obj = @tabid
    select @upd_trigid = id from sysobjects where
        type = N'TR' and name like N'trg_MSsync_upd_%' and parent_obj = @tabid
    select @del_trigid = id from sysobjects where
        type = N'TR' and name like N'trg_MSsync_del_%' and parent_obj = @tabid

    if trigger_nestlevel( @ins_trigid ) > 0
    begin
         select @trigger_op = 'ins'
         return 1
    end
    else    -- if nestlevel of insert trigger on same table > 0 then bail
    if trigger_nestlevel( @upd_trigid ) > 0
    begin
         select @trigger_op = 'upd'
         return 1
    end
    else
    if trigger_nestlevel( @del_trigid ) > 0
    begin
         select @trigger_op = 'del'
         return 1
    end
    else
        return 0
end
go
exec dbo.sp_MS_marksystemobject sp_check_for_sync_trigger
go
grant execute on dbo.sp_check_for_sync_trigger to public
go

--------------------------------------------------------------------------------
--. sp_MShelpmergedynamicsnapshotjob
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MShelpmergedynamicsnapshotjob')
   drop procedure sp_MShelpmergedynamicsnapshotjob
go
raiserror('Creating procedure sp_MShelpmergedynamicsnapshotjob', 0,1)
go 
create procedure sp_MShelpmergedynamicsnapshotjob (
    @publication sysname = N'%',
    @dynamic_snapshot_jobname sysname = N'%',
    @dynamic_snapshot_jobid uniqueidentifier = null
    )
as
begin
	declare @retcode int
    set nocount on
	/*
    ** Security Check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)
    if not exists (select * from sysobjects where name = 'sysmergepublications')
    begin
        return 0
    end

    select 'id' = j.id,
           'job_name' = j.name,
           'job_id' = j.job_id, 
           'dynamic_filter_login' = j.dynamic_filter_login,
           'dynamic_filter_hostname' = j.dynamic_filter_hostname,
           'dynamic_snapshot_location' = j.dynamic_snapshot_location
      from sysmergepublications p
     inner join MSdynamicsnapshotjobs j
        on p.pubid = j.pubid
     where (p.name = @publication or @publication = N'%')
       and (j.name = @dynamic_snapshot_jobname or @dynamic_snapshot_jobname = N'%')
       and (j.job_id = @dynamic_snapshot_jobid or @dynamic_snapshot_jobid is null) 

    if @@error <> 0
        return (1)
    else
        return (0)

end
go
exec dbo.sp_MS_marksystemobject sp_MShelpmergedynamicsnapshotjob
go
grant execute on dbo.sp_MShelpmergedynamicsnapshotjob to public
go
--------------------------------------------------------------------------------
--. sp_addtabletocontents
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_addtabletocontents')
   drop procedure sp_addtabletocontents
go
raiserror('Creating procedure sp_addtabletocontents', 0,1)
go
create procedure sp_addtabletocontents 
    (@table_name sysname,
     @owner_name sysname = NULL)
AS

    declare @qualified_table_name nvarchar(270)
    declare @tablenick int
    declare @tablenickstr nvarchar(12)
    declare @repl_nick int
    declare @lineage varbinary(249)
    declare @colv varbinary(2000)
    declare @coltrack int
    declare @objid int
    declare @maxcolid int
    declare @retcode int
    declare @gen int

	/*
    ** Security Check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)
    
    set nocount on
    create table #temp_cont(rowguid uniqueidentifier)
    execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output
    if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

	if @owner_name is NULL
		begin
		select @owner_name = user_name(uid) from sysobjects where name = @table_name
		end
	set @qualified_table_name = QUOTENAME(@owner_name) + '.' + QUOTENAME(@table_name)
	
    set @objid = object_id(@qualified_table_name)
    if @objid is NULL return (1)
    select @gen = max(gen_cur), @tablenick = max(nickname), @coltrack = max(column_tracking) from sysmergearticles where objid = @objid
	if @gen is null
		set @gen = 0
    select @maxcolid = max(colid) from syscolumns where id = @objid

    if @coltrack = 1
		set @colv = { fn INITCOLVS(@maxcolid, @repl_nick) }
    else
        set @colv = NULL
    set @lineage = { fn UPDATELINEAGE(0x0, @repl_nick, 1) }

    set @tablenickstr = convert(nchar, @tablenick)

    exec ('insert into #temp_cont(rowguid) select RowGuidCol from ' + @qualified_table_name + ' where
            RowGuidCol not in (select rowguid from MSmerge_contents where tablenick = 
            ' + @tablenickstr + ')')

    insert into MSmerge_contents (tablenick, rowguid, generation, joinchangegen, lineage, colv1)
        select @tablenick, rowguid, @gen, @gen, @lineage, @colv from #temp_cont

    drop table #temp_cont
GO
exec dbo.sp_MS_marksystemobject sp_addtabletocontents 
go
grant exec on dbo.sp_addtabletocontents to public
go

--------------------------------------------------------------------------------
--. sp_MSaddpubtocontents
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSaddpubtocontents')
   drop procedure sp_MSaddpubtocontents
go
raiserror('Creating procedure sp_MSaddpubtocontents', 0,1)
go
create procedure sp_MSaddpubtocontents 
    (@publication   sysname)
AS
    declare     @pubid  uniqueidentifier
    declare     @tablenick int
    declare     @retcode int
	declare 	@objid int
	declare 	@owner sysname
	declare		@table sysname
	
    set nocount on
	/*
    ** Security Check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    select @pubid = pubid from sysmergepublications 
        where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    if @pubid is NULL
        begin
            raiserror (20026, 11, -1, @publication)
            return (1)
        end
    
    select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid

    while @tablenick is not null
        begin
		select @objid = objid from sysmergearticles where pubid = @pubid and
			nickname = @tablenick
		select @owner = user_name(uid) from sysobjects where id = @objid
		set @table = OBJECT_NAME(@objid)
        exec @retcode = dbo.sp_addtabletocontents @table, @owner
        
        IF @@ERROR <> 0 or @retcode <> 0
            return (1)

        select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid and
                nickname > @tablenick
        end
GO
exec dbo.sp_MS_marksystemobject sp_MSaddpubtocontents 
go
grant exec on dbo.sp_MSaddpubtocontents to public
go

--------------------------------------------------------------------------------
--. sp_MScomputemergeunresolvedrefs
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScomputemergeunresolvedrefs')
   drop procedure sp_MScomputemergeunresolvedrefs
go
raiserror(15339,-1,-1,'sp_MScomputemergeunresolvedrefs')
GO
CREATE PROCEDURE sp_MScomputemergeunresolvedrefs
    @publication sysname, -- Must provide the publication name
    @article     sysname = '%' -- '%' means all articles in the specified publication, otherwise an exact match is performed
AS
    SET NOCOUNT ON 
    DECLARE @pubid uniqueidentifier 

    
    -- Parameter check: @publication

    IF @publication IS NULL
    BEGIN
        RAISERROR (14043, 16, -1, '@publication')
        RETURN (1)
    END

    SELECT @pubid = NULL 
    -- Get the pubid of the publication
    SELECT @pubid = pubid 
      FROM sysmergepublications
     WHERE name = @publication
       AND UPPER(publisher) = UPPER(@@SERVERNAME)
       AND publisher_db = DB_NAME()
    
    IF @pubid IS NULL
    BEGIN
        RAISERROR (20026, 11, -1, @publication)
        RETURN (1)    
    END

	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin    
		RAISERROR (14126, 11, -1)
		return (1)

	end	

    SELECT DISTINCT 
           'article' = a.name, 
           'dependent object' = o.name, 
           'dependent object owner' = u.name, 
           'dependent objectid' = o.id 
      FROM dbo.sysmergeextendedarticlesview a
    INNER JOIN sysdepends dep
        ON a.objid = dep.id
       AND a.pubid = @pubid
       AND (@article = '%' OR name = @article)
       AND dep.depid NOT IN (SELECT objid FROM dbo.sysmergeextendedarticlesview
                              WHERE pubid = @pubid 
                                AND (@article = '%' OR name = @article))
    INNER JOIN sysobjects o
        ON dep.depid = o.id
    INNER JOIN sysusers u
        ON u.uid = o.uid          
GO

exec dbo.sp_MS_marksystemobject sp_MScomputemergeunresolvedrefs
go
grant exec on dbo.sp_MScomputemergeunresolvedrefs to public
go

--------------------------------------------------------------------------------
-- procedures from rlrecon.sql regarding security stuff
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSfetchidentityrange')
drop procedure sp_MSfetchidentityrange

raiserror('Creating procedure sp_MSfetchidentityrange', 0,1)
GO

CREATE PROCEDURE sp_MSfetchidentityrange 
@tablename			sysname,
@adjust_only		bit
AS

declare @retcode 			int
declare @objid				int
declare @distributor		sysname
declare @distribdb			sysname
declare @publisher			sysname
declare @publisher_db		sysname
declare @next_seed			bigint
declare @range				bigint
declare @threshold			int
declare @tablenick 			int
declare @distproc			nvarchar(300)
declare @identity_support	int
select @publisher=@@SERVERNAME
select @publisher_db=db_name()

select @objid = object_id(@tablename)

select @identity_support=identity_support, @tablenick = nickname from sysmergearticles where objid=@objid

/*
** do permission checking
*/
exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
if @retcode<>0 or @@ERROR<>0 return (1)


exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
		IF @@ERROR <> 0 or @retcode <> 0
			return (1)
SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange'
exec @retcode = @distproc @publisher=@publisher, 
							@publisher_db=@publisher_db, 
							@tablename=@tablename, 
							@adjust_only=1, --do adjust only
							@next_seed=@next_seed OUTPUT,
							@range=@range OUTPUT,
							@threshold=@threshold OUTPUT
IF @@ERROR <> 0 OR @retcode <> 0
	return (1)

--initialize article collection for agents.
if @adjust_only=0
	select @identity_support, @next_seed-range, range, threshold from MSrepl_identity_range where  objid = @objid
GO
exec dbo.sp_MS_marksystemobject sp_MSfetchidentityrange 
go
grant exec on dbo.sp_MSfetchidentityrange to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScheckidentityrange')
drop procedure sp_MScheckidentityrange

raiserror('Creating procedure sp_MScheckidentityrange', 0,1)
GO

CREATE PROCEDURE sp_MScheckidentityrange 
	@pubid 				uniqueidentifier,
	@artname			sysname,
	@next_seed			bigint,
	@range				bigint,
	@threshold			int,
	@checkonly			int
AS
	declare @colid				int
	declare @colname			sysname
	declare @retcode			int
	declare @objid				int
	declare @identity_so_far	bigint
	declare @current_max		bigint
	declare @max_identity		bigint
	declare @tablename			sysname
	declare @flag				smallint
	declare @distributor		sysname
	declare @distribdb			sysname
	declare @republisher		bit
	declare @publisher			sysname
	declare @publisher_db		sysname
	declare @distproc			nvarchar(300)
	declare @pub_range			bigint

	/*
	** Check to see if current publication has permission
	*/
	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin	
		RAISERROR (14126, 11, -1)
		return (1)
	end
	
	select @objid = objid from sysmergearticles where pubid=@pubid and name=@artname
	select @flag = 1
	select @republisher = 0
	select @tablename=object_name(@objid)

	if exists (select * from sysmergearticles where objid=@objid and pubid <>@pubid and pubid in (select pubid from 
					sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
	begin
		select @publisher=@@SERVERNAME
		select @publisher_db=db_name()
		select @republisher = 1
		exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
		IF @@ERROR <> 0 or @retcode <> 0
		begin
			raiserror(14071, 16, -1)
			return (1)
			end
	end

	if @checkonly=1
	begin
		if @republisher=0
		begin
			--current_max is defaulted to max_identity value if not republished at subscribers.
			select @current_max = current_max from MSrepl_identity_range where objid=@objid
			select @identity_so_far = ident_current(@tablename)		
			if ident_incr(@tablename) < 0
				select @flag = -1
			if @flag * 100 * (@identity_so_far - (@current_max + 1 - @range))/@range > @threshold
				select 1 --needs bump up
			else
				select 0 --no need to bump up
		end
		else
		begin
			select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0, @max_identity=0  --make them non-NULL
			SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
			exec  @retcode=	@distproc @publisher=@@SERVERNAME,
									  @publisher_db=@publisher_db,
									  @tablename=@tablename,
									  @range=@range OUTPUT,
									  @max_identity=@max_identity OUTPUT,
									  @next_seed = @next_seed OUTPUT,
									  @pub_range=@pub_range OUTPUT
			if @retcode<>0 or @@ERROR<>0
			begin
				raiserror(21195, 16, -1) 
				return (1)
			end
			if (@max_identity-@next_seed)<@range or (@max_identity-@next_seed)<@pub_range
				select 1
			else
				select 0
		end
	end
	else
	begin
		if @republisher=0
		begin
			--its current_max value is to be set by sp_addmergearticle, if to be republished.
			update MSrepl_identity_range set max_identity=@next_seed + @range, next_seed=@next_seed, current_max=@next_seed + @range -1
				where objid = @objid
			exec sp_MSreseed @objid, @next_seed, @range 
			if @@ERROR <> 0 
				goto FAILURE
		end
		else
		begin
			SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange'
			exec @retcode = @distproc @publisher=@publisher, 
							@publisher_db=@publisher_db, 
							@tablename=@tablename, 
							@for_publisher = 2,  --for repub case, increment max_identity at distributor side
							@next_seed = @next_seed,
							@range=@range OUTPUT,
							@adjust_only=1 --do adjust only
			if @retcode<>0 or @@ERROR<>0
			begin
				raiserror(21315, 16, -1, @tablename)
				return (1)
			end
		end
	end

	return (0)
FAILURE:
	select 0
	return (1)
go
exec dbo.sp_MS_marksystemobject sp_MScheckidentityrange 
go
grant exec on dbo.sp_MScheckidentityrange to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MShelpmergearticles')
drop procedure sp_MShelpmergearticles

raiserror('Creating procedure sp_MShelpmergearticles', 0,1)
GO

CREATE PROCEDURE sp_MShelpmergearticles 
	@publication sysname,
	@compatibility_level int = 7000000,
	@pubidin uniqueidentifier = NULL
as
	declare @pubid 					uniqueidentifier
	declare @artid 					uniqueidentifier
	declare @user_name				sysname
	declare @guid_col				sysname
	declare @identity_support 		int
	declare @nickname				int
	declare @identity_so_far		bigint
	declare @next_seed				bigint
	declare @pub_range				bigint
	declare @objid					int
	declare @qualname				nvarchar(270)
	declare @retcode				int
	declare @tablename				sysname
	declare @range					bigint
	declare @current_max			bigint
	declare @threshold				int
	declare @distributor			sysname
	declare @distribdb				sysname
	declare @distproc				nvarchar(300)
	declare @flag					smallint
	declare @c_max					bigint
	declare @n_seed					bigint
	declare @db_name				sysname
	declare @has_joins				int
	declare @article_filter_category int
	declare @haspartfilters			int
	declare @grouppartfilterarticles int
	declare @injoinfilters			int
	declare @nofilters				int
	declare @objid_looper			int
	declare @indexcol				int
	declare @rowcount1				int
	declare @rowcount2				int

	declare @tmp_table TABLE (tablename sysname, user_name sysname,  
			guid_col sysname NULL, next_seed bigint, range bigint, threshold int, artid uniqueidentifier, pubid uniqueidentifier, has_joins int, article_filter_category int, objid int, has_relation_with_joinarticles int default 0, node_visited bit default 0)
	declare @worktable TABLE (objid int NOT NULL, indexcol int)

	set @nofilters = 1
	set @haspartfilters = 2
	set @injoinfilters = 4
	set @grouppartfilterarticles = 8
	
	/*
	** To public.
	*/
	set nocount on
	if (@publication is null)
		begin
		RAISERROR(14003, 16, -1)
		return (1)
		end
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end

	EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
	IF @@ERROR <> 0 or @retcode <> 0
		return (1)

	
	select @db_name = db_name()

	if @pubidin is not NULL
		set @pubid = @pubidin
	else
		select @pubid = pubid from sysmergepublications
			where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name

	if (@pubid is null)
		begin
        RAISERROR (20026, 11, -1, @publication)
		return (1)
		end

	/*
	** Check to see if current publication has permission
	*/
	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin	
		RAISERROR (14126, 11, -1)
		return (1)
	end


	select TOP 1 @artid=artid from sysmergearticles where pubid=@pubid order by nickname ASC
	while (@artid is not NULL)
	begin
		select @objid=objid, @nickname=nickname, @identity_support=identity_support from sysmergearticles 
				where pubid=@pubid and artid=@artid
		select @tablename=object_name(@objid)
		select @user_name=user_name(uid) from sysobjects where id=@objid
		select @qualname=QUOTENAME(@user_name) + '.' + QUOTENAME(@tablename)
		select @next_seed=NULL, @range=NULL, @threshold=NULL --null if not being updated later
		if @identity_support=1 and exists (select * from sysmergepublications where
			pubid = @pubid and  UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name)
		begin
			select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0  --make them non-NULL
			SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
			exec  @retcode=	@distproc @publisher=@@SERVERNAME,
									  @publisher_db=@db_name,
									  @tablename=@tablename,
									  @range=@range OUTPUT,
									  @current_max=@current_max OUTPUT,
									  @threshold=@threshold OUTPUT,
									  @next_seed = @next_seed OUTPUT,
									  @pub_range=@pub_range OUTPUT
			if @retcode<>0 or @@ERROR<>0
				return (1)

			select @identity_so_far = IDENT_CURRENT(@tablename)
			select @flag=1
			if ident_incr(@tablename) < 0
				select @flag = -1

			-- we attempted to adjust publisher side identity range based on its threshodl if needed
			-- however, non-dbo/sysadmin's will not be able to do so.
			-- so this is limited to dbos or sysadmins.
			if @flag * 100 * (@identity_so_far - (@current_max + 1 - @pub_range))/@pub_range > @threshold
					and ((is_srvrolemember('sysadmin') = 1) or (is_member('db_owner') = 1)) 
			begin
				select @c_max=@next_seed + @pub_range - 1
				select @n_seed=@next_seed + @pub_range
				SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
				exec  @retcode=@distproc @publisher=@@SERVERNAME,
										@publisher_db=@db_name,
										@tablename=@tablename,
										@current_max=@c_max,
										@next_seed = @n_seed
				if @retcode<>0 or @@ERROR<>0
					return (1)

				exec @retcode=sp_MSreseed @objid, @next_seed, @pub_range, 1
				if @@ERROR <> 0 or @retcode<>0
				begin
					raiserror(21197, 16, -1)
					return (1)
				end
				select @next_seed=@next_seed + @pub_range

			end
		end
		else if @identity_support=1 and not exists (select * from sysmergepublications where
			pubid = @pubid and  UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=@db_name)
		begin
			/* This is the case of a message based subscriber acting like publisher */
			select @range = range, @threshold = threshold, @next_seed = next_seed
				from MSrepl_identity_range where objid = @objid
		end

		if exists (select * from sysmergesubsetfilters where join_nickname = @nickname)
			set @has_joins = 1
		else 
			set @has_joins = 0

		-- reset for subsequent bitwise OR operations.
		set @article_filter_category = 0

		if exists (select * from sysmergesubsetfilters where pubid = @pubid and (join_nickname = @nickname or art_nickname = @nickname))
			set @article_filter_category = (@article_filter_category | @injoinfilters)
		
		if exists (select * from sysmergearticles where pubid = @pubid and nickname = @nickname and datalength(subset_filterclause) > 1)
			set @article_filter_category = (@article_filter_category | @haspartfilters | @grouppartfilterarticles)
		
		if (@article_filter_category = 0)
			set @article_filter_category = @nofilters

		select @guid_col=name from syscolumns where id=@objid and ColumnProperty(@objid, name, 'IsRowGuidCol')=1
		insert @tmp_table values(@tablename, @user_name, @guid_col, 
			@next_seed, @range, @threshold, @artid, @pubid, @has_joins, @article_filter_category, @objid, 0, 0)
		if @@ERROR<>0
		begin
			raiserror(21197, 16, -1)
			return (1)
		end
		select @artid = NULL 
		select TOP 1 @artid=artid from sysmergearticles 
			where pubid=@pubid and nickname>@nickname order by nickname ASC
	end

	-- Find articles that have no relations (in either direction - referring or referenced) with any articles in the join filter category.

	if exists (select * from @tmp_table where (article_filter_category & @injoinfilters) = @injoinfilters)
	begin

		--create unique index #uncworktable on @worktable(objid, indexcol)
		update @tmp_table set node_visited = 1 
		where objid not in (select fkeyid from sysreferences)
		and objid not in (select rkeyid from sysreferences)
		and (article_filter_category & @injoinfilters) = 0

		-- get the min objid from the temp table of all articles
		select @objid_looper = min(objid) from @tmp_table where node_visited = 0
		
		while (@objid_looper is not null)
		begin
			delete from @worktable

			select @indexcol = 0

			insert into @worktable values (@objid_looper, @indexcol)
						
			-- find all the objects referenced by this object and all objects that reference this object.
			insert into @worktable select distinct rkeyid, @indexcol+1 from sysreferences where fkeyid = @objid_looper
											and rkeyid not in (select objid from @worktable)
			select @rowcount1 = @@rowcount
			
			insert into @worktable select distinct fkeyid, @indexcol+1 from sysreferences where rkeyid = @objid_looper
											and fkeyid not in (select objid from @worktable)
			select @rowcount2 = @@rowcount
			
			while (@rowcount1 <> 0 or @rowcount2 <> 0)
			begin
				
				select @indexcol = @indexcol+1

				insert into @worktable select distinct s.rkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.fkeyid = w.objid and w.objid = t.objid
											and w.indexcol = @indexcol and t.node_visited = 0 and s.rkeyid not in (select objid from @worktable)
				select @rowcount1 = @@rowcount
				
				insert into @worktable select distinct s.fkeyid, @indexcol+1 from sysreferences s, @worktable w, @tmp_table t where s.rkeyid = w.objid and w.objid = t.objid
											and w.indexcol = @indexcol and t.node_visited = 0 and s.fkeyid not in (select objid from @worktable)
				select @rowcount2 = @@rowcount
			end

			if exists (select * from @worktable w, @tmp_table t where w.objid = t.objid and (t.article_filter_category & @injoinfilters) = @injoinfilters)
			begin
				-- all articles in @worktable have a direct or indirect relation with at least one object in the join articles category.
				update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 1 
				from @tmp_table t, @worktable w 
				where w.objid = t.objid 
			end
			else
			begin
				-- none of the articles in @worktable has any relation (direct or indirect) with any article in the join articles category.			
				update @tmp_table set node_visited = 1, has_relation_with_joinarticles = 0 
				from @tmp_table t, @worktable w 
				where w.objid = t.objid 
			end

			-- process more unvisited articles from @tmp_table
			select @objid_looper = min(objid) from @tmp_table where objid > @objid_looper and node_visited = 0
		end
	end
	
	/* If the 7.0 merge agent is making this call then we need to make sure that the CLSID of the sp resolver is the old one and not the new one */
	if @compatibility_level = 7000000
		begin
			begin transaction 
				update sysmergearticles set resolver_clsid = '{6F31CE30-7BE4-11d1-9B0A-00C04FC2DEB3}' where article_resolver = 'Microsoft SQLServer Stored Procedure Resolver'
				select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname,
					column_tracking, status, resolver_clsid, conflict_script, conflict_table,
					insert_proc, update_proc, select_proc, destination_object, missing_col_count, 
					missing_cols, t.guid_col, 
					article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, 
					excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, 
					verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, t.article_filter_category, t.has_relation_with_joinarticles
				from sysmergearticles a, @tmp_table t
				where a.artid=t.artid and a.pubid=t.pubid order by a.nickname
			rollback transaction				
		end
	else
		begin
			select name, t.tablename, t.user_name, a.artid, pre_creation_command, a.pubid, nickname,
				column_tracking, status, resolver_clsid, conflict_script, conflict_table,
				insert_proc, update_proc, select_proc, destination_object, missing_col_count, 
				missing_cols, t.guid_col, 
				article_resolver, resolver_info, subset_filterclause, has_joins, excluded_col_count, 
				excluded_cols, destination_owner, identity_support, t.next_seed, t.range, t.threshold, 
				verify_resolver_signature, allow_interactive_resolver, fast_multicol_updateproc, check_permissions, t.article_filter_category, t.has_relation_with_joinarticles
			from sysmergearticles a, @tmp_table t
			where a.artid=t.artid and a.pubid=t.pubid order by a.nickname
		end			

	return (0)	
go
exec dbo.sp_MS_marksystemobject sp_MShelpmergearticles 
go
grant exec on dbo.sp_MShelpmergearticles to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScreateretry')
drop procedure sp_MScreateretry
go
raiserror('Creating procedure sp_MScreateretry', 0,1)
GO

CREATE PROCEDURE sp_MScreateretry 
as
	declare @tname sysname
	declare @pname sysname
	declare @tempname sysname
	declare @guid uniqueidentifier
	declare @guidstr varchar(40)
	declare @retcode smallint

	/*
	** Check to see if current publication has permission
	*/
	if not exists (select * from dbo.sysmergepublications 
							where 1 = {fn ISPALUSER(pubid)})
	begin    
		RAISERROR (14126, 11, -1)
		return (1)
	end

	set @guid = newid()
	exec @retcode=sp_MSguidtostr @guid, @guidstr out
	if @retcode<>0 or @@ERROR<>0 return (1)
	set @tempname = '##retry_' + @guidstr

	exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out
	if (@@error <> 0) OR @retcode <> 0
		begin
		RAISERROR(15001, 16, -1, 'sp_MSuniquetempname')
		return (1)
		end

	exec ('create table ' + @tempname + ' (tablenick int NOT NULL, rowguid uniqueidentifier ROWGUIDCOL default newid() not null, errcode int NOT NULL, errtext nvarchar(255) NULL, type tinyint NOT NULL)' )

	if (@@error <> 0)
		begin
		RAISERROR(15001, 16, -1, @tempname)
		return (1)
		end

	set	 @tname = @tempname
	set @tempname = '##insert_' + @guidstr

	exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out
	if (@@error <> 0)
		begin
		RAISERROR(15001, 16, -1, 'sp_MSuniquetempname')
		return (1)
		end

	exec @retcode = dbo.sp_MSmaketempinsertproc @tname, @tempname
	if  @@ERROR <>0 or @retcode<>0 return (1)

	select @pname = @tempname
	select @tname, @pname
	return (0)	
go
exec dbo.sp_MS_marksystemobject sp_MScreateretry 
go
grant exec on dbo.sp_MScreateretry to public

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSdropretry')
drop procedure sp_MSdropretry

raiserror('Creating procedure sp_MSdropretry', 0,1)
GO

CREATE PROCEDURE sp_MSdropretry (@tname sysname, @pname sysname)
as
	declare @retcode int
	/*
	** To public
	*/
	if not exists (select * from dbo.sysmergepublications 
							where 1 = {fn ISPALUSER(pubid)})
	begin    
		RAISERROR (14126, 11, -1)
		return (1)
	end
	
	exec ('drop table ' + @tname)
	if @@ERROR <> 0 return(1)
	exec ('drop procedure ' + @pname)
	if @@ERROR <> 0 return(1)
	return (0)	
go
exec dbo.sp_MS_marksystemobject sp_MSdropretry 
go
grant exec on dbo.sp_MSdropretry to public
go


if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenumretries')
drop procedure sp_MSenumretries

raiserror('Creating procedure sp_MSenumretries', 0,1)
GO

CREATE PROCEDURE sp_MSenumretries
	(@tname nvarchar(386),
	 @maxrows int,
	 @tablenick int,
	 @rowguid uniqueidentifier)
as
	declare @tnstring nvarchar(12)
	declare @rgstring nvarchar(38)
	declare @retcode int

	/*
	** do permission checking
	*/
	exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
	if @retcode<>0 or @@ERROR<>0 return (1)

	/*
	** Modify temp table, granted to public.
	*/

	declare @selecttop nvarchar(20)
	if (@maxrows = 0)
		set @selecttop= 'select'
	else
		set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
	
	if (@tablenick < 1)
	begin
		execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @tname + 
				 ' order by tablenick, rowguidcol')
		IF @@ERROR <>0 RETURN (1) 		 
	end
	else
	begin
		set @tnstring = convert(nchar, @tablenick)
		set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
		execute (@selecttop + ' tablenick, rowguidcol, errcode, errtext, type from ' + @tname + 
				' where (tablenick = ' + @tnstring + ' and  rowguidcol > ' + @rgstring + ') or
					 tablenick > ' + @tnstring + ' order by tablenick, rowguidcol' )
		if @@ERROR <> 0 RETURN (1)
	end
	return (0)	
go
exec dbo.sp_MS_marksystemobject sp_MSenumretries
go
grant exec on dbo.sp_MSenumretries to public

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSdeletepushagent')
drop procedure sp_MSdeletepushagent
go
raiserror('Creating procedure sp_MSdeletepushagent', 0,1)
GO

/*
** This procedure is obselete for dropping push agent at distribution database.
** If we were to recover, don't use server id as parameter for RPC into distributor.
** Use server name instead.
*/
CREATE PROCEDURE sp_MSdeletepushagent (
	@publisher		 	sysname,
	@publisher_db	 	sysname,
	@publication 		sysname,
	@subscriber	 		sysname,
	@subscriber_db	 	sysname
	) AS

declare @distributor 	sysname
declare @distribdb		sysname
declare @pubid			uniqueidentifier
declare @distproc		nvarchar(300)
declare @pub_srvid		smallint
declare @sub_srvid		smallint
declare @retcode		smallint

/*
** Do permission checking
*/
exec @retcode=sp_MSreplcheck_publish
if @retcode<>0 or @@ERROR<>0 return (1)


EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
		IF @@ERROR <> 0 or @retcode <> 0
			return (1)
		
select @pub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
select @sub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db

SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_agent_entry'

EXEC @retcode = @distproc @pub_srvid, @publisher_db, @publication, @sub_srvid, @subscriber_db
	    IF @@ERROR <> 0 OR @retcode <> 0
			return (1)
return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSdeletepushagent
go
grant exec on dbo.sp_MSdeletepushagent to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgetlastrecgen')
drop procedure sp_MSgetlastrecgen

raiserror('Creating procedure sp_MSgetlastrecgen', 0,1)
GO

CREATE PROCEDURE sp_MSgetlastrecgen
	(@repid uniqueidentifier)
as
	declare @pubid 		uniqueidentifier
	declare @pubname 	sysname
	declare @status 	int
	declare @retcode	int

	/*
	** do permission checking
	*/
	exec @retcode=sp_MSreplcheck_connection @repid = @repid
	if @retcode<>0 or @@ERROR<>0 return (1)

	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end

	if (@repid is null)
		begin
			RAISERROR(14043, 16, -1, '@repid')
			return (1)
		end
    /*
    ** Check the publication status at the publisher - if it is inactive ( say because of a 
	** metadata cleanup event then return an error so the current merge will quit.
    */
	select @pubid = pubid from sysmergesubscriptions where subid = @repid
	if (@pubid is not null)
		begin
		    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
		    IF @retcode = 0
		        BEGIN

					select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
					if @status = 0
						begin
							RAISERROR(21505, 16, -1, @pubname)
							return (1)
						end
		        END
		end

	select recgen, recguid from MSmerge_replinfo where repid = @repid
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetlastrecgen
go
grant exec on dbo.sp_MSgetlastrecgen to public

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgetlastsentrecgens')
drop procedure sp_MSgetlastsentrecgens

raiserror('Creating procedure sp_MSgetlastsentrecgens', 0,1)
GO

CREATE PROCEDURE sp_MSgetlastsentrecgens
	(@repid uniqueidentifier)
as
	declare @pubid 		uniqueidentifier
	declare @pubname 	sysname
	declare @status 	int
	declare @retcode	int

	if (@repid is null)
		begin
			RAISERROR(14043, 16, -1, '@repid')
			return (1)
		end
	/*
	** do permission checking
	*/
	exec @retcode=sp_MSreplcheck_connection @repid = @repid
	if @retcode<>0 or @@ERROR<>0 return (1)

    /*
    ** Check the publication status at the publisher - if it is inactive ( say because of a 
	** metadata cleanup event then return an error so the current merge will quit.
    */
	select @pubid = pubid from sysmergesubscriptions where subid = @repid
	if (@pubid is not null)
		begin
		    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
		    IF @retcode = 0
		        BEGIN

					select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
					if @status = 0
						begin
							RAISERROR(21505, 16, -1, @pubname)
							return (1)
						end
		        END
		end

	select sentgen, sentguid, recgen, recguid from MSmerge_replinfo where repid = @repid
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetlastsentrecgens
go
grant exec on dbo.sp_MSgetlastsentrecgens to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgetlastsentgen')
drop procedure sp_MSgetlastsentgen

raiserror('Creating procedure sp_MSgetlastsentgen', 0,1)
GO

CREATE PROCEDURE sp_MSgetlastsentgen
	(@repid uniqueidentifier)
as
	declare @pubid 		uniqueidentifier
	declare @pubname 	sysname
	declare @status 	int
	declare @retcode	int

	/*
	** do permission checking
	*/
	exec @retcode=sp_MSreplcheck_connection @repid = @repid
	if @retcode<>0 or @@ERROR<>0 return (1)

	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end

	if (@repid is null)
		begin
			RAISERROR(14043, 16, -1, '@repid')
			return (1)
		end
    /*
    ** Check the publication status at the publisher - if it is inactive ( say because of a 
	** metadata cleanup event then return an error so the current merge will quit.
    */
	select @pubid = pubid from sysmergesubscriptions where subid = @repid
	if (@pubid is not null)
		begin
		    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
		    IF @retcode = 0
		        BEGIN

					select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
					if @status = 0
						begin
							RAISERROR(21505, 16, -1, @pubname)
							return (1)
						end
		        END
		end

	select sentgen, sentguid from MSmerge_replinfo where repid = @repid
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetlastsentgen
go
grant exec on dbo.sp_MSgetlastsentgen to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenumgenerations')
drop procedure sp_MSenumgenerations

raiserror('Creating procedure sp_MSenumgenerations', 0,1)
GO

CREATE PROCEDURE sp_MSenumgenerations
	(@genstart int, @pubid uniqueidentifier, @return_count_of_generations bit = 0)
as
	declare @retcode 	smallint
	declare @guidnull 	uniqueidentifier
	declare @generation_range TABLE (generation int NOT NULL, guidsrc uniqueidentifier NOT NULL, art_nick int NULL, guidlocal uniqueidentifier NOT NULL, pubid uniqueidentifier NULL, nicknames varbinary(1000) NOT NULL, okaytoskip bit NOT NULL)
	declare @status 	int
	declare @pubname 	sysname
	declare @rowcount	int
	set @guidnull = '00000000-0000-0000-0000-000000000000'

	/*
	** Check to see if current publication has permission
	*/
	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin	
		RAISERROR (14126, 11, -1)
		return (1)
	end

	/*
	** To public
	*/
	
	if (@genstart is null)
		begin
		RAISERROR(14043, 16, -1, '@genstart')
		return (1)
		end
	if (@pubid is null)
		begin
		RAISERROR(14043, 16, -1, '@pubid')
		return (1)
		end
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end
    /*
    ** Check the publication status at the publisher - if it is inactive ( say because of a 
	** metadata cleanup event then return an error so the current merge will quit.
    */
    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
    IF @retcode = 0
        BEGIN

			select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
			if @status = 0
				begin
					RAISERROR(21505, 16, -1, @pubname)
					return (1)
				end
        END

	insert into @generation_range (generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip)
	select DISTINCT generation, guidsrc, art_nick, guidlocal, pubid, nicknames, 0
	from dbo.MSmerge_genhistory 
	where generation >= @genstart 
	and (art_nick = 0 or art_nick is NULL or 
		art_nick in (select nickname from sysmergearticles 
		where pubid = @pubid)) 
	select @rowcount = @@rowcount

	if (@return_count_of_generations = 1)
		select @rowcount

	-- optimizations 
	-- 1. skip all rows that are for incomplete generations for articles that have no joins.
	-- 2. skip all rows for join articles if all the join article rows are incomplete generations.

	update @generation_range set okaytoskip = 1
	where art_nick is not null and art_nick <> 0
	and guidlocal = @guidnull 
	and 
	(
		(	
			-- 1. skip all rows that are for incomplete generations for articles that have no joins.
			not exists (select 1 from sysmergesubsetfilters where join_nickname = art_nick or art_nickname = art_nick)
		)
		or
		(	
			-- 2. skip all rows for join articles if all the rows for join and joined articles (i.e. the articles represented by join_nickname 
			--    and art_nickname in sysmergesubsetfilters) are incomplete generations.

			art_nick in (select join_nickname from sysmergesubsetfilters) 
			and not exists 
				(	
					select 1 from @generation_range b where b.guidlocal <> @guidnull 
					and exists (select 1 from sysmergesubsetfilters where join_nickname = b.art_nick or art_nickname = b.art_nick)
					and b.generation > @genstart
				) 
		)
	)
	
	select generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip from @generation_range
	ORDER BY generation ASC

	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumgenerations
go
grant exec on dbo.sp_MSenumgenerations to public
go

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSchecksnapshotstatus')
drop procedure sp_MSchecksnapshotstatus

raiserror('Creating procedure sp_MSchecksnapshotstatus', 0,1)
GO
CREATE PROCEDURE sp_MSchecksnapshotstatus
	@publication		sysname
AS
	declare @db_name		sysname
	declare @retention		int
	declare @snapshot_ready	int
	declare @pubid			uniqueidentifier
	declare @last_snapshot 	datetime
	
	select @snapshot_ready = NULL
	select @db_name = db_name()

	select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid
		from sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=@db_name
	if @snapshot_ready is NULL
		select @snapshot_ready=snapshot_ready, @retention=retention, @pubid=pubid
			from sysmergepublications where name=@publication
	if @snapshot_ready is NULL
	begin
		raiserror (20026, 11, -1, @publication)
		return (1)
	end

	/*
	** Check to see if current publication has permission
	*/
	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin	
		RAISERROR (14126, 11, -1)
		return (1)
	end
	
	if @snapshot_ready=1 and @retention>0
	begin
		select @last_snapshot=last_validated from sysmergesubscriptions where subid=@pubid
		if dateadd(day, @retention, @last_snapshot)<getdate()
			select @snapshot_ready=3 /* snapshot is obsolete */
	end
	select @snapshot_ready
go
exec dbo.sp_MS_marksystemobject sp_MSchecksnapshotstatus
go
grant exec on dbo.sp_MSchecksnapshotstatus to public


if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScheckexistsgeneration')
drop procedure sp_MScheckexistsgeneration

raiserror('Creating procedure sp_MScheckexistsgeneration', 0,1)
GO

CREATE PROCEDURE sp_MScheckexistsgeneration
	(@genguid uniqueidentifier, @gen int output, @pubid uniqueidentifier = NULL)
as
	/*
	** Check input parameter
	*/
	if (@genguid is null)
		begin
			RAISERROR(14043, 16, -1, '@genguid')
			return (1)
		end
	/*
	** check permission
	*/
	if @pubid is not NULL
	begin
		if ({ fn ISPALUSER(@pubid) } <> 1)
		begin    
			RAISERROR (14126, 11, -1)
			return (1)

		end
	end
	else
	begin
		if not exists (select * from dbo.sysmergepublications 
								where 1 = {fn ISPALUSER(pubid)})
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end	
	end	
	/* Normal case : do not qualify by pubid */
	if (@pubid IS NULL)
		select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000'
	else		
	/* If we are reinitializing from an alternate publisher, check if the subscription has received generations for the alternate publication */
		select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000'
			and ((pubid = @pubid) or (pubid is null))
	IF @@ERROR <>0 return (1)
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MScheckexistsgeneration
go
grant exec on dbo.sp_MScheckexistsgeneration to public
GO

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenumreplicas')
drop procedure sp_MSenumreplicas
raiserror('Creating procedure sp_MSenumreplicas', 0,1)
GO

CREATE PROCEDURE sp_MSenumreplicas (@pubid uniqueidentifier)
as
	declare @inactive tinyint

	/*
	** Check to see if current publication has permission
	*/
	if ({ fn ISPALUSER(@pubid) } <> 1)
	begin	
		RAISERROR (14126, 11, -1)
		return (1)
	end

	/*
	** To public
	*/

	select @inactive = 0
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
	begin
		RAISERROR(20054 , 16, -1)
		return (1)
	end

	select subs.subid, replinfo.replnickname, subs.subscriber_type, subs.subscription_type, 
		subs.priority, replinfo.schemaversion, replinfo.schemaguid, subs.datasource_type, subs.datasource_path, servers.srvname,  
		subs.db_name, subs.status, subs.partnerid, subs.sync_type, subs.description, subs.pubid, subs.publication, subs.distributor
		from sysmergesubscriptions subs, MSmerge_replinfo replinfo, master..sysservers servers
			where replinfo.repid = subs.subid 
				and subs.srvid = servers.srvid
				and subs.status <> @inactive
				and subs.subscriber_type = 1
				order by convert(binary, subs.subid)
	IF @@ERROR <>0 return (1) 
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumreplicas 
go
grant exec on dbo.sp_MSenumreplicas to public

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSenumpartialdeletes')
drop procedure sp_MSenumpartialdeletes
go
raiserror('Creating procedure sp_MSenumpartialdeletes', 0,1)
GO

CREATE PROCEDURE sp_MSenumpartialdeletes
	(@maxrows int,
	 @tablenick int,
	 @rowguid uniqueidentifier,
	 @tablenotbelongs nvarchar(255),
	 @bookmark int = NULL,
	 @specified_article_only int = 0)
as

	declare @tnstring 		nvarchar(12)
	declare @rgstring 		nvarchar(38)
	declare @lowrangestr 	nvarchar(12) 
	declare @highrangestr 	nvarchar(12) 
	declare @retcode		int
	
	/*
	** do permission checking
	*/
	exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
	if @retcode<>0 or @@ERROR<>0 return (1)

	/*
	** To public.
	*/
	
	declare @selecttop nvarchar(20)
	if (@maxrows = 0)
		set @selecttop= 'select'
	else
		set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 

-- DEBUG	insert into MSmerge_debug
-- DEBUG		(okay, artnick, twhen, comment)
-- DEBUG		values (0, @tablenick, getdate(), 'sp_MSenumpartialdeletes; maxrows=' + convert(nvarchar, @maxrows) 
-- DEBUG		+ ', startguid=' + convert(nchar(36), @rowguid) + ', bookmark=' + convert(nvarchar, @bookmark)
-- DEBUG		+ ', specified_article_only=' + convert(nchar(1), @specified_article_only))

	if (@tablenick < 1)
	begin
		execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
					order by tablenick desc, rowguid asc' )
		IF @@ERROR <>0 
		begin
-- DEBUG	insert into MSmerge_debug (okay, twhen, comment)
-- DEBUG		values (1, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed')
			return (1) 	
		end

-- DEBUG	execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, twhen, comment) ' +
-- DEBUG				@selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, getdate(), ''sp_MSenumpartialdeletes'' 
-- DEBUG				from ' + @tablenotbelongs + ' order by tablenick desc, rowguid asc' )
	end
	else 
	begin
		set @tnstring = convert(nchar, @tablenick)
		set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''

		/* 
		** If a 7.0 SP1 Merge agent is calling this sp, it passed a valid bookmark parameter 
		** Use the bookmark column in the ##belongs_<> table to retrieve the next batch of rows
		*/
		if @bookmark is NOT NULL 
		begin
			set @lowrangestr = convert(nchar, @bookmark)
			set @highrangestr = convert(nchar, (@bookmark + @maxrows))

			if (@specified_article_only = 1)
			begin
				-- don't rely on @highrangestr since it will be equal to @lowrangestr if @maxrows=0.
				execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
							where  tablenick = ' + @tnstring + ' and 
							bookmark > ' + @lowrangestr + ' 
							order by rowguid' )

				if @@ERROR<>0
				begin
-- DEBUG			insert into MSmerge_debug (okay, twhen, comment)
-- DEBUG			values (2, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed')
					return (1)
				end						

-- DEBUG		execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + 
-- DEBUG					@selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 1''
-- DEBUG					from ' + @tablenotbelongs + '
-- DEBUG					where  tablenick = ' + @tnstring + ' and 
-- DEBUG					bookmark > ' + @lowrangestr + ' 
-- DEBUG					order by rowguid' )

			end
			else
			begin
				execute ('select tablenick, rowguid, COALESCE (generation, 0), lineage, type, bookmark from ' + @tablenotbelongs + '
							where  ((tablenick = ' + @tnstring + ' and 
							bookmark > ' + @lowrangestr + ' and bookmark <= ' + @highrangestr + ') or
							tablenick < ' + @tnstring + ') 
							order by tablenick desc, rowguid asc' )

				if @@ERROR<>0
				begin
-- DEBUG			insert into MSmerge_debug (okay, twhen, comment)
-- DEBUG				values (3, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed')
					return (1)
				end						

-- DEBUG		execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment)
-- DEBUG					select 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only <> 1'' 
-- DEBUG					from ' + @tablenotbelongs + '
-- DEBUG					where  ((tablenick = ' + @tnstring + ' and 
-- DEBUG					bookmark > ' + @lowrangestr + ' and bookmark <= ' + @highrangestr + ') or
-- DEBUG					tablenick < ' + @tnstring + ') 
-- DEBUG					order by tablenick desc, rowguid asc' )
			end
		end

		/* 
		** Backward compatibilty mode : If a 7.0 Merge agent is calling this sp, it will pass a NULL bookmark parameter 
		** Use the rowguid and set rowcount to retrieve the next batch of rows
		*/
		else
		begin
			if (@specified_article_only = 1)
			begin
				execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + '
							where  tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + '
							order by rowguid' )
				IF @@ERROR <>0 
				begin
-- DEBUG				insert into MSmerge_debug (okay, twhen, comment)
-- DEBUG				values (4, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed')
					return (1) 	
				end

-- DEBUG				execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + 
-- DEBUG					@selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 0''
-- DEBUG					from ' + @tablenotbelongs + '
-- DEBUG					where  tablenick = ' + @tnstring + ' and 
-- DEBUG					rowguid > ' + @rgstring + ' 
-- DEBUG					order by rowguid' )
			end
			else
			begin
				execute (@selecttop + ' tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + '
							where  ((tablenick = ' + @tnstring + ' and 
							rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') 
							order by tablenick desc, rowguid asc' )
				IF @@ERROR <>0 
				begin
-- DEBUG				insert into MSmerge_debug (okay, twhen, comment)
-- DEBUG				values (5, getdate(), 'sp_MSenumpartialdeletes: select from notbelong failed')
					return (1) 	
				end

-- DEBUG				execute ('insert into MSmerge_debug (okay, artnick, rowguid, generation_new, lineage_new, type, twhen, comment) ' + 
-- DEBUG					@selecttop + ' 0, tablenick, rowguid, COALESCE (generation, 0), lineage, type, getdate(), ''sp_MSenumpartialdeletes: @specified_article_only = 0''
-- DEBUG					from ' + @tablenotbelongs + '
-- DEBUG					where  ((tablenick = ' + @tnstring + ' and 
-- DEBUG					rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ')
-- DEBUG					order by tablenick desc, rowguid asc' )
			end
		end
	end
	return (0)
go		
exec dbo.sp_MS_marksystemobject sp_MSenumpartialdeletes
go
grant exec on dbo.sp_MSenumpartialdeletes to public
go

if exists (select * from sysobjects
	where type = 'P '
			and name = 'sp_MSaddanonymousreplica')
	drop procedure sp_MSaddanonymousreplica
go
raiserror('Creating procedure sp_MSaddanonymousreplica',0,1)
GO
CREATE PROCEDURE sp_MSaddanonymousreplica
	(@publication 		sysname,
	 @publisher			sysname,
	 @publisherDB		sysname,
	 @anonymous			int,
	 @sync_type			int = 1, /* sync type is automatic by default */
	 @preexists			bit=0 OUTPUT
)
as
set nocount on
declare @retcode 				int
declare @subscription_type 		nvarchar(15)
declare @sync_typestr	 		nvarchar(15)
declare @sub_typeid				int
declare @pubid					uniqueidentifier

/*
** need more than PAL to do this.
*/
exec @retcode = sp_MSreplcheck_subscribe
if @@error<>0 or @retcode<>0
    return (1)

select @preexists = 0

if @anonymous = 1 
begin
	select @subscription_type = 'anonymous'
	select @sub_typeid	= 2 --subscription type value for anonymous
end
else 
begin
	select @subscription_type = 'local'
	select @sub_typeid = 1 --subscription type value for well known pull
end

if @sync_type = 1 select @sync_typestr = 'automatic'
	else select @sync_typestr = 'none'

-- this change is made so that we will try to add pull/anonymous subscriptions, even if
-- there is a already a subscription for that publication, however the subscription type
-- does not match. In this way we can prevent users from using incorrect subscription type
-- through command line or merge control. 

if exists (select * from sysobjects where name='sysmergepublications')
begin
	select @pubid=pubid from sysmergepublications 
		where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisherDB
	if @pubid is not NULL
	begin
		/* Check if theres is a subscriptions entry that matches the pubid and current subscription with the right type */
		if exists (select * from sysmergesubscriptions where pubid =@pubid  and UPPER(subscriber_server) = @@SERVERNAME and db_name = DB_NAME() and subscription_type=@sub_typeid)
			begin
				select @preexists = 1
				return (0)   -- replica exists. 
			end
		/* 
		** Check if theres is a subscriptions entry that matches the pubid and current subscription - 
		** If there is a match and the types are not the same, then return appropriate error.
		*/
		else if exists (select * from sysmergesubscriptions where pubid =@pubid  and UPPER(subscriber_server) = @@SERVERNAME and db_name = DB_NAME())
			begin
            RAISERROR (21500, 16, -1, @publication)    
			-- replica exists with wrong subscription type 
			select @preexists = 1

			return (1)   
			end
		
	end
end

-- Call this SP to add this replica
exec @retcode = dbo.sp_addmergepullsubscription 
	@publication = @publication,
	@publisher = @publisher,
	@publisher_db=@publisherDB,
	@subscriber_type =@subscription_type,
	@sync_type = @sync_typestr

IF @retcode<>0 or @@ERROR<>0 return (1)
return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSaddanonymousreplica
go
grant execute on dbo.sp_MSaddanonymousreplica to public
go 

--------------------------------------------------------------------------------
--. sp_helpreplfailovermode
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_helpreplfailovermode')
drop procedure sp_helpreplfailovermode
go
raiserror('Creating procedure sp_helpreplfailovermode', 0,1)
go
create procedure sp_helpreplfailovermode (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,
	@failover_mode_id tinyint = 0 output,
	@failover_mode nvarchar(10) = NULL output)
as
BEGIN
	declare	@subfound bit
			,@retcode int

	--
	-- security check
	--
	exec @retcode = sp_MSreplcheck_subscribe
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- Check if the table MSsubscription_agents exists
	--
	if exists (select * from dbo.sysobjects 
					where name = 'MSsubscription_agents')
	begin
		--
		-- Only valid to get failover_mode, if failover_mode is failover (3,5)
		--
		if exists (select * from dbo.MSsubscription_agents
				where publisher = @publisher and 
					publisher_db = @publisher_db and
					publication = @publication and
					update_mode in (3,5) )
			select @subfound = 1
		else
			select @subfound = 0
	end
	else
		select @subfound = 0
	
	--
	-- Did we find an entry for initialized failover subscription
	--
	if (@subfound = 0)
	begin
		--
		-- Three possibilities : uninitialized subscription, non existent subscription
		-- or a non-mixed mode. Check If we have a PULL uninitialized subscription
		--
		if exists (select * from dbo.sysobjects 
						where name = 'MSreplication_subscriptions')
		begin
			if exists (select * from dbo.MSreplication_subscriptions
							where publisher = @publisher and 
								publisher_db = @publisher_db and
								publication = @publication and
								update_mode in (3,5) )
			begin
				--
				-- unitialized PULL subscription : return the default values
				--
				select @failover_mode_id = 0
				select @subfound = 1
			end
		end

		if (@subfound = 0)
		begin
			raiserror ('sp_helpreplfailovermode: Subscription for [%s].[%s].[%s] either has not been initialized or does not exist or does not support mixed mode',
						16, 1, @publisher, @publisher_db, @publication)
			return 1
		end
	end
	else
	begin
		--
		-- we found our subscription
		--
		select @failover_mode_id = failover_mode
		from dbo.MSsubscription_agents
		where publisher = @publisher and 
			publisher_db = @publisher_db and
			publication = @publication and
			update_mode in (3,5) 
			
		--
		-- initialize to 'immediate' if necessary
		--
		if @failover_mode_id not in (0, 1)
		begin
			raiserror ('sp_helpreplfailovermode: invalid failover_mode value %d for [%s].[%s].[%s], setting to 0 [immediate]', 
				11, 1, @failover_mode_id, @publisher, @publisher_db, @publication)
			update dbo.MSsubscription_agents 
			set failover_mode = 0
			where publisher = @publisher and 
				publisher_db = @publisher_db and
				publication = @publication and
				update_mode in (3,5) 

			select @failover_mode_id = 0
		end
	end

	--
	-- prepare the output
	--
	select @failover_mode = case 
		when @failover_mode_id = 0 then N'immediate'
		when @failover_mode_id = 1 then N'queued'
		end
		
	select N'failover_mode value'  = @failover_mode_id, 
			N'failover_mode' = @failover_mode

	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_helpreplfailovermode
go
grant execute on dbo.sp_helpreplfailovermode to public
go

--------------------------------------------------------------------------------
--. sp_setreplfailovermode
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_setreplfailovermode')
drop procedure sp_setreplfailovermode
go
raiserror('Creating procedure sp_setreplfailovermode', 0,1)
go
create procedure sp_setreplfailovermode (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,
	@failover_mode nvarchar (10), 
	@override tinyint = 0)
as
begin
	set nocount on
	declare	@failover_mode_id tinyint, 
			@current_failover_mode_id bit,
			@retcode int,
			@queue_id sysname,
			@fqueue_empty int,
			@update_mode int,
			@queue_server sysname

	--
	-- security check
	--
	exec @retcode = sp_MSreplcheck_subscribe
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- validate @failover_mode
	--
	if @failover_mode not in (N'immediate', N'sync', N'queued')
	begin
		raiserror (21184, 16, 1, '@failover_mode', 'immediate', 'sync', 'queued')
		return 1			
	end
	else
	begin
		if @failover_mode = 'immediate' or @failover_mode = 'sync'
			select @failover_mode_id = 0
		else if @failover_mode = 'queued'
			select @failover_mode_id = 1
	end

	--
	-- Only valid to get/set failover_mode, 
	-- if update_mode is failover (3,5)
	--
	select	@queue_id = queue_id, 
			@queue_server = queue_server,
			@current_failover_mode_id = failover_mode,
			@update_mode = update_mode
	from MSsubscription_agents
	where UPPER(publisher) = UPPER(@publisher) and 
		publisher_db = @publisher_db and
		publication = @publication and
		update_mode in (3,5)

	-- no such row exists
	if (@current_failover_mode_id is NULL)		
	begin
		raiserror (21185, 16, 1)
		return 1
	end

	-- should have a queue entry
	if (@queue_id is NULL)
	begin
		raiserror(21186, 16, 1, @publisher)
		return 1
	end

	--
	-- do the transition
	--
	if ((@current_failover_mode_id = 0 and @failover_mode_id = 0) or
			(@current_failover_mode_id = 1 and @failover_mode_id = 1))
	begin
		--
		-- Going from immediate to immediate, queued to queued is no-op
		--
		raiserror (21187, 16, 1)
	end
	else if (@current_failover_mode_id = 0 and @failover_mode_id = 1)
	begin
		--
		-- Going from immediate to queued : update MSsubscription_agents
		--
		update MSsubscription_agents
			set failover_mode = @failover_mode_id
			where UPPER(publisher) = UPPER(@publisher) and 
				publisher_db = @publisher_db and
				publication = @publication and
				update_mode in (3,5)

		raiserror (21188, 10, 1, 'immediate', 'queued')
	end
	else if (@current_failover_mode_id = 1 and @failover_mode_id = 0)
	begin
		--
		-- Going from queued to immediate : if override is not set
		-- then check if the queue is empty and then allow if empty.
		-- If override is set, just update MSsubscription_agents
		--
		if (@override = 0)
		begin
			if (@update_mode = 3)
			begin
				--
				-- MSMQ processing
				-- prefix the queue_id with queue server in direct format
				-- and then perform peek in the queue
				--
				select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
				
				exec @retcode = master.dbo.xp_peekqueue @queue_id, @fqueue_empty output, 0
				if (@@error != 0 or @retcode != 0)
				begin
					raiserror('sp_setreplfailovermode(debug): xp_peekqueue execution failed', 16, 1)
					return 1
				end

				if (@fqueue_empty != 1)
				begin
					raiserror(21189, 16, 1, @queue_id)
					return 1
				end
			end
			else
			begin
				--
				-- SQL Queue processing
				--
				if exists (select * from MSreplication_queue 
					where UPPER(publisher) = UPPER(@publisher) and 
							publisher_db = @publisher_db and
							publication = @publication )
				begin
					raiserror(21189, 16, 2, @queue_id)
					return 1
				end
			end
		end
		else
		begin
			raiserror(21190, 10, 1, 'queued', 'immediate')
		end

		--
		-- update MSsubscription_agents
		--
		update MSsubscription_agents
			set failover_mode = @failover_mode_id
			where publisher = @publisher and 
				publisher_db = @publisher_db and
				publication = @publication and
				update_mode in (3,5)

		raiserror (21188, 10, 1, 'queued', 'immediate')
	end

	-- All done
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_setreplfailovermode
go
grant execute on dbo.sp_helpreplfailovermode to public
go

--------------------------------------------------------------------------------
--. sp_addqueued_artinfo
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_addqueued_artinfo')
drop procedure sp_addqueued_artinfo
go
raiserror('Creating procedure sp_addqueued_artinfo', 0,1)
go
CREATE PROCEDURE sp_addqueued_artinfo (
	@artid				int
	,@article			sysname
	,@publisher 		sysname
	,@publisher_db		sysname
	,@publication		sysname
	,@dest_table		sysname
	,@owner				sysname
	,@cft_table			sysname
	,@columns			binary(32))
AS
BEGIN
	set nocount on
	declare 	@agent_id int
				,@update_mode int
				,@retcode int

	--
	-- security check
	--
	exec @retcode = sp_MSreplcheck_subscribe
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- Create system table MSsubscription_articles if it does not exist
	--
	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND name = 'MSsubscription_articles')
	BEGIN
		CREATE TABLE dbo.MSsubscription_articles
		(
			agent_id		int NOT NULL,		-- related entry in MSsubscription_agents
			artid			int NOT NULL,		-- article id
			article			sysname,			-- article name
			dest_table		sysname,			-- destination table
			owner			sysname,
			cft_table		sysname,			-- conflict table
			columns			binary(32)
		)
		IF (@@ERROR != 0)
		begin
			raiserror('Debug:sp_addqueued_artinfo - create MSsubscription_articles failed', 16, 1)
			return (1)
		end

		CREATE UNIQUE CLUSTERED INDEX ucMSsubscription_articles ON dbo.MSsubscription_articles(agent_id, artid)
		IF (@@ERROR != 0)
		begin
			raiserror('Debug:sp_addqueued_artinfo - create index for MSsubscription_articles failed', 16, 1)
			return (1)
		end
		
		EXEC dbo.sp_MS_marksystemobject 'MSsubscription_articles'
	END

	--
	-- insert the row for the given article
	--
	select @agent_id = id, @update_mode = update_mode
	from MSsubscription_agents 
	where UPPER(publisher) = UPPER(@publisher) and 
		publisher_db = @publisher_db and 
		publication = @publication 

	if (@agent_id IS NULL)
	begin
		raiserror('Debug:sp_addqueued_artinfo - agent_id is null for [%s].[%s].[%s]', 
			16, 1, @publisher, @publisher_db, @publication)
		return (1)
	end

	-- If the subscription is read only or immediate, no need to article info.
	if @update_mode in (0,1)
		return 0

	--
	-- If MSMQ Queued mode - check if the subscriber is compliant for MSMQ 2.0
	--
	if (@update_mode in (2,3))
	begin
		if ((platform() & 0x1) != 0x1)
		begin
			--
			-- Win 9X platform
			--
			raiserror(21334, 16, 1, '2.0')
			return (1)
		end

		--
		-- Now we use xp_MSver to detect NT OS version
		-- MSMQ subscription only allowed for platforms that support MSMQ 2.0
		-- version 5.0.2195 or higher
		--
		create table #tosversion ( propid int, propname sysname collate database_default, value int, charvalue nvarchar(255) collate database_default)
		insert into #tosversion (propid, propname, value, charvalue)
			exec master.dbo.xp_msver N'WindowsVersion'

		declare @vervalue int
			,@lobyte tinyint
			,@hibyte tinyint
			,@loword smallint
			,@hiword smallint

		--
		-- low order byte of low order word = OSmajor, high order byte of low order word = OSminor
		-- high order word = OSbuild
		--
		select @vervalue = value from #tosversion where propname = N'WindowsVersion'
		select @loword = (@vervalue & 0xffff)
				,@hiword = (@vervalue / 0x10000) & 0xffff
		select @lobyte = @loword & 0xff
				,@hibyte = (@loword / 100) & 0xff
		drop table #tosversion

		--
		-- check for OS major version
		--
		if (@lobyte < 5)
		begin
			raiserror(21334, 16, 2, '2.0')
			return (1)
		end

		--
		-- check for OS build version
		--
		if (@lobyte = 5 and @hiword < 2195)
		begin
			raiserror(21334, 16, 3, '2.0')
			return (1)
		end
	end

	--
	-- Check for owner - use current user for NULL value
	--
	if (@owner IS NULL or lower(@owner) = N'null' collate database_default)
		select @owner = user_name()

	if exists (select * from MSsubscription_articles where agent_id = @agent_id and artid = @artid)
		delete MSsubscription_articles where agent_id = @agent_id and artid = @artid
		
	insert into MSsubscription_articles(agent_id, artid, article, dest_table, owner, cft_table, columns)
		values (@agent_id, @artid, @article, @dest_table, @owner, @cft_table, @columns)

	IF (@@ERROR != 0)
	begin
		raiserror('Debug:sp_addqueued_artinfo - insert failed', 16, 1)
		return (1)
	end

	--
	-- Do the queue initialization here
	-- this way we can initialize Snapshot/Logbased queued tran from one place
	--
	exec @retcode = dbo.sp_MSreset_queue @publisher, @publisher_db, @publication, @artid
	IF (@retcode != 0 or @@ERROR != 0)
	begin
		raiserror('Debug:sp_addqueued_artinfo - sp_MSreset_queue failed', 16, 1)
		return (1)
	end
	
	--
	-- all done
	--
	return 0	
END
go
exec dbo.sp_MS_marksystemobject sp_addqueued_artinfo
go
grant execute on dbo.sp_addqueued_artinfo to public
go

--------------------------------------------------------------------------------
--. sp_MSreset_queued_reinit
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSreset_queued_reinit')
drop procedure sp_MSreset_queued_reinit
go
raiserror('Creating procedure sp_MSreset_queued_reinit', 0,1)
go
create procedure sp_MSreset_queued_reinit (
	@subscriber      sysname,					-- subscriber server name
	@subscriber_db   sysname,					-- subscribing database name. 
	@artid	int)				   				-- article id
as
begin
	set nocount on
	declare @srvid int
		,@retcode int
		,@publication sysname
	--
	-- PAL security check
	-- Get publication name using artid
	--
	select @publication = p.name
	from syspublications p join sysarticles a on p.pubid = a.pubid
	where a.artid = @artid
	if (@publication is null)
	begin
		return 1
	end
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	select @srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
	--
	-- set the reinit flag
	--
	update dbo.syssubscriptions
	set queued_reinit = 0
	where 
		artid = @artid 
		and srvid = @srvid
		and dest_db = @subscriber_db
	if (@@error != 0)
	    return 1

	-- all done
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSreset_queued_reinit
go
grant execute on dbo.sp_MSreset_queued_reinit to public
go
--------------------------------------------------------------------------------
--. fn_escapecmdshellsymbols
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'FN'
    and name = N'fn_escapecmdshellsymbols' )
drop function system_function_schema.fn_escapecmdshellsymbols
go
raiserror('Creating function fn_escapecmdshellsymbols', 0,1) with nowait
go
--
-- Name: fn_escapecmdshellsymbols
--
-- Descriptions: This function returns an escaped version of a given string
--               with carets ('^') added in front of all the special 
--               command shell symbols. In the W2K online help (Start->
--               Help->Index->Command Reference->Command Symbols...), the 
--               following symbols are listed as special command symbols:
--                 (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"')
--
-- Parameter: @command_string nvarchar(4000)
-- 
-- Example: select fn_escapecmdshellsymbols(N'The % quick < brown > dog | jumps & over ( the ) lazy ^ fox.') 
--             will return 
--    
--    The ^% quick ^< brown ^> dog ^| jumps ^& over ^( the ^) lazy ^^ fox
--
-- Security: This function is granted to public
--
create function system_function_schema.fn_escapecmdshellsymbols(
    @command_string nvarchar(4000)
    ) returns nvarchar(4000)
as
begin
    declare @escaped_command_string nvarchar(4000),
            @curr_char nvarchar(1),
            @curr_char_index int    
    select @escaped_command_string = N'',
           @curr_char = N'', 
           @curr_char_index = 1
    while @curr_char_index <= len(@command_string)
    begin
        select @curr_char = substring(@command_string, @curr_char_index, 1) 
        if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"')
        begin
            select @escaped_command_string = @escaped_command_string + N'^'
        end
        select @escaped_command_string = @escaped_command_string + @curr_char
        select @curr_char_index = @curr_char_index + 1 
    end
    return @escaped_command_string
end
go
grant execute on system_function_schema.fn_escapecmdshellsymbols to public

--------------------------------------------------------------------------------
--. fn_escapecmdshellsymbolsremovequotes
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'FN'
    and name = N'fn_escapecmdshellsymbolsremovequotes' )
    drop function system_function_schema.fn_escapecmdshellsymbolsremovequotes

raiserror('Creating function fn_escapecmdshellsymbolsremovequotes', 0,1) with nowait
go
--
-- Name: fn_escapecmdshellsymbolsremovequotes
--
-- Descriptions: The only difference between this function and 
--               fn_escapecmdshellsymbols is that "'s are removed from the 
--               resulting command line.
--
-- Parameter: @command_string nvarchar(4000)
-- 
-- Security: This function is granted to public
--
create function system_function_schema.fn_escapecmdshellsymbolsremovequotes(
    @command_string nvarchar(4000)
    ) returns nvarchar(4000)
as
begin
    declare @escaped_command_string nvarchar(4000),
            @curr_char nvarchar(1),
            @curr_char_index int    
    select @escaped_command_string = N'',
           @curr_char = N'', 
           @curr_char_index = 1
    while @curr_char_index <= len(@command_string)
    begin
        select @curr_char = substring(@command_string, @curr_char_index, 1) 
        if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^')
        begin
            select @escaped_command_string = @escaped_command_string + N'^'
        end
        if @curr_char <> '"'
        begin
            select @escaped_command_string = @escaped_command_string + @curr_char
        end
        select @curr_char_index = @curr_char_index + 1 
    end
    return @escaped_command_string
end
go
grant execute on system_function_schema.fn_escapecmdshellsymbolsremovequotes to public

--------------------------------------------------------------------------------
--. sp_MSget_file_existence
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSget_file_existence')
drop procedure sp_MSget_file_existence
go
print ''
print 'Creating procedure sp_MSget_file_existence'
go
create procedure sp_MSget_file_existence (
@filename nvarchar(260),
@exists bit = 0 output
)
AS
    SET NOCOUNT ON

    DECLARE @command nvarchar(512)
    DECLARE @retcode int
	declare @echo_text nvarchar(20)

	select @echo_text = 'file_exists'

    /*
    ** The return code from xp_cmdshell is not a reliable way to check whether the file exists or
    ** not. It is always 0 on Win95 as long as xp_cmdshell succeeds.
    */  

	select @command = N'if exist "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + N'" echo ' + @echo_text

    create table #text_ret(cmdoutput nvarchar(20) collate database_default null)

    insert into #text_ret exec @retcode = master..xp_cmdshell @command
	if @@error <> 0 or @retcode <> 0
		return 1

    if exists (select * from #text_ret where ltrim(rtrim(cmdoutput)) = @echo_text)
        select @exists = 1
    else 
        select @exists = 0

    drop table #text_ret
go
EXEC dbo.sp_MS_marksystemobject sp_MSget_file_existence
GO

--------------------------------------------------------------------------------
--. sp_replicationoption
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_replicationoption')
drop procedure sp_replicationoption
go
raiserror('Creating procedure sp_replicationoption', 0,1)
go

CREATE PROCEDURE sp_replicationoption (
@optname		sysname,
@value			nvarchar(5),
@security_mode	int = 0,
@login			sysname = 'sa',
@password		sysname = NULL,
@reserved       nvarchar(20) = NULL
)
AS
	DECLARE @optbit bit
	DECLARE @osql_path nvarchar(260)
    DECLARE @osql_cmd1 nvarchar (255)
    DECLARE @osql_cmd_full nvarchar (255)
	DECLARE @osql_for_nt int

	DECLARE @install_path nvarchar (255)

    DECLARE @retcode int
	DECLARE @undo_install nvarchar(20)
	DECLARE @no_scripts nvarchar(10)
    DECLARE @platform_nt binary
    
    SELECT @platform_nt = 0x1

    if	is_srvrolemember('sysadmin') <> 1
        BEGIN
            RAISERROR (15232, 14, -1)
            RETURN (1)
        END
	
	SELECT @no_scripts = 'no_scripts'

	SELECT @undo_install = 'undo_install'

	IF db_name() <> 'master'
	BEGIN
		RAISERROR(5001, 16,-1)
		GOTO FAILURE
	END

	IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('transactional','merge')
	BEGIN
		RAISERROR(21014, 16, -1)
		GOTO FAILURE
	END
	IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false')
	BEGIN
		RAISERROR(14137,16,-1)
		GOTO FAILURE
	END
	
	IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		SELECT @optbit = 1
	ELSE
		SELECT @optbit = 0

	/*
	** Check if the option is set as required already
	*/
	IF @reserved <> @undo_install AND EXISTS (SELECT * FROM MSreplication_options
		WHERE	optname  = @optname
		AND		value = @optbit)
	BEGIN
		IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
			RAISERROR (21015, 10, -1, @optname)		
		ELSE
			RAISERROR (21016, 10, -1, @optname)
		GOTO FAILURE
	END

	/* Install replication */
	IF @optbit = 1
	BEGIN

		IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = @no_scripts
			GOTO NO_SCRIPTS

		-- Set the flag for platform
		IF (( platform() & @platform_nt = @platform_nt ))
			SELECT @osql_for_nt = 1
		ELSE
			SELECT @osql_for_nt = 0

		/* 
		** Get installation path -- osql client (TOOLS) path
		*/
		EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
		IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
		BEGIN
			GOTO FAILURE       
		END

		/* 
		** Get installation path -- instance specific (INSTALL) directory
		*/
		exec @retcode = master.dbo.sp_MSget_setup_paths
			@sql_path = @install_path output
		IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path=''
			BEGIN
				GOTO FAILURE       
			END

		/* 
		** Install replcom.sql and repltran.sql
		*/
		IF @security_mode = 1
		begin
			SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E ' 
			if serverproperty('instancename') is not null
				SELECT @osql_cmd1 = @osql_cmd1 + ' -S"' + @@SERVERNAME + '" '
		end
		ELSE
			-- cannot specify -S w/ -E for local execution, SID does not map
			SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
				fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '

		select @osql_cmd1 = @osql_cmd1 + '-l30 -t30 '

		-- Install replcom.sql 
		-- Only apply replcom.sql if it was not applied before.
		-- '-b' option will make osql stop at errors and return error code
		-- We must use this option.
		IF NOT EXISTS (SELECT * FROM MSreplication_options
			WHERE value = 1)
		BEGIN
			-- Initialize the Command
			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = '" '
			ELSE
				SELECT @osql_cmd_full = ' '

			SELECT @osql_cmd_full = @osql_cmd_full +
				@osql_cmd1 + 
				' -dmaster' +  ' -b ' +
				' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.sql"' + 
				' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.out"' 

			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = @osql_cmd_full + ' "'

			EXEC @retcode = master..xp_cmdshell @osql_cmd_full
			IF @@ERROR<> 0 OR @retcode <> 0
			BEGIN
				RAISERROR (14113, 16, -1, @osql_cmd_full, 'replcom.out')
				GOTO UNDO_INSTALL     
			END
		END

		IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional'
		BEGIN
			-- Install repltran.sql
			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = '" '
			ELSE
				SELECT @osql_cmd_full = ' '

			SELECT @osql_cmd_full = @osql_cmd_full +
				@osql_cmd1 + 
				' -dmaster' +  ' -b ' +
				' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.sql"' + 
				' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.out"' 

			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = @osql_cmd_full + ' "'

			EXEC @retcode = master..xp_cmdshell @osql_cmd_full
			IF @@ERROR<> 0 OR @retcode <> 0
			BEGIN
				RAISERROR (14113, 16, -1, @osql_cmd_full, 'repltran.out')
				GOTO UNDO_INSTALL     
			END

		END

		IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge'
		BEGIN
			-- Install replmerg.sql 
			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = '" '
			ELSE
				SELECT @osql_cmd_full = ' '

			SELECT @osql_cmd_full = @osql_cmd_full +
				@osql_cmd1 + 
				' -dmaster' + ' -b ' +
				' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.sql"' + 
				' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.out"' 
			
			IF (@osql_for_nt = 1)
				SELECT @osql_cmd_full = @osql_cmd_full + ' "'

			EXEC @retcode = master..xp_cmdshell @osql_cmd_full 
			
			IF  @@ERROR<> 0 OR @retcode <> 0
			BEGIN
				RAISERROR (14113, 16, -1, @osql_cmd_full, 'replmerg.out')
				GOTO UNDO_INSTALL     
			END
		END

NO_SCRIPTS:

		UPDATE MSreplication_options SET value = @optbit
			WHERE optname = @optname
		IF @@ERROR <> 0 
		BEGIN
			GOTO UNDO_INSTALL    
		END

	END
	/* Uninstall replication */
	ELSE
	BEGIN

		/* 
		** Make sure no distributor installed before dropping 
		** replication stored procedures
		*/
		IF EXISTS (SELECT * FROM master..sysservers
              WHERE  srvstatus & 8 <> 0)
		BEGIN
			RAISERROR (21021, 16, -1)
			RETURN(1)
		END

		UPDATE MSreplication_options SET value = @optbit
			WHERE optname = @optname
		IF @@ERROR <> 0 
		BEGIN
			GOTO FAILURE
		END

		/* 
		*********** Do not drop replication stored procs anymore.

		IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional'
		BEGIN
			if exists (select * from sysobjects
				where type = 'P '
						and name = 'sp_MSdrop_repltran')
			begin
				exec @retcode = dbo.sp_MSdrop_repltran
				if @@ERROR = 0 and @retcode = 0
					drop procedure sp_MSdrop_repltran
			end
		END

		IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge'
		BEGIN
			if exists (select * from sysobjects
				where type = 'P '
						and name = 'sp_MSdrop_replmerg')
			begin
				exec @retcode = dbo.sp_MSdrop_replmerg
				if @@ERROR = 0 and @retcode = 0
					drop procedure sp_MSdrop_replmerg
			end
		END

		IF NOT EXISTS (SELECT * FROM MSreplication_options
			WHERE value = 1)
		BEGIN
			if exists (select * from sysobjects
				where type = 'P '
						and name = 'sp_MSdrop_replcom')
			begin
				exec @retcode = dbo.sp_MSdrop_replcom
				if @@ERROR = 0 and @retcode = 0
					drop procedure sp_MSdrop_replcom
			end
		END

		*/
	END

	RETURN(0)

UNDO_INSTALL:
	/* This is needed to drop the stored procedures that were created. */
	EXEC dbo.sp_replicationoption @optname =  @optname, 
		@value = 'false', @reserved = @undo_install

FAILURE:
	RETURN(1)
GO
exec dbo.sp_MS_marksystemobject sp_replicationoption
go
grant execute on dbo.sp_replicationoption to public
go

--------------------------------------------------------------------------------
--. sp_vupgrade_replication
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_vupgrade_replication')
drop procedure sp_vupgrade_replication
go
raiserror('Creating procedure sp_vupgrade_replication', 0,1)
GO

create procedure sp_vupgrade_replication ( @login sysname = N'sa', @password sysname = N'', @ver_old int = 517, @force_remove tinyint = 0, @security_mode bit = 0 )
as
begin
/* 
 * Dispatcher proc for handling schema and metadata changes during setup initiated version upgrade 
 * for replication components. Any schema changes to replication system tables may require modifications 
 * here to maintain upgrade path. All modifications called in these procs are within "if exists" checks
 * making them repeatable for debugging and to support incremental upgrades (e.g. Beta 1 to Beta 2 to RTM)
 * 
 * If server is a distributor, run new instdist.sql against all distribution dbs.
 *
 * This proc gets called by setup at the end of an install over an existing version.
*/

	set nocount on 

	declare @dbname sysname
	declare @has_dbaccess bit
	declare @install_path nvarchar(255)
	declare @osql_path nvarchar(260)
	declare @osql_cmd nvarchar(512)
	declare @osql_for_nt int
	declare @retcode int
	declare @platform_nt binary
	declare @db_distbit int
	declare @ver_min			int
	declare @ver_retention	int 

	select @db_distbit = 16
	select @platform_nt = 0x1
	select @ver_retention = 576 --build # on 9/17

	-- raiserror('sp_vupgrade_replication', 0,1) with nowait

	/*
	 * obsolete check; ver check was to prevent repl upgrade from
	 * versions prior to SQL7.0 Beta 3; check is removed by setting @ver_min = -1
	*/
	select @ver_min= -1 -- change if later wish to support a minimum upgrade version
	if ( @ver_old < @ver_min ) or ( @force_remove = 1 )
		exec dbo.sp_removesrvreplication
	else
	begin

		/* 
		 * always need to run instdist.sql to update distribution databases on a distributor
		 * setup must restart in non-single user mode so we can shell out to run instdist.sql scripts
		*/
		if exists( select * from master..sysdatabases where category & @db_distbit = @db_distbit )
		begin

			/* 
			** Get installation path -- osql client (TOOLS) path
			*/
			EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
			IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
			BEGIN
				RETURN (1)
			END

			/* 
			** Get installation path -- instance specific (INSTALL) directory
			*/
			exec @retcode = master.dbo.sp_MSget_setup_paths
				@sql_path = @install_path output
			IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path=N''
			BEGIN
				RETURN (1)
			END

			-- Set the flag for platform
			if (( platform() & @platform_nt = @platform_nt ))
				select @osql_for_nt = 1
			else
				select @osql_for_nt = 0

			declare cur_distdb CURSOR LOCAL FAST_FORWARD for 
				select name, has_dbaccess(name) from master..sysdatabases 
					where category & @db_distbit = @db_distbit
				for read only
			
			open cur_distdb
			fetch cur_distdb into @dbname, @has_dbaccess
			while ( @@fetch_status <> -1 )
			begin

				-- if distribution database is available upgrade it; if offline error out
				if ( @has_dbaccess = 1 )
				begin
					raiserror( 21374, 0, 1, @dbname) with nowait

					/*
					 * Format osql cmd line appropriate for security mode and OS to run instdist.sql against
					 * each distribution database. Instdist.sql will recompile procs and will also do some
					 * schema and metadata upgrade of changed replication tables. Query timeout increased to
					 * make enough time for alter tables in instdist.sql run for upgrade to complete.
					*/
					if ( @osql_for_nt = 1 )
						select @osql_cmd = N'" "'
					else
						select @osql_cmd = N' "'
					
					-- Cannot specify -S w/ -E for local execution, SID does not map (nofix)
					if ( @security_mode = 1 and @osql_for_nt = 1 )
					begin
						select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E '
						if serverproperty('instancename') is not null
							select @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
					end
					else
						select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U' + fn_escapecmdshellsymbols(isnull(@login, N'sa')) collate database_default + ' -P' + fn_escapecmdshellsymbols(isnull(@password, N'')) collate database_default + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '

					select @osql_cmd = @osql_cmd + ' -l30 -t120 '
					select @osql_cmd = @osql_cmd + ' -b ' + ' -d' + fn_escapecmdshellsymbols(@dbname) collate database_default
					select @osql_cmd = @osql_cmd +	' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + 
													' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"'			

					if (@osql_for_nt = 1)
						select @osql_cmd = @osql_cmd + ' "'

	 				exec @retcode = master..xp_cmdshell @osql_cmd
					if @retcode <> 0 or @@error <> 0
					begin
						raiserror (14113, 16, -1, @osql_cmd, 'instdist.out')
					end

					/*
					 * Process schema and metadata changes for each distribution database
					*/

					select @dbname = quotename(@dbname)
					exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_distdb')
					if @@error <> 0
						return(1)
				end
				else
				begin
					/* Report informational message stating distribution
					** database is not accessible.
					*/
					raiserror( 21378, 10, 1, @dbname) with nowait
				end
				
				fetch next from cur_distdb into @dbname, @has_dbaccess
			end
			close cur_distdb
			deallocate cur_distdb
		end

		-- vupgrade_publisher runs at 
		exec @retcode = dbo.sp_vupgrade_publisher 
			@ver_old = @ver_old, 
			@ver_retention = @ver_retention
		if @retcode<>0 or @@error<>0
			return (1)
	
		-- Update subscription database schema
		exec @retcode = dbo.sp_vupgrade_subscription_databases
		if @retcode <> 0 or @@error <> 0
			return (1)


	end

	return (0)

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_replication
go

--------------------------------------------------------------------------------
--. sp_MScopysnapshot
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScopysnapshot')
drop procedure sp_MScopysnapshot
go
raiserror('Creating procedure sp_MScopysnapshot', 0,1)
go
CREATE PROCEDURE sp_MScopysnapshot (
    @source_folder           nvarchar(255),
    @destination_folder      nvarchar(255)
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @directory_exists bit    
    DECLARE @ftporuncdir      nvarchar(5)
    DECLARE @pubdir           nvarchar(255)
    DECLARE @timestampdir     nvarchar(255)
    DECLARE @bslashindex      int
    DECLARE @bslashindex2     int
    DECLARE @bslashcounter    int
    DECLARE @command          nvarchar(1000)
    DECLARE @retcode          int
    DECLARE @platform_nt      bit

    IF platform() & 0x1 = 0x1
        SELECT @platform_nt = 1
    ELSE
        SELECT @platform_nt = 0

    -- If @source_folder is NULL then either the snapshot has not been 
    -- generated or it has been cleaned up
    IF @source_folder IS NULL OR @source_folder = N''
    BEGIN
        RAISERROR(21289, 16, -1)
        RETURN (1)
    END

    -- Make sure that the @destination folder is not null
    IF @destination_folder IS NULL OR
       @destination_folder = N''
    BEGIN
        RAISERROR(21287, 16, -1)      
        RETURN (1)
    END

    -- Append backslash to @destination_folder if it is not 
    -- there already
    IF SUBSTRING(@destination_folder, LEN(@destination_folder), 1) <> N'\'
    BEGIN
        SELECT @destination_folder = @destination_folder + N'\'
    END

    -- Check if the destination folder exists 
    EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT
    IF @directory_exists = 0
    BEGIN
        RAISERROR(21287, 16, -1)      
        RETURN (1)
    END    
    
    -- Parse out the last three components in the source folder 
    -- Note that the source_folder must have a trailing backslash
    SELECT @bslashindex = 1
    SELECT @bslashindex2 = 1
    SELECT @bslashcounter = 0
    WHILE (@bslashindex <> 0)
    BEGIN
        SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex + 1)
        SELECT @bslashcounter = @bslashcounter + 1
        IF @bslashcounter > 4
        BEGIN
            SELECT @bslashindex2 = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
        END    
    END  

    SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
    SELECT @ftporuncdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1)
    SELECT @bslashindex2 = @bslashindex

    SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
    SELECT @pubdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) 
    SELECT @bslashindex2 = @bslashindex

    SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
    SELECT @timestampdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) 
    SELECT @bslashindex2 = @bslashindex
        
    -- Create the subdirectory structure underneath the specified snapshot
    -- folder. Ignore errors for now, we will check whether the directory 
    -- is successfully created later on.

    -- Don't suppress output from xp_cmdshell so user knows what's going on
    -- in case something goes wrong 
    SELECT @destination_folder = @destination_folder + @ftporuncdir + '\'
    SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'
    IF (@platform_nt = 1)
        SELECT @command = '" ' + @command + ' "'
    EXEC master..xp_cmdshell @command
    
    SELECT @destination_folder = @destination_folder + @pubdir + '\'
    SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate  database_default + '"'
    IF (@platform_nt = 1)
        SELECT @command = '" ' + @command + ' "'
    EXEC master..xp_cmdshell @command

    SELECT @destination_folder = @destination_folder + @timestampdir + '\'
    SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'
    IF (@platform_nt = 1)
        SELECT @command = '" ' + @command + ' "'
    EXEC master..xp_cmdshell @command

    -- Check if the real destination folder exists
    EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT
    IF @directory_exists = 0
    BEGIN
        RAISERROR(21288, 16, -1)
        RETURN (1)
    END

    -- Do the actual copying
    SELECT @command = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@source_folder) collate database_default + '*.*" "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'    
    IF (@platform_nt = 1)
        SELECT @command = '" ' + @command + ' "'
    
    EXEC @retcode = master..xp_cmdshell @command
    
    IF @retcode <> 0
        RETURN (1)
    ELSE
        RETURN (0)
END
go
EXEC dbo.sp_MS_marksystemobject sp_MScopysnapshot
go

--------------------------------------------------------------------------------
--. sp_copymergesnapshot
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_copymergesnapshot')
drop procedure sp_copymergesnapshot
go
raiserror('Creating procedure sp_copymergesnapshot', 0,1)
go
CREATE PROCEDURE sp_copymergesnapshot (
    @publication          sysname,
    @destination_folder   nvarchar(255)
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @retcode       int
    DECLARE @source_folder nvarchar(255)
    SELECT @retcode = 0
    
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 OR @retcode <> 0
		RETURN (1)

    CREATE TABLE #snapshot_folders
    (
        id              int identity, 
        snapshot_folder nvarchar(255) collate database_default
    )
    IF @@ERROR <> 0
    BEGIN
        RETURN 1
    END

    INSERT INTO #snapshot_folders
    EXEC @retcode = sp_browsemergesnapshotfolder @publication = @publication
    IF @retcode <> 0 OR @@ERROR <> 0
    BEGIN
        GOTO Failure
    END
    
    SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id ASC)
    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END        
    SET ROWCOUNT 0    

    EXEC @retcode = sp_MScopysnapshot @source_folder,
                                      @destination_folder
    IF @retcode <> 0 OR @@ERROR <> 0 
    BEGIN
        GOTO Failure
    END

    DROP TABLE #snapshot_folders
    RETURN 0
Failure:
    SET ROWCOUNT 0    
    DROP TABLE #snapshot_folders        
    RETURN 1
END
GO
EXEC dbo.sp_MS_marksystemobject sp_copymergesnapshot
go
grant execute on dbo.sp_copymergesnapshot to public
go

--------------------------------------------------------------------------------
--. sp_copysubscription
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_copysubscription')
drop procedure sp_copysubscription
go
print ''
print 'Creating procedure sp_copysubscription'
go
CREATE PROCEDURE sp_copysubscription (
@filename nvarchar(260),
@temp_dir nvarchar(260) = NULL,
-- Directory contains temp files. If not specified, SQL
-- server default data directory will be used.
@overwrite_existing_file bit = 0
)
AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @cmd nvarchar(4000)
	declare @retcode int
	declare @data_path nvarchar(260)
	declare @subscriber_srvid 	int
	declare @subscriber_db		sysname
	declare @backup_path nvarchar(260)
	declare @temp_data_path nvarchar(260)
	declare @temp_log_path nvarchar(260)
	declare @retention			int
	declare @retention_date   	datetime
    declare @pubid	 			uniqueidentifier


	/*
	* Initializations
	*/
	select @retcode = 0
	select @subscriber_srvid = 0
	select @subscriber_db = db_name()

	-- We only support single file attach. Check to make sure
	-- there are only 2 files, one data file and one log file
	if (select count(*) from sysfiles) > 2
	begin
		raiserror(21212,16, -1)
		return 1
	end

	/* Make sure all tran sub allows attach */
	declare @publication 				sysname
	declare @publisher					sysname
	declare @tran_found					bit
	declare @merge_found				bit
	select @tran_found = 0
	select @merge_found = 0

	/* 
	** Make sure all merge subscriptions in the current database 
	** have allow_subscription_copy set to TRUE
	** and there are no push subscriptions. 
	*/
	if exists (select * from sysobjects where name = 'MSsubscription_agents')
	begin
		set @publisher = NULL
		-- Not using @publication because share agent case.
		select top 1 @publisher = publisher from MSsubscription_agents where
			allow_subscription_copy = 0
        IF @publisher is not null
	    BEGIN
			RAISERROR(21236, 16, -1, @publisher)
	        RETURN (1)
	    END

		set @publisher = null
		select top 1 @publisher = publisher from MSreplication_subscriptions where
			subscription_type = 0
        IF @publisher is not null
	    BEGIN
			RAISERROR(21237, 16, -1, @publisher)	        
			RETURN (1)
	    END
		if exists (select * from MSsubscription_agents)
			select @tran_found = 1
	end			

	/* 
	** Make sure all merge subscriptions in the current database 
	** have allow_subscription_copy set to TRUE
	** and there are no push subscriptions. 
	*/
	if exists (select * from sysobjects where name = 'sysmergepublications')
		begin
			set @publication = NULL
			select top 1 @publication = name from sysmergepublications where
				allow_subscription_copy = 0
	        IF @publication is not null
		        BEGIN
		            RAISERROR (21204, 16, -1, @publication)    
		            RETURN (1)
		        END

			set @publication = null
			select top 1 @publication = p.name from sysmergepublications p, 
				sysmergesubscriptions s where
				p.pubid = s.pubid and
				s.subid <> s.pubid and 
				db_name = db_name() collate database_default and 
				subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default  and
				s.subscription_type = 0
			IF @publication is not null
		    BEGIN
				RAISERROR(21238, 16, -1, @publication)	        
				RETURN (1)
			END

			-- Does db contains subscriptions?
			if exists (select * from sysmergesubscriptions where subid <> pubid and 
				db_name = db_name() collate database_default and 
				subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default)
				select @merge_found = 1

			/* Retention check : Make sure that the subscription copy is not too old */
			declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT p.name, p.pubid, p.retention from sysmergepublications p, sysmergesubscriptions s 
		        where s.subid=p.pubid and s.pubid=p.pubid for read only
		    open PC
		    fetch PC into @publication, @pubid, @retention 
		    
		    WHILE (@@fetch_status <> -1)
		        BEGIN
					/* Compute the retention period cutoff dates per publication */
					select @retention_date = dateadd(day, -@retention, getdate())
			       	if @retention is not NULL and @retention > 0
		        	begin
						if not exists (select coldate from sysmergearticles , MSmerge_genhistory 
											where	nickname = art_nick 
													and coldate > @retention_date 
													and sysmergearticles.pubid = @pubid)
							begin
					            RAISERROR (21306, 16, -1, @publication)
								return (1)
							end					            
		            end
		            fetch PC into @publication, @pubid, @retention
		        END

		end			

	if @tran_found = 0 and @merge_found = 0
	begin
		raiserror(21239, 16 , -1)
		return (1)
	end
	
	-- Security check
	-- Only DBO or sysadmin can do this
	-- The user also must have create db permissions.
	exec @retcode = dbo.sp_MSreplcheck_subscribe
    IF @retcode <> 0 or @@error <> 0
		return 1

	if @overwrite_existing_file is null
		set @overwrite_existing_file = 0

	-- Check to see if the file already exists
	declare @exists bit

	if @overwrite_existing_file = 0
	begin
		exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output
		if @@error <> 0 or @retcode <> 0
			return 1
		if @exists <> 0 
		begin
			raiserror(21214, 16, -1, @filename)
			return 1
		end
	end

	-- Check to see if have write permissions to the file location.
	-- Try create the file
	-- Echo text can be anything.
	select @cmd = 'echo Subscription copy failed. > "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"'
	exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT
	if @@error <> 0 or @retcode <> 0
	begin
		raiserror(21247, 16, -1, @filename)
		select @retcode = 1
		goto Cleanup
	end	
	-- File should be created.
	exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output
	if @@error <> 0 or @retcode <> 0
	begin
		select @retcode = 1
		goto Cleanup
	end
	if @exists = 0
	begin
		raiserror(21247,16, -1, @filename)
		select @retcode = 1
		goto Cleanup
	end

	/*
    ** Get the MSSQL DATA path. Note that users can have a SQLDataRoot directory different from SQLPath
    */
	if @temp_dir is null
	begin
		exec @retcode = master.dbo.sp_MSget_setup_paths
			@data_path = @temp_dir output
		IF @retcode <> 0 or @@error <> 0
			return 1
		select @temp_dir = @temp_dir + '\DATA\'
	end
	else
	begin
		-- Check to make sure working dir is valid.
		exec @retcode = dbo.sp_MSget_file_existence @temp_dir, @exists output
		if @@error <> 0 or @retcode <> 0
		begin
			select @retcode = 1
			goto Cleanup
		end
		if @exists = 0
		begin
			raiserror (21037, 16, -1, @temp_dir)		
			select @retcode = 1
			goto Cleanup
		end
		if substring(@temp_dir, len(@temp_dir), 1) <> '\'
			select @temp_dir = @temp_dir + '\'
	end

	-- Get temp db name
	-- Use a guid to avoid name colision.
	declare @dbname sysname
	select @dbname = db_name()
	declare @temp_db_name sysname
    declare @guid_name nvarchar(36)
    select @guid_name =  convert (nvarchar(36), newid())

	select @temp_db_name = 'repl_sub_restore_' + @guid_name

	select @backup_path = @temp_dir + @temp_db_name + '.bak'

	-- Create table used to signal attach or restored process to do different things
	if not exists (select * from sysobjects where name = 'MSreplication_restore_stage')
	begin 
		CREATE TABLE dbo.MSreplication_restore_stage
		(
		stage_id int -- not used for now
		)
		IF @@ERROR <> 0
			return 1
	end
	
	-- First backup the database to the file given
	-- Overwrite the existing file with INIT option.
	BACKUP DATABASE @dbname TO DISK = @backup_path WITH INIT
	if @@error<> 0
	begin
		select @retcode = 1
		goto Cleanup
	end


	-- Restore it to a temporary working database
	-- Get phy data and log file name for the temp db
	select @temp_data_path = @temp_dir + @temp_db_name + '.mdf'
	select @temp_log_path = @temp_dir + @temp_db_name + '.ldf'

	-- Get the command
	select @cmd = 'restore database ' + quotename(@temp_db_name) + ' from disk = ' 
		+ quotename(@backup_path,'''') + ' with replace, move '

	-- Get the logical file name for data file.
	select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where
		(status & 0x40) = 0

	-- Use passed in filename as phy data file name for the temp db

	-- Use the passed in file as phy data file for the temp db
	select @cmd = @cmd + ' to ' + quotename(@temp_data_path,'''') + ', move '

	-- Get the logical file name for the log file
	select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where
		(status & 0x40) <> 0

	-- Use the passed in file as phy file for the temp db
	select @cmd = @cmd + ' to ' + quotename(@temp_log_path,'''') + ' '
	exec (@cmd)
	if @@error<> 0
	begin
		select @retcode = 1
		goto Cleanup
	end

	-- Once we successfully restored, we delete to back up file to save disk space.
	if @backup_path is not null
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
		set @backup_path = null
	end

	-- Prepare the database for detach. 2 things will be done
	-- 1. Set a flag to indicate that this is a prepare sub db for detach
	-- 2. For merge, create table to store sysservers info for later fixing up after attach
	select @cmd = quotename(@temp_db_name) + '.dbo.sp_MSprepare_sub_for_detach'
	
	exec @retcode = @cmd @subscriber_srvid = @subscriber_srvid, @subscriber_db = @subscriber_db
	if @retcode<>0 or @@error<>0
	begin
		select @retcode = 1
		goto Cleanup
	end

	-- Shink the size of the temp db before detach
	DBCC SHRINKDATABASE (@temp_db_name, 10)
	if @@error <> 0
		goto Cleanup

	-- detach the database
	-- Wait for the db to be closed
	WAITFOR DELAY '00:00:00.500'
	exec @retcode = sp_detach_db @temp_db_name
	if @retcode<>0 or @@error<>0
	begin
		select @retcode = 1
		goto Cleanup
	end

	-- Delete the log file to save disk space
	if @temp_log_path is not null
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
		set @temp_log_path = null
	end

	-- Compress the file
	exec @retcode = master..xp_makecab
		@cabfilename = @filename,
		@compression_mode ='mszip',
		@verbose_level = 0,
		@filename1 = @temp_data_path
	if @retcode<>0 or @@error<>0
	begin
		select @retcode = 1
		goto Cleanup
	end


Cleanup:
	if exists (select * from sysobjects where name = 'MSreplication_restore_stage')
		drop table dbo.MSreplication_restore_stage


	if exists (select * from master..sysdatabases where name = @temp_db_name collate database_default)
	begin
		select @cmd = 'drop database ' + quotename(@temp_db_name)
		exec (@cmd)
	end

	if @backup_path is not null
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
	end

	if @temp_data_path is not null
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_data_path) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
	end

	if @temp_log_path is not null
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
	end

	if @retcode <> 0
	begin
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
	end

	return @retcode
go
EXEC dbo.sp_MS_marksystemobject sp_copysubscription
GO
grant execute on dbo.sp_copysubscription to public
go

--------------------------------------------------------------------------------
--. sp_attachsubscription
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_attachsubscription')
drop procedure sp_attachsubscription
go
print ''
print 'Creating procedure sp_attachsubscription'
go
CREATE PROCEDURE sp_attachsubscription (
@dbname	sysname,
@filename nvarchar(260),
@subscriber_security_mode		int = NULL,						/* 0 standard; 1 integrated */
@subscriber_login				sysname = NULL,
@subscriber_password			sysname = NULL
)
AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @cmd nvarchar(4000)
	declare @retcode int
	DECLARE @platform_nt binary
	declare @copy_created bit
    declare @exists bit

	select @platform_nt = 0x1	
	select @retcode = 0
	select @copy_created = 0
    select @exists = 0

	-- Parameter check: @subscriber_security_mode
	if @subscriber_security_mode is null
	begin
		if ( platform() & @platform_nt ) = @platform_nt
			select @subscriber_security_mode = 1
		else
			select @subscriber_security_mode = 0
	end	

	if ( ( platform() & @platform_nt ) <> @platform_nt and @subscriber_security_mode = 1 )
	begin
		RAISERROR(21038, 16, -1)
		RETURN (1)
	end

	if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
		set @subscriber_login = 'sa'

	-- Check to make sure the database does not exists.
	if exists (select * from master..sysdatabases where name = @dbname collate database_default)
	begin
		raiserror(20621, 16, -1, @dbname)
		return (1)
	end

	-- Check to see if users has permissions to create database
	-- permissions() have to be run in master to return create db permission.
	declare @pm int
	exec @retcode = master.dbo.sp_executesql N'select @pm = permissions()', N'@pm int output', @pm output
	if @@error <> 0 or @retcode <> 0
		return 1
	if @pm & 1 = 0
	begin
		raiserror(20618, 16, -1)
		return 1
	end

	-- Decompress the file
	-- We have to copy the file to another location first. 
	-- (cannot use source as destination')
	declare @temp_copy nvarchar(260)
	declare @file_dir nvarchar(260)
	declare @file_name nvarchar(260)
	declare @dir_cmd nvarchar(260)
	-- Set @drive_cmd if needed 
	-- Set temp copy to be the file directory first
	-- Note @file_dir include '\'
	if (charindex('\', @filename, 1) = 0)
	begin
		select @file_dir = ''
		select @file_name = @filename
	end
	else
	begin
		select @file_dir = left(@filename,len(@filename) + 1 - 
			charindex('\', reverse(@filename), 1))
		select @file_name = right(@filename, len(@filename) - len(@file_dir))
	end
	-- Get guid name
    declare @guid_name nvarchar(36)
    select @guid_name =  convert (nvarchar(36), newid())
	select @temp_copy = @file_dir + @guid_name + '.tmp'


	-- copy file
	select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '"'
	exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT
	if @@error <> 0 or @retcode <> 0
	begin
		raiserror(21248, 16, -1, @filename)
		select @retcode = 1
		goto Cleanup
	end	

    exec @retcode = dbo.sp_MSget_file_existence @temp_copy, @exists output
    if @@error <> 0 or @retcode <> 0
    begin
        select @retcode = 1
        goto Cleanup
    end
    if @exists = 0
    begin
		raiserror(21247, 16, -1, @temp_copy)        
        select @retcode = 1
        goto Cleanup
    end

	select @copy_created = 1

	-- decompress
	exec @retcode = master.dbo.xp_unpackcab 
		@cabfilename = @temp_copy,
		@destination_folder = @file_dir,
		@verbose_level = 0,
		@destination_file = @file_name,
		@suppress_messages = 1
		
	if @@error <> 0 
	begin
		select @retcode = 1
		goto Cleanup
	end

	if @retcode in (1030,1029,2005)
	begin
		raiserror(20609, 16, -1, @filename)
		select @retcode = 1
		goto Cleanup
	end	
	else if @retcode <> 0
	-- re-issue the command to get errors
	begin
		exec @retcode = master.dbo.xp_unpackcab 
			@cabfilename = @temp_copy,
			@destination_folder = @file_dir,
			@verbose_level = 0,
			@destination_file = @file_name,
			@suppress_messages = 0
		select @retcode = 1
		goto Cleanup
	end

	-- Attach
	exec @retcode = dbo.sp_attach_single_file_db
		@dbname = @dbname,
		@physname = @filename
	if @retcode<>0 or @@error<>0
	begin
		raiserror(21248, 16, -1, @filename)
		select @retcode = 1
		goto Cleanup
	end


	-- Prepare the database for detach. 2 things will be done
	-- 1. Set a flag to indicate that this is a prepare sub db for detach
	-- 2. For merge, create table to store sysservers info for later fixing up after attach
	select @cmd = quotename(@dbname) + '.dbo.sp_MSrestore_sub'
	exec @retcode = @cmd
		@subscriber_security_mode = @subscriber_security_mode,	
		@subscriber_login = @subscriber_login,
		@subscriber_password = @subscriber_password
	if @retcode<>0 or @@error<>0
	begin
		select @retcode = 1
		goto Cleanup
	end

Cleanup:
	if @retcode <> 0
	begin
		-- The files will be deleted if some thing failed. 
		if exists (select * from master..sysdatabases where name = @dbname collate database_default)
			begin
				select @cmd = 'drop database ' + quotename(@dbname)
				exec (@cmd)
			end				
	end

	if @temp_copy is not null
	begin
		-- Restore the original file, ignore errors
		if @retcode <> 0 and @copy_created = 1
		begin
			select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"'
			exec master.dbo.xp_cmdshell @cmd, NO_OUTPUT
		end

		-- Delete the temp file.
		select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default+ '"' 
		EXEC master..xp_cmdshell @cmd, NO_OUTPUT
	end

	return @retcode
go
EXEC dbo.sp_MS_marksystemobject sp_attachsubscription
GO
grant execute on dbo.sp_attachsubscription to public
go
--------------------------------------------------------------------------------
--. sp_browsesnapshotfolder
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_browsesnapshotfolder')
drop procedure sp_browsesnapshotfolder
go
raiserror('Creating procedure sp_browsesnapshotfolder', 0,1)
go
CREATE PROCEDURE sp_browsesnapshotfolder (
    @publication    sysname,
    @subscriber     sysname = NULL,
    @subscriber_db  sysname = NULL
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @publisher      sysname
    DECLARE @publisher_db   sysname
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       nvarchar(300)
    DECLARE @article_id     INT
    
    SELECT @retcode = 0
    SELECT @publisher = NULL
    SELECT @publisher_db = DB_NAME()
    SELECT @distributor = NULL
    SELECT @distributiondb = NULL
    SELECT @article_id = NULL
    
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    -- Either both of @subscriber and @subscriber_db are NULL or
    -- both of them have to be non-null
    IF ((@subscriber IS NULL OR @subscriber = N'') 
        AND @subscriber_db IS NOT NULL AND @subscriber_db <> N'') OR
       ((@subscriber_db IS NULL OR @subscriber_db = N'') 
        AND @subscriber IS NOT NULL AND @subscriber <> N'')
    BEGIN
        RAISERROR(21148, 16, -1)
    END
    
    IF EXISTS (SELECT * FROM sysobjects WHERE name = N'syspublications') AND
       EXISTS (SELECT * FROM sysobjects WHERE name = N'sysextendedarticlesview')
    BEGIN    
        SELECT @publisher = @@SERVERNAME
    
        -- Get the smallest article id for the publication since 
        -- method for identifying a publication is not readily available 
        -- on the distributor

        SELECT @article_id = MIN(artid) 
          FROM sysextendedarticlesview sa
    INNER JOIN syspublications sp
            ON sa.pubid = sp.pubid
         WHERE sp.name = @publication

        IF @article_id IS NULL
        BEGIN
            RAISERROR(20026, 16, -1, @publication)
        END         

        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                               @distribdb = @distributiondb OUTPUT
        IF @retcode <> 0
            RETURN @retcode
    
        SELECT @distributor = RTRIM(@distributor)
    
        IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
        BEGIN
            SELECT @distproc = @distributor + '.' + @distributiondb + 
                               '.dbo.sp_MSbrowsesnapshotfolder'
        END
        ELSE
        BEGIN
            SELECT @distproc = @distributiondb + '.dbo.sp_MSbrowsesnapshotfolder'
        END
        EXECUTE @retcode = @distproc
                    @publisher = @publisher, 
                    @publisher_db = @publisher_db,
                    @article_id = @article_id,
                    @subscriber = @subscriber,
                    @subscriber_db = @subscriber_db
        RETURN @retcode
    END
    ELSE
    BEGIN
        RAISERROR(21149, 16, -1, @publisher_db)
        RETURN 1
    END
END
GO
EXEC dbo.sp_MS_marksystemobject sp_browsesnapshotfolder
go
grant execute on dbo.sp_browsesnapshotfolder to public
go
--------------------------------------------------------------------------------
--. sp_copysnapshot
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_copysnapshot')
drop procedure sp_copysnapshot
go

raiserror('Creating procedure sp_copysnapshot', 0,1)
go
CREATE PROCEDURE sp_copysnapshot (
    @publication        sysname,
    @destination_folder nvarchar(255),
    @subscriber         sysname = NULL,
    @subscriber_db      sysname = NULL
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @retcode       int
    DECLARE @source_folder nvarchar(255)
    SELECT @retcode = 0
    
    -- security check, db_owner
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    CREATE TABLE #snapshot_folders
    (
        id              int identity,
        snapshot_folder nvarchar(255) collate database_default
    )
    IF @@ERROR <> 0
    BEGIN
        RETURN 1
    END

    INSERT INTO #snapshot_folders
    EXEC @retcode = sp_browsesnapshotfolder @publication = @publication,
                                            @subscriber = @subscriber,
                                            @subscriber_db = @subscriber_db
    IF @retcode <> 0 OR @@ERROR <> 0
    BEGIN
        GOTO Failure
    END

    SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id)
    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END        
    SET ROWCOUNT 0

    EXEC @retcode = sp_MScopysnapshot @source_folder,
                                      @destination_folder
    IF @retcode <> 0 OR @@ERROR <> 0 
    BEGIN
        GOTO Failure
    END

    DROP TABLE #snapshot_folders
    RETURN 0
Failure:
    SET ROWCOUNT 0
    DROP TABLE #snapshot_folders        
    RETURN 1
END
GO
EXEC dbo.sp_MS_marksystemobject sp_copysnapshot
go
grant execute on dbo.sp_copysnapshot to public
go

--------------------------------------------------------------------------------
--. sp_getagentoffloadinfo
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_getagentoffloadinfo')
drop procedure sp_getagentoffloadinfo
go
print ''
print 'Creating procedure sp_getagentoffloadinfo'
go
CREATE PROCEDURE sp_getagentoffloadinfo (
    @job_id         VARBINARY(16)
) AS
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       NVARCHAR(300)

    SELECT @retcode = 0
    SELECT @distributor    = NULL
    SELECT @distributiondb = NULL

    -- security check, db_owner
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)


    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distributiondb OUTPUT

    IF @retcode <> 0
        RETURN @retcode

    SELECT @distributor = RTRIM(@distributor)

    SELECT @distproc = @distributor + '.' + @distributiondb + 
                           '.dbo.sp_MSgetagentoffloadinfo'

    EXECUTE @retcode = @distproc 
                @job_id = @job_id

    RETURN @retcode
GO
EXEC dbo.sp_MS_marksystemobject sp_getagentoffloadinfo
GO
grant execute on sp_getagentoffloadinfo to public
go

--------------------------------------------------------------------------------
--.	System objects (replcom.sql)
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
--. sp_adddistributiondb
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_adddistributiondb')
drop procedure sp_adddistributiondb
go
raiserror('Creating procedure sp_adddistributiondb', 0,1)
go

CREATE PROCEDURE sp_adddistributiondb (
    @database sysname,
    @data_folder nvarchar(255) = NULL,
    @data_file nvarchar(255) = NULL,            /* physical file name */
    @data_file_size int = 2,                    /* Default: 2MB */            
    @log_folder nvarchar(255) = NULL,
    @log_file nvarchar(255) = NULL,             /* physical file name */
    @log_file_size int = 0,
    @min_distretention int = 0,                 /* min distribution retention period in hours */
    @max_distretention int = 72,                /* max distribution retention period in hours */
    @history_retention int = 48,                /* history retention period in hours */
    @security_mode int = 0,                     /* distributor login security 0 standard 1 integrated */
    @login sysname = 'sa',                      /* standard login name */
    @password sysname = NULL,                   /* standard login password */
    @createmode int = 0,  /* 0: use create db for attach (recommended), 
                            1: create db or use existing but no attach (this is the old way), 
                            2: create for instdist and detach only */
	@from_scripting bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @data_path nvarchar(512)
    DECLARE @log_path nvarchar(512)
    
    DECLARE @data_path_quoted_for_copy nvarchar(512)
    DECLARE @log_path_quoted_for_copy nvarchar(512)

    DECLARE @logical_data_file nvarchar(255)
    DECLARE @logical_log_file nvarchar(255)
    DECLARE @canneddbdata_file nvarchar(255)
    DECLARE @canneddblog_file nvarchar(255)
    DECLARE @filecopy_cmd nvarchar(255)
    DECLARE @file_exists bit
    DECLARE @data_file_preexists int
    DECLARE @log_file_preexists int
	DECLARE @osql_path nvarchar(260)
    DECLARE @osql_cmd nvarchar(1000)
	DECLARE @osql_for_nt int
    DECLARE @devnum int
    --DECLARE @num_pages int
    DECLARE @retcode int
    DECLARE @reg_key nvarchar(255)
    DECLARE @agentname nvarchar(100)
    DECLARE @command nvarchar (2048)
    DECLARE @distbit int
    DECLARE @install_path nvarchar(255)
    DECLARE @mssql_data_path nvarchar(255)
    DECLARE @on_clause nvarchar(512)
    DECLARE @logon_clause nvarchar(512)
    DECLARE @distproc nvarchar(255)
    DECLARE @major_version int
    DECLARE @db_exists bit
    DECLARE @trunc_log_bit int
    DECLARE @description nvarchar(100)
    DECLARE @category_name sysname
    DECLARE @createmode_attach int
    DECLARE @createmode_noattach int
    DECLARE @createmode_fordetach int

    --DECLARE @filegrowth nvarchar(10)
    DECLARE @data_file_size_str nvarchar(10)
    DECLARE @log_file_size_str nvarchar(10)
    DECLARE @platform_nt binary

    --DECLARE @max_datafile_size int
    --DECLARE @max_logfile_size int
    
	IF @password = N''
		select @password = NULL

    select @platform_nt = 0x1
    --select @filegrowth = N'512KB'

    -- on error, delete the data and log files only if they didn't pre-exist.
    -- by default, assume they pre-exist.
    select @data_file_preexists = 1
    select @log_file_preexists = 1
    select @file_exists = 0

    if (@data_file_size IS NULL) or (@data_file_size = 0)
        select @data_file_size_str = N'512KB'
    else
        select @data_file_size_str = convert(nvarchar(10), @data_file_size)

    if (@log_file_size IS NULL) or (@log_file_size = 0)
        select @log_file_size_str = N'512KB'
    else
        select @log_file_size_str = convert(nvarchar(10), @log_file_size)
    
    --if (@data_file_size > 16)
    --  select @max_datafile_size = @data_file_size
    --else
    --  select @max_datafile_size = 16
    
    --if (@log_file_size > 16)
    --  select @max_logfile_size = @log_file_size
    --else
    --  select @max_logfile_size = 16

    select @createmode_attach = 0, @createmode_noattach = 1, @createmode_fordetach = 2
    SELECT @trunc_log_bit = 8
    SELECT @distbit = 16

    if (@createmode <> @createmode_fordetach)
    begin
    
        /* 
        ** Check if replication components are installed on this server
        */
        exec @retcode = dbo.sp_MS_replication_installed
        if (@retcode <> 1)
        begin
            return (1)
        end
    
        /* 
        ** Check for invalid security modes
        */
        IF @security_mode < 0 OR @security_mode > 1
        BEGIN
            RAISERROR(14109, 16, -1)
            RETURN (1)
        END

        IF ( ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1)
        BEGIN
            RAISERROR(21038, 16, -1)
            RETURN (1)
        END
    
        /* 
        ** Check for invalid retention values 
        */
        IF @min_distretention < 0 OR @max_distretention < 0 
        BEGIN
            RAISERROR(14106, 16, -1)
            RETURN (1)
        END
        IF @min_distretention > @max_distretention
        BEGIN
            RAISERROR(14107, 16, -1) 
            RETURN (1)
        END

        /*
        ** Check to make sure this is a distributor
        */
        IF NOT EXISTS (SELECT * FROM master..sysservers
              WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
                 AND srvstatus & 8 <> 0)
        BEGIN
            RAISERROR (14114, 16, -1, @@SERVERNAME)
            RETURN(1)
        END
    
        /*
        ** Check if database is already configured as a distributor database
        */
        IF EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @database collate database_default)
        BEGIN
            RAISERROR (14119, 16, -1, @database)
            RETURN(1)
        END    
    end

    /* 
    ** Get path to osql client (TOOLS) directory
    */
    EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
    IF ( @retcode <> 0 ) or ( @@ERROR <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
    BEGIN
        GOTO UNDO       
    END

    /* 
    ** Get path to version specific INSTALL directory
    */
	exec @retcode = master.dbo.sp_MSget_setup_paths
		@sql_path = @install_path output,
		@data_path = @mssql_data_path output
    IF @retcode <> 0 or @install_path is NULL or @install_path='' or @mssql_data_path = ''
    BEGIN
        GOTO UNDO       
    END

    IF @data_folder IS NULL or @data_folder = ''
        select @data_folder = @mssql_data_path + '\DATA'

    IF @log_folder IS NULL or @log_folder = ''
        select @log_folder = @mssql_data_path + '\DATA'

    IF @data_file IS NULL
        SELECT @data_file = @database + '.MDF'

    IF @log_file IS NULL
        SELECT @log_file = @database + '.LDF'

    if substring(@data_folder, len(@data_folder), 1) = '\'
    select @data_folder = substring (@data_folder, 1, len(@data_folder) -1)
    if substring(@log_folder, len(@log_folder), 1) = '\'
    select @log_folder = substring (@log_folder, 1, len(@log_folder) -1)

    SELECT @data_path = @data_folder + '\' + @data_file
    SELECT @log_path = @log_folder + '\' + @log_file

    SELECT @data_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@data_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@data_file) collate database_default + '"'
    SELECT @log_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@log_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@log_file) collate database_default + '"'

    select @logical_data_file = @database

    /* 
    ** Truncate the logical log file name back to 128 characters
    ** long so the 'CREATE DATABASE' statement won't complain.
    */
    /* LEN(@logical_log_file) = LEN(@database) + LEN('_log') and
       LEN(@logical_log_file) <= 128 implies 
       LEN(@database) <=124 */
    IF (LEN(@database) > 124)
        SELECT @logical_log_file = SUBSTRING(@database, 1, 124) + '_log'  
    ELSE 
        SELECT @logical_log_file = @database + '_log'

    if (@createmode = @createmode_attach)
    begin
        select @canneddbdata_file = @mssql_data_path + '\DATA\DISTMDL.MDF'
        select @canneddblog_file = @mssql_data_path + '\DATA\DISTMDL.LDF'

        exec dbo.sp_MSget_file_existence @canneddbdata_file, @file_exists OUTPUT
        if (@file_exists = 0)
        begin
            /* Fallback to mode where instdist.sql needs to be run */
            select @createmode = @createmode_noattach
        end

        exec dbo.sp_MSget_file_existence @canneddblog_file, @file_exists OUTPUT
        if (@file_exists = 0)
        begin
            /* Fallback to mode where instdist.sql needs to be run */
            select @createmode = @createmode_noattach
        end
    end

    /*
    ** Create the distributor database if it does not exist
    */
    IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode <> @createmode_attach)
    BEGIN

        -- Note: Use system's default file growth.
        IF @logical_data_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_data_file collate database_default)
        BEGIN
            SELECT @on_clause = ' ON (NAME =''' + @logical_data_file + ''',FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + 
                ''', SIZE=' + @data_file_size_str + ', MAXSIZE = UNLIMITED)'
        END

        IF @logical_log_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_log_file collate database_default)
        BEGIN
            SELECT @logon_clause = ' LOG ON (NAME =''' + @logical_log_file + ''',FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + 
                ''', SIZE=' + @log_file_size_str + ', MAXSIZE= UNLIMITED)'          
        END

        /*
        ** Create distributor database
        */
        SELECT @command = 'USE master  CREATE DATABASE ' +  QUOTENAME(@database) + 
            + isnull(@on_clause, ' ') + isnull(@logon_clause, ' ')

        EXEC (@command)
        IF @@ERROR <> 0
            RETURN (1)
        SELECT @db_exists = 0
    END
    ELSE IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode = @createmode_attach)
    BEGIN
    /* DO THE CREATE DATABASE FOR ATTACH STUFF */
        
        exec dbo.sp_MSget_file_existence @data_path, @data_file_preexists OUTPUT
        if (@data_file_preexists = 1)
        begin
            raiserror(5170, 16, -1, @data_path)
            return 1
        end
    
        SELECT @on_clause = ' ON (NAME = ''' + @logical_data_file + ''', FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + ''')'
        
        exec dbo.sp_MSget_file_existence @log_path, @log_file_preexists OUTPUT
        if (@log_file_preexists = 1)
        begin
            raiserror(5170, 16, -1, @log_path)
            return 1
        end

        SELECT @logon_clause = ' LOG ON (NAME = ''' + @logical_log_file + ''', FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + ''')'

        select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddbdata_file) collate database_default + '" ' + @data_path_quoted_for_copy
        EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT
        IF @retcode <> 0 OR @@ERROR <> 0
        BEGIN
            RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out')
            return (1)
        END

        select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddblog_file) collate database_default + '" ' + @log_path_quoted_for_copy
        EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT
        IF @retcode <> 0 OR @@ERROR <> 0
        BEGIN
            RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out')
            return (1)
        END

        /*
        ** Create distributor database
        */
        SELECT @command = 'USE master  CREATE DATABASE ' +  QUOTENAME(@database) + 
            + @on_clause + @logon_clause + ' FOR ATTACH'

        EXEC (@command)
        IF @@ERROR <> 0
        begin
            RETURN (1)
        end
        dbcc dbreindexall(@database, 240) with no_infomsgs

        SELECT @db_exists = 0
    END
    ELSE
    BEGIN
        SELECT @db_exists = 1
    END

    -- Must make the dist db owned by sa so that the sps in it can select from
    -- security cache tables in tempdb by owership chain rule.
    declare @retcode2 int
    select @retcode2 = 0
    select @distproc = QUOTENAME(@database) + '.dbo.sp_executesql'
    SELECT @command = 
        -- If the db is created by sa or from attach, sa is dbo already.
        -- sp_changedbowner will fail is the new owner is an user in the db already.
        ' if not exists (select * from sysusers where sid = 0x01) ' +
        ' exec @retcode2 = dbo.sp_changedbowner ''sa'''
    EXEC @retcode = @distproc @command, N'@retcode2 int output', @retcode2 output
    IF @retcode <> 0 or @retcode2 <> 0 or @@ERROR <> 0
    BEGIN
        GOTO UNDO
    END

    /* Set the database option truncate log on checkpoint & turn off autoclose which is default of win9x*/
    IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE 
        name = @database collate database_default AND
        (status & @trunc_log_bit) = 0 )   -- if its not already marked
    BEGIN
        EXEC @retcode = dbo.sp_dboption @database, 'trunc. log on chkpt.', 'true'
        IF @retcode <> 0 OR @@ERROR <> 0
        BEGIN
            GOTO UNDO
        END
    END

    EXEC @retcode = dbo.sp_dboption @database, 'autoclose', 'false'
        IF @retcode <> 0 OR @@ERROR <> 0
        BEGIN
            GOTO UNDO
        END

    /*
    **
    ** Update sysdatabase category bit
    ** This is to prevent user from dropping the database.
    **/
    if (@createmode <> @createmode_fordetach)
    begin
        UPDATE master..sysdatabases SET category = category | @distbit WHERE name = @database collate database_default
        IF @@ERROR <> 0
        BEGIN
            GOTO UNDO
        END
    end

    /* 
    ** Install instdist.sql
    */

    if (@createmode <> @createmode_attach) OR (@db_exists = 1)
    begin
		if (( platform() & @platform_nt = @platform_nt ))
			select @osql_for_nt = 1
		else
			select @osql_for_nt = 0

        -- Always use integrated security on WINNT since @login passed-in is for remote 
        -- subscriber and may not have enough privilege to apply the script
        IF (@security_mode = 1 or @osql_for_nt = 1) AND NOT (@security_mode = 0 AND @createmode = 2)
		BEGIN
            SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E '  
			if serverproperty('instancename') is not null
				SELECT @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
		END
        ELSE
		BEGIN
        -- cannot specify -S w/ -E for local execution, SID does not map 
		if (@osql_for_nt = 1)
            SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
                fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
		else
			SELECT @osql_cmd = '"'   + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
                fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
		END
    
        select @osql_cmd = @osql_cmd + '-l60 -t60 '

        -- We must use -b option to make osql return error code !!
        SELECT @osql_cmd = @osql_cmd + 
            ' -d"' + fn_escapecmdshellsymbols(@database) collate database_default + '" -b ' +
            ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + 
            ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"'

		if (@osql_for_nt = 1)
		BEGIN
	        SELECT @osql_cmd = @osql_cmd + ' "'
		END
    
        EXEC @retcode = master..xp_cmdshell @osql_cmd
        IF @retcode <> 0 OR @@ERROR <> 0
        BEGIN
            RAISERROR (14113, 16, -1, @osql_cmd, 'instdist.out')
            GOTO UNDO       
        END
    end
    
    if (@createmode <> @createmode_fordetach)
    begin
        /* Set db_existed bit in MSrepl_version */
        IF @db_exists = 1
        BEGIN
            SELECT @distproc = 'UPDATE ' +
                @database + '..MSrepl_version SET db_existed = 0x1'
    
            EXEC(@distproc)
            IF @@ERROR <> 0
            BEGIN
                GOTO UNDO       
            END
        END

        DELETE msdb.dbo.MSdistributiondbs WHERE name = @database collate database_default
        IF @@ERROR <> 0
        BEGIN
            GOTO UNDO       
        END

        INSERT INTO msdb.dbo.MSdistributiondbs VALUES (
            @database, @min_distretention, @max_distretention, @history_retention
            )
        IF @@ERROR <> 0
        BEGIN
            GOTO UNDO       
        END

        -- This login need db_owner priviledge to call sps in distribution db
        declare @distributor_login sysname
        select @distributor_login = 'distributor_admin'

        select @command = quotename(@database) + '.dbo.sp_MSrepl_dbrole'
        exec @retcode = @command 'db_owner', @distributor_login, 'add'
        IF @@error <> 0 OR @retcode <> 0
            GOTO UNDO

		if @from_scripting = 0
		begin
			/*
			** Create the history cleanup agent.
			*/
			SELECT @agentname = formatmessage (20567, @database)
			SELECT @command =  'EXEC dbo.sp_MShistory_cleanup @history_retention = ' + 
				CONVERT(nvarchar(12), @history_retention)

			IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
				UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
			BEGIN
				EXEC @retcode = msdb.dbo.sp_delete_job 
					@job_name = @agentname
				IF @@ERROR <> 0 or @retcode <> 0
				BEGIN
					GOTO UNDO
				END
			END

			set @description = formatmessage(20535)

			-- Get History Cleanup category name (assumes category_id = 12)
			select @category_name = name FROM msdb.dbo.syscategories where category_id = 12

			EXECUTE @retcode = dbo.sp_MSadd_repl_job @agentname,
			@subsystem = 'TSQL',
			@server = @@SERVERNAME,
			@databasename = @database,
			@description = @description,
			@freqtype = 4,    
			@freqsubtype = 4,         
			@freqsubinterval = 10,    /* Number of minutes between runs */ 
			@command = @command,
			@enabled = 1,
			@retryattempts = 0,
			@loghistcompletionlevel = 0,
			@category_name = @category_name
    
			IF @@ERROR <> 0 or @retcode <> 0
			BEGIN
				GOTO UNDO
			END

			/*
			** Create the distribution cleanup agent.
			*/
			SELECT @agentname = formatmessage (20568, @database)
			SELECT @command =  'EXEC dbo.sp_MSdistribution_cleanup @min_distretention = ' + 
				CONVERT(nvarchar(12), @min_distretention) + ', @max_distretention = ' +
				CONVERT(nvarchar(12), @max_distretention)

			IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
				UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
			BEGIN
				EXEC @retcode = msdb.dbo.sp_delete_job 
					@job_name = @agentname
				IF @@ERROR <> 0 or @retcode <> 0
				BEGIN
					GOTO UNDO
				END
			END

			set @description = formatmessage(20541)
			-- Get Distribution Cleanup category name (assumes category_id = 11)
			select @category_name = name FROM msdb.dbo.syscategories where category_id = 11
    
			EXECUTE @retcode = msdb.dbo.sp_MSadd_repl_job @agentname,
			@subsystem = 'TSQL',
			@server = @@SERVERNAME,
			@databasename = @database,
			@description = @description,
			@freqtype = 4,    
			@freqsubtype = 4,         
			@freqsubinterval = 10,    /* Number of minutes between runs */ 
			@command = @command,
			@retryattempts = 0,
			@enabled = 0,
			@loghistcompletionlevel = 0,
			@category_name = @category_name,
			-- Start  and end time is 5 min off from the history cleanup, which use the default.
			@activestarttimeofday = 000500,
			@activeendtimeofday   = 000459

			IF @@ERROR <> 0 or @retcode <> 0
			BEGIN
				GOTO UNDO
			end
		end
    end
    else
    begin
        /*detach */
        dbcc detachdb(@database)
    end
    
    RETURN(0)

UNDO:

    IF @db_exists = 0
        EXECUTE dbo.sp_dropdistributiondb @database

    /* Need to do it since sp_dropdistributiondb will fail in some cases */
    UPDATE master..sysdatabases SET category = category & ~@distbit WHERE name = @database collate database_default
    
    DELETE msdb.dbo.MSdistributiondbs where name = @database collate database_default

    /* drop the database and ignore error */
    IF @db_exists = 0 AND
        EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default)
    BEGIN
        SELECT @command = 'USE master  DROP DATABASE ' +  QUOTENAME(@database) 
        EXEC (@command)
    END

    if (@createmode = @createmode_attach)
    begin
        if (@data_file_preexists = 0)
        begin
            select @command = 'del ' + @data_path_quoted_for_copy
            exec master..xp_cmdshell @command
            --ignore errors
        end
        if (@log_file_preexists = 0)
        begin
            select @command = 'del ' + @log_path_quoted_for_copy
            exec master..xp_cmdshell @command
            --ignore errors
        end
    end
        
    RETURN(1)        
GO

--------------------------------------------------------------------------------
--. sp_adddistpublisher
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_adddistpublisher')
drop procedure sp_adddistpublisher
go
raiserror('Creating procedure sp_adddistpublisher', 0,1)
go

CREATE PROCEDURE sp_adddistpublisher (
    @publisher sysname,      /* publisher server name */
    @distribution_db sysname,
    @security_mode int = NULL,
    @login sysname = 'sa',
    @password sysname = NULL,
    @working_directory nvarchar(255),
    @trusted nvarchar(5) = NULL,
    @encrypted_password bit = 0,
    @thirdparty_flag bit = 0
        ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode int
    DECLARE @reg_key nvarchar(255)
    DECLARE @distbit int
    DECLARE @active_value int
    DECLARE @server_added bit
    DECLARE @proc nvarchar(255)
    declare @fExists int
    declare @command nvarchar(255)
    declare @trusted_id bit
    declare @platform_nt binary
	declare @qv_replication varchar(10)
	declare @qv_replication_unlimited integer
	declare @qv_value_replication integer
    declare @enc_password nvarchar(524)

    select @platform_nt = 0x1
	select @qv_replication = '2745196162', @qv_replication_unlimited = 0

    SELECT @distbit = 16
    SELECT @server_added = 0

    /* 
    ** Check if replication components are installed on this server
    */
    exec @retcode = dbo.sp_MS_replication_installed
    if (@retcode <> 1)
    begin
        return (1)
    end

    IF @working_directory IS NULL or ltrim(rtrim(@working_directory)) = ''
    BEGIN
        RAISERROR (14043, 16, -1, '@working_directory')
        return (1)
    END


    /*
    ** Parameter Check:  @publisher.
    ** Check to make sure that the publisher is not NULL and that it
    ** conforms to the rules for identifiers.
    */

    IF @publisher IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publisher')
            return (1)
        END

    EXECUTE @retcode = dbo.sp_validname @publisher

    IF @@ERROR <> 0 OR @retcode <> 0
        return (1)

	IF @password = N''
		select @password = NULL

    /* On REPLICATION_LIMITED server, only local publisher is supported.
     * Note: The login and password registered for local publisher will be used for 
     * local agents to login to distributor, thus local publisher has to be installed first.
     * We choose not to support remote dist publshers on REPLICATION_LIMITED server altogether.
     * On NT, local agents will always use integrated security to log into 
     * distributor
	 * Today, REPLICATION_LIMITED means desktop but we check specific sku entry just in case
	*/
	exec @qv_value_replication = master.dbo.sp_MSinstance_qv @qv_replication	

	if ( @qv_value_replication != @qv_replication_unlimited ) and ( UPPER(@publisher) <> UPPER(@@servername) )
    begin
        -- remote dist publisher is not supported on this server version
        raiserror(21041,16,-1)
        return (1)
    end


    -- Set default security
    IF @security_mode IS NULL
    BEGIN
        IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( platform() & @platform_nt = @platform_nt ) )
            SELECT @security_mode = 1
        ELSE
            SELECT @security_mode = 0
    END

    /* 
    ** Check for invalid security mode
    */
    IF @security_mode < 0 OR @security_mode > 1
        BEGIN
            RAISERROR(14109, 16, -1)
            return (1)
        END

    IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1)
    BEGIN
        RAISERROR(21038, 16, -1)
        RETURN (1)
    END

    -- Encrypt the password
    select @enc_password = @password
    IF @encrypted_password = 0
    BEGIN
        EXEC @retcode = master.dbo.xp_repl_encrypt @enc_password OUTPUT
        IF @@error <> 0 OR @retcode <> 0
            return 1
    END

    -- Validate the working directory 
    -- Remove heading and trailing spaces
    select @working_directory = RTRIM(LTRIM(@working_directory))
    
    -- if the last char is '\', remove it.
    if substring(@working_directory, len(@working_directory),1) = '\'
        select @working_directory = substring(@working_directory, 1,
            len(@working_directory)-1)

    -- Don't do validation if it is a UNC path due to security problem.
    -- If the server is started as a service using local system account, we
    -- don't have access to the UNC path.
    if substring(@working_directory, 1,2) <> '\\'
    begin
        select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@working_directory) collate database_default + '"'
        exec @retcode = master..xp_cmdshell @command, 'no_output'
        if @@error <> 0
            return (1)
        if @retcode <> 0 
        begin
            raiserror (21037, 16, -1, @working_directory)
            return (1)
        end
    end

    /*
    ** Parameter Check:  @trusted
    */

    if @trusted is null
    begin
        if UPPER(@publisher) = UPPER(@@servername)
            select @trusted = 'false'
        else
            select @trusted = 'true'
    end

    IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@trusted')
            RETURN (1)
        END

    IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @trusted_id = 1
    ELSE SELECT @trusted_id = 0

    /*
    ** Check to make sure this is a distributor
    */
    IF NOT EXISTS (SELECT * FROM master..sysservers
              WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
                 AND srvstatus & 8 <> 0)
    BEGIN
        RAISERROR (14114, 16, -1, @@SERVERNAME)
        return (1)
    END

    /*
    ** Check if database is configured as a distributor database
    */
    IF NOT EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @distribution_db collate database_default)
    BEGIN
        RAISERROR (14117, 16, -1, @distribution_db)
        return (1)
    END

    /* Check if publisher is already defined. */
    IF EXISTS (SELECT *
         FROM msdb..MSdistpublishers
        WHERE UPPER(name) = UPPER(@publisher) collate database_default)

    BEGIN
        RAISERROR (14074, 16, -1, @publisher)
        RETURN (1)
    END



    IF NOT EXISTS (SELECT *
             FROM master..sysservers
            WHERE UPPER(srvname) = UPPER(@publisher) collate database_default)

    /* Add the server if it does not exist. */
    BEGIN
        EXECUTE @retcode = dbo.sp_addserver @publisher
        IF @@error <> 0 OR @retcode <> 0
        BEGIN
            RAISERROR (14075, 16, -1)
            GOTO UNDO
        END
        SELECT @server_added = 1
    END
    ELSE
    BEGIN
        SELECT @publisher = fn_getpersistedservernamecasevariation(@publisher) collate database_default
    END
     
    /*
    ** Set the Active  value.
    ** If the @publisher is local, set it to true.
    ** Otherwise, set it to false
    */
    IF UPPER(@publisher) = UPPER(@@SERVERNAME)
        SELECT @active_value = 1
    ELSE
        SELECT @active_value = 0


    DELETE msdb.dbo.MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default
    IF @@ERROR <> 0
    BEGIN
        GOTO UNDO       
    END

    INSERT INTO msdb.dbo.MSdistpublishers VALUES (
        @publisher, @distribution_db, @working_directory,
        @security_mode, @login, @enc_password, @active_value, @trusted_id, @thirdparty_flag)
    IF @@ERROR <> 0
    BEGIN
        GOTO UNDO       
    END

    -- Add distributor_admin to distribution_admin non trusted mapping
    exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 
        'distributor_admin'
    if( @fExists = 0 )
    BEGIN

        EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 
            'distributor_admin'
        IF @@error <> 0 OR @retcode <> 0
        BEGIN
            RAISERROR (14075, 16, -1)
            GOTO UNDO
        END
    END

    -- For 6x publisher, we still need the trusted sa to sa.
    -- For 6x publisher upgrading to 7.0, distributor_admin to distributor_admin need to be trusted.
    -- add remotelogin of SA if it doesn't already exist
    -- If there's a mapping for remote login sa already, we cannot map it to distributor_admin
    -- this is the case of server upgraded from 6.5.
    exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 'sa'
    if( @fExists = 0 )
    BEGIN
        EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 'sa'
        IF @@error <> 0 OR @retcode <> 0
        BEGIN
            RAISERROR (14075, 16, -1)
            GOTO UNDO
        END
    END
    if @trusted_id = 1
    begin
        exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
        if( @fExists = 1 )
        BEGIN
            EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true
            IF @@error <> 0 OR @retcode <> 0
            BEGIN
                RAISERROR (14075, 16, -1)
                GOTO UNDO
            END
        END

        EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'distributor_admin', trusted, true
        IF @@error <> 0 OR @retcode <> 0
        BEGIN
            RAISERROR (14075, 16, -1)
            GOTO UNDO
        END
    END


    /* Add remotelogin enabling the 'probe' of the publisher to
    ** RPC for distribution counter information.
    */
/* SECURITY ********************************
    IF NOT EXISTS (SELECT *
              FROM master..sysremotelogins srl,
               master..sysservers ss
             WHERE UPPER(ss.srvname) = UPPER(@publisher) collate database_default
           AND srl.remoteserverid = ss.srvid
           AND srl.remoteusername = 'probe'
       AND srl.suid = 10)    -- 'probe' 
    exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'probe', 'probe'
    if (@fExists = 0)
    BEGIN
       EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'probe', 'probe'
       IF @@error <> 0 OR @retcode <> 0
       BEGIN
        RAISERROR (14075, 16, -1)
        GOTO UNDO
       END
    END
*********************************/
    
    RETURN(0)

UNDO:
    -- If the server is marked, drop it
    IF EXISTS (SELECT *
         FROM msdb..MSdistpublishers
        WHERE UPPER(name) = UPPER(@publisher) collate database_default)
        EXEC dbo.sp_dropdistpublisher @publisher

    IF @server_added = 1
        EXEC dbo.sp_dropserver @publisher

    RETURN(1)
GO

--------------------------------------------------------------------------------
--. sp_changedistpublisher
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_changedistpublisher')
drop procedure sp_changedistpublisher
go
raiserror('Creating procedure sp_changedistpublisher', 0,1)
go

CREATE PROCEDURE sp_changedistpublisher (
    @publisher sysname,
    @property sysname     = NULL,     /* The property to change */
    @value nvarchar(255)     = NULL      /* The new property value */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @retcode int
    DECLARE @new_database sysname
    DECLARE @new_security_mode int
    DECLARE @new_login sysname
    DECLARE @new_password nvarchar(524)
    DECLARE @distbit int
    DECLARE @new_active int
    DECLARE @new_trusted bit
    DECLARE @command nvarchar(255)
    declare @distribdb sysname
    DECLARE @platform_nt binary

    SELECT @platform_nt = 0x1
    SELECT @distbit = 16
    
    /*
    ** Parameter Check:  @property.
    ** If the @property parameter is NULL, print the options.
    */

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname collate database_default not null)
            INSERT INTO #tab1 VALUES ('distribution_db')
            INSERT INTO #tab1 VALUES ('working_directory')
            INSERT INTO #tab1 VALUES ('security_mode')
            INSERT INTO #tab1 VALUES ('login')
            INSERT INTO #tab1 VALUES ('password')
            INSERT INTO #tab1 VALUES ('active')
            INSERT INTO #tab1 VALUES ('trusted')
            SELECT * FROM #tab1
            RETURN (0)
        END

    /*
    ** Parameter Check:  @property.
    ** Check to make sure that @property is a valid property in
    ** msdb.dbo.MSdistpublishers.
    */
    IF @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
        ('distribution_db',
         'working_directory',
         'security_mode',
         'login',
         'password',
         'active',
         'trusted')
        BEGIN
            RAISERROR (14115, 16, -1, 
            '''distribution_db'', ''working_directory'', ''security_mode'', ''login'', ''password'', ''active'', or ''trusted''')
            RETURN (1)
        END

    /*
    ** Check to make sure this is a distributor
    */
    IF NOT EXISTS (SELECT * FROM master..sysservers
              WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
                 AND srvstatus & 8 <> 0)
    BEGIN
        RAISERROR (14114, 16, -1, @@SERVERNAME)
        RETURN(1)
    END

    -- Get the distribution db name.
    select @distribdb = distribution_db from msdb..MSdistpublishers where
        UPPER(name) = UPPER(@publisher) collate database_default

    /*
    ** Change the property.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distribution_db'
        BEGIN
            IF @value IS NULL
                BEGIN
                    RAISERROR (14043, 16, -1, '@value') 
                    RETURN (1)
                END

            IF @value <> @distribdb and 
                EXISTS (SELECT * FROM msdb.dbo.MSdistpublishers WHERE
                UPPER(name) = UPPER(@publisher) collate database_default and active = 1)
            BEGIN
                RAISERROR (21046, 16, -1)
                RETURN (1)
            END

            /*
            ** Check if database is configured as a distributor database
            */
            IF NOT EXISTS (SELECT * FROM master..sysdatabases
              WHERE name = @value collate database_default
                 AND category & @distbit <> 0)
                BEGIN
                    RAISERROR (14117, 16, -1, @new_database)
                    RETURN(1)
                END

            UPDATE msdb..MSdistpublishers SET distribution_db = @value
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
        END
   
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'working_directory'
        BEGIN
            IF @value IS NULL
                BEGIN
                    RAISERROR (14043, 16, -1, '@value') 
                    RETURN (1)
                END

            
            -- Validate the working directory 
            -- Remove heading and trailing spaces
            select @value = RTRIM(LTRIM(@value))

            -- if the last char is '\', remove it.

            if substring(@value, len(@value),1) = '\'
                select @value = substring(@value, 1,
                    len(@value)-1)

            -- Don't do validation if it is a UNC path due to security problem.
            -- If the server is started as a service using local system account, we
            -- don't have access to the UNC path.
            if substring(@value, 1,2) <> '\\'
            begin
                select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@value) collate database_default + N'"'
                exec @retcode = master..xp_cmdshell @command, 'no_output'
                if @@error <> 0
                    return 1
                if @retcode <> 0 
                begin
                    raiserror (21037, 16, -1, @value)
                    return 1
                end
            end

            UPDATE msdb..MSdistpublishers SET working_directory = @value
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'security_mode'
        BEGIN
            IF @value IS NULL
                BEGIN
                    RAISERROR (14043, 16, -1, '@value') 
                    RETURN (1)
                END

            /*
            ** Set the SecurityMode registry key value
            */
            SELECT @new_security_mode = CONVERT(int, @value)

            /* 
            ** Check for invalid values 
            */
            IF @new_security_mode < 0 OR @new_security_mode > 1
                BEGIN
                    RAISERROR(14109, 16, -1)
                    RETURN (1)
                END

            IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @new_security_mode = 1)
            BEGIN
                RAISERROR(21038, 16, -1)
                RETURN (1)
            END

            UPDATE msdb..MSdistpublishers SET security_mode = @new_security_mode
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'login'
        BEGIN
            IF @value IS NULL
                BEGIN
                    RAISERROR (14043, 16, -1, '@value') 
                    RETURN (1)
                END

            /*
            ** Set the Login registry key value
            */
            SELECT @new_login = CONVERT(sysname, @value)

            UPDATE msdb..MSdistpublishers SET login = @new_login
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'password'
        BEGIN
            /*
            ** Set the Password registry key value
            */
            SELECT @new_password = CONVERT(nvarchar(524), @value)

            -- Encrypt the password
            EXEC @retcode = master.dbo.xp_repl_encrypt @new_password OUTPUT
            IF @@error <> 0 OR @retcode <> 0
                RETURN (1)

            UPDATE msdb..MSdistpublishers SET password = @new_password
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
         END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'active'
        BEGIN
            /*
            ** Check for a valid  value.
            */

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
            BEGIN
                RAISERROR (14137, 16, -1)
                RETURN (1)
            END

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            begin
                -- Clean up the database in case of the remote publisher is reinstalling publishing.
                SELECT @command = @distribdb + '.dbo.sp_MSdistpublisher_cleanup'
                exec @retcode = @command @publisher
                if @retcode <> 0 or @@error <> 0
                    return 1
                SELECT @new_active = 1
            end
            ELSE
            BEGIN
                SELECT @new_active = 0
            END

            /*
            ** Set the Active registry key value
            */
            UPDATE msdb..MSdistpublishers SET active = @new_active
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0
                BEGIN
                    RETURN (1)
                END

        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'trusted'
        BEGIN
            /*
            ** Check for a valid  value.
            */

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
            BEGIN
                RAISERROR (14137, 16, -1)
                RETURN (1)
            END

            declare @fExists int

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            begin
                SELECT @new_trusted = 1
                exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
                if( @fExists = 1 )
                BEGIN
                    EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true
                    IF @@error <> 0 OR @retcode <> 0
                    BEGIN
                        RAISERROR (14075, 16, -1)
                        RETURN (1)
                    END
                END


                EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 
                    'distributor_admin', trusted, true
                IF @@error <> 0 OR @retcode <> 0
                BEGIN
                    RAISERROR (14075, 16, -1)
                    RETURN (1)
                END
            end
            ELSE
            BEGIN
                SELECT @new_trusted = 0
     
                exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
                if( @fExists = 1 )
                BEGIN
                    EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, false
                    IF @@error <> 0 OR @retcode <> 0
                    BEGIN
                        RAISERROR (14075, 16, -1)
                        RETURN (1)
                    END
                END


                EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin',
                    'distributor_admin', trusted, 'false'
                IF @@error <> 0 OR @retcode <> 0
                BEGIN
                    RAISERROR (14075, 16, -1)
                    RETURN (1)
                END
            END

            /*
            ** Set the trusted property
            */
            UPDATE msdb..MSdistpublishers SET trusted = @new_trusted
                WHERE UPPER(name) = UPPER(@publisher) collate database_default
            IF @@error <> 0
                BEGIN
                    RETURN (1)
                END
        END

  
    /*
    ** Return succeed.
    */
    RAISERROR (21035, 10, -1, @property)

DONE:    
    RETURN (0)
go

--------------------------------------------------------------------------------
--. sp_MScopyscriptfile
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScopyscriptfile')
drop procedure sp_MScopyscriptfile
go
create proc sp_MScopyscriptfile (
	@scriptfile nvarchar(4000), 
	@cmd nvarchar(4000) OUTPUT
)
as
declare @directory nvarchar(4000)
declare @filename nvarchar(1024)
declare @subdirectory nvarchar(1024)
declare @retcode int

IF @scriptfile IS NULL
BEGIN
	RAISERROR (14043, 16, -1, '@scriptfile')
	RETURN (1)
END
-- Create the directory on distributor to store script.
exec sp_helpdistributor @directory=@directory OUTPUT
select @subdirectory = convert(nvarchar(64), GetDate(), 121)
select @subdirectory = replace(@subdirectory, N'-', N'')
select @subdirectory = replace(@subdirectory, N' ', N'')
select @subdirectory = replace(@subdirectory, N':', N'')
select @subdirectory = replace(@subdirectory, N'.', N'')
if(right(@directory, 1) = N'\')
	select @directory = @directory + @subdirectory
else
	select @directory = @directory + N'\' + @subdirectory
select @cmd = N'md "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + '"'
exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT
if(@retcode <> 0)
begin
	raiserror(21330, 16, -1, @cmd)
	return (1)
end

-- Copy script to distributor
select @cmd = N'copy "' + fn_escapecmdshellsymbolsremovequotes(@scriptfile) collate database_default + N'" "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + N'"'
exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT
if(@retcode <> 0)
begin 
	raiserror(21331, 16, -1, @cmd)
	return (1)
end

-- Prepare command, to be posted to log
select @filename = right(@scriptfile, charindex(N'\', reverse(@scriptfile)))
if(left(@filename, 1) = N'\')	
	select @cmd = @directory + @filename
else
	select @cmd = @directory + N'\' + @filename
go
exec sp_MS_marksystemobject sp_MScopyscriptfile
go

--------------------------------------------------------------------------------
--. sp_replproberemoteserver
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_replproberemoteserver')
drop procedure sp_replproberemoteserver
go
raiserror('Creating procedure sp_replproberemoteserver', 0,1)
go
--
-- Name: sp_replproberemoteserver
--
-- Description: This is a lightweight wrapper for calling xp_replproberremsrv
--              with the added nicety of looking up the agent command line
--              using the given jobid. This procedure supports two different
--              modes of operation based on the @no_rpc parameter. If the 
--              @no_rpc parameter is 1, this procedure will not attempt to make
--              rpc call to the Distributor. The local mode is mainly useful 
--              for verifying remote pull subscription agent.
-- 
-- Parameters: @remoteservername sysname (mandatory) 
--             @agent_type nvarchar(16) (optional, default = null) 
--             @agent_jobid uniqueidentifier (optional default = null)
--             @no_rpc bit (optional default = 0)
--
-- Notes: If @job_id is null, only activation verification will be carried
--        out.
--
-- Security: Execute permission of this procedure is granted to public. 
--           Internal security check is performed inside this procedure to
--           make sure that the caller is at least a db_owner of the current 
--           database.
--
-- Result: 'probe_succeeded' 0 or 1
--
-- Returns: 0    - succeeded
--          <> 0 - failed
--
create procedure dbo.sp_replproberemoteserver (
    @remoteservername sysname,
    @agent_type       nvarchar(16) = null,
    @agent_jobid      uniqueidentifier = null,
    @no_rpc           bit = 0
    ) 
as
begin
    set nocount on
    declare @retcode        int
    declare @commandline    nvarchar(3200)
    declare @distributor    sysname
    declare @distributiondb sysname     
    declare @distproc       nvarchar(255)
    declare @succeeded      nvarchar(10)

    select @retcode = 0
    select @commandline = null
    select @succeeded = null

    -- security check, db_owner
    -- Note that this proc can be called from either a publisher database or
    -- a subscriber database
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
        return (1)
    
    if @agent_type is null
    begin
        select @agent_type = 'distribution'
    end
    
    -- @remoteservername cannot be null or empty
    select @remoteservername = rtrim(ltrim(@remoteservername))
    if @remoteservername is null or
       @remoteservername = N''
    begin
        raiserror(21263,16,-1,'@remoteservername')
        return 1
    end     
    
    -- @agent_type must be 'distribution' or 'merge'
    if @agent_type not in (N'distribution', N'merge')
    begin
        raiserror(21182,16,-1) 
        return 1
    end

    -- Get Distributor information
    if @no_rpc = 0
    begin
        exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor output,
                                          @distribdb = @distributiondb output
        if @@error <> 0 or @retcode <> 0
            return 1
    end
    else
    begin
        select @distributor = @@servername
    end

    if upper(@@servername) <> upper(@distributor)
    begin
        select @distproc = ltrim(rtrim(@distributor)) + '.' + 
            'master.dbo.sp_replproberemoteserver'
        exec @retcode = @distproc @remoteservername, 
                                  @agent_type, 
                                  @agent_jobid, 
                                  1
        return @retcode
    end        
    else
    begin
        -- If the given @job_id is not null, try to get
        -- the agent command line
        if @agent_jobid is not null 
        begin
            select @commandline = fn_replgetagentcommandlinefromjobid(
                @agent_type,
                @agent_jobid) collate database_default

            if @commandline is null
            begin
                raiserror(21361,6,-1, @agent_type) 
                select 'probe_succeeded' = 0
                return 1
            end

        end 
 
        exec @retcode = master.dbo.xp_replproberemsrv 
            @remoteservername, 
            @agent_type, 
            @succeeded output,
            @commandline 

        if lower(@succeeded collate SQL_Latin1_General_CP1_CS_AS) = N'true'  
            select 'probe_succeeded' = 1
        else
            select 'probe_succeeded' = 0

        return @retcode
    end

    select 'probe_succeeded' = 0

    return 1
end
go
exec sp_MS_marksystemobject sp_replproberemoteserver
go
grant execute on dbo.sp_replproberemoteserver to public
go
if exists (select * from sysobjects
     where type = 'X'
          and name = 'sp_replsetoriginator_internal' )
exec dbo.sp_dropextendedproc 'sp_replsetoriginator_internal'
go
sp_addextendedproc  'sp_replsetoriginator_internal', 'replsetoriginator extended procedure'
go
if exists (select * from sysobjects
     where type = 'X'
          and name = 'sp_replsetoriginator' )
exec dbo.sp_dropextendedproc 'sp_replsetoriginator'
go
if exists (select * from sysobjects
     where type = 'P'
          and name = 'sp_replsetoriginator' )
drop procedure sp_replsetoriginator
go
--
-- Name:    
--          sp_replsetoriginator
--          
-- Description: 
--          wrapper for sp_replsetoriginator_internal with DBO check
--  
-- Security: 
--          DBO only
--
-- Returns:  	0 : success
--		1 : failure          
--      
-- Owner:   
--          qunguo
--
--
raiserror('Creating procedure sp_replsetoriginator',0,1)
go
create proc sp_replsetoriginator (
	@originator_srv sysname, 
	@originator_db sysname
)
as
	declare @retcode int
	/*
    	** Security Check, this proc is only called by distrib.exe, against sub db as DBO
    	*/
    	exec @retcode = dbo.sp_MSreplcheck_subscribe
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

    	exec @retcode = dbo.sp_replsetoriginator_internal @originator_srv, @originator_db
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

	return 0
go
exec sp_MS_marksystemobject sp_replsetoriginator
go
grant execute on dbo.sp_replsetoriginator to public
go

if exists (select * from sysobjects
     where type = 'P'
          and name = 'sp_replsetoriginator_pal' )
drop procedure sp_replsetoriginator_pal
go
--
-- Name:    
--          sp_replsetoriginator_pal
--          
-- Description: 
--          wrapper for sp_replsetoriginator_internal with pull access check
--  
-- Security: 
--          DBO or PAL access
--
-- Returns:  	0 : success
--		1 : failure          
--      
-- Owner:   
--          qunguo
--
--
raiserror('Creating procedure sp_replsetoriginator_pal',0,1)
go
create proc sp_replsetoriginator_pal (
	@originator_srv sysname, 
	@originator_db sysname,
	@publication sysname
)
as
	declare @retcode int
	/*
    	** Security Check, this is called by updatable subscriber in sync-tran proc, hence PAL access
    	*/
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end

    	exec @retcode = dbo.sp_replsetoriginator_internal @originator_srv, @originator_db
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

	return 0
go
exec sp_MS_marksystemobject sp_replsetoriginator_pal
go
grant execute on dbo.sp_replsetoriginator_pal to public
go
if exists (select * from sysobjects
     	where type = 'X'
            and name = 'sp_replincrementlsn' )
	exec dbo.sp_dropextendedproc 'sp_replincrementlsn'
go
if exists (select * from sysobjects
     	where type = 'P'
            and name = 'sp_replincrementlsn' )
	drop procedure sp_replincrementlsn

if exists (select * from sysobjects
     	where type = 'X'
            and name = 'sp_replincrementlsn_internal' )
	exec dbo.sp_dropextendedproc 'sp_replincrementlsn_internal'
go
sp_addextendedproc  'sp_replincrementlsn_internal', 'replincrementlsn_internal extended procedure'
go
--
-- Name:    
--          sp_replincrementlsn
--          
-- Description: 
--          wrapper for sp_replincrementlsn_internal with DBO check
--  
-- Security: 
--          DBO only
--
-- Returns:  	0 : success
--		1 : failure          
--      
-- Owner:   
--          qunguo
--
--
raiserror('Creating procedure sp_replincrementlsn',0,1)
go
create proc sp_replincrementlsn (
	@xact_seqno binary(10) OUTPUT
)
as
	declare @retcode int
	/*
    	** Security Check, this proc is called by snapshot agent or sp_repladd(drop)column, against pub db as DBO
    	*/
    	exec @retcode = dbo.sp_MSreplcheck_publish
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

    	exec @retcode = dbo.sp_replincrementlsn_internal @xact_seqno OUTPUT
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

	return 0
go
exec sp_MS_marksystemobject sp_replincrementlsn
go
grant execute on dbo.sp_replincrementlsn to public
go

if exists (select * from sysobjects
	where type = 'X'
                and name = 'sp_replpostsyncstatus' )
        exec dbo.sp_dropextendedproc 'sp_replpostsyncstatus'

if exists (select * from sysobjects
	where type = 'P'
                 and name = 'sp_replpostsyncstatus' )
        drop procedure sp_replpostsyncstatus

if exists (select * from sysobjects
        where type = 'X'
                 and name = 'sp_replpostsyncstatus_int' )
        exec dbo.sp_dropextendedproc 'sp_replpostsyncstatus_int'
go
sp_addextendedproc  'sp_replpostsyncstatus_int', 'sp_replpostsyncstatus_int extended procedure'
go

--
-- Name:    
--          sp_replpostsyncstatus
--          
-- Description: 
--          wrapper for sp_replpostsyncstatus_int with DBO check
--  
-- Security: 
--          DBO only
--
-- Returns:  	0 : success
--		1 : failure          
--      
-- Owner:   
--          qunguo
--
--
raiserror('Creating procedure sp_replpostsyncstatus',0,1)
go
create proc sp_replpostsyncstatus (
	@pubid int, 
	@artid int, 
	@syncstat int, 
	@xact_seqno binary(10) OUTPUT
)
as
	declare @retcode int
	/*
    	** Security Check, this proc is called by snapshot agent as DBO on publisher
    	*/
    	exec @retcode = dbo.sp_MSreplcheck_publish
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

    	exec @retcode = dbo.sp_replpostsyncstatus_int @pubid, @artid, @syncstat, @xact_seqno OUTPUT
    	if @@ERROR <> 0 or @retcode <> 0
	begin
        	return(1)
	end

	return 0
go
exec sp_MS_marksystemobject sp_replpostsyncstatus
go
grant execute on dbo.sp_replpostsyncstatus to public
go


--------------------------------------------------------------------------------
--.	System objects (repltran.sql)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScreate_pub_tables')
drop procedure sp_MScreate_pub_tables

print ''
print 'Creating procedure sp_MScreate_pub_tables'
go
CREATE PROCEDURE sp_MScreate_pub_tables
AS
    DECLARE @fError int
    SELECT @fError = 0

    -- enable 'create tables as pseudo system tables

    -- sp_MS_upd_sysobj_category is obsolete, use sp_MS_marksystemobject instead
    -- exec dbo.sp_MS_upd_sysobj_category 1


    /* 
    ** Msg 226, Level 16, State 9
    ** CREATE TABLE system-table command not allowed within multi-statement transaction.
    */
    /*
    BEGIN TRAN sp_create_central_pub_tables
    */
    
    /* Creating 'sysarticles' */
    IF not exists (select * from sysobjects where name = 'sysarticles')
    BEGIN
        create table dbo.sysarticles
        (
        artid               int                 identity NOT NULL,
        columns             varbinary(32)       NULL,
        creation_script     nvarchar(255)       NULL,
        del_cmd             nvarchar(255)       NULL,
        description         nvarchar(255)       NULL,
        dest_table          sysname             NOT NULL,
        filter              int                 NOT NULL,
        filter_clause       ntext               NULL,
        ins_cmd             nvarchar(255)       NULL,
        name                sysname             NOT NULL,
        objid               int                 NOT NULL,
        pubid               int                 NOT NULL,
        pre_creation_cmd    tinyint             NOT NULL,
        status              tinyint             NOT NULL,
        sync_objid          int                 NOT NULL,
        type                tinyint             NOT NULL,
        upd_cmd             nvarchar(255)       NULL,
        schema_option       binary(8)           NULL,
        dest_owner          sysname             NULL
        -- Note: Please update sysextendedarticlesview whenever
        -- there is a schema change in sysarticles
        )

        EXEC dbo.sp_MS_marksystemobject 'sysarticles'

        IF @@error<>0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1sysarticles
            on sysarticles(artid, pubid) 
        
        IF @@error<>0
        BEGIN
            GOTO ERROR
        END

    END

    /* Creating 'sysschemaarticles' */
    IF not exists (select * from sysobjects where name = 'sysschemaarticles')
    BEGIN
        create table dbo.sysschemaarticles
        (
        artid               int                 NOT NULL,
        creation_script     nvarchar(255)       NULL,
        description         nvarchar(255)       NULL,
        dest_object         sysname             NOT NULL,
        name                sysname             NOT NULL,
        objid               int                 NOT NULL,
        pubid               int                 NOT NULL,
        pre_creation_cmd    tinyint             NOT NULL,
        status              int                 NOT NULL,
        type                tinyint             NOT NULL,
        schema_option       binary(8)           NULL,
        dest_owner          sysname             NULL
        )
        
        IF @@error<>0
        BEGIN
            GOTO ERROR
        END

        EXEC dbo.sp_MS_marksystemobject 'sysschemaarticles'

        IF @@error<>0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1sysschemaarticles
            on sysschemaarticles(artid, pubid)

        IF @@error<>0
        BEGIN
            GOTO ERROR
        END
        
    END

    /* Creating 'sysextendedarticlesview' */
    IF not exists (select * from sysobjects where name = 'sysextendedarticlesview')
    BEGIN
        exec ('create view dbo.sysextendedarticlesview
               as
               select * from sysarticles
               union all
               select artid, NULL, creation_script, NULL, description,
               dest_object, NULL, NULL, NULL, name, objid, pubid, 
               pre_creation_cmd, status, NULL, type, NULL, 
               schema_option, dest_owner from sysschemaarticles
               go')

        IF @@error<>0
        BEGIN
            GOTO ERROR
        END 

        EXEC dbo.sp_MS_marksystemobject 'sysextendedarticlesview'

        IF @@error<>0
        BEGIN
            GOTO ERROR
        END

    END

    /* Creating 'syspublications' */
    IF NOT EXISTS (select * from sysobjects where name = 'syspublications')
    BEGIN
        CREATE TABLE dbo.syspublications (
        description                 nvarchar(255)   NULL,
        name                        sysname         NOT NULL,
        pubid                       int    identity NOT NULL,
        repl_freq                   tinyint         NOT NULL,
        status                      tinyint         NOT NULL,
        sync_method                 tinyint         NOT NULL,
        snapshot_jobid              binary(16)		NULL,
        independent_agent           bit             NOT NULL,
        immediate_sync              bit             NOT NULL,
        enabled_for_internet        bit             NOT NULL,
        allow_push                  bit             NOT NULL,
        allow_pull                  bit             NOT NULL,
        allow_anonymous             bit             NOT NULL,
        immediate_sync_ready        bit             NOT NULL,
        -- SyncTran
		allow_sync_tran             bit             NOT NULL,
        autogen_sync_procs          bit             NOT NULL,
        retention                   int             NULL,
		-- The following are post 7.0
        allow_queued_tran           bit   default 0	not null, 
        -- portable snapshot support
        snapshot_in_defaultfolder           bit   default 1 NOT NULL,         
        alt_snapshot_folder         nvarchar(255)   NULL,
        -- snapshot pre/post- command
        pre_snapshot_script         nvarchar(255)   NULL,
        post_snapshot_script        nvarchar(255)   NULL,
        -- Snapshot compression
        compress_snapshot           bit   default 0 NOT NULL,          
        -- Post 7.0 Ftp support
        ftp_address                 sysname         NULL,
        ftp_port                    int   default 21 NOT NULL,
        ftp_subdirectory            nvarchar(255)   NULL,
        ftp_login                   sysname         NULL default N'anonymous',
        ftp_password                nvarchar(524)   NULL,
		allow_dts		bit default 0 not null,
		allow_subscription_copy		bit default 0 not null,
		centralized_conflicts		bit				NULL, -- 0 False, 1 True
		conflict_retention			int				NULL, -- 60
		conflict_policy				int 			NULL, -- 1 = PubWins, 2 = SubWins, 3 = Reinit
		queue_type					int				NULL,  -- 1 = MSMQ, 2 = SQL
		ad_guidname					sysname			NULL,
		backward_comp_level	int default 10 not NULL -- default is sphinx
        )

        EXEC dbo.sp_MS_marksystemobject 'syspublications'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique clustered index uc1syspublications
            on syspublications (pubid) 
        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc2syspublications
            on syspublications (name)

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

    END

       /* Creating 'syssubscriptions' */
    IF not exists (select * from sysobjects where name = 'syssubscriptions')
    BEGIN

        CREATE TABLE dbo.syssubscriptions
        (
        artid                    int                NOT NULL,
        srvid                    smallint        NOT NULL,
        dest_db                    sysname        NOT NULL,
        status                    tinyint            NOT NULL,
        sync_type                tinyint            NOT NULL,
        login_name                sysname        NOT NULL,
        subscription_type        int                NOT NULL,
        distribution_jobid      binary(16)          NULL,
        timestamp NOT NULL,
        -- SyncTran
        update_mode             tinyint            NOT NULL, -- 0 (read only), 1 (Sync Tran), 
		                                                     -- Queued Tran
															 -- 2 (Queued Tran) , 3 (Failover), 4(sqlqueued), 5(sqlqueued failover)
        loopback_detection      bit NOT NULL,
  		queued_reinit		   bit DEFAULT 0 NOT NULL 
      )

        EXEC dbo.sp_MS_marksystemobject 'syssubscriptions'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1syssubscriptions
            on syssubscriptions (artid, srvid, dest_db)

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

    END

    -- SyncTran
    /* Creating 'sysarticleupdates' */

    IF not exists (select * from sysobjects where name = 'sysarticleupdates')
    BEGIN

        CREATE TABLE dbo.sysarticleupdates
        (
        artid                  int       NOT NULL,
        pubid                  int       NOT NULL,
        sync_ins_proc          int       NOT NULL,     -- ID of sproc handling Insert Sync Transactions
        sync_upd_proc          int       NOT NULL,     -- ID of sproc handling Update Sync Transactions
        sync_del_proc          int       NOT NULL,     -- ID of sproc handling Delete Sync Transactions
        autogen                bit       NOT NULL,
		sync_upd_trig          int       NOT NULL,     -- Note 7.0 upgrade issue
		conflict_tableid	   int		 NULL,		   -- ID of conflict table for this article
		ins_conflict_proc	   int		 NULL,		   -- ID of sproc to log conflicts
		identity_support	   bit default 0 not null  -- Whether or not do auto identity range 
		)     

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END


        -- mark the index as a system object
        exec dbo.sp_MS_marksystemobject 'sysarticleupdates'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1sysarticleupdates
            on sysarticleupdates (artid, pubid)

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END
    END
    -- end SyncTran


    IF not exists (select * from sysobjects where name = 'MSpub_identity_range')
    BEGIN
        CREATE TABLE dbo.MSpub_identity_range
        (
			objid int not null,
			range bigint not null,
			pub_range bigint not null,
            current_pub_range bigint not null,
			threshold int not null,
			last_seed bigint null -- It will be not when uninitialized.
		)     

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END


        -- mark the index as a system object
        exec dbo.sp_MS_marksystemobject 'MSpub_identity_range'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1MSpub_identity_range
            on MSpub_identity_range (objid)

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END
    END

    IF not exists (select * from sysobjects where name = 'systranschemas' and uid = 1)
    BEGIN
        CREATE TABLE dbo.systranschemas
        (
			tabid int not null,
			startlsn binary(10) not null,
			endlsn binary(10) not null
	)     

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        -- mark the index as a system object
        exec dbo.sp_MS_marksystemobject 'systranschemas'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique clustered index uncsystranschemas
            on systranschemas (startlsn)

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END
    END

CLEANUP:

    -- disable 'create tables as pseudo system tables
    -- sp_MS_upd_sysobj_category is obsolete, use sp_MS_marksystemobject instead
    -- exec dbo.sp_MS_upd_sysobj_category 2
    RETURN( @fError )

ERROR:

    select @fError = 1
    GOTO CLEANUP

GO
 
EXEC dbo.sp_MS_marksystemobject sp_MScreate_pub_tables
GO
--------------------------------------------------------------------------------
--. sp_articlesynctranprocs
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_articlesynctranprocs')
revoke exec on dbo.sp_articlesynctranprocs from public

--------------------------------------------------------------------------------
--. sp_gettypestring
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_gettypestring')
revoke exec on dbo.sp_gettypestring from public

--------------------------------------------------------------------------------
--. sp_MSgettranconflictname
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgettranconflictname')
revoke execute on dbo.sp_MSgettranconflictname from public

--------------------------------------------------------------------------------
--. sp_MSmakeconflicttable
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSmakeconflicttable')
revoke execute on dbo.sp_MSmakeconflicttable from public

--------------------------------------------------------------------------------
--. sp_MSmaketrancftproc
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSmaketrancftproc')
revoke execute on dbo.sp_MSmaketrancftproc from public

--------------------------------------------------------------------------------
--. sp_MSmark_proc_norepl
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSmark_proc_norepl')
revoke execute on dbo.sp_MSmark_proc_norepl from public

--------------------------------------------------------------------------------
--. sp_MSscript_beginproc
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_beginproc')
revoke execute on dbo.sp_MSscript_beginproc  from public

--------------------------------------------------------------------------------
--. sp_MSscript_compensating_send
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_compensating_send')
revoke execute on dbo.sp_MSscript_compensating_send from public

--------------------------------------------------------------------------------
--. sp_MSscript_delete_pubwins
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_delete_pubwins')
revoke execute on dbo.sp_MSscript_delete_pubwins from public

--------------------------------------------------------------------------------
--. sp_MSscript_delete_statement
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_delete_statement')
revoke execute on dbo.sp_MSscript_delete_statement from public

--------------------------------------------------------------------------------
--. sp_MSscript_delete_subwins
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_delete_subwins')
revoke execute on dbo.sp_MSscript_delete_subwins from public

--------------------------------------------------------------------------------
--. sp_MSscript_ExecutionMode_stmt
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_ExecutionMode_stmt')
revoke execute on dbo.sp_MSscript_ExecutionMode_stmt from public

--------------------------------------------------------------------------------
--. sp_MSscript_insert_statement
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_insert_statement')
revoke execute on dbo.sp_MSscript_insert_statement from public

--------------------------------------------------------------------------------
--. sp_MSscript_security
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_security')
revoke execute on dbo.sp_MSscript_security  from public

--------------------------------------------------------------------------------
--. sp_MSscript_update_statement
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_update_statement')
revoke execute on dbo.sp_MSscript_update_statement from public

--------------------------------------------------------------------------------
--. sp_scriptpkwhereclause
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptpkwhereclause')
revoke exec on dbo.sp_scriptpkwhereclause from public

--------------------------------------------------------------------------------
--. sp_scriptreconwhereclause
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptreconwhereclause')
revoke exec on dbo.sp_scriptreconwhereclause from public

--------------------------------------------------------------------------------
--. sp_scriptupdateparams
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptupdateparams')
revoke exec on dbo.sp_scriptupdateparams from public
go
--------------------------------------------------------------------------------
--. sp_MSscript_ExecutionMode_stmt
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_ExecutionMode_stmt')
drop procedure sp_MSscript_ExecutionMode_stmt
go
raiserror('Creating procedure sp_MSscript_ExecutionMode_stmt', 0,1)
go
create procedure sp_MSscript_ExecutionMode_stmt (
	@publication sysname, 
	@article     sysname,
	@proctype	int = 0)		-- 0 insert, 1 delete, 2 update
as
begin
	declare @cmd		nvarchar(4000)
			,@artid		int
			,@pubid		int
			,@queued_pub bit

	select @pubid = pubid, @queued_pub = allow_queued_tran 
		from syspublications where name = @publication
	select @artid = artid from sysarticles where name = @article and pubid = @pubid

	--
	-- For queued execution check if we are in the phase of reinitialization
	--
	select @cmd = N'
	' + N'--
	' + N'-- Check if we are in the process of Reinitialization
	' + N'-- if yes then return
	' + N'--' 
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
	exec @retcode = dbo.sp_MSgetarticlereinitvalue @orig_server, @orig_db, ' + 
	cast(@artid as nvarchar(5)) + N', @reinit output
	if (@retcode != 0 or @@error != 0)
		return -1 '
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
	if (@reinit = 1) -- Resync state
	begin
		if (@execution_mode = @immediate)
			return -2'
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
		else
			return 4 -- Queued Resync state'
	end
	select @cmd = @cmd + N'
	end
	'
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- set loopback detection for immediate
	--
	select @cmd = N'
	if (@execution_mode = @immediate)
	begin
		' + N'--
		' + N'-- For immediate
		' + N'-- enable loopback detection
		' + N'--
		exec @retcode = dbo.sp_replsetoriginator_pal @orig_server, @orig_db, ''' 
			+ master.dbo.fn_MSgensqescstr(@publication) collate database_default + N'''
		if (@retcode != 0 or @@error != 0) 
			return -1
	end'
	insert into #proctext(procedure_text) values( @cmd )

	/********* no need to disable since we never enable
	if (@queued_pub = 1)
	begin
		--
		-- disable loopback for queued
		--
		select @cmd = N'
	else if (@execution_mode in (@QFirstPass, @QSubWins))
	begin
		' + N'--
		' + N'-- For queued
		' + N'-- disable loopback detection
		' + N'--
		exec @retcode = dbo.sp_replsetoriginator N''anull'', N''anull''
		if (@retcode != 0 or @@error != 0) 
			return -1
	end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	**********/

	if (@queued_pub = 1)
	begin
		--
		-- Queued reinitialization mode execution
		--
		select @cmd = N'
	else if (@execution_mode = @QReinit)
	begin
		' + N'--
		' + N'-- For Queued reinitialization
		' + N'-- Set the Queue and subscription for reinit
		' + N'--'
		insert into #proctext(procedure_text) values( @cmd )

		select @cmd = N'
		exec @retcode = dbo.sp_reinitsubscription @publication = ''' 
			+ master.dbo.fn_MSgensqescstr(@publication) collate database_default + N''', @article = ''' +  
			master.dbo.fn_MSgensqescstr(@article) collate database_default + N''', @subscriber = @orig_server, @destination_db = @orig_db
		if (@retcode != 0 or @@error != 0)
			return -1
		else
			return 0
	end'

		insert into #proctext(procedure_text) values( @cmd )
	end

	--
	-- all done
	--
	return 0
end 
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_ExecutionMode_stmt
GO

--------------------------------------------------------------------------------
--. sp_MSscript_pub_upd_trig
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_pub_upd_trig')
drop procedure sp_MSscript_pub_upd_trig
go
raiserror('Creating procedure sp_MSscript_pub_upd_trig', 0,1)
go
create procedure sp_MSscript_pub_upd_trig
(
    @publication sysname, 
    @article     sysname,
    @procname    sysname
)
as
begin
    declare @cmd       nvarchar(4000)
    declare @qualname  nvarchar(512)
    declare @objid	   int
    declare @columns   binary(32)
                ,@retcode int

    set nocount on
    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end

    -- Create temp table
    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)


    -- Retrieve underlying table name and replicated columns
    select @objid = objid, @columns = columns from sysarticles a, syspublications p
        where a.name = @article and
              p.name = @publication and
              a.pubid = p.pubid

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	-- Trigger should be invoked for repl processes as well.
	select @cmd = N'create trigger ' + QUOTENAME(@procname) + N' on ' + @qualname + N' '
    select @cmd = @cmd + N'for update as ' 

    exec dbo.sp_MSflush_command @cmd output, 1

    insert into #proctext(procedure_text) values(N'
')
    -- declare common local variables
	insert into #proctext(procedure_text) values 
		(N'declare @rc int
')
    insert into #proctext(procedure_text) values(N'select @rc = @@ROWCOUNT 

')
		
	-- Optimization. Return immediately if no row changed
	-- This must be at the beginning of the trigger to @@rowcount be overwritten.
    insert into #proctext(procedure_text) values(N'if @rc = 0 return 
')
    insert into #proctext(procedure_text) values(N'if update (msrepl_tran_version) return 
')

    -- update the version column of all the updated rows all at once.
	select @cmd = N'update ' + @qualname + N' set msrepl_tran_version = newid() from ' +
        @qualname + ', inserted '
    exec dbo.sp_MSflush_command @cmd output, 1
    insert into #proctext(procedure_text) values(N'
')
    exec dbo.sp_MSscript_where_clause @objid, @columns, 'version pk', null, 4

    insert into #proctext(procedure_text) values(N'
')
    -- send fragments to client
    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_pub_upd_trig
go
grant exec on dbo.sp_MSscript_pub_upd_trig to public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_del_proc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_del_proc')
drop procedure sp_MSscript_sync_del_proc
go
raiserror('Creating procedure sp_MSscript_sync_del_proc', 0,1)
go
create procedure sp_MSscript_sync_del_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
	declare @colname sysname
	declare @indid int
	declare @cmd          nvarchar(4000)
	declare @columns      binary(32)
	declare @outvars      nvarchar(4000)
	declare @rc           int
	declare @error_cmd	tinyint
	declare @queued_pub bit

	set nocount on
	--
	-- security check
	--
	exec @rc = dbo.sp_MSreplcheck_publish
	if @@error <> 0 or @rc <> 0
	begin
		return (1)
	end
	--
	-- Create temp table
	--
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	select @queued_pub = allow_queued_tran from syspublications where name = @publication

	--
	-- proc definition
	--
	exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
	if @rc = 0
	    return

	--
	-- construct parameter list
	--
	exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null

	--
	-- add other parameters and start body of proc
	--
	exec dbo.sp_MSscript_procbodystart @queued_pub 

	--
	-- script out security check
	--
	exec dbo.sp_MSscript_security @publication

	--
	-- script the execution mode checks
	--
	exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 1

	--
	-- script out subscription validation
	--
	exec dbo.sp_MSscript_validate_subscription @publication, @article

	--
	-- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
	-- *** Do we need to check this here - 
	-- *** we should be checking this when creating subscription
	-- 
	exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
	if @rc = 1
		select @error_cmd = 1
	else
	begin
		exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
		if (@outvars != null and @indid = 0)
			-- no insert/update allowed if timestamp/identity col and no unique index
			select @error_cmd = 1
		else
			select @error_cmd = 0		
	end

	if (@error_cmd = 0)
	begin
		-- Continue generation
		
		--
		-- script delete statemnt
		--
		exec dbo.sp_MSscript_delete_statement @publication, @article, @source_objid, @columns, @queued_pub

		--
		-- script queued specific stuff
		--
		if (@queued_pub = 1)
		begin
			--
			-- script Conflict resolution block for Subscriber Wins case
			--
			exec dbo.sp_MSscript_delete_subwins @publication, @article, @source_objid, @columns

			--
			-- script Conflict resolution block for Publisher Wins case
			--
			exec dbo.sp_MSscript_delete_pubwins @publication, @article, @source_objid, @columns
		end
		
		--
		-- script closing 
		--
		exec dbo.sp_MSscript_endproc @source_objid, 'del', @columns, @outvars, @queued_pub
	end
	else
	begin
		--
		-- Generate error command and finish
		--
		insert into #proctext(procedure_text) values( N'
	exec sp_MSreplraiserror 20516
END
')
	end
	              
	--
	-- send fragments to client
	--
	select procedure_text from #proctext order by c1 asc

END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_del_proc
GO
grant exec on dbo.sp_MSscript_sync_del_proc to public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_ins_proc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_ins_proc')
drop procedure sp_MSscript_sync_ins_proc
go
raiserror('Creating procedure sp_MSscript_sync_ins_proc', 0,1)
go
create procedure sp_MSscript_sync_ins_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
			,@colname sysname
			,@indid int
			,@cmd          nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@error_cmd	tinyint
			,@identity_insert bit
			,@queued_pub bit

	set nocount on
	--
	-- security check
	--
	exec @rc = dbo.sp_MSreplcheck_publish
	if @@error <> 0 or @rc <> 0
	begin
		return (1)
	end
	--
	-- Create temp table
	--
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	select @queued_pub = allow_queued_tran from syspublications where name = @publication

	--
	-- proc definition
	--
	exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
	if @rc = 0
	    return

	--
	-- construct parameter list
	--
	exec dbo.sp_MSscript_params @source_objid, @columns, null, 1,  @outvars output

	--
	-- add other parameters and start body of proc
	--
	exec dbo.sp_MSscript_procbodystart @queued_pub

	--
	-- script out security check
	--
	exec dbo.sp_MSscript_security @publication

	--
	-- script the execution mode checks
	--
	exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 0

	--
	-- script out subscription validation
	--
	exec dbo.sp_MSscript_validate_subscription @publication, @article

	--
	-- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
	-- *** Do we need to check this here - 
	-- *** we should be checking this when creating subscription
	-- 
	exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
	if @rc = 1
		select @error_cmd = 1
	else
	begin
		exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
		if (@outvars != null and @indid = 0)
			-- no insert/update allowed if timestamp/identity col and no unique index
			select @error_cmd = 1
		else
			select @error_cmd = 0		
	end

	if (@error_cmd = 0)
	begin
		-- Continue generation
	
		-- Check to see if identity insert must be turned on
		-- i.e. Does the table has identity that are included in the partition?
		exec sp_MSis_identity_insert @publication, @article, @identity_insert output
		--
		-- script insert statemnt
		--
		exec dbo.sp_MSscript_insert_statement @source_objid, @columns, @identity_insert, @queued_pub

		--
		-- script queued specific stuff
		--
		if (@queued_pub = 1)
		begin
			--
			-- script Conflict resolution block for Subscriber Wins case
			--
			exec dbo.sp_MSscript_insert_subwins @publication, @article, @source_objid, @columns, @identity_insert

			--
			-- script Conflict resolution block for Publisher Wins case
			--
			exec dbo.sp_MSscript_insert_pubwins @publication, @article, @source_objid, @columns
		end
		
		--
		-- script closing 
		--
		exec dbo.sp_MSscript_endproc @source_objid, 'ins', @columns, @outvars, @queued_pub
	end
	else
	begin
		--
		-- Generate error command and finish
		--
		insert into #proctext(procedure_text) values( N'
	exec sp_MSreplraiserror 20516
END
')
	end
	              
	--
	-- send fragments to client
	--
	select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_proc
GO
grant exec on dbo.sp_MSscript_sync_ins_proc to public
go

--------------------------------------------------------------------------------
--. sp_MSscript_sync_upd_proc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_sync_upd_proc')
drop procedure sp_MSscript_sync_upd_proc
go
raiserror('Creating procedure sp_MSscript_sync_upd_proc', 0,1)
go
create procedure sp_MSscript_sync_upd_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
			,@colname sysname
			,@indid int
			,@cmd          nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@error_cmd	tinyint
			,@identity_insert bit
			,@queued_pub bit

	set nocount on
	--
	-- security check
	--
	exec @rc = dbo.sp_MSreplcheck_publish
	if @@error <> 0 or @rc <> 0
	begin
		return (1)
	end
	--
	-- Create temp table
	--
	create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	select @queued_pub = allow_queued_tran from syspublications where name = @publication

	--
	-- proc definition
	--
	exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
	if @rc = 0
	    return

	--
	-- construct parameter list
	-- Script bitmap parameter
	--
	exec dbo.sp_MSscript_params @source_objid, @columns, null, 1,  @outvars output
	insert into #proctext(procedure_text) values( N',')
	exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null
	insert into #proctext(procedure_text) values( N'
	,@bitmap varbinary(4000)')

	--
	-- add other parameters and start body of proc
	--
	exec dbo.sp_MSscript_procbodystart @queued_pub 

	--
	-- script out security check
	--
	exec dbo.sp_MSscript_security @publication

	--
	-- script the execution mode checks
	--
	exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 2

	--
	-- script out subscription validation
	--
	exec dbo.sp_MSscript_validate_subscription @publication, @article

	--
	-- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
	-- *** Do we need to check this here - 
	-- *** we should be checking this when creating subscription
	-- 
	exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
	if @rc = 1
		select @error_cmd = 1
	else
	begin
		exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
		if (@outvars != null and @indid = 0)
			-- no insert/update allowed if timestamp/identity col and no unique index
			select @error_cmd = 1
		else
			select @error_cmd = 0		
	end

	if (@error_cmd = 0)
	begin
		-- Continue generation
		
		--
		-- script update statemnt
		--
		exec dbo.sp_MSscript_update_statement @publication, @article, @source_objid, @columns, @queued_pub

		--
		-- script queued specific stuff
		--
		if (@queued_pub = 1)
		begin
			-- Check to see if identity insert must be turned on
			-- i.e. Does the table has identity that are included in the partition?
			exec sp_MSis_identity_insert @publication, @article, @identity_insert output
			--
			--
			-- script Conflict resolution block for Subscriber Wins case
			--
			exec dbo.sp_MSscript_update_subwins @publication, @article, @source_objid, @columns, @identity_insert

			--
			-- script Conflict resolution block for Publisher Wins case
			--
			exec dbo.sp_MSscript_update_pubwins @publication, @article, @source_objid, @columns
		end

		--
		-- script closing 
		--
		exec dbo.sp_MSscript_endproc @source_objid, 'upd', @columns, @outvars, @queued_pub
	end
	else
	begin
		--
		-- Generate error command and finish
		--
		insert into #proctext(procedure_text) values( N'
	exec sp_MSreplraiserror 20516
END
')
	end
	              
	--
	-- send fragments to client
	--
	select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_proc
GO
grant exec on dbo.sp_MSscript_sync_upd_proc to public
go

--------------------------------------------------------------------------------
--. sp_script_reconciliation_insproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_script_reconciliation_insproc')
drop procedure sp_script_reconciliation_insproc
go
raiserror('Creating procedure sp_script_reconciliation_insproc', 0,1)
go
create procedure sp_script_reconciliation_insproc (
	@artid int)
as
BEGIN
declare @retcode int
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @artcolumns   binary(32)
declare @pkcolumns    binary(32)
declare @ins_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(1)
	, @identity_insert bit
	
--
-- security check
--
exec @retcode = dbo.sp_MSreplcheck_publish
if @@error <> 0 or @retcode <> 0
begin
    return (1)
end

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @ins_cmd = ins_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid


-- save off cmd fragment

insert into #proctext(procedure_text) values( @cmd )

insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

---- if already exists, apply as update

insert into #proctext(procedure_text) 
    values( N'if exists ( select * from ' + @dest_owner + QUOTENAME(@dest_tabname) )
exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output
exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
insert into #proctext(procedure_text) values( N')' )
insert into #proctext(procedure_text) values (N'begin')


if( @artcolumns != @pkcolumns )
begin
	-- construct update 

	select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

	-- create SET clause

	select @art_col = 1
	select @spacer = N' '

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
		if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset = 0
			begin
				if not (@identity_insert = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
					select @spacer = N','

					if len( @cmd ) > 3000
					begin
						insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
			end
			select @art_col = @art_col + 1
		end
		FETCH hCColid INTO @this_col
   	end
	CLOSE hCColid
	DEALLOCATE hCColid

	insert into #proctext(procedure_text) values( @cmd )

	exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
end

-- all article columns are included in the PK, & PK already exists, do nothing
else 
begin
	insert into #proctext(procedure_text ) values( N'return' )
end


insert into #proctext(procedure_text) values (N'end')
insert into #proctext(procedure_text) values (N'else')
insert into #proctext(procedure_text) values (N'begin')

---- normal insert

-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end

-- prepare the column list

select @cmd = N'insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ('
select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col))  
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- now the data parameter list

select @cmd = @cmd + N' ) values ('
select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) 
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- finish up proc body

select @cmd = @cmd + N' )'

-- save off cmd fragement

insert into #proctext(procedure_text) values( @cmd )

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

insert into #proctext(procedure_text) values (N'end')

-- send fragments to client

select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_insproc
GO
grant exec on dbo.sp_script_reconciliation_insproc to public
go

--------------------------------------------------------------------------------
--. sp_script_reconciliation_delproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_script_reconciliation_delproc')
drop procedure sp_script_reconciliation_delproc
go
raiserror('Creating procedure sp_script_reconciliation_delproc', 0,1)
go
create procedure sp_script_reconciliation_delproc 
( 
	@artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'


    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_delproc
GO
grant exec on dbo.sp_script_reconciliation_delproc to public
go

--------------------------------------------------------------------------------
--. sp_script_reconciliation_xdelproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_script_reconciliation_xdelproc')
drop procedure sp_script_reconciliation_xdelproc
go
raiserror('Creating procedure sp_script_reconciliation_xdelproc', 0,1)
go
create procedure sp_script_reconciliation_xdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @columns    binary(32)
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @columns = columns
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
       FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_xdelproc
GO
grant exec on dbo.sp_script_reconciliation_xdelproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptinsproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptinsproc')
drop procedure sp_scriptinsproc
go
raiserror('Creating procedure sp_scriptinsproc', 0,1)
go
create procedure sp_scriptinsproc (
	@artid int)
as
BEGIN
declare @cmd          nvarchar(4000)
		,@dest_owner   nvarchar(255)
		,@dest_tabname sysname
		,@src_objid    int
		,@columns      binary(32)
		,@ins_cmd      nvarchar(255)
		,@dest_proc    sysname
		,@this_col     int
		,@art_col      int
		,@isset        int
		,@pubid		  int

		,@identity_insert bit
		,@rc int
		,@colname sysname
		,@ccoltype     sysname
		,@typestring   nvarchar(255)
		,@spacer       nvarchar(1)
		,@queued_check bit
		,@column_string nvarchar(4000)
		,@var_string nvarchar(4000)

set nocount on
--
-- security check
--
exec @rc = dbo.sp_MSreplcheck_publish
if @@error <> 0 or @rc <> 0
begin
    return (1)
end

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments and insert column list

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #collisttab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @columns = columns, @ins_cmd = ins_cmd,
       @pubid = pubid
from sysarticles
where artid = @artid

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check if this is a queued publication
select @queued_check = ISNULL(allow_queued_tran, 0) 
from syspublications
where pubid = @pubid

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off cmd fragment

insert into #proctext(procedure_text) values( @cmd )

select @cmd = N'
AS
BEGIN
'
insert into #proctext(procedure_text) values( @cmd )

------- construct proc body

-- Generate strings for col names and variables
select @art_col = 0
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
	exec @rc = dbo.sp_MSget_colinfo @src_objid, @this_col, @columns, 1, @colname output, @ccoltype output
	if @rc = 0  and EXISTS (select name from syscolumns where id=@src_objid and colid=@this_col and iscomputed<>1)
	begin
		select @art_col = @art_col + 1
		if (@art_col = 1)
		begin
			select @column_string = QUOTENAME(@colname)
			select @var_string = N'@c' + cast(@art_col as nvarchar(4))
		end
		else
		begin
			select @column_string = @column_string + N', ' + QUOTENAME(@colname)
			select @var_string = @var_string + N', @c' + cast(@art_col as nvarchar(4))
		end

		-- transfer column list string to table if too large
		if (len(@column_string) > 3000)
		begin
			insert into #collisttab(procedure_text) values( @column_string )
			select @column_string = ' '
		end
	end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- insert the remaining strings for column list and where clause
insert into #collisttab(procedure_text) values( @column_string )

--
-- If we are a part of queued publication then 
-- insert only if PK or other unique key(s) do not exist
--
if (@queued_check = 1)
begin
    select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
    insert into #proctext(procedure_text) values( @cmd )
    exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                        ,@columns = @columns
                                                        ,@prefix = '@c' 
                                                        ,@mode = 1
    if (@@error != 0 or @rc != 0)
        return 1
    select @cmd = N')
BEGIN'
    insert into #proctext(procedure_text) values( @cmd )
end

-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end

--
-- prepare the insert statement now
--
select @cmd = N'
insert into ' +  @dest_owner + QUOTENAME(@dest_tabname)  + N'( '
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) 
	select procedure_text from #collisttab order by c1 asc
select @cmd = N' )'
insert into #proctext(procedure_text) values( @cmd )
if @art_col > 0
begin
	select @cmd = N'
values ( '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) values( @var_string )
	select @cmd = N' )
'
	insert into #proctext(procedure_text) values( @cmd )
end

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

--
-- If we are a part of queued publication then 
-- add the block delimiter
--
drop table #collisttab
if (@queued_check = 1)
begin
	select @cmd = N'
END
END'
end
else
	select @cmd = N'
END'
insert into #proctext(procedure_text) values( @cmd )

-- send fragements to client

select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc
GO
grant exec on dbo.sp_scriptinsproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptdelproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptdelproc')
drop procedure sp_scriptdelproc
go
raiserror('Creating procedure sp_scriptdelproc', 0,1)
go
create procedure sp_scriptdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int, @pubid int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    
    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if exists (select * from syspublications where pubid = @pubid and allow_queued_tran = 0)
    	exec dbo.sp_MSscript_missing_row_check
    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptdelproc
GO
grant exec on dbo.sp_scriptdelproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptxdelproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptxdelproc')
drop procedure sp_scriptxdelproc
go
raiserror('Creating procedure sp_scriptxdelproc', 0,1)
go
create procedure sp_scriptxdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @columns    binary(32)
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int
    declare @pubid		  int
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @queued_check bit
    		,@qwhere_string nvarchar(4000)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    
    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @columns = columns
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -- Check if this is a queued publication
    select @queued_check = ISNULL(allow_queued_tran, 0) 
    from syspublications
    where pubid = @pubid

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 

    		--
    		-- Queued processing:if this is the row version column : need to add to where clause
    		--
    		if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    			select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )

            select @art_col = @art_col + 1
            select @spacer = N','
       end
       FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns
    if (@queued_check = 1)
    	insert into #proctext(procedure_text) values( @qwhere_string )
    else
    	exec dbo.sp_MSscript_missing_row_check

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptxdelproc
GO
grant exec on dbo.sp_scriptxdelproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptupdproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptupdproc')
drop procedure sp_scriptupdproc
go
raiserror('Creating procedure sp_scriptupdproc', 0,1)
go
create procedure sp_scriptupdproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @pkart_col    int
    declare @isset        int
    declare @pkcomputed   int
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @pubid        int, @allow_queued_tran bit, @need_end bit

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    select @need_end = 0

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -------- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 6, len( @upd_cmd ) - 4 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    insert into #proctext(procedure_text) values ( N'as' )

    -------- now create the update statement

    -- construct test to see if pk has changed 
    -- only do this if the article has columns not included in the pk

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    declare @pk_is_identity bit
    select @pk_is_identity = 0

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @cmd = N'if'

        select @art_col = 1
        select @pkart_col = 1
        select @spacer = ' '

        DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
        select colid from syscolumns where id = @src_objid order by colid asc

        OPEN hCColid

        FETCH hCColid INTO @this_col

        select @pk_is_identity = 1
        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col ) + N' = @pkc' + convert( nvarchar, @pkart_col ) 
    					select @spacer = N' and '
    					select @pkart_col = @pkart_col + 1
    					if len( @cmd ) > 3000
    					begin
    					insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end

        CLOSE hCColid
        DEALLOCATE hCColid

    	if @pk_is_identity = 0
    	begin
    		insert into #proctext(procedure_text) values( @cmd )

    		insert into #proctext(procedure_text) values( N'begin' )

    		-- construct update if pk hasn't changed

    		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    		-- create SET clause

    		select @art_col = 1
    		select @spacer = N' '

    		DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    		select colid from syscolumns where id = @src_objid order by colid asc

    		OPEN hCColid

    		FETCH hCColid INTO @this_col
    		WHILE (@@fetch_status <> -1)
    		begin
    			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    			begin
    				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    				if @isset = 0
    				begin
    					if not (@keep_identity = 1 and 
    						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    					begin
    						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
    						select @spacer = N','

    						if len( @cmd ) > 3000
    						begin
    							insert into #proctext(procedure_text) values( @cmd )
    							select @cmd = N''
    						end
    					end
    				end
    				select @art_col = @art_col + 1
    			end
    			FETCH hCColid INTO @this_col
    		end
    		CLOSE hCColid
    		DEALLOCATE hCColid

    		insert into #proctext(procedure_text) values( @cmd )

    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check

    		insert into #proctext(procedure_text) values( N'end' )
    		insert into #proctext(procedure_text) values( N'else' )
    		insert into #proctext(procedure_text) values( N'begin' )

    		select @need_end = 1

    	end
    end -- end if artcols != pkcols


    -- construct update if pk has changed

    select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    -- create SET clause

    select @art_col = 1
    select @spacer = N' '

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col
    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
    			select @spacer = N','

    			if len( @cmd ) > 3000
    			begin
    			insert into #proctext(procedure_text) values( @cmd )
    				select @cmd = N''
    			end
    		end
    		select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    insert into #proctext(procedure_text) values( @cmd )

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if @allow_queued_tran <> 1
    	exec dbo.sp_MSscript_missing_row_check

    if @need_end = 1
    	insert into #proctext(procedure_text) values( N'end' )
    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptupdproc
GO
grant exec on dbo.sp_scriptupdproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptmappedupdproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptmappedupdproc')
drop procedure sp_scriptmappedupdproc
go
raiserror('Creating procedure sp_scriptmappedupdproc', 0,1)
go
create procedure sp_scriptmappedupdproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @art_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @pkart_col    int
    declare @isset        int
    declare @bytestr      nvarchar(10)
    declare @bitstr       nvarchar(10)
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @update_created  bit
    declare @pkcomputed   int
    declare @pubid        int, @allow_queued_tran bit

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    select @update_created	 = 0

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )

    -------- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
    	   @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'MCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
      

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    ----- add changed data bitmap

    select @art_col = 1


    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
       begin
            select @art_col = @art_col + 1
       end
       FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- Note that bitmap size is based on number of article columns
    -- (computed by loop above) not source table columns

    select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )


    -- construct IF statement to examine colbitmap and determine if a 
    -- primary key column has been updated.  

    -- do this only if the article contains columns not included in the pk
    -- and at least one of the columns in the PK is real ( i.e. not computed )

    -- note that if all the article columns are PK columns, we will
    -- construct the 'update all columns including PK columns' statement
    -- w/o a preceeding IF, and we will NOT construct the 'only update non-pk columns' 
    -- part of the procedure

    -- also note that this is pretty much worthless since 7.0 and above are
    -- guaranteed to NEVER generate an UPDATE if a PK columns is updated... oh well.
    declare @pk_is_identity bit
    select @pk_is_identity = 0

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @art_col = 1
        select @spacer = N' '

        select @cmd = N'if'

    	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    	select colid from syscolumns where id = @src_objid order by colid asc

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	select @pk_is_identity = 1

        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin 
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    					select @cmd = @cmd + @spacer + N'substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    							 N' = ' + @bitstr 
                    
    					select @spacer = N' or '

    					if len( @cmd ) > 3000
    					begin
    						insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
    		FETCH hCColid INTO @this_col
        end
        CLOSE hCColid
        DEALLOCATE hCColid

        if @pk_is_identity = 0
            insert into #proctext(procedure_text) values( @cmd )

    end  -- if artcolumns != pkcolumns

    -- construct update statement including PK columns

    insert into #proctext(procedure_text) values( N'begin' )

    insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )

    -- create SET clause consisting of CASE statements

    select @art_col = 1
    select @spacer = N''

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    			select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    			insert into #proctext(procedure_text) values (
    				 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    				 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
    				 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

    			select @spacer = ',' 
    		end

            select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- create where clause

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if @allow_queued_tran <> 1
    	exec dbo.sp_MSscript_missing_row_check

    -- construct UPDATE that does not set PK cols
    -- only do this if the article contains columns that are not included
    -- in the pk

    if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
    begin

        -- create SET clause consisting of CASE statements

        select @art_col = 1
        select @spacer = N''

        DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
        select colid from syscolumns where id = @src_objid order by colid asc

        OPEN hCColid

        FETCH hCColid INTO @this_col

        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns 
                if @isset = 0 
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
                		if (@update_created = 0)
                		begin
                			insert into #proctext(procedure_text) values( N'end' )
                			insert into #proctext(procedure_text) values( N'else' )
                			insert into #proctext(procedure_text) values( N'begin' )
    			    		insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )
    			    		select @update_created = 1
    					end
    					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    					insert into #proctext(procedure_text) values (
    						 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    						 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
    						 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

    					select @spacer = ',' 
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end
        CLOSE hCColid
        DEALLOCATE hCColid

        if @update_created = 1
        begin
    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns
    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check
    	end
    end

    insert into #proctext(procedure_text) values( N'end' )
    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptmappedupdproc
GO
grant exec on dbo.sp_scriptmappedupdproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptdynamicupdproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptdynamicupdproc')
drop procedure sp_scriptdynamicupdproc
go
raiserror('Creating procedure sp_scriptdynamicupdproc', 0,1)
go
create procedure sp_scriptdynamicupdproc 
(
    @artid int
)
as
    begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @art_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @pk_col       int
    declare @pkart_col    int
    declare @isset        int
    declare @ispk         int
    declare @isidentity   bit
    declare @iscomputed   bit
    declare @bytestr      nvarchar(10)
    declare @bitstr       nvarchar(10)
    declare @typestring   nvarchar(255)
    declare @spacer_param nvarchar(10)
    declare @update_created  bit
    declare @pkcomputed   int
    declare @pubid        int, @allow_queued_tran bit

    set nocount on 

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    select @update_created	 = 0

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_params ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_paramdef ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_pkparams ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )



    -------- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
    	   @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'MCALL', upper(@upd_cmd) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
      

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    ----- add changed data bitmap

    select @art_col = 1
    select @pk_col = 1

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
       begin
            select @art_col = @art_col + 1
       end
       FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- Note that bitmap size is based on number of article columns
    -- (computed by loop above) not source table columns

    select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )



    -- Find out if pk is identity
    declare @pk_is_identity bit
    select @pk_is_identity = 0

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @art_col = 1

    	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    	select colid from syscolumns where id = @src_objid order by colid asc

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	select @pk_is_identity = 1

    	WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin 
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    				end
                end
                select @art_col = @art_col + 1
            end
    		FETCH hCColid INTO @this_col
        end
    	CLOSE hCColid
    	DEALLOCATE hCColid
    end 

    -- construct UPDATE that does not set PK cols
    -- only do this if the article contains columns that are not included
    -- in the pk
    -- Note: we assume pk columns never change. pk changes will be replicated
    -- as delete insert.

    if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
    begin

        -- create SET clause consisting of CASE statements

        select @art_col = 1
        select @spacer_param = N''

    	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    	select colid from syscolumns where id = @src_objid order by colid asc

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0  
    		begin
                exec @ispk = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    			
    			if EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    				select @iscomputed = 0
    			else
    				select @iscomputed = 1
    			
    			if (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)  
    				select @isidentity = 1
    			else
    				select @isidentity = 0
    				
    			-- If not pk, not computed and not identity	
    			if @ispk = 0 and @iscomputed = 0 and @isidentity = 0
                begin
                	if (@update_created = 0)
                	begin
    			    	insert into #proctext(procedure_text) values( 
    						N'declare @stmt nvarchar(4000), @spacer nvarchar(1)')

    			    	insert into #proctext(procedure_text) values( 
    						N'select @spacer =N''''')

    			    	insert into #proctext(procedure_text) values( 
    						N'select @stmt = N''update ' + 
    						replace(@dest_owner + QUOTENAME(@dest_tabname), N'''', N'''''' ) +
    						N' set ''')

    			    	select @update_created = 1
    				end

    				select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    				select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    				insert into #proctext(procedure_text) values (
    					 N'if substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    					 N' = ' + @bitstr)

    				insert into #proctext(procedure_text) values (N'begin')

    				-- Append statement
    				insert into #proctext(procedure_text) values (
    					 N'select @stmt = @stmt + @spacer + ' + 
    					 N'N''' + replace(QUOTENAME(col_name( @src_objid, @this_col)), N'''', N'''''') + N''' + ' +
    					 N'N''=@'+ convert( nvarchar, @art_col ) + N'''')

    				-- Set @spacer is the proc
    				insert into #proctext(procedure_text) values (
    					N'select @spacer = N'',''')

    				insert into #proctext(procedure_text) values (N'end')
                end
    			-- If pk or (not computed and not identity) add the param
    			if @ispk <> 0 or (@iscomputed = 0 and @isidentity = 0)
    			begin
    				-- Add to param list
    			    if (@ispk <> 0)
    				  begin
    				    -- Use primary key value
    				    insert into #proctext_params(procedure_text) values( 
    						@spacer_param + N'@pkc' + convert( nvarchar, @pk_col ))

    				    -- Increment primary key counter
    				    select @pk_col = @pk_col + 1;

    				  end
    				else
    				    -- Use column value
    					insert into #proctext_params(procedure_text) values( 
    						@spacer_param + N'@c' + convert( nvarchar, @art_col ))

    				-- Get type str
    				exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT

    				-- Append typedef
    				insert into #proctext_paramdef(procedure_text) values (
    					 @spacer_param + N'@' + convert( nvarchar, @art_col ) + 
    					 N' ' + @typestring )

    				select @spacer_param = ',' 
    			end

                select @art_col = @art_col + 1
            end
           	FETCH hCColid INTO @this_col
        end
    	CLOSE hCColid
    	DEALLOCATE hCColid

        if @update_created = 1
    	begin

    		-- Append statement of the start of where clause
    		insert into #proctext(procedure_text) values (
    			 N'	select @stmt = @stmt + N'' ')

    		-- Escape ' in the where clause
    		declare @low_mark int, @high_mark int
    		select @low_mark = max(c1) from #proctext
    		-- Pass in @artcolumns so that the where clause will use the ordinal in the
    		-- article bit map rather then one in pk bitmap. This is consistent with
    		-- the type def string.
    		-- UNDONE: change comments in sp_scriptpkwhereclause
    		-- Use prefix '@' to be consistent with type def string
    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, '@', @artcolumns
    		select @high_mark = max(c1) from #proctext
    		update #proctext set procedure_text = replace ( procedure_text, N'''', N'''''') 
    			where c1 > @low_mark and c1 <= @high_mark

    		-- Close the where clause
    		insert into #proctext(procedure_text) values (
    			 N'''')

    		-- Add call to sql_executesql and the param list
    		insert into #proctext(procedure_text) values( 
    			N'exec sp_executesql @stmt, N'' ')

    		-- Add param def
    		insert into #proctext(procedure_text) 
    			select procedure_text from #proctext_paramdef order by c1 asc

    		-- Close the param def
    		insert into #proctext(procedure_text) values (
    			 N''',')

    		-- Add param list
    		insert into #proctext(procedure_text) 
    			select procedure_text from #proctext_params order by c1 asc

    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check
    	end

    end

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptdynamicupdproc
GO
grant exec on dbo.sp_scriptdynamicupdproc to public
go

--------------------------------------------------------------------------------
--. sp_scriptxupdproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_scriptxupdproc')
drop procedure sp_scriptxupdproc
go
raiserror('Creating procedure sp_scriptxupdproc', 0,1)
go
create procedure sp_scriptxupdproc @artid int
as
BEGIN
    declare @cmd          nvarchar(4000),
                @dest_owner   nvarchar(255),
                @dest_tabname sysname,
                @src_objid    int,
                @artcolumns   binary(32),
                @pkcolumns    binary(32),
                @upd_cmd      nvarchar(255),
                @dest_proc    sysname,
                @this_col     int,
                @art_col      int,
                --@pkart_col    int,
                @isset        int,
                @rc int,
                @fhasnonpkuniquekeys int,
                @pkcomputed   int,
                @typestring   nvarchar(255),
                @spacer       nvarchar(10),
                @pubid		  int, 
                @param_count  int
                ,@queued_check bit, @exists_else bit
                ,@qwhere_string nvarchar(4000)

    set nocount on
    --
    -- security check
    --
    exec @rc = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @rc <> 0
    begin
        return (1)
    end

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    select @exists_else = 0
             ,@fhasnonpkuniquekeys = 0

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

    -------- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -- Check if this is a queued publication
    select @queued_check = ISNULL(allow_queued_tran, 0) 
    from syspublications
    where pubid = @pubid

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    declare @keep_identity bit
    if exists (select * from syspublications where pubid = @pubid and
    	allow_queued_tran = 1) and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    -- Send null as @pkcolumns. We don't need pk parameters.
    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, NULL, @param_count output

    insert into #proctext(procedure_text) values ( N'as' )

    --
    -- If we are a part of queued publication 
    --
    if (@queued_check = 1)
    begin
        --
        -- Check if we have non PK unique keys
        --
        exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @src_objid
        if (@fhasnonpkuniquekeys = 1)
        begin
            --
            -- There are non PK unique keys
            -- update only if updated values of non PK unique key(s) do not exist
            --
            select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
            insert into #proctext(procedure_text) values( @cmd )
            exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                            ,@columns = @artcolumns
                                                            ,@prefix = '@c' 
                                                            ,@mode = 2
                                                            ,@paramcount = @param_count
            if (@@error != 0 or @rc != 0)
                return 1
            select @cmd = N')
begin'
            insert into #proctext(procedure_text) values( @cmd )
        end
    end

    -------- now create the update statement

    -- construct test to see if pk has changed 
    -- only do this if the article has columns not included in the pk

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    declare @pk_is_identity bit
    select @pk_is_identity = 0

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @cmd = N'if'

        select @art_col = 1
        --select @pkart_col = 1
        select @spacer = ' '

        DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
        select colid from syscolumns where id = @src_objid order by colid asc

        OPEN hCColid

        FETCH hCColid INTO @this_col

        select @pk_is_identity = 1
        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col + @param_count/2) + 
    						N' = @c' + convert( nvarchar, @art_col ) 
    					select @spacer = N' and '
    					--select @pkart_col = @pkart_col + 1
    					if len( @cmd ) > 3000
    					begin
    					insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end

        CLOSE hCColid
        DEALLOCATE hCColid

    	if @pk_is_identity = 0
    	begin
    		insert into #proctext(procedure_text) values( @cmd )

    		insert into #proctext(procedure_text) values( N'begin' )

    		-- construct update if pk hasn't changed
    		-- We know that there would be a least one column for the update below, even if
    		-- the columns outside the pk are identity or timestamp. Since identity and timestamp
    		-- will be mapped off unless it is queued tran. In that case, we have 'msrepl_tran_version'
    		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    		-- create SET clause

    		select @art_col = 1
    		select @spacer = N' '

    		DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    		select colid from syscolumns where id = @src_objid order by colid asc

    		OPEN hCColid

    		FETCH hCColid INTO @this_col
    		WHILE (@@fetch_status <> -1)
    		begin
    			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    			begin
    				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    				if @isset = 0
    				begin
    					if not (@keep_identity = 1 and 
    						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    					begin
    						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
    							N' = @c' + convert( nvarchar, @art_col + @param_count/2) 
    						select @spacer = N','

    						if len( @cmd ) > 3000
    						begin
    							insert into #proctext(procedure_text) values( @cmd )
    							select @cmd = N''
    						end

    						--
    						-- Queued processing:if this is the row version column : need to add to where clause
    						--
    						if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    							select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
    					end
    				end
    				select @art_col = @art_col + 1
    			end
    			FETCH hCColid INTO @this_col
    		end
    		CLOSE hCColid
    		DEALLOCATE hCColid

    		insert into #proctext(procedure_text) values( @cmd )

    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
    		if (@queued_check = 1)
    			insert into #proctext(procedure_text) values( @qwhere_string )
    		else
    			exec dbo.sp_MSscript_missing_row_check

    		insert into #proctext(procedure_text) values( N'end' )
    		insert into #proctext(procedure_text) values( N'else' )
    		insert into #proctext(procedure_text) values( N'begin' )

    		select @exists_else = 1

    	end
    end -- end if artcols != pkcols

    --
    -- If we are a part of queued publication then 
    -- update only if updated value of PK does not exist
    --
    if (@queued_check = 1 and @pk_is_identity = 0)
    begin
        select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
        insert into #proctext(procedure_text) values( @cmd )
        exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                            ,@columns = @artcolumns
                                                            ,@prefix = '@c' 
                                                            ,@mode = 3
                                                            ,@paramcount = @param_count
        if (@@error != 0 or @rc != 0)
            return 1
        select @cmd = N')
begin'
        insert into #proctext(procedure_text) values( @cmd )
    end

    -- construct update if pk has changed
    select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    -- create SET clause

    select @art_col = 1
    select @spacer = N' '

    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col
    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
    				N' = @c' + convert( nvarchar, @art_col + @param_count/2 ) 
    			select @spacer = N','

    			if len( @cmd ) > 3000
    			begin
    			insert into #proctext(procedure_text) values( @cmd )
    				select @cmd = N''
    			end

    			--
    			-- Queued processing:if this is the row version column : need to add to where clause
    			--
    			if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    				select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
    		end
    		select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    insert into #proctext(procedure_text) values( @cmd )

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
    if (@queued_check = 1)
    begin
        insert into #proctext(procedure_text) values( @qwhere_string ) 
        if (@pk_is_identity = 0)
        begin
            select @cmd = N'
end'
            insert into #proctext(procedure_text) values( @cmd )
        end
    end
    else
    	exec dbo.sp_MSscript_missing_row_check

    if @exists_else = 1
    	insert into #proctext(procedure_text) values( N'end' )

    --
    -- End the if exists block for Queued publications
    --
    if (@queued_check = 1) and (@fhasnonpkuniquekeys = 1)
    begin
        select @cmd = N'
end'
        insert into #proctext(procedure_text) values( @cmd )
    end

    -- flush to client

    select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_scriptxupdproc
GO
grant exec on dbo.sp_scriptxupdproc to public
go

--------------------------------------------------------------------------------
--. sp_MSgetarticlereinitvalue
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgetarticlereinitvalue')
drop procedure sp_MSgetarticlereinitvalue
go
raiserror('Creating procedure sp_MSgetarticlereinitvalue', 0,1)
go
create procedure sp_MSgetarticlereinitvalue (
	@subscriber 			sysname,
	@subscriberdb 		sysname,
	@artid	 			int, 
	@reinit		 		int output
)
as
begin
	set NOCOUNT ON
	declare @orig_srvid int
		,@retcode int
		,@publication sysname

	--
	-- PAL security check
	-- Get publication name using artid
	--
	select @publication = p.name
	from syspublications p join sysarticles a on p.pubid = a.pubid
	where a.artid = @artid
	if (@publication is null)
	begin
		return 1
	end
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- get the value of reinit flag
	--
	select @orig_srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
	select @reinit = queued_reinit 
	from syssubscriptions 
	where 
		artid = @artid 
		and srvid = @orig_srvid
		and dest_db = @subscriberdb

	-- All done
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSgetarticlereinitvalue
go
grant execute on dbo.sp_MSgetarticlereinitvalue to public
go

--------------------------------------------------------------------------------
--.	sp_MScomputearticlescreationorder
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScomputearticlescreationorder')
drop procedure sp_MScomputearticlescreationorder
go
print ''
print 'Creating procedure sp_MScomputearticlescreationorder'
go
CREATE PROCEDURE sp_MScomputearticlescreationorder
    @publication sysname
AS
    SET NOCOUNT ON
    DECLARE @pubid int 
    DECLARE @max_level int
    DECLARE @current_level int
    DECLARE @update_level int
    DECLARE @limit int
    DECLARE @result int
    DECLARE @retcode int

    SELECT @retcode = 0

    EXEC @retcode = sp_MSreplcheck_publish
    IF @@ERROR <> 0 OR @retcode <> 0
        return (1)

    SELECT @pubid = NULL
    -- Get the pubid from syspublications 
    SELECT @pubid = pubid 
      FROM syspublications
     WHERE name = @publication

    IF @@ERROR <> 0
        RETURN (1)

    IF @pubid IS NULL
    BEGIN
        RAISERROR(20026, 16, -1, @publication)
        RETURN (1)
    END

    EXEC @result = sp_getapplock @Resource = @publication, 
				@LockMode = N'Shared', 
				@LockOwner = N'Session', 
				@LockTimeout = 0

    IF @result < 0
    BEGIN
        RAISERROR(21385, 16, -1, @publication)
        RETURN (1)
    END

    -- Find out the total number of articles in this publication and
    -- compute the maximum tree height based on the number of articles in 
    -- the publication. Here, the tree height is counted from the
    -- leaf-nodes towards the root(s)
    SELECT @max_level = COUNT(*) + 10,
           @limit =2 *  COUNT(*) + 11 
      FROM sysextendedarticlesview 
     WHERE pubid = @pubid
 
    IF @@ERROR <> 0
    BEGIN
        RETURN (1)
    END
   
    -- The following temp table contains the minimal amount of 
    -- article information that we want to keep around and the current
    -- computed tree level of the article
    CREATE TABLE #article_level_info
    (
        article         sysname collate database_default not null,
        source_objid    INT     NOT NULL,
        tree_level      INT     NOT NULL,
        ref_level       INT     NOT NULL,
        major_type      TINYINT NOT NULL  -- 1-view&func, 0-other 
    )  
   
    CREATE CLUSTERED INDEX ucarticle_level_info 
        ON #article_level_info(source_objid)

    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END

    -- Populate the article level info table. All articles will be
    -- assigned 0 as their initial tree level. Having 
    -- a tree level of 0 means that the algorithm hasn't discovered 
    -- any objects that the article depends on within the publication.

    INSERT INTO #article_level_info 
    SELECT name, objid, 0, 0, 
        CASE type    
            WHEN 0x40 THEN 1
            WHEN 0x80 THEN 1
            ELSE 0 
        END
      FROM sysextendedarticlesview
     WHERE pubid = @pubid
      
    -- To jump-start the algorithm, update the tree_level of 
    -- all articles with no dependency to @max_level.

    UPDATE #article_level_info 
       SET tree_level = @max_level
     WHERE NOT EXISTS (SELECT * 
                         FROM sysdepends 
                        WHERE source_objid = id
                          and id <> depid)
    IF @@ERROR <> 0
        GOTO Failure

    -- For each increasing tree level starting from @max_level, update the 
    -- the tree_level of articles depending on objects at the current
    -- level to current level + 1
    SELECT @current_level = @max_level
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1

        UPDATE #article_level_info
           SET tree_level = @update_level
          FROM #article_level_info 
        INNER JOIN sysdepends d
            ON #article_level_info.source_objid = d.id 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid       
               AND ali1.tree_level = @current_level
               AND d.id <> d.depid)
    
        -- Terminate the algorithm if we cannot find any articles 
        -- depending on articles at the current level     
        IF @@ROWCOUNT = 0
            GOTO PHASE1

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1

        -- Although there should not be any circular 
        -- dependencies among the articles, the following
        -- check is performed to guarantee that 
        -- the algorithm will terminate even if there 
        -- is circular dependency among the articles
        
        -- Note that with at least one node per level,
        -- the current level can never exceed the total 
        -- number of articles (nodes) unless there is
        -- circular dependency among the articles.
        
        -- @limit is defined to be # of articles + 1
        -- although @limit = # of articles - 1 will be
        -- sufficient. This is to make absolutely sure that 
        -- the algorithm will never terminate too early

        IF @current_level > @limit
            GOTO PHASE1
    END

PHASE1:

    -- There may be interdependencies among articles 
    -- that haven't been included in the previous calculations so
    -- we compute the proper order among these articles here.
    SELECT @limit = @max_level - 9
    SELECT @current_level = 0
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info 
           SET tree_level = @update_level
          FROM #article_level_info
        INNER JOIN sysdepends d
            ON (#article_level_info.source_objid = d.id
                AND #article_level_info.tree_level < @max_level) 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid
                AND ali1.tree_level = @current_level
                AND d.id <> d.depid)
        IF @@ROWCOUNT = 0
            GOTO PHASE2
        
        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE2
    END         

PHASE2:

    -- Since transactional doesn't keep the nickname around in 
    -- sysmergearticles as merge does, we need to compute FK/PK ordering on 
    -- the fly. 
    SELECT @current_level = 0
    SELECT @limit = @max_level - 9
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info
           SET ref_level = @update_level
          FROM #article_level_info
        INNER JOIN sysreferences r
            ON (#article_level_info.source_objid = r.fkeyid
                and r.rkeyid <> r.fkeyid)
        INNER JOIN #article_level_info ali1
            ON (r.rkeyid = ali1.source_objid 
                AND ali1.ref_level = @current_level)
        IF @@ROWCOUNT = 0
            GOTO PHASE3

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE3
    END

PHASE3:

    -- Select the articles out of #article_level_info 
    -- in ascending order of tree_level. This will give
    -- the proper order in which articles can be created
    -- without violating the internal dependencies among
    -- themselves. Note that this algorithm still allows 
    -- unresolved external references outside the publication.
    -- All this algorithm can guarantee is that all articles will
    -- be created successfully using the resulting order if 
    -- there is no dependent object outside the publication. 
    -- We need to order the articles in reverse ref_level
    -- to account for FK/PK constraints when dropping/deleting rows/truncating
    -- tables on the Subscriber.

    SELECT article
      FROM #article_level_info
    ORDER BY major_type ASC, tree_level ASC, ref_level DESC

    DROP TABLE #article_level_info
    RETURN (0)

Failure:

    DROP TABLE #article_level_info
    RETURN (1)
GO

exec dbo.sp_MS_marksystemobject sp_MScomputearticlescreationorder
go
grant execute on sp_MScomputearticlescreationorder to public
go

--------------------------------------------------------------------------------
--.	sp_MSscriptmvastablenci
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscriptmvastablenci')
drop procedure sp_MSscriptmvastablenci
go
print ''
print 'Creating procedure sp_MSscriptmvastablenci'
go

create procedure sp_MSscriptmvastablenci @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int
declare @status		  int
declare @unique	      nvarchar(10)
declare @cmd_sep	  nvarchar(10)


-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default
select @cmd_sep = N''

DECLARE hCIdx CURSOR LOCAL FAST_FORWARD FOR
select name, indid, status from sysindexes where id = @src_objid and indid > 1 order by indid asc

OPEN hCIdx
FETCH hCIdx INTO @constraint_name, @indid, @status

WHILE (@@fetch_status <> -1)
begin
	if @status & 2 = 2
	begin
		select @unique = N' unique '
	end
	else
	begin
		select @unique = N' '
	end

	insert into #proctext(procedure_text) values( @cmd_sep )
	select @cmd_sep = N'GO'

	select @cmd = N'create' + @unique + N'nonclustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'('
	insert into #proctext(procedure_text) values( @cmd )

	select @spacer = N' '
	select @cmd = N''

	select @indkey = 1
	while (@indkey <= 16)
	begin	
		select @colname = index_col(@srcobj, @indid, @indkey)
		if (@colname is null)
		begin
			select @indkey = 16
		end
		else
		begin
			select @cmd = @cmd + @spacer + QUOTENAME(@colname)
			select @spacer = N','

			if len( @cmd ) > 3000
			begin
				insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		select @indkey = @indkey + 1
	end

	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) values( N')' )
	
	FETCH hCIdx INTO @constraint_name, @indid, @status
end

CLOSE hCIdx
DEALLOCATE hCIdx
select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablenci
GO
grant exec on dbo.sp_MSscriptmvastablenci to public
go
--------------------------------------------------------------------------------
--. sp_MSscriptmvastablepkc
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscriptmvastablepkc')
drop procedure sp_MSscriptmvastablepkc
go
print ''
print 'Creating procedure sp_MSscriptmvastablepkc'
go

create procedure sp_MSscriptmvastablepkc @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default

select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0

select @cmd = N'alter table ' + @dest_owner + QUOTENAME(@dest_tabname) collate database_default + N' add constraint ' + QUOTENAME(@constraint_name) collate database_default + N' primary key clustered ('
insert into #proctext(procedure_text) values( @cmd )

select @spacer = N' '
select @cmd = N''

select @indkey = 1
while (@indkey <= 16)
begin	
	select @colname = index_col(@srcobj, @indid, @indkey)
	if (@colname is null)
	begin
		select @indkey = 16
	end
	else
	begin
		select @cmd = @cmd + @spacer + QUOTENAME(@colname) collate database_default
		select @spacer = N','

		if len( @cmd ) > 3000
		begin
			insert into #proctext(procedure_text) values( @cmd )
			select @cmd = N''
		end
	end
	select @indkey = @indkey + 1
end

insert into #proctext(procedure_text) values( @cmd )

insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablepkc
GO
grant exec on dbo.sp_MSscriptmvastablepkc to public
go
--------------------------------------------------------------------------------
--. sp_MSscriptmvastableidx
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscriptmvastableidx')
drop procedure sp_MSscriptmvastableidx
go
print ''
print 'Creating procedure sp_MSscriptmvastableidx'
go

create procedure sp_MSscriptmvastableidx @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default

select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0

select @cmd = N'create unique clustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'('
insert into #proctext(procedure_text) values( @cmd )

select @spacer = N' '
select @cmd = N''

select @indkey = 1
while (@indkey <= 16)
begin	
	select @colname = index_col(@srcobj, @indid, @indkey)
	if (@colname is null)
	begin
		select @indkey = 16
	end
	else
	begin
		select @cmd = @cmd + @spacer + QUOTENAME(@colname)
		select @spacer = N','

		if len( @cmd ) > 3000
		begin
			insert into #proctext(procedure_text) values( @cmd )
			select @cmd = N''
		end
	end
	select @indkey = @indkey + 1
end

insert into #proctext(procedure_text) values( @cmd )

insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastableidx
GO
grant exec on dbo.sp_MSscriptmvastableidx to public
go
--------------------------------------------------------------------------------
--. sp_MSscriptmvastable
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscriptmvastable')
drop procedure sp_MSscriptmvastable
go
print ''
print 'Creating procedure sp_MSscriptmvastable'
go

create procedure sp_MSscriptmvastable @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @artcolumns   binary(32)
declare @schema_option binary(8)
declare @art_col	  int
declare @this_col	  int
declare @isset	      int
declare @use_base_type tinyint

declare @spacer		  nvarchar(1)
declare @nullability  nvarchar(10)
declare @typestring   nvarchar(255)
declare @col_name	  sysname

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, 
	   @use_base_type = substring(schema_option,8,1) & 32
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- script out CREATE TABLE statement

-- begin create table
select @cmd = N'create table ' + @dest_owner + QUOTENAME(@dest_tabname) + N'('
insert into #proctext(procedure_text) values( @cmd )

-- columns
select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   select @col_name = name, 
          @nullability = case isnullable 
		  when 0 then N'NOT NULL' 
		  else N'NULL' end
		  from syscolumns where id=@src_objid and @this_col=colid 
   if @isset != 0 and @col_name is not null
   begin
		if @use_base_type <> 0
		begin
			exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
		end
		else
		begin
			exec dbo.sp_MSgettypestringudt @src_objid, @this_col, @typestring OUTPUT
		end
        select @cmd = @spacer + QUOTENAME(@col_name) + N' ' + @typestring + N' ' + @nullability 
        insert into #proctext(procedure_text) values( @cmd )
		select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- end create table
insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc
go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastable
GO
grant exec on dbo.sp_MSscriptmvastable to public
go
--------------------------------------------------------------------------------
--. sp_verify_publication
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_verify_publication')
revoke execute on sp_verify_publication to public
go
--------------------------------------------------------------------------------
--. sp_MSscript_insert_subwins
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_insert_subwins')
drop procedure sp_MSscript_insert_subwins
go
raiserror('Creating procedure sp_MSscript_insert_subwins', 0,1)
go
create procedure sp_MSscript_insert_subwins (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@identity_insert bit)
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@qualname nvarchar(512)
			,@column_string nvarchar(4000)
			,@var_string nvarchar(4000)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	select @cmd = N'
	if (@error in (0, 547, 2601, 2627) and @execution_mode = @QSubWins)
	begin
		' + N'--
		' + N'-- Subscriber Wins resolution
		' + N'--
		if (@rowcount = 1 and @error = 0)
		begin'

	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			' + N'--
			' + N'-- No conflict for this command
			' + N'-- do nothing
			' + N'-- will remove this code block later 
			' + N'-- for optimization
			' + N'--
			select @retcode = 0
		end'

	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'		
		else if (@rowcount = 0 and @error in (547, 2601, 2627))
		begin
			' + N'--
			' + N'-- Conflict for this command
			' + N'-- Row already exists
			' + N'-- delete and insert row with Queue values
			' + N'-- '
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script delete
	--
	select @cmd = N'
			delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0

	--
	-- script the insert assignment
	--
	select @num_col = 0
	create table #worktab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	create table #worktab2 ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col
	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
            if rtrim(@ccoltype) not like N'timestamp' 
            begin
				select @num_col = @num_col + 1
				select @column_string = QUOTENAME(@colname)
				select @var_string = N'@c' + cast(@this_col as nvarchar(4))
				
				if (@num_col > 1)
				begin
					select @column_string = N', ' + @column_string
					select @var_string = N', ' +@var_string 
				end

				insert into #worktab(procedure_text) values( @column_string )				
				insert into #worktab2(procedure_text) values( @var_string )				
				
            end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	if (@num_col > 0)
	begin
		if (@identity_insert = 1)
		begin
			-- Only to call set if identity is not marked for 'not for repl'
			-- This is to avoid security failure of 'SET' for PAL users
			if not exists (select * from syscolumns where id = @objid and
				ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
			begin
				select @cmd = N'
			set identity_insert ' + @qualname + N' on '
				insert into #proctext(procedure_text) values( @cmd )
			end
		end

		select @cmd = N'
			insert into ' + @qualname + N'( '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from #worktab order by c1 asc
		select @cmd = N' )
			values ( '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from #worktab2 order by c1 asc
		select @cmd = N' )'
		insert into #proctext(procedure_text) values( @cmd )

		if (@identity_insert = 1)
		begin
			-- Only to call set if identity is not marked for 'not for repl'
			-- This is to avoid security failure of 'SET' for PAL users
			if not exists (select * from syscolumns where id = @objid and
				ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
			begin
				select @cmd = N'
			set identity_insert ' + @qualname + N' off '
				insert into #proctext(procedure_text) values( @cmd )
			end
		end
	end
	
	select @cmd = N'
			if (@@error != 0 or @retcode != 0)
				return -1
		end
		else
			return -1
	end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	drop table #worktab
	drop table #worktab2
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_insert_subwins
go

--------------------------------------------------------------------------------
--. sp_MSscript_insert_pubwins
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_insert_pubwins')
drop procedure sp_MSscript_insert_pubwins
go
raiserror('Creating procedure sp_MSscript_insert_pubwins', 0,1)
go
create procedure sp_MSscript_insert_pubwins (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32) )
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(512)
			,@cast_str nvarchar(1000)
			,@decl_str nvarchar(2000)
			,@assign_str nvarchar(4000)
			,@typestring nvarchar(100)
			,@exec_str nvarchar(1000)

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
				
	--
	-- start script generation
	--
	select @cmd = N'
	else if (@error in (0, 547, 2601, 2627) and @execution_mode = @QPubWins)
	begin
		' + N'--
		' + N'-- Publisher Wins resolution
		' + N'-- Find where we have to generate compensating action
		' + N'--
		if (@rowcount = 1 and @error = 0)
		begin'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			' + N'--
			' + N'-- No conflict for this command
			' + N'-- Row does not exist
			' + N'-- Generate delete compensating action
			' + N'--
			select @cftcase = 23'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- Continue with scripting
	--
	select @cmd = N'
		end
		else if (@rowcount = 0 and @error in (547, 2601, 2627))
		begin
			' + N'--
			' + N'-- conflict for this command
			' + N'-- Row already exists
			' + N'-- generate update compensating action
			' + N'-- DELETE compensating command + INSERT compensating command
			' + N'--			
			select @cftcase = 21'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue with scripting
	--			
	select @cmd = N'		
		end
		else
			return -1

		' + N'--
		' + N'-- generate compensating command according to the cases
		' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
		if (@cftcase in (21,23))
		begin
			' + N'--
			' + N'-- delete compensating command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- Generate the delete compensating code
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1

	select @cmd = N'
		end

		if (@cftcase = 21)
		begin
			' + N'--
			' + N'-- insert compensating command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- generate the compensating insert command
	--
	exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 0

	--
	-- continue with scripting
	--			
	select @cmd = N'		
		end
	end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	return 0	
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_insert_pubwins
go

--------------------------------------------------------------------------------
--. sp_MSscript_update_subwins
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_update_subwins')
drop procedure sp_MSscript_update_subwins
go
raiserror('Creating procedure sp_MSscript_update_subwins', 0,1)
go
create procedure sp_MSscript_update_subwins (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@identity_insert bit)
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@column_string nvarchar(4000)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@art_col	  int
			,@bitstr nvarchar(20)
			,@bytestr nvarchar(20)
			,@isset int
			,@timestamp_subscribed bit

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid from sysarticles 
		where name = @article and pubid = @pubid
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- special flag for timestamp column subscription
	--
	if exists (select * from sysarticles where pubid = @pubid and
		name = @article and
		status & 32 <> 0)
		select @timestamp_subscribed = 1
	else
		select @timestamp_subscribed = 0

	--
	-- start scripting
	--
	select @cmd = N'
	if (@error in (0, 547, 2601, 2627) and @execution_mode = @QSubWins)
	begin
		' + N'--
		' + N'-- Subscriber Wins resolution
		' + N'--
		select @retcode = 0
		if (@rowcount = 0)
		begin
			--
			-- Conflict for this command
			-- Check if PK update was being done
			--'
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- script the PK update check
	--
	select @cmd = N'
			exec @retcode = dbo.sp_MSispkupdateinconflict ' + 
		cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			if (@retcode = -1)
				return -1
			if (@retcode = 0)
			begin
				' + N'--
				' + N'-- PK update is not being done
				' + N'-- '
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script the if exists code using OLD_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N' )')
	
	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row with OLD_PK exists
					' + N'-- update row with OLD_PK with queue values
					' + N'-- 
					select @cftcase = 11
				end'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
				else
				begin
					' + N'--
					' + N'-- row with OLD_PK does not exists
					' + N'-- insert row with queue values using OLD_PK
					' + N'-- 
					select @cftcase = 13
				end
			end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
			else
			begin
				' + N'--
				' + N'-- PK update is being done
				' + N'-- drop rows with OLD_PK, NEW_PK and insert row with queue values
				' + N'--
				select @cftcase = 0'
	insert into #proctext(procedure_text) values( @cmd )
				
	--
	-- script the if exists code using OLD_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N' )')
	
	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row with OLD_PK exists
					' + N'-- insert row with queue values using NEW_PK +
					' + N'-- delete row with OLD_PK
					' + N'-- 
					select @cftcase = 14
				end' 
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- script the if exists code using NEW_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0
	insert into #proctext(procedure_text) values( N' )')

	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row with NEW_PK exists
					' + N'-- case 15: rows with NEW_PK and OLD_PK exist
					' + N'-- update row with NEW_PK with queue values + 
					' + N'-- delete row with OLD_PK'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
					' + N'-- case 16: row with NEW_PK exists
					' + N'-- update row with NEW_PK with queue values
					' + N'--
					select @cftcase = case when (@cftcase = 14) then 15 else 16 end
				end'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
				if (@cftcase = 0)
				begin
					' + N'--
					' + N'-- no existing rows with OLD_PK or NEW_PK
					' + N'-- insert with queue values
					' + N'--
					select @cftcase = 12
				end
			end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
			' + N'--
			' + N'-- based on retcode do the resolution
			' + N'-- 
			if (@cftcase in (12, 13, 14))
			begin
				' + N'--
				' + N'-- insert
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- prepare the insert statement
	--
	if (@identity_insert = 1)
	begin
		-- Only to call set if identity is not marked for 'not for repl'
		-- This is to avoid security failure of 'SET' for PAL users
		if not exists (select * from syscolumns where id = @objid and
			ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
		begin
			select @cmd = N'
				set identity_insert ' + @qualname + N' on '
			insert into #proctext(procedure_text) values( @cmd )
		end
	end

	select @cmd = N'
				insert into ' + @qualname + N'('
	insert into #proctext(procedure_text) values( @cmd )

	select @num_col = 0
			,@art_col = 0
			,@cmd = NULL
	create table #collisttab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	create table #worktab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from dbo.syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col
	WHILE (@@fetch_status != -1)
	begin
		-- Get the ordinal of the article partition or not.
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
		if @isset = 0
		begin
			if ((@timestamp_subscribed = 1) and 
					exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
				select @art_col = @art_col + 1
		end
		else
			select @art_col = @art_col + 1

		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0 and EXISTS (select name from dbo.syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) != N'timestamp' 
			begin
				select @num_col = @num_col + 1
						,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar)
						,@bitstr =  cast( power(2, (@art_col-1) % 8 ) as nvarchar)

				select @column_string = N'case substring(@bitmap,' + 
					@bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + 
					N' then @c' + cast(@this_col as nvarchar(4)) + 
					N' else @c' + cast(@this_col as nvarchar(4)) + N'_old end '

				if (@num_col = 1)
				begin
					select @cmd = quotename(@colname)
					select @column_string = N'
					' + @column_string
				end
				else
				begin
					select @cmd = @cmd + N',' + quotename(@colname)
					select @column_string = N'
					, ' + @column_string
				end

				-- transfer the column list string to table if large
				if (len(@cmd) > 3000)
				begin
					insert into #collisttab(procedure_text) values( @cmd )
					select @cmd = N' '
				end
				insert into #worktab(procedure_text) values( @column_string )
				
            end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	-- transfer the remaining column list string to table
	insert into #collisttab(procedure_text) values( @cmd )
	
	insert into #proctext(procedure_text) 
		select procedure_text from #collisttab order by c1 asc
	select @cmd = N')
				select '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) 
		select procedure_text from #worktab order by c1 asc

	if (@identity_insert = 1)
	begin
		-- Only to call set if identity is not marked for 'not for repl'
		-- This is to avoid security failure of 'SET' for PAL users
		if not exists (select * from syscolumns where id = @objid and
			ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
		begin
			select @cmd = N'
				set identity_insert ' + @qualname + N' off '
			insert into #proctext(procedure_text) values( @cmd )
		end
	end

	--
	-- continue with scripting
	--
	select @cmd = N'
			end

			if (@cftcase = 11)
			begin
				' + N'--
				' + N'-- update using OLD_PK
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- prepare the column list for update statement
	--
	select @num_col = 0
			,@art_col = 0
	create table #worktab2 ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col
	WHILE (@@fetch_status <> -1)
	begin
		-- Get the ordinal of the article partition or not.
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
		if @isset = 0
		begin
			if ((@timestamp_subscribed = 1) and 
					exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
				select @art_col = @art_col + 1
		end
		else
			select @art_col = @art_col + 1

		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if (rtrim(@ccoltype) != N'timestamp') and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
			begin
				select @num_col = @num_col + 1
						,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar)
						,@bitstr =  cast( power(2, (@art_col-1) % 8 ) as nvarchar)

				select @column_string = quotename(@colname) + N' = case substring(@bitmap,' + 
					@bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + 
					N' then @c' + cast(@this_col as nvarchar(4)) + 
					N' else @c' + cast(@this_col as nvarchar(4)) + N'_old  end '

				if (@num_col = 1)
				begin
					select @column_string = N'
					' + @column_string
				end
				else
				begin
					select @column_string = N'
					, ' + @column_string
				end

				insert into #worktab2(procedure_text) values( @column_string )
				
			end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	--
	-- script the update with OLD_PK statement
	--
	select @cmd = N'
				update ' + @qualname + N' set '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) 
		select procedure_text from #worktab2 order by c1 asc
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	
	--
	-- continue with scripting
	--
	select @cmd = N'
			end

			if (@cftcase in (15, 16))
			begin
				' + N'--
				' + N'-- update using NEW_PK
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
				
	--
	-- script the update with NEW_PK statement
	--
	select @cmd = N'
				update ' + @qualname + N' set '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) 
		select procedure_text from #worktab2 order by c1 asc
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0
	
	--
	-- continue with scripting
	--
	select @cmd = N'
			end

			if (@cftcase in (14, 15))
			begin
				' + N'--
				' + N'-- Do not delete if subscriber has already
				' + N'-- updated this row as part of this transaction
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script the if exists code using OLD_PK and msprepl_tran_version
	--
	select @cmd = N'
				if not exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'subwins_check', 'msrepl_tran_version', 0
	insert into #proctext(procedure_text) values( N' )')

	select @cmd = N'
				begin
					' + N'-- 
					' + N'-- delete row with OLD_PK
					' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script delete with OLD_PK
	--
	select @cmd = N'
					delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0

	--
	-- continue with rest of scripting
	--
	select @cmd = N'
				end
			end
	
			if (@@error != 0)
				return -1

			select @retcode = 0
		end
	end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	drop table #collisttab
	drop table #worktab
	drop table #worktab2
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_update_subwins
go

--------------------------------------------------------------------------------
--. sp_MSscript_update_pubwins
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_update_pubwins')
drop procedure sp_MSscript_update_pubwins
go
raiserror('Creating procedure sp_MSscript_update_pubwins', 0,1)
go
create procedure sp_MSscript_update_pubwins (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32) )
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(512)
			,@cast_str nvarchar(1000)
			,@decl_str nvarchar(2000)
			,@assign_str nvarchar(4000)
			,@typestring nvarchar(100)
			,@exec_str nvarchar(1000)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- start scripting
	--
	select @cmd = N'
	else if (@error in (0, 547, 2601, 2627) and @execution_mode = @QPubWins)
	begin '
	insert into #proctext(procedure_text) values( @cmd )
	--
	--  special declare for case when we have non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	if (@fhasnonpkuniquekeys = 1)
	begin
 		declare @spacer nvarchar(5)
			,@art_col int
			,@isset int
			,@pkcolumns varbinary(32)

		select @cmd = N'
		declare '
			,@spacer = N''
			,@art_col = 1
		exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
		declare #hccolid cursor local fast_forward for 
			select colid from syscolumns where id = @objid order by colid asc
		open #hccolid
		fetch #hccolid into @this_col
		while (@@fetch_status != -1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset != 0 and exists ( select name from syscolumns where id=@objid and colid=@this_col and iscomputed !=1 ) 
			begin
				exec dbo.sp_gettypestring @objid, @this_col, @typestring output
				select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
				select @art_col = @art_col + 1
						,@spacer = N','

				if len( @cmd ) > 3000
				begin
					insert into #proctext(procedure_text) values( @cmd )
					select @cmd = N''
				end
			end
			fetch #hccolid into @this_col
		end
		close #hccolid
		deallocate #hccolid
		if len(@cmd) > 0
			insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		if (@rowcount = 1)
		begin
			' + N'--
			' + N'-- no conflict for this command
			' + N'-- Check if PK update was being done
			' + N'-- '
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script the PK update check
	--
	select @cmd = N'
			exec @retcode = dbo.sp_MSispkupdateinconflict ' + 
		cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
			if (@retcode = -1)
				return -1
			if (@retcode = 0)
			begin
				' + N'--
				' + N'-- PK update is not being done
				' + N'-- generate delete + insert compensating action with OLD_PK
				' + N'-- 
				select @cftcase = 0
			end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
			else
			begin
				' + N'--
				' + N'-- PK update is being done
				' + N'-- generate delete + insert compensating action with OLD_PK
				' + N'-- generate delete compensating action with NEW_PK
				' + N'-- 
				select @cftcase = 1
			end
		end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
		else
		begin
			' + N'--
			' + N'-- Conflict for this command
			' + N'-- Check if PK update was being done
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script the PK update check
	--
	select @cmd = N'
			exec @retcode = dbo.sp_MSispkupdateinconflict ' + 
		cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			if (@retcode = -1)
				return -1
			if (@retcode = 0)
			begin
				' + N'--
				' + N'-- PK update is not being done
				' + N'-- Now find the type of conflict
				' + N'-- '
	insert into #proctext(procedure_text) values( @cmd )
				
	--
	-- script the if exists code using OLD_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N' )')

	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row exists
					' + N'-- generate delete + insert compensating action with OLD_PK
					' + N'--
					select @cftcase = 11'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- special scripting for table with unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
					if (@error in (2601, 2627))
					begin
						' + N'--
						' + N'-- Unique key violation
						' + N'-- case 15 : row with OLD_PK exist and row with NEW_UNK exists 
						' + N'-- generate delete compensating action with OLD_PK'
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
						' + N'-- insert compensating action with OLD_PK 
						' + N'-- insert compensating action with rows that qualify the NEW_UNKEYS
						' + N'--
						select @cftcase = 15
					end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	select @cmd = N'
				end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
				else
				begin
					' + N'--
					' + N'-- row does not exist
					' + N'-- generate delete compensating action with OLD_PK
					' + N'--
					select @cftcase = 13'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- special scripting for table with unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
					if (@error in (2601, 2627))
					begin
						' + N'--
						' + N'-- Unique key violation
						' + N'-- case 16 : rows with OLD_PK does not exist and row with NEW_UNK exists 
						' + N'-- generate delete compensating action with OLD_PK'
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
						' + N'-- insert compensating action with rows that qualify the NEW_UNKEYS
						' + N'--
						select @cftcase = 16
					end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	select @cmd = N'
				end
			end'
	insert into #proctext(procedure_text) values( @cmd )
			
	--
	-- continue scripting
	--
	select @cmd = N'
			else
			begin
				' + N'--
				' + N'-- PK update is being done
				' + N'-- Now find the type of conflict
				' + N'-- 
				select @cftcase = 0'
	insert into #proctext(procedure_text) values( @cmd )
				
	--
	-- script the if exists code using OLD_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N' )')

	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row with OLD_PK exists
					' + N'-- generate delete compensating action with OLD_PK +
					' + N'-- insert compensating action with OLD_PK 
					' + N'--
					select @cftcase = 14
				end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script the if exists code using NEW_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0
	insert into #proctext(procedure_text) values( N' )')

	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- row with NEW_PK exists
					' + N'-- case 15: rows with NEW_PK and OLD_PK exist
					' + N'-- generate delete compensating actions with OLD_PK, NEW_PK +
					' + N'-- insert compensating actions with OLD_PK, NEW_PK' 
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
					' + N'-- case 16: row with NEW_PK exists and OLD_PK does not exist
					' + N'-- generate delete compensating action with OLD_PK, NEW_PK +
					' + N'-- insert compensating action with NEW_PK 
					' + N'--
					select @cftcase = case when (@cftcase = 14) then 15 else 16 end
				end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--	
	select @cmd = N'
				else
				begin
					' + N'--
					' + N'-- row with NEW_PK does not exists
					' + N'-- case 12 : no existing rows with OLD_PK or NEW_PK
					' + N'-- generate delete compensating action with OLD_PK, NEW_PK '
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
					' + N'-- case 17 : row with OLD_PK exist and NEW_PK does not exist 
					' + N'-- generate delete compensating action with OLD_PK, NEW_PK +
					' + N'-- insert compensating action with OLD_PK 
					' + N'-- 
					select @cftcase = case when (@cftcase = 0) then 12 else 17 end 
				end '
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
			end
		end' 		
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue scripting
	--
	select @cmd = N'
		if (@cftcase in (0, 1, 11, 12, 13, 14, 15, 16, 17))
		begin
			' + N'--
			' + N'-- generation of delete compensating command with OLD_PK
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- generate delete compensating cmd with OLD_PK
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'del'
	
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		
		if (@cftcase in (1, 12, 15, 16, 17))
		begin
			' + N'--
			' + N'-- generation of delete compensating command with NEW_PK
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- generate delete compensating cmd with NEW_PK
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
	
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		if (@cftcase in (0, 1, 11, 14, 15, 17))
		begin
			' + N'--
			' + N'-- generate and send insert compensating command with OLD_PK
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script compensating insert with OLD_PK
	--
	exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 1, 0
	
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		if (@cftcase in (15, 16))
		begin
			' + N'--
			' + N'-- generate and send insert compensating command with NEW_PK
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- script compensating insert with NEW_PK
	--
	exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 0, 0
	
	--
	-- continue with scripting
	--
	select @cmd = N'
		end
		select @retcode = 0
	end'
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- all done
	--
	return 0	
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_update_pubwins
go
--------------------------------------------------------------------------------
--. sp_MSscript_compensating_insert
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_compensating_insert')
drop procedure sp_MSscript_compensating_insert
go
raiserror('Creating procedure sp_MSscript_compensating_insert', 0,1)
go
create procedure sp_MSscript_compensating_insert (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@proctype	int = 1,		-- 0 = use new_pk, 1 = use old_pk
	@fdodeclare bit = 1		-- 0 = do not script declares for non PK unique key processing
)
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(540)
			,@cast_str nvarchar(4000)
			,@column_string nvarchar(4000)
			,@ins_cmd nvarchar(255)
			,@startoffset int
			,@setprefix bit
			,@commandlen int
			,@fragmentlen int
			,@collen int
			,@first_time bit
			,@fullcastlen int
			,@splitlen int
			,@pkcolumns varbinary(32)
			,@fhasnonpkuniquekeys int
	declare @pkfetch table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, 
		@dest_owner = dest_owner, @ins_cmd = ins_cmd from sysarticles 
	where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
			,@fhasnonpkuniquekeys = 0
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- Do we have non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	if (@fhasnonpkuniquekeys = 1)
	begin
		--
		-- We have to generate commands based on where it was confict with PK or with other
		-- unique keys - so we will declare a cursor and walk through all the rows on publisher
		-- that could have conflicts with the subscriber row. For each row (PK) we will now perform
		-- compensating delete of non PK unique keys and then an compensating insert
		--
 		declare @cmd2 nvarchar(4000)
			,@cmd3 nvarchar(4000)
			,@spacer nvarchar(5)
			,@typestring sysname
			,@art_col int
			,@isset int
		declare @pkvars table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
		declare @pkcols table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

		--
		-- build some strings for PK columns and PK variables (@pkc1..)
		--
		exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
		select @cmd = N''
			,@cmd2 = N''
			,@cmd3 = N''
			,@spacer = N''
			,@art_col = 1
		declare #hccolid cursor local fast_forward for 
			select colid, name from syscolumns where id = @objid order by colid asc
		open #hccolid
		fetch #hccolid into @this_col, @colname
		while (@@fetch_status != -1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset != 0 and (@colname is not null)
			begin
				exec dbo.sp_gettypestring @objid, @this_col, @typestring output
				select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
						,@cmd2 = @cmd2 + @spacer + quotename(@colname)
						,@cmd3 = @cmd3 + @spacer + N'@pkc' + convert( nvarchar, @art_col )

				select @art_col = @art_col + 1
						,@spacer = N','

				if len( @cmd ) > 3000
				begin
					insert into @pkvars(procedure_text) values( @cmd )
					select @cmd = N''
				end
				if len( @cmd2 ) > 3000
				begin
					insert into @pkcols(procedure_text) values( @cmd2 )
					select @cmd2 = N''
				end
				if len( @cmd3 ) > 3000
				begin
					insert into @pkfetch(procedure_text) values( @cmd3 )
					select @cmd3 = N''
				end
			end
			fetch #hccolid into @this_col, @colname
		end
		close #hccolid
		deallocate #hccolid
		if len(@cmd) > 0
			insert into @pkvars(procedure_text) values( @cmd )
		if len(@cmd2) > 0
			insert into @pkcols(procedure_text) values( @cmd2 )
		if len(@cmd3) > 0
			insert into @pkfetch(procedure_text) values( @cmd3 )
		--
		-- script the PK variable declare now
		--
		if (@fdodeclare = 1)
		begin
			select @cmd = N'
			declare '
			insert into #proctext(procedure_text) values( @cmd )
			insert into #proctext(procedure_text) 
				select procedure_text from @pkvars order by c1 asc
		end
		--
		-- script the cursor declare now
		--
		select @cmd = N'
			declare #hccompins cursor local fast_forward for 
				select distinct '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkcols order by c1 asc
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		if (@proctype = 1)
		begin
			exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
						,@columns = @columns
						,@prefix = N'@c' 
						,@suffix = N'_old'
						,@mode = 5
		end
		else
		begin
			exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
						,@columns = @columns
						,@prefix = N'@c' 
						,@mode = 5
		end
		--
		-- script the cursor open and fetch
		--
		select @cmd = N'
			open #hccompins
			fetch #hccompins into '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkfetch order by c1 asc
		select @cmd = N'
			while (@@fetch_status != -1)
			begin '
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- The table has unique keys other than PK We will issue a compensating
		-- DELETE command to clear any rows that already have values for the 
		-- unique key columns - the subsequent compensating INSERT has to succeed.
		-- We will restore the current view of the publisher on to the subscriber
		-- if Subscriber had a rows that were different from publisher - then they will
		-- be resolved during the Queue reader run. So we are covered
		--
		select @cmd = N'
			' + '--
			' + '-- Issue a delete command for unique keys
			' + '-- '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
			+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec dbo.sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@mode = 4
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_scriptpkwhereclause @src_objid = @objid
					,@pkcolumns = @pkcolumns
					,@prefix = N'@pkc'
					,@artcolumns = @columns
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		select @cmd = N'
			' + '--
			' + '-- Issue the compensating insert for this PK row
			' + '-- '
		insert into #proctext(procedure_text) values( @cmd )
	end
	
	--
	-- The compensating command will be split into one or more
	-- fragment commands if the length exceeds 3450 characters in length 
	-- (to accomodate compensating server/db names)
	-- For correctly estimating the length of the compensating command
	-- we have to take the max column length of the data into consideration along
	-- with the scripting command length
	--

	--
	-- use the insert command if available
	--
	select @commandlen = 0
			,@setprefix = 1

	if (@ins_cmd = N'SQL')
	begin
		select @cmd = N'
			select @cmd = ''INSERT INTO ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
						+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N''' + 
						'' SELECT '' + '
	end
	else
	begin
		select @cmd = N'
			select @cmd = ''EXEC ' + substring(@ins_cmd, 5, len(@ins_cmd) - 4) + N' '' + '
	end
	insert into #proctext(procedure_text) values( @cmd )
 	select @commandlen = @commandlen + len(@cmd)
	
	select @num_col = 0
	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid, length from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col, @collen
	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) not like N'timestamp' 
			begin
				select @num_col = @num_col + 1

				--
				-- Compute the command fragment length needed for this column
				-- based on the coltype
				--				
				if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('ntext','text','image'))
				begin
					--
					-- For compensating commands we have to include the text and image data
					-- as the custom procs used by Distribution process expects them - as it
					-- done for regular transactional replication - but we will only send NULLs
					-- as it is not possible to ascertain the size of the data during the generation
					--		
					select @cast_str = N' ''null'' '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
				begin
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
						select @collen = (@collen / 2)
	
					select @cast_str = case 
							when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
								then N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
								else N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
							end
	   
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
				begin
					--
					-- each byte has 2 nibbles - we need a char to represent each nibble
					--
					select @collen = @collen * 2
					select @cast_str = N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' + quotename(@colname) + N',1,0) collate database_default, ''null'') '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen + 2
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CONVERT(nvarchar(40),' + quotename(@colname) + N',2), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CAST(' + quotename(@colname) + N' as nvarchar(40)) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 112) + N'' '' +  CONVERT(nvarchar(40), ' + quotename(@colname) + N', 114) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
				begin
					--
					-- need to revisit this later
					--
					select @cast_str = N' ISNULL(master.dbo.fn_sqlvarbasetostr(' + quotename(@colname) + N' ) collate database_default, ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end					
				else
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
			
				--
				-- for fixed datatypes - we will not split the data at all we will
				-- flush the command script and continue
				-- for varying/large datatypes, we will have to split data if necessary
				--
				if ((lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar','binary','varbinary')) 
						and (@fragmentlen + @commandlen > 3450))
				begin
			 		--
			 		-- the column length is too big, we have to break the data string
			 		-- initialize
			 		--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' 
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' 
					end

					--
					-- use substring to break the string value in the
					-- compensating command
					--
					select @first_time = 1
							,@startoffset = 1
					while (@collen > 0)
					begin
				 		select @splitlen = case when ((@first_time = 1) or (@collen > 3450))
				 								then (3450 - @commandlen - 30 - @fullcastlen)
				 								else @collen end
				 		if (@splitlen < 1)
				 		begin
				 			--
				 			-- we have overcompensated the splitlen
				 			-- set to half of the column length
				 			--
				 			select @splitlen = @collen / 2
				 		end

						--
						-- Do we need to put quotes (many datatypes need it)
						--
					 	if (@first_time = 1)
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
								select @column_string = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
										then @column_string + N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr( '
										else @column_string + N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr( '
									end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' 
						end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
						 		select @column_string = N' + ISNULL(master.dbo.fn_MSgensqescstr( '
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' + ISNULL(master.dbo.fn_varbintohexsubstring(0,' 
					 	end

						--
						-- prepare the substring script
						--
						if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							select @cast_str = N'SUBSTRING(' + quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast(@splitlen as nvarchar) + N')'
						else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
							select @cast_str = quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast((@splitlen/2) as nvarchar)

						if (@first_time = 1)
					 	begin
							select @cast_str = @cast_str + N') collate database_default, ''null'') '
									,@first_time = 0
					 	end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							begin
								--
								-- for strings the last fragment needs the single
								-- quote to be added for the string
								--
								select @cast_str = @cast_str + N') collate database_default '
								select @cast_str = case 
									when (@collen - @splitlen < 1)
										then @cast_str + N'+ '''''''', '''') '											
										else @cast_str + N', '''') ' 
									end
							end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @cast_str = @cast_str + N') collate database_default, '''') '
						end
						 		
						select @column_string = @column_string + @cast_str
						insert into #proctext(procedure_text) values( @column_string )

						if (@fragmentlen + @commandlen > 3450)
						begin
							select @cmd = N'
			from ' + @qualname 
							insert into #proctext(procedure_text) values( @cmd )
							--
							-- script the where clause
							--
							if (@fhasnonpkuniquekeys = 1)
							begin
								--
								-- Non PK unique keys
								-- we are in the cursor for qualifying row
								-- 
								exec dbo.sp_scriptpkwhereclause @src_objid = @objid
											,@pkcolumns = @pkcolumns
											,@prefix = N'@pkc'
											,@artcolumns = @columns
							end
							else
							begin
								--
								-- only PK unique key
								--
								if (@proctype = 1)
									exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
								else
									exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
							end
							--
							-- Script the compensating send
							--
							exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
							if (@setprefix = 1)
								select @setprefix = 0

							select @cmd = N'
			select @cmd = N''''' 
							insert into #proctext(procedure_text) values( @cmd )
							select @commandlen = 0
						end
						else
							select @commandlen = @commandlen + len(@column_string)

						--
						-- update vars for next round
						--
						select @collen = @collen - @splitlen
								,@column_string = N''
								,@startoffset = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) 
										then (@splitlen/2) + @startoffset 
										else @splitlen + @startoffset 
									end
						select @fragmentlen = @fullcastlen + 4 + @collen
					end							

					--
					-- we done with this column now
					-- skip processing further and continue
					--						
					select @commandlen = @commandlen + len(@column_string)
			 	end
			 	else
			 	begin
					--
					-- Handling general fixed type column cases
					--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' + @cast_str
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' + @cast_str
					end

					--
					-- check if we need to flush the command first
					--
					if (@fragmentlen + len(@column_string) + @commandlen > 3450)
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )
						--
						-- script the where clause
						--
						if (@fhasnonpkuniquekeys = 1)
						begin
							--
							-- Non PK unique keys
							-- we are in the cursor for qualifying row
							-- 
							exec dbo.sp_scriptpkwhereclause @src_objid = @objid
										,@pkcolumns = @pkcolumns
										,@prefix = N'@pkc'
										,@artcolumns = @columns
						end
						else
						begin
							--
							-- only PK unique key
							--
							if (@proctype = 1)
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
							else
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
						end
						--
						-- Script the compensating send
						--
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end

					--
					-- script out the column string
					--
					insert into #proctext(procedure_text) values( @column_string )

					--
					-- if we are processing sql_variants, flush the command again
					--
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )
						--
						-- script the where clause
						--
						if (@fhasnonpkuniquekeys = 1)
						begin
							--
							-- Non PK unique keys
							-- we are in the cursor for qualifying row
							-- 
							exec dbo.sp_scriptpkwhereclause @src_objid = @objid
										,@pkcolumns = @pkcolumns
										,@prefix = N'@pkc'
										,@artcolumns = @columns
						end
						else
						begin
							--
							-- only PK unique key
							--
							if (@proctype = 1)
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
							else
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
						end
						--
						-- Script the compensating send
						--
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end
					else
						select @commandlen = @commandlen + @fragmentlen + len(@column_string)
				end
			end
		end

		--
		-- process the next column
		--
		FETCH hCColid INTO @this_col, @collen
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	--
	-- Check if we need to flush the command one more time (final)
	--
	if (@commandlen > 0)
	begin
		--
		-- send the last fragment of the command
		--
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script the where clause
		--
		if (@fhasnonpkuniquekeys = 1)
		begin
			--
			-- Non PK unique keys
			-- we are in the cursor for qualifying row
			-- 
			exec dbo.sp_scriptpkwhereclause @src_objid = @objid
						,@pkcolumns = @pkcolumns
						,@prefix = N'@pkc'
						,@artcolumns = @columns
		end
		else
		begin
			--
			-- only PK unique key
			--
			if (@proctype = 1)
				exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
			else
				exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
		end
		--
		-- Script the compensating send
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, @setprefix
	end

	--
	-- More scripting for non PK unique key case
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		--
		-- script the cursor fetch
		--
		select @cmd = N'
			fetch #hccompins into '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkfetch order by c1 asc
		--
		-- script the cursor close and deallocate
		--
		select @cmd = N'
			end
			close #hccompins
			deallocate #hccompins '
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_compensating_insert
go

--------------------------------------------------------------------------------
--. sp_MSscript_endproc
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSscript_endproc')
drop procedure sp_MSscript_endproc
go
raiserror('Creating procedure sp_MSscript_endproc', 0,1)
go
create procedure sp_MSscript_endproc (
	@objid int, 
	@op_type varchar(3) = 'ins', -- 'ins', 'upd', 'del'
	@columns binary(32),
	@outvars nvarchar(4000),
	@queued_pub bit = 0
)
as
BEGIN
	declare @cmd nvarchar(4000)
	declare @qualname nvarchar(512)

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- decide the return code
	' + N'--
	if (@execution_mode = @immediate)
	begin
		if @error != 0
      		return -1
		-- Return special code to indicate the subscriber row needs to be
		-- refreshed.
		if @rowcount = 0
      		return 5
	end'
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- operation specific stuff
	--
	if (@queued_pub = 1)
	begin
		if (@op_type = 'ins')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (547, 2601, 2627))
				return 2 -- insert conflict
			else
				return -1 -- error
		end
	end'
		end
		else if (@op_type = 'upd')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (0, 547, 2601, 2627))
				return 1 -- update conflict
			else
				return -1 -- error
		end
	end'
		end
		else if (@op_type = 'del')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (0, 547))
				return 3 -- delete conflict
			else
				return -1 -- error
		end
	end'
		end
		insert into #proctext(procedure_text) values(@cmd)
		
		--
		-- continue with scripting
		--
		select @cmd = N'
	
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin		
		if (@@error != 0 or @retcode != 0)
			return -1 -- error
	end
    '
		insert into #proctext(procedure_text) values(@cmd)
	end

	--
	-- if we have output vars to assign do it now
	--
	if (@outvars is not null)
	begin   
		if @op_type = 'upd'
		begin
			--
			-- Script out pk var assigment that used in sp_MSscript_where_clause
			--
			exec dbo.sp_MSscript_pkvar_assignment @objid, @columns, 1
			insert into #proctext(procedure_text) values(N'
	')
		end

		select @cmd = N'
	select ' + @outvars + N'
	from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd)
		insert into #proctext(procedure_text) values( N'
	')
	
		if (@op_type = 'ins')
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'new pk', null, 4
		else if (@op_type = 'upd')
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'old pk', null, 4
	end

	--
	-- Final part of the proc
	--
    select @cmd = N'
    
	' + N'--
	' + N'-- past all checks
	' + N'--
	return 0
END
'
	insert into #proctext(procedure_text) values(@cmd)
	
	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_endproc
go
--------------------------------------------------------------------------------
--. sp_repltablehasnonpkuniquekey
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_repltablehasnonpkuniquekey')
drop procedure sp_repltablehasnonpkuniquekey
go
raiserror('Creating procedure sp_repltablehasnonpkuniquekey',0,-1)
go
create procedure sp_repltablehasnonpkuniquekey 
(
    @tabid int              -- id of the table
)
as
begin
    set nocount on
    declare @retcode int
    --
    -- security check - should be dbo or sysadmin
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR != 0 or @retcode != 0
        return (1)
    --
    -- process if the object is a table and has index
    --
    if (ObjectProperty(@tabid, 'IsTable') = 1) and (ObjectProperty(@tabid, 'TableHasIndex') = 1)
    begin
        --
        -- Set return flag if it is Unique key but not PK
        --
        if exists (select indid from sysindexes 
                where id = @tabid 
                    and indid > 0 and indid < 255
                    and (status & 2) != 0 and (status & 2048) = 0 )
        begin
            select @retcode = 1
        end
    end
    --
    -- all done
    --
    return @retcode
end
go
exec sp_MS_marksystemobject sp_repltablehasnonpkuniquekey
go

--------------------------------------------------------------------------------
--. sp_replscriptuniquekeywhereclause
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_replscriptuniquekeywhereclause')
drop procedure sp_replscriptuniquekeywhereclause
go
raiserror('Creating procedure sp_replscriptuniquekeywhereclause', 0,1)
go
create procedure sp_replscriptuniquekeywhereclause 
(
    @tabid int                                  -- id of the table
    ,@columns binary(32)                 -- column map for the article
    ,@prefix nvarchar(10) = '@c'       -- prefix for the scripted column variables
    ,@suffix nvarchar(10) = null	   -- suffix for the scripted column variables
    ,@mode tinyint                           -- 1 = insert custom proc, 2 = upd custom proc non PK, 3 = upd custom proc PK only 4 = compensating delete, 5 = compensating insert cursor declare
    ,@paramcount int = null              -- Total number of parameters - needed for mode = 2 and 3
 )
as
begin
    set nocount on
    declare @retcode int
                ,@indid int
                ,@indstatus int
                ,@indkey int
                ,@qualname nvarchar(512)
                ,@colname sysname
                ,@var sysname
                ,@artcol int
                ,@thiscol int
                ,@cmd nvarchar(4000)
                ,@findexstarted bit
                ,@fisfirstindex bit
    --
    -- constants
    --
                ,@modeinscustproc tinyint
                ,@modeupdcustprocnonpk tinyint
                ,@modeupdcustprocpkonly tinyint
                ,@modedelcompensating tinyint
                ,@modeinscompensatingcursordeclare tinyint

    --
    -- initialize
    --
    select @modeinscustproc = 1
            ,@modeupdcustprocnonpk = 2
            ,@modeupdcustprocpkonly = 3
            ,@modedelcompensating = 4
            ,@modeinscompensatingcursordeclare = 5
    --
    -- security check - should be dbo or sysadmin
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error != 0 or @retcode != 0
        return (1)
    --
    -- process if the object is a table and has index
    --
    if (ObjectProperty(@tabid, 'IsTable') != 1) or (ObjectProperty(@tabid, 'TableHasIndex') != 1)
        return (1)
    --
    -- Get the qualified name of the table
    --
    exec @retcode = sp_MSget_qualified_name @tabid, @qualname OUTPUT
    if @@error != 0 or @retcode != 0 or @qualname is null
        return (1)
    --
    -- @columns cannot be null
    --
    if (@columns is null)
        return (1)
    --
    -- Check @mode
    --
    if (@mode not in (@modeinscustproc, @modeupdcustprocnonpk, @modeupdcustprocpkonly, @modedelcompensating, @modeinscompensatingcursordeclare))
    begin
        return (1)
    end
    --
    -- validate @paramcount
    --
    if ((@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) and (@paramcount is null))
    begin
        return (1)
    end
    --
    -- enumerate all the unique indices
    -- The scripting will be done as follows :
    --      where (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ...
    -- If we are scripting for the cursor declare in insert compensating then it will be as follows:
    --      where (ui1k1 = @cx or ui1k2 = @cy ...) or (u2k1 = @cz or ...) ...
    --
    select @cmd = case when (@mode = @modedelcompensating) then N' '' where '
                            else N' where ' end
            ,@findexstarted = 0
            ,@fisfirstindex = 1
    declare #hcindid cursor local fast_forward for
        select indid, status from sysindexes 
                where id = @tabid and (status & 2) != 0
                    and indid > 0 and indid < 255
                    order by indid asc
    open #hcindid
    fetch #hcindid into @indid, @indstatus
    while (@@fetch_status != -1)
    begin
        --
        -- If we are in @modedelcompensating or @modeupdcustprocnonpk mode skip processing the PK index
        -- If we are in @modeupdcustprocpkonly mode skip processing the non PK index
        --
        if ((@mode in (@modeupdcustprocnonpk,@modedelcompensating)) and (@indstatus & 2048) != 0) 
            or ((@mode = @modeupdcustprocpkonly) and (@indstatus & 2048) = 0)
        begin
            --
            -- fetch next unique index
            --
            fetch #hcindid into @indid, @indstatus
            continue
        end
        --
        -- Enumerate the keys in this index
        --
        select @indkey = 1
        while (@indkey <= 16)
        begin
            --
            -- get the column name for the key
            --
            select @colname = index_col(@qualname, @indid, @indkey)
            if (@colname is null) 
                break
            --
            -- check if this column is enabled for replication
            --
            select @artcol = 0
            exec dbo.sp_MSget_col_position @tabid, @columns, @colname, NULL, @artcol output, 0, NULL, @thiscol output
            if (@artcol > 0)
            begin
                --
                -- check if we are scripting the first key for this index
                --
                if (@findexstarted = 1)
                begin
                    select @cmd = case when (@mode = @modedelcompensating) then @cmd + N' + '' and '
                                            when (@mode = @modeinscompensatingcursordeclare) then @cmd + N' or ' 
                                            else @cmd + N' and ' end
                end
                else
                begin
                    --
                    -- check if we are scripting the first index. 
                    --
                    if (@fisfirstindex = 0)
                    begin
                        select @cmd =  @cmd + N' or ' 
                    end
                    else
                    begin
                        select @fisfirstindex = 0
                    end
                    --
                    -- set @findexstarted while processing the first key
                    --
                    select @findexstarted = 1
                    select @cmd = @cmd + N' ( ' 
                end
                --
                -- script this column
                --
                if (@mode = @modedelcompensating)
                begin
                    --
                    -- scripting a compensating command - we are building a dynamic string
                    --
                    declare @ccoltype sysname

                    select @cmd = @cmd + quotename(@colname)				
                            ,@var = quotename(@colname)
                    exec dbo.sp_MSget_colinfo @tabid, @thiscol, @columns, 0, NULL, @ccoltype output
                    if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
                        select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
                        select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
                        select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
                        select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
                        select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_varbintohexstr(' + @var + N') collate database_default, ''null'') ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
                        select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
                        select @cmd = @cmd + N' = '' + ISNULL(CONVERT(nvarchar(40),' + @var + N', 2), ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
                        select @cmd = @cmd + N' = '' + ISNULL('''''''' + CAST(' + @var + N' as nvarchar(40)) + '''''''', ''null'') '
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
                        select @cmd = @cmd + N' = '' + ISNULL('''''''' + CONVERT(nvarchar(40), ' + @var + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @var + N', 114) + '''''''', ''null'') '	
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
                        select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_sqlvarbasetostr(' + @var + N' ) collate database_default, ''null'') '
                    else
                        select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') '
                end
                else
                begin
                    --
                    -- scripting for custom procs - static script
                    --
                    select @var = case when (@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) 
                                                    then @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
                                                    else @prefix + cast(@artcol as nvarchar(10)) end
                    if (@suffix is not null)
                        select @var = @var + @suffix
                    --
                    -- Does the column allow NULLs
                    --
                    if (columnproperty( @tabid , @colname , 'AllowsNull' ) = 1)
                    begin
                        --
                        -- static scripting should handle NULL valued column
                        -- ((<@var> is null and <colname> is null) or (<@var> is not null and <colname> = <@var>)) 
                        --
                        select @cmd = @cmd + N'((' + @var + N' is null and ' + quotename(@colname) + N' is null) or (' 
                                                + @var + N' is not null and ' + quotename(@colname) + N' = ' + @var + N'))' 
                    end
                    else
                    begin
                        --
                        -- static scripting does not need to check for NULL values
                        -- <colname> = <@var>
                        --
                        select @cmd = @cmd + quotename(@colname) + N' = ' + @var
                    end
                    --
                    -- special processing for @modeupdcustprocnonpk
                    --
                    if (@mode = @modeupdcustprocnonpk)
                    begin
                        select @cmd = @cmd + N' and ' + @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
                        if (@suffix is not null)
                            select @cmd = @cmd + @suffix
                        select @cmd = @cmd + N' != ' + @prefix + cast(@artcol as nvarchar(10))
                        if (@suffix is not null)
                            select @cmd = @cmd + @suffix
                    end
                end
                --
                -- transfer command string to table if too large
                --
                if (len(@cmd) > 3000)
                    exec dbo.sp_MSflush_command @cmd output, 1, 0                
            end            
            --
            -- get the next key for the index
            --
            select @indkey = @indkey + 1
        end
        --
        -- done with current index
        --
        select @findexstarted = 0
                ,@cmd = case when (@mode = @modedelcompensating) then @cmd + N' + '' ) '
                                            else @cmd + N' ) ' end
        --
        -- fetch next unique index
        --
        fetch #hcindid into @indid, @indstatus
    end
    close #hcindid
    deallocate #hcindid
    --
    -- Final flush
    --
    if (@mode = @modedelcompensating)
        select @cmd = @cmd + N''''
    if (len(@cmd) > 0)
        exec dbo.sp_MSflush_command @cmd output, 1, 0                
    --
    -- all done
    --
    return 0
end
go
exec sp_MS_marksystemobject sp_replscriptuniquekeywhereclause
go

--------------------------------------------------------------------------------
--. sp_MSgettrancftsrcrow
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSgettrancftsrcrow')
drop procedure sp_MSgettrancftsrcrow
go
raiserror('Creating procedure sp_MSgettrancftsrcrow',0,-1)
go
create procedure sp_MSgettrancftsrcrow ( 
	@tran_id sysname,
	@row_id sysname,
	@conflict_table nvarchar(256),
	@is_subscriber bit,
	@is_debug bit=0 )
as 
begin
	set nocount on
	declare @decllist nvarchar(4000)
			,@sellist nvarchar(4000)
			,@wherelist nvarchar(4000)
			,@cmd nvarchar(4000)
			,@cmdrow nvarchar(4000)
			,@srctable sysname
			,@srctabid int
			,@srcowner sysname
			,@columns  binary(32)
			,@indid int
			,@indkey int
			,@key sysname
			,@this_col int
			,@col sysname
			,@typestring nvarchar(60)
			,@dbname sysname
			,@retcode smallint
			,@unqualified_cft_tab sysname
			,@startoffset int
			
	--
	-- validate
	--
	if ((@tran_id is null) or (@row_id is null) or 
		(@conflict_table is null) or (@is_subscriber is null))
	begin
		raiserror('sp_MSgettrancftsrcrow(debug): @tran_id,@row_id,@conflict_table,@is_subscriber cannot be null', 16, 1)
		return (1)
	end

	--
	-- check if the conflict table is owner qualified
	--
	select @startoffset = charindex(N'].[', @conflict_table, 0)
	select @unqualified_cft_tab = case when (@startoffset > 0) 
		then substring(@conflict_table, @startoffset + 2, len(@conflict_table) - @startoffset - 1)
		else quotename(@conflict_table) end
		
	--
	-- get the source table info
	--
	if (@is_subscriber = 1)
	begin
		select @srcowner = owner, @srctable = dest_table, 
			@srctabid = OBJECT_ID(dest_table), @columns = columns
		from MSsubscription_articles
		where quotename(cft_table) = @unqualified_cft_tab
	end
	else
	begin
		select @srcowner = user_name(OBJECTPROPERTY(objid,'OwnerId')), @srctable = OBJECT_NAME(objid), 
			@srctabid = objid, @columns = columns
		from sysarticles a join sysarticleupdates b on
			a.pubid = b.pubid and 
			a.artid = b.artid
		where b.conflict_tableid = OBJECT_ID(@conflict_table)
	end

    --
    -- create code for the following :
    -- select the row of conflict with given tranid and insertdate
    -- retrieve the values of the PK/UI columns for the source table from this row in cft_table
    -- select all columns from source table using the values in a where clause for PK/UI
    --

    --
    -- PK/UI check for source table
    --
	exec @indid = dbo.sp_MStable_has_unique_index @srctabid
	if (@indid = 0)
	begin
		raiserror('sp_MSgettrancftsrcrow(debug):source table %s does not have unique index', 16, 1, @srctable)
		return (1)
	end

	--
	-- create temp tables
	--
    create table #decltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
    create table #seltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
    create table #wheretext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)

	--
	-- walk through each column in PK/UI and build parts of code
	--
	select @indkey = 1
	while (@indkey <= 16)
	begin	
		select @key = index_col(@srctable, @indid, @indkey)
		if (@key is null)
		begin
			select @indkey = 16
		end
		else
		begin
			--
			-- get the column index in the source table for this index key
			--
			exec dbo.sp_MSget_col_position @srctabid, @columns, @key, @col output, @this_col output

			--
			-- get the typestring for this column in source table
			--
			exec dbo.sp_gettypestring @srctabid, @this_col, @typestring OUTPUT

			--
			-- build command strings
			--
			if (@decllist is NULL)
				select @decllist = N'declare @' + @col + N' ' + @typestring
			else
				select @decllist = N' ,@' + @col + N' ' + @typestring
			
			if (@sellist is NULL)
				select @sellist = N'select @' + @col + N' = ' + quotename(@key)
			else
				select @sellist = N' ,@' + @col + N' = ' + quotename(@key)
				
			if (@wherelist is NULL)
				select @wherelist = N'where ' + quotename(@key) + N' = @' + @col
			else
				select @wherelist = N' and ' + quotename(@key) + N' = @' + @col

			--
			-- store them in the temp tables
			--
			insert into #decltext(cmdtext) values(@decllist)
			insert into #seltext(cmdtext) values(@sellist)
			insert into #wheretext(cmdtext) values(@wherelist)
			
		end
		select @indkey = @indkey + 1
	end

    --
    -- Now put all the code in order in the codetext
    --
    if exists (select * from sysobjects where name = 'MSsrcrow_codetext')
    	drop table MSsrcrow_codetext
    	
    create table MSsrcrow_codetext ( step int identity NOT NULL, cmdtext nvarchar(4000) NULL)

    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #decltext order by c1
    insert into MSsrcrow_codetext(cmdtext) values (N' ')
    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #seltext order by c1
    select @cmd = N' 
	from ' 

	if (@startoffset > 0)
		select @cmd = @cmd + @conflict_table
	else
		select @cmd = @cmd + quotename(@srcowner) + N'.' + @unqualified_cft_tab
		
	select @cmd = @cmd + N'
	where tranid = ''' + @tran_id + ''' and qcfttabrowid = ''' + @row_id + ''' '
    insert into MSsrcrow_codetext(cmdtext) values (@cmd)
    select @cmd = N'select * from ' + quotename(@srcowner) + N'.' + quotename(@srctable) + N' '
    insert into MSsrcrow_codetext(cmdtext) values (@cmd)
    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #wheretext order by c1

	--
	-- now execute the code we just built
	--
	if (@is_debug = 0)
	begin
		--
		-- Build 139:
		-- NOTE xp_execresultset should work here but does not
		-- return for a long time. Using exec() - should revisit
		-- this for more stable builds
		--
		declare #srccursor cursor local FAST_FORWARD FOR 
		select cmdtext from MSsrcrow_codetext order by step 
		FOR READ ONLY

		select @cmd = N' '
		select @dbname = db_name()
		open #srccursor
		fetch #srccursor into @cmdrow
		while (@@FETCH_STATUS = 0)
		begin
			select @cmd = @cmd + @cmdrow
			fetch #srccursor into @cmdrow	
		end		
		close #srccursor
		deallocate #srccursor
		
		execute(@cmd)
		if (@@error != 0)
		begin
			raiserror('sp_MSgettrancftsrcrow(debug): execute() failed for [%s] in db [%s] ', 16, 1, @cmd, @dbname)
			return (1)
		end

	end
	else
		select cmdtext from MSsrcrow_codetext order by step 

	--
	-- all done
	--
	drop table MSsrcrow_codetext
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSgettrancftsrcrow
go
grant execute on dbo.sp_MSgettrancftsrcrow to public
go
--------------------------------------------------------------------------------
--. sp_check_for_sync_trigger
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_script_synctran_commands')
drop procedure sp_script_synctran_commands
go
raiserror('Creating procedure sp_script_synctran_commands', 0,1)
GO
CREATE PROCEDURE sp_script_synctran_commands(
    @publication sysname,    /* publication name */
    @article sysname = 'all'    /* article name, all means all article */
) 
AS
begin
    declare @retcode int

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    --
    -- Generate the scripts by calling internal SP
    --
    exec @retcode = dbo.sp_MSget_synctran_commands 
        @publication = @publication,
        @article = @article,
        @command_only = 1
    if @retcode <> 0 or @@error <> 0
        return (1)
end
go
EXEC dbo.sp_MS_marksystemobject sp_script_synctran_commands
GO
grant execute on dbo.sp_script_synctran_commands to public
go

--------------------------------------------------------------------------------
--. sp_replsqlqgetrows
--------------------------------------------------------------------------------

if exists (select * from sysobjects
    where type = 'P' and name = 'sp_replsqlqgetrows')
drop procedure sp_replsqlqgetrows
go
raiserror('Creating procedure sp_replsqlqgetrows', 0,1)
go
create proc sp_replsqlqgetrows (
	@publisher 		sysname
	,@publisherdb 	sysname
	,@publication 	sysname
)
as
begin
	set nocount on
	declare @retcode int

	--
	-- security check
	--
	exec @retcode = sp_MSreplcheck_subscribe
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- return rows
	--
	if exists (select * from dbo.sysobjects where name = 'MSreplication_queue')
	begin
		select tranid, datalen, data, commandtype, insertdate, orderkey, cmdstate 
		from dbo.MSreplication_queue with (READPAST) 
		where UPPER(publisher) = UPPER(@publisher) 
			and publisher_db = @publisherdb 
			and publication = @publication
		order by orderkey, tranid 

		if (@@error != 0)
			return 1
	end
	else
	begin
		--
		-- create empty rowset
		--
		declare @nomesgs TABLE (tranid     sysname, datalen int, data varbinary(8000),
			commandtype int, insertdate datetime, orderkey bigint, cmdstate bit)
		select * from @nomesgs
	end
	
	--
	-- All done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_replsqlqgetrows
go
grant execute on dbo.sp_replsqlqgetrows to public
go
--------------------------------------------------------------------------------
--. sp_changesubstatus
--------------------------------------------------------------------------------
if exists (select * from sysobjects
     where type = 'P '
           and name = 'sp_changesubstatus')
    drop procedure sp_changesubstatus
go
print ''
print 'Creating procedure sp_changesubstatus'
go
CREATE PROCEDURE sp_changesubstatus (
    @publication sysname = '%',    /* publication name */
    @article sysname = '%',        /* article name */
    @subscriber sysname = '%',      /* subscriber name */
    @status sysname,                /* subscription status */
    @previous_status sysname=NULL,  /* previous subscription status */
    @destination_db sysname = '%',   /* destination database name */

    @frequency_type int = NULL,
    @frequency_interval int = NULL,
    @frequency_relative_interval int = NULL,
    @frequency_recurrence_factor int = NULL,
    @frequency_subday int = NULL,
    @frequency_subday_interval int = NULL,
    @active_start_time_of_day int = NULL,
    @active_end_time_of_day int = NULL,
    @active_start_date int = NULL,
    @active_end_date int = NULL,
    @optional_command_line nvarchar(4000) = NULL,
    @distribution_jobid binary(16) = NULL OUTPUT,
    @from_auto_sync bit = 0,
    @ignore_distributor bit = 0,
    -- Agent offload
    @offloadagent bit = 0,
    @offloadserver sysname = NULL,
	@dts_package_name sysname = NULL,
	@dts_package_password nvarchar(524) = NULL,
	@dts_package_location int = 0,
    @schemastabilityonly int = 0,
	@distribution_job_name sysname = NULL

) AS

    SET NOCOUNT ON
    DECLARE @inactive tinyint
    DECLARE @subscribed tinyint
    DECLARE @active tinyint
	DECLARE @initiated tinyint
    DECLARE @public tinyint
    DECLARE @replicate_bit smallint
    DECLARE @msg nvarchar(255)
    DECLARE @prevstatid tinyint
    DECLARE @artid int
    DECLARE @tabid int
    DECLARE @srvid smallint
    DECLARE @statusid tinyint
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @pub_db sysname
    DECLARE @dest_db sysname
    DECLARE @sub_name sysname
    DECLARE @sub_status tinyint
    DECLARE @sub_ts varbinary (16)
    DECLARE @non_sql_flag bit
    DECLARE @qcmd nvarchar (4000)
    DECLARE @cmd1 nvarchar (255)
    DECLARE @cmd2 nvarchar (255)
    DECLARE @cmd3 nvarchar (255)
    DECLARE @retcode int
    DECLARE @repl_freq tinyint
    DECLARE @art_type tinyint
    DECLARE @proccmd  nvarchar(255)
    DECLARE @procnum  smallint
    DECLARE @finished_real bit
    DECLARE @finished_virtual bit
    DECLARE @virtual_id smallint
    DECLARE @immediate_sync bit
    DECLARE @enabled_for_internet bit
    DECLARE @allow_anonymous bit
    DECLARE @subscription_type int
    DECLARE @xact_seqno binary(10)
    DECLARE @sync_type tinyint
    DECLARE @automatic tinyint
    DECLARE @bcp_char tinyint	
    DECLARE @concurrent_char tinyint	

    DECLARE @art_change bit
    declare @login_name sysname

	DECLARE @pubid int
	DECLARE @syncinit_lsn binary(10)

	DECLARE @f_syncstat_posted bit

    -- synctran
    DECLARE @update_mode tinyint
    DECLARE @art_name sysname
    declare @synctran tinyint
    declare @no_distproc bit
    declare @loopback_detection bit
	
    /*
    ** Initializations.
    */
    select @synctran = 1
			
    SELECT @automatic = 1
    SELECT @inactive = 0        /* Const: subscription status 'inactive' */
    SELECT @subscribed = 1      /* Const: subscription status 'subscribed' */
    SELECT @active = 2          /* Const: subscription status 'active' */
	SELECT @initiated = 3        /* Const: subscription status 'initiated' */
    SELECT @public = 0          /* Const: publication status 'public' */
    SELECT @pub_db = DB_NAME()
    SELECT @virtual_id = -1
    SELECT @art_change = 0
    select @bcp_char = 1
    select @concurrent_char = 4	

	SELECT @f_syncstat_posted = 0

    SELECT @replicate_bit = 2

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

    /*
    ** Parameter Check:  @publication
    ** Check to make sure that the publication exists, that it's not NULL,
    ** and that it conforms to the rules for identifiers.
    */

    IF @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END

    IF @publication <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @publication
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END

    IF NOT EXISTS (SELECT * FROM syspublications WHERE name LIKE @publication)
        BEGIN
        IF @publication = '%'
                RAISERROR (14008, 11, -1)
        ELSE
                RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
        END

    /*
    ** Parameter Check:  @article
    ** Check to make sure that the article exists, that it's not null,
    ** and that it conforms to the rules for identifiers.
    */

    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END

    /*
    IF @article <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @article
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END
    */

    IF NOT EXISTS (SELECT *
                     FROM sysextendedarticlesview a,
                          syspublications b
                WHERE a.name LIKE @article
                      AND a.pubid = b.pubid
                      AND b.name LIKE @publication)

        BEGIN
        IF @article = '%'
                RAISERROR (14009, 11, -1, @publication)
        ELSE
                RAISERROR (20027, 11, -1, @article)
        RETURN (1)
        END

    /*
    ** Parameter Check:  @subscriber
    ** Check to make sure that the subscriber exists, that it is not NULL,
    ** and that it conforms to the rules for identifiers.
    ** Null subscriber represents virtual subscriptions
    */

    IF @subscriber IS NOT NULL AND @subscriber <> '%'
    BEGIN    
        EXECUTE @retcode = dbo.sp_validname @subscriber
        IF @@ERROR <> 0 OR @retcode <> 0
        RETURN (1)

        IF NOT EXISTS (SELECT *
                         FROM master..sysservers
                        WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
                          AND (srvstatus & 4) <> 0)

            BEGIN
                RAISERROR (14063, 11, -1)
                RETURN (1)
            END
    END

    /*
    ** Parameter Check: @status.
    ** Set the @statusid according to the @status value.  Values can be
    ** any of the following:
    **
    **      status      statusid
    **      =========   ========
    **      inactive           0
    **      subscribed         1
    **      active             2
	**		initiated          3
    */

    IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('active', 'subscribed', 'inactive', 'initiated')
        BEGIN
            RAISERROR (14065, 16, -1)
        RETURN (1)
        END

	IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
		SELECT @statusid = @initiated
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
        SELECT @statusid = @active
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
        SELECT @statusid = @subscribed
    ELSE
        SELECT @statusid = @inactive

    /*
    ** Parameter Check: @previous_status.
    ** Set the @prevstatid according to the @previous_status value.
    ** Values can be any of the following:
    **
    **      previous_status      prevstatid
    **      ===============      ==========
    **      inactive                      0
    **      subscribed                    1
    **      active                        2
	**		initiated					  3
    */

    IF @previous_status IS NOT NULL
    BEGIN
        IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('initiated','active', 'subscribed', 'inactive')
        BEGIN
            RAISERROR (14066, 16, -1)
            RETURN (1)
        END

        IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS)
        BEGIN
            RAISERROR (14067, 16, -1)
            RETURN (1)
        END

		IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
			SELECT @prevstatid = @initiated
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
            SELECT @prevstatid = @active
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
            SELECT @prevstatid = @subscribed
        ELSE
           SELECT @prevstatid = @inactive
    END

    /*
    ** Parameter Check: @destination_db.
    ** Set @destination_db to current database if not specified.  Make
    ** sure that the @destination_db conforms to the rules for identifiers.
    */

    IF @destination_db <> '%' 
    BEGIN
		EXECUTE @retcode = dbo.sp_validname @destination_db
		IF @retcode <> 0
		RETURN (1)
    END

    /*
    ** Get distribution server information for remote RPC
    ** subscription calls.
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 1 
        select @no_distproc = 1
    else
        select @no_distproc = 0

    IF @no_distproc = 0 --and @from_auto_sync = 0 
    BEGIN
        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distribdb OUTPUT

        IF @@ERROR <> 0
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END

        IF @retcode <> 0 OR @distribdb IS NULL OR @distributor IS NULL
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END
    END


    create table #sysextendedarticlesview
    (
    artid               int                 NULL,
    columns             varbinary(32)       NULL,
    creation_script     nvarchar(255)       collate database_default null,
    del_cmd             nvarchar(255)       collate database_default null,
    description         nvarchar(255)       collate database_default null,
    dest_table          sysname             collate database_default null,
    filter              int                 NULL,
    filter_clause       ntext               NULL,
    ins_cmd             nvarchar(255)       collate database_default null,
    name                sysname             collate database_default null,
    objid               int                 NULL,
    pubid               int                 NULL,
    pre_creation_cmd    tinyint             NULL,
    status              tinyint             NULL,
    sync_objid          int                 NULL,
    type                tinyint             NULL,
    upd_cmd             nvarchar(255)       collate database_default null,
    schema_option       binary(8)           NULL,
    dest_owner          sysname             collate database_default null
    )

    insert into #sysextendedarticlesview select * from sysextendedarticlesview

    begin tran
    save TRANSACTION changesubstatus

        SELECT @finished_virtual = 0
        SELECT @finished_real = 0

        /* 
        ** If @subscriber is null, don't process real subscriptions
        ** If @subscriber is not null and '%', don't process virtual subscriptions
        */
        IF @subscriber IS NULL SELECT @finished_real = 1
        ELSE IF @subscriber <> '%'  SELECT @finished_virtual = 1

        WHILE (@finished_real = 0 OR @finished_virtual = 0)
        BEGIN
            /*
            ** Declare cursor containing subscriptions to be updated.
            */
            IF @finished_real = 0
            BEGIN
                IF @previous_status IS NOT NULL
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND sub.status = @prevstatid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db collate database_default))
                END
                ELSE
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db))
                END		   
                SELECT @finished_real = 1
            END

            ELSE IF @finished_virtual = 0  
            BEGIN
                DECLARE @sub_bit smallint
                DECLARE @null_name sysname

                SELECT @sub_bit = 4
                SELECT @null_name = NULL

                /*
                ** Treat anonymous virtual subscription as DSN subscriber.
                ** This will cause sp_MSarticlecol being called in sp_changesubstatus
                */
                DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                    SELECT sub.artid,
                           art.objid,
                           sub.srvid,
                           @null_name,              /* subscriber name. NULL for virtual */
                           sub.dest_db,
                           sub.status,
                      case when (pub.allow_anonymous = 1 and (pub.sync_method = @bcp_char or pub.sync_method = @concurrent_char)) or
							pub.allow_dts = 1 then 1
                       else 0 end, /*indicate dsn or not */ 
                       pub.repl_freq,
                       art.type,
                       pub.immediate_sync,
                       pub.enabled_for_internet,
                       pub.allow_anonymous,
                       sub.subscription_type,
                       sub.sync_type,
                       sub.update_mode,
                       art.name,
                       login_name,
                       sub.loopback_detection,
					   pub.pubid

                      FROM syssubscriptions sub,
                           #sysextendedarticlesview art,
                           syspublications pub
                     WHERE pub.name LIKE @publication
                       AND art.name LIKE @article
                       AND sub.srvid = -1
                       AND sub.artid = art.artid
                       AND art.pubid = pub.pubid
                SELECT @finished_virtual = 1
            END

            OPEN hCsubstatus
            FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
                @sub_status, @non_sql_flag, @repl_freq, @art_type,
                @immediate_sync, @enabled_for_internet,
                @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection,@pubid


            WHILE (@@fetch_status <> -1)
            BEGIN

                IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
                    AND is_member ('db_owner') <> 1
                BEGIN
                        RAISERROR (14126, 11, -1)
                        RETURN (1)
                END
                /*
				** condition 1:
                ** If current status is same as new status, and status is not 'initiated' do nothing.
				** If both old and new status = 'initiated', this indicates that the 
				** snapshot agent previously bombed out between the initiation and activation stages and
				** is now again trying to sync the publication.
				**
				** condition 2:
                ** @auto_sync_only is used by snapshot for immediate_sync
                ** publications.
				**
				** condition 3:
				** Because sp_MSactivate_auto_sub (and thus the snapshot agent)
				** calls this procedure for all subscriptions, we need to ignore
				** the real subscriptions that are already active so that they won't be
				** transitioned to the initiated state.  If we don't do this, those
				** subscriptions will be resynced using the new snapshot.
				** 
				** however, we DO want a new snapshot to be generated for virtual
				** subscriptions to active publications.
				**
                */
                IF  (@sub_status = @statusid AND @sub_status <> @initiated ) OR
                    (@from_auto_sync = 1 AND @sync_type <> @automatic) OR
					(@sub_status = @active AND @statusid = @initiated AND @srvid <> -1 AND @from_auto_sync = 1)
                BEGIN
                    FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name,
                       @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type, 
                       @immediate_sync, @enabled_for_internet,
                       @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                       @art_name, @login_name, @loopback_detection, @pubid

                    CONTINUE
                END

				-- If changing a virtual subscription to 'subscribed' status
				-- change the immediate_sync_ready bit
				if @statusid = @subscribed and @sub_name is NULL
				begin
					UPDATE syspublications SET immediate_sync_ready = 0 WHERE 
						pubid = @pubid and
						immediate_sync_ready <> 0
                    IF @@ERROR <> 0
                    BEGIN
                      CLOSE hCsubstatus
                      DEALLOCATE hCsubstatus
                      if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION changesubstatus
                            commit tran
                        end
                      RETURN (1)
                    END
				end


				-- acquire schema lock, mark rollback point in order to allow
				-- for 'unflush' of proc cache

                declare @qualified_name nvarchar(512)

                exec dbo.sp_MSget_qualified_name @tabid, @qualified_name output
                exec dbo.sp_replupdateschema @qualified_name, @schemastabilityonly

                /*
                ** Update syssubscription status
                */
                UPDATE syssubscriptions
                       SET status = @statusid
                       FROM syssubscriptions sub,
                           sysextendedarticlesview art,
                           syspublications pub
                       WHERE pub.name LIKE @publication
                            AND art.artid = @artid
                            AND sub.srvid = @srvid
                            AND sub.artid = @artid
                            AND art.pubid = pub.pubid
                            AND sub.dest_db = @dest_db
                if @@ERROR <> 0
                               BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                                   RETURN (1)
                               END

				--
				-- Subscription reinitialization processing for Immediate 
				-- and Queued publications
				--
				if (@update_mode in (1,2,3,4,5))
				begin
					select @retcode = 0
					IF ((@statusid != @active) AND (@sub_status = @active))
					begin
						--
						-- If we are going from active state to subscribed
						-- set the reinit column so that no more updates from
						-- subscriber are applied until (re)activation
						--
						update dbo.syssubscriptions
						set queued_reinit = 1
						where 
							artid = @artid 
							and srvid = @srvid
							and dest_db = @dest_db
					end
					ELSE IF ((@statusid = @active) AND (@sub_status != @active ))
					begin
						--
						-- If we are going from subscribed state to active state
						--
						if (@update_mode = 1)
						begin
							--
							-- Sync tran case : reset the reinit column
							--
							update dbo.syssubscriptions
							set queued_reinit = 0
							where 
								artid = @artid 
								and srvid = @srvid
								and dest_db = @dest_db
						end
						--
						-- For queued case : we do not need to send compensating
						-- command anymore, sp_addqueued_artinfo will do the 
						-- queue reinitialization for all types of queued
						-- subscriptions
						--
					end					

					--
					-- Check for error
					--
					if (@@error != 0 or @retcode != 0)
					begin
						CLOSE hCsubstatus
						DEALLOCATE hCsubstatus
						if @@trancount > 0
						begin
							ROLLBACK TRANSACTION changesubstatus
							commit tran
						end
						RAISERROR (14053, 16, -1)
						RETURN (1)
					end
				end

                /*
                ** Get timestamp of subscription.
                */
                EXEC @retcode = dbo.sp_replincrementlsn_internal @xact_seqno OUTPUT
                IF @@ERROR <> 0 or @retcode <> 0
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                               RETURN (1)
                            END
                select @sub_ts = @xact_seqno


                IF @sub_ts IS NULL
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                               RETURN (1)
                            END
				
				-------------------------------------------------------------------
				-- If initiating the subscription, toss a SYNCINIT token into the 
				-- log for the article and return LSN as a results set
				--
				-- Note:  This should come after the subscription LSN is obtained.
				-- in order to assure proper application of SYNSTAT tokens in the
				-- distribution database
				-------------------------------------------------------------------

				IF @statusid = @initiated --and @sub_status <> @initiated
				BEGIN
					-- set filtered status.  Must log old text information during initiated state
					-- in order to support update splitting

					exec sp_MSsetfilteredstatus @tabid

					-- set nonsqlsub status.  must prevent UPDATETEXT operations during
					-- initiated state

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'add'
					exec sp_replpostsyncstatus @pubid, @artid, 1, @syncinit_lsn output
					if @f_syncstat_posted = 0
					begin
						select @pubid, @artid, @syncinit_lsn
						select @f_syncstat_posted = 1
					end
				END

				-------------------------------------------------------------------
				-- If changing the state FROM initiated, post a SYNCDONE token to the 
				-- log for the article. 
				-------------------------------------------------------------------
				IF @sub_status = @initiated and @statusid <> @initiated
				BEGIN
					-- reset filtered status to normal value

					exec sp_MSsetfilteredstatus @tabid

					-- clear nonsqlsub status for this article.

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'drop'

					--if @f_syncstat_posted = 0
					--begin
						exec sp_replpostsyncstatus @pubid, @artid, 0, @syncinit_lsn output
					--	select @f_syncstat_posted = 1
					--end
				END

                /*
                ** If activating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */
                IF @statusid in ( @active, @initiated )
                BEGIN
                    
                    /*
                    ** Update status of article to show it has been activated.
                    */
                    IF @repl_freq = 0 and EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                        AND status & 1 <> 1)
                    BEGIN
                        -- At most one row will be updated in the following two updates as the artid is unique
                        -- among both sysarticles and sysschemaarticles
                        UPDATE sysarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        UPDATE sysschemaarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        SELECT @art_change = 1
                    END

                        /*
                        ** Turn the replication flag on for this object in the
                        ** sysobjects table (make it logbased).
                        */

                    if @repl_freq = 0
                      BEGIN
                        UPDATE sysobjects SET replinfo = replinfo | @replicate_bit
                        WHERE id = ( SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )
                      END

                      IF @@ERROR <> 0
                      BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                      END

                END

                /*
                ** Update status of all columns if subscriber is non-SQL Server.
                */
                IF @non_sql_flag <> 0 AND ( @art_type & 1 ) = 1
                BEGIN
                    IF @statusid = @subscribed OR @statusid = @active
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'add'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RAISERROR (14068, 16, -1)
                            RETURN (1)
                        END


                    END
                    ELSE IF @statusid = @inactive
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'drop'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                        END
                    END
                END

				
                /*
                ** If deactivating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */

                IF @statusid NOT IN( @active, @initiated ) AND @sub_status IN ( @active, @initiated )
                BEGIN
                    /*
                    ** Set the article status to 'inactive' if there are
                    ** no other active subscriptions on it.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                       artid = @artid AND status = @active)
                    BEGIN
                        IF EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                            AND status & 1 = 1)
                        BEGIN
                            -- At most one row will be updated in the following two updates as the artid is unique
                            -- among both sysarticles and sysschemaarticles
                            UPDATE sysarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                            UPDATE sysschemaarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END

                            SELECT @art_change = 1
                        END
                    END

                    /*
                    ** Set the object replication bits  to 'inactive' if
                    ** there are no other active subscriptions on the
                    ** table.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                        artid IN (SELECT sa.artid FROM sysextendedarticlesview sa, syspublications sp WHERE
                        sa.objid = @tabid and sa.pubid = sp.pubid and sp.repl_freq = 0) AND status = @active)
                    BEGIN
                        UPDATE sysobjects SET replinfo =  replinfo & ~@replicate_bit
                        WHERE id = (SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )

                        IF @@ERROR <> 0
                        BEGIN
                           CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14068, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                END

				-- Note:  Not only do we need to have the replupdateschema already executed
				-- so we can handle rollbacks, we also need to
                -- acquire the schema lock before RPC to the distributor to avoid livelock
                -- with snapshot agents. Snapshot agents acquire lock on user table before
                -- updating the distribution db.

                if @no_distproc = 0
                begin
                    /*
                    ** Add the active subscription to the distributor's
                    ** subscriptions table if changing status from @inactive
                    */
                    IF @sub_status = @inactive 
                    -- From inactive to subscribed or active
                    BEGIN

                        DECLARE @null_char sysname
                        SELECT @null_char = NULL

                        DECLARE @zero_bit bit
                        SELECT @zero_bit = 0

                        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadd_subscription'
                        EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, 
                            @artid, @dest_db, @statusid, @sub_ts,
                            @publication, 
                            @null_char, /* Pass null to @article, we already gave @artid */
                            @subscription_type,
                            --@immediate_sync, 
                            @sync_type, 
                            @zero_bit,
                            @frequency_type,
                            @frequency_interval,
                            @frequency_relative_interval,
                            @frequency_recurrence_factor,
                            @frequency_subday,
                            @frequency_subday_interval,
                            @active_start_time_of_day,
                            @active_end_time_of_day,
                            @active_start_date,
                            @active_end_date,
                            @optional_command_line = @optional_command_line,
                            -- synctran
                            @update_mode = @update_mode,
                            @loopback_detection = @loopback_detection,
                            @distribution_jobid = @distribution_jobid OUTPUT,
                            @offloadagent = @offloadagent,
                            @offloadserver = @offloadserver,
							@dts_package_name = @dts_package_name,
							@dts_package_password = @dts_package_password,
							@dts_package_location = @dts_package_location,
							@distribution_job_name = @distribution_job_name

                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14070, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                    ELSE
                    -- From subscribed or active to others
                    BEGIN
                        /*
                        ** Drop the deactivated subscription from the distributor's
                        ** subscriptions table.
                        */
                        IF @statusid = @inactive
                        -- From subscribed to inactive or from active to inactive
                        BEGIN
                            SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_subscription'
                            EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name,  @artid, @dest_db, @publication
                            IF @@ERROR <> 0 OR @retcode <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                RAISERROR (14070, 16, -1)
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RETURN (1)
                            END
                        END
                        ELSE 
                        -- From subscribed to initiated to active or from active to subscribed.
                        BEGIN
                            -- Don't do it if activating the subscription for snapshot agent.
                            --IF NOT (@from_auto_sync = 1 AND @statusid in(@active, @initiated) )
                            IF NOT (@from_auto_sync = 1 AND @statusid in(@active) )
                            BEGIN
                                SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSupdate_subscription'
                                EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @statusid, @sub_ts, @dest_db
                                IF @@ERROR <> 0 OR @retcode <> 0
                                BEGIN
                                    CLOSE hCsubstatus
                                    DEALLOCATE hCsubstatus
                                    RAISERROR (14070, 16, -1)
                                    if @@trancount > 0
                                    begin
                                        ROLLBACK TRANSACTION changesubstatus
                                        commit tran
                                    end
                                    RETURN (1)
                                END
                            END
                        END
                    END
                end

                /*
                ** Set internal object replication bit  to 'inactive' if
                ** there are no other active subscriptions on the
                ** table.
                */

                IF @statusid = @inactive AND @sub_status IN (@active,@initiated) AND
                    NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                    artid IN (SELECT artid FROM sysextendedarticlesview WHERE
                    objid = @tabid) AND status IN (@active,@initiated) )
                BEGIN
                       /*
                       ** If it's a procedure execution article, clear proc status bits
                       */
                       IF (@art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo & ~24 WHERE id = @tabid
                       END
                END


                /* Turn on object replication */

                ELSE IF @statusid = @active
                BEGIN
                       IF (@art_type & 24 ) = 24
                       BEGIN

                           UPDATE sysobjects SET replinfo = replinfo | 24 WHERE id = @tabid
                       END
                       ELSE IF( @art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo | 8 WHERE id = @tabid
                       END
                END


                exec dbo.sp_MSget_qualified_name @tabid, @qualified_name output
                exec dbo.sp_replupdateschema @qualified_name, @schemastabilityonly

               /*
               ** Get next row.
               */
               FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
               @sub_status, @non_sql_flag, @repl_freq, @art_type ,  
               @immediate_sync, @enabled_for_internet,
               @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection, @pubid

          
                                    
           END  -- end while for cursor

           CLOSE hCsubstatus
           DEALLOCATE hCsubstatus
        
        END -- end while for virtual and real

        -- force refresh of article cache
        -- Only do it if necessary
        -- No need on brute force cleanup
        IF ( @art_change = 1 ) and ( @ignore_distributor = 0 )
            EXECUTE dbo.sp_replflush

    COMMIT TRANSACTION
    drop table #sysextendedarticlesview
    RETURN(0)
go
 
EXEC dbo.sp_MS_marksystemobject sp_changesubstatus
GO
grant execute on dbo.sp_changesubstatus to public
go
--------------------------------------------------------------------------------
--.	System objects (rladmin.sql)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--.	sp_MSremove_userscript
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MSremove_userscript')
drop procedure sp_MSremove_userscript
go
create procedure sp_MSremove_userscript(
@pubid				uniqueidentifier,
@drop_publication	bit = 0
)as
	declare @retention			int
	declare @last_snapshot		datetime
	declare @post_snapshot_ver	int
	declare @post_snapshot_type	int
	declare @user_script_type	int
	declare @retcode			int
	declare @len				int

	declare @file_path			nvarchar(4000)
	declare @delfile_cmd		nvarchar(4000)
	declare @rmdir_cmd			nvarchar(4000)
	
	select @post_snapshot_type=52
	select @user_script_type=46
	
	if not exists (select * from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type)
		return (0)
	select @retention=retention from sysmergepublications where pubid=@pubid
	select @last_snapshot=last_validated from sysmergesubscriptions where pubid=@pubid and subid=@pubid

	--I do not want to remove  script files by setting retention to 0
	if (@retention=0 or dateadd(day, -@retention, getdate()) < @last_snapshot) and @drop_publication = 0
		return (0)

	select @post_snapshot_ver=schemaversion from sysmergeschemachange 
		where schematype=@post_snapshot_type and pubid=@pubid
		
	--only get those script that can be safely removed
	
	declare #per_script cursor local fast_forward for
		select schematext from sysmergeschemachange 
			where pubid=@pubid and schematype=@user_script_type 
			and (schemaversion<@post_snapshot_ver or @drop_publication = 1)
	open #per_script
	fetch #per_script into @file_path
	while (@@fetch_status<>-1)
	begin
	if(left(@file_path, 1) = N'0' or left(@file_path, 1) = N'1')
		select @file_path = right(@file_path, len(@file_path) - 1)
        select @delfile_cmd = N'del "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
        EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
		if @@ERROR<>0
			goto FAILURE
		select @len=CHARINDEX ( '\' , reverse(@file_path) ) 
		select @file_path=SUBSTRING(@file_path , 1 , len(@file_path)-@len + 1)
		
        select @delfile_cmd = N'rmdir "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
        EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
		if @@ERROR<>0
			goto FAILURE
		fetch next from #per_script into @file_path
	end
	
	close #per_script
	deallocate #per_script
	return (0)
FAILURE:
	close #per_script
	deallocate #per_script
	return (1)
go
EXEC dbo.sp_MS_marksystemobject 'sp_MSremove_userscript'
go

--------------------------------------------------------------------------------
--.	sp_MScomputemergearticlescreationorder
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P' and name = 'sp_MScomputemergearticlescreationorder')
drop procedure sp_MScomputemergearticlescreationorder
go
raiserror(15339,-1,-1,'sp_MScomputemergearticlescreationorder')
GO
CREATE PROCEDURE sp_MScomputemergearticlescreationorder
    @publication sysname
AS
    SET NOCOUNT ON
    DECLARE @pubid uniqueidentifier 
    DECLARE @max_level int
    DECLARE @current_level int
    DECLARE @update_level int
    DECLARE @limit int
    DECLARE @retcode int

    SELECT @retcode = 0

    EXEC @retcode = sp_MSreplcheck_publish
    IF @@ERROR <> 0 OR @retcode <> 0
        return (1)

    SELECT @pubid = NULL
    -- Get the pubid from sysmergepublications 
    SELECT @pubid = pubid 
      FROM sysmergepublications
     WHERE name = @publication
       AND UPPER(publisher) = UPPER(@@SERVERNAME)
       AND publisher_db = DB_NAME()

    IF @@ERROR <> 0
        RETURN (1)

    IF @pubid IS NULL
    BEGIN
        RAISERROR(20026, 16, -1, @publication)
        RETURN (1)
    END

    -- Find out the total number of articles in this publication and
    -- compute the maximum tree height based on the number of articles in 
    -- the publication. Here, the tree height is counted from the
    -- leaf-nodes towards the root(s) starting from @max_level
    SELECT @max_level = COUNT(*) + 10,
           @limit = 2 * COUNT(*) + 11 
      FROM sysmergeextendedarticlesview 
     WHERE pubid = @pubid
 
    IF @@ERROR <> 0
    BEGIN
        RETURN (1)
    END
   
    -- The following temp table contains the minimal amount of 
    -- article information that we want to keep around and the current
    -- computed tree level of the article
    CREATE TABLE #article_level_info
    (
        article         sysname collate database_default not null,
        source_objid    INT     NOT NULL,
        tree_level      INT     NOT NULL,
        nickname        INT     NOT NULL,
        major_type      TINYINT NOT NULL  -- 1-view&func, 0-other
    )  
   
    CREATE CLUSTERED INDEX ucarticle_level_info 
        ON #article_level_info(source_objid)

    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END

    -- Populate the article level info table. All articles will be
    -- assigned 0 as their initial tree level. Having 
    -- a tree level of 0 means that the algorithm hasn't discovered 
    -- any objects that the article depends on within the publication.

    INSERT INTO #article_level_info 
    SELECT name, objid, 0, ISNULL(nickname, 5*@max_level),
        CASE type
            WHEN 0x40 THEN 1
            WHEN 0x80 THEN 1
            ELSE 0
        END 
      FROM sysmergeextendedarticlesview
     WHERE pubid = @pubid
      
    -- To jump-start the algorithm, update the tree_level of 
    -- all articles with no dependency to @max_level.

    UPDATE #article_level_info 
       SET tree_level = @max_level
     WHERE NOT EXISTS (SELECT * 
                         FROM sysdepends 
                        WHERE source_objid = id
                          AND id <> depid)
    IF @@ERROR <> 0
        GOTO Failure

    -- For each increasing tree level starting from @max_level, update the 
    -- the tree_level of articles depending on objects at the current
    -- level to current level + 1
    SELECT @current_level = @max_level
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1

        UPDATE #article_level_info
           SET tree_level = @update_level
          FROM #article_level_info 
        INNER JOIN sysdepends d
            ON #article_level_info.source_objid = d.id 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid       
               AND ali1.tree_level = @current_level
               AND d.id <> d.depid)
    
        -- Terminate the algorithm if we cannot find any articles 
        -- depending on articles at the current level     
        IF @@ROWCOUNT = 0
            GOTO PHASE1

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1

        -- Although there should not be any circular 
        -- dependencies among the articles, the following
        -- check is performed to guarantee that 
        -- the algorithm will terminate even if there 
        -- is circular dependency among the articles
        
        -- Note that with at least one node per level,
        -- the current level can never exceed the total 
        -- number of articles (nodes) unless there is
        -- circular dependency among the articles.
        
        -- @limit is defined to be # of articles + 1
        -- although @limit = # of articles - 1 will be
        -- sufficient. This is to make absolutely sure that 
        -- the algorithm will never terminate too early

        IF @current_level > @limit
            GOTO PHASE1
    END

PHASE1:
    
    -- There may be interdependencies among articles 
    -- that haven't been included in the previous calculations so
    -- we compute the proper order among these articles here.
    SELECT @limit = @max_level - 9
    SELECT @current_level = 0
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info 
           SET tree_level = @update_level
          FROM #article_level_info
        INNER JOIN sysdepends d
            ON (#article_level_info.source_objid = d.id
                AND #article_level_info.tree_level < @max_level) 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid
                AND ali1.tree_level = @current_level
                AND d.id <> d.depid)
        IF @@ROWCOUNT = 0
            GOTO PHASE2
        
        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE2
    END         

PHASE2:

    -- Select the articles out of #article_level_info 
    -- in ascending order of tree_level. This will give
    -- the proper order in which articles can be created
    -- without violating the internal dependencies among
    -- the themselves. Note that this algorithm still allows 
    -- unresolved external references outside the publication.
    -- All this algorithm can guarantee is that all articles will
    -- be created successfully using the resulting order if 
    -- there is no dependent object outside the publication. 

    SELECT article
      FROM #article_level_info
    ORDER BY major_type ASC, tree_level ASC, nickname ASC

    DROP TABLE #article_level_info
    RETURN (0)

Failure:

    DROP TABLE #article_level_info
    RETURN (1)
GO

exec dbo.sp_MS_marksystemobject sp_MScomputemergearticlescreationorder
go
grant exec on dbo.sp_MScomputemergearticlescreationorder to public
go

--------------------------------------------------------------------------------
--.	System objects (rlrecon.sql)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
            where type = 'P' and 
            name = 'sp_MSenumschemachange_80')
    drop procedure sp_MSenumschemachange_80

raiserror('Creating procedure sp_MSenumschemachange_80', 0,1)
GO

CREATE PROCEDURE sp_MSenumschemachange_80(
	@pubid 			       uniqueidentifier,
	@AlterTableOnly					int,
	@schemaversion 	       int
	)
as
    set nocount on
	/*
	** To public
	*/
	declare	@alter_table_type		int
	declare @reinit_all_type 		int
	declare @reinit_all_upload_type int
	declare @schemaversion_of_snapshottrailer int
	
	select @reinit_all_type = 12
	select @alter_table_type = 11
	select @reinit_all_upload_type = 14
	
	if (@schemaversion is null)
		begin
		RAISERROR(14043, 16, -1, '@schemaversion')
		return (1)
		end

		--	@schema_needed = 0 - only send back reinitall command, if any 
		--  @schema_needed = 1 - normal enumeration
		--  @schema_needed = 2 - only send back alter-table command, if any
		--  @schema_needed = 3 - only send back reinitall-with-upload command, if any.

	if (@AlterTableOnly = 1)
		begin
			select pubid, artid, schemaversion, schemaguid, schematype, schematext
				from sysmergeschemachange where pubid=@pubid and schemaversion > @schemaversion and schematype = @alter_table_type
			return (0)			
		end
		
	if exists (select * from sysmergeschemachange where 
		pubid=@pubid and ((schemaversion > @schemaversion and schematype = @reinit_all_type)
		or (schemaversion > @schemaversion and schematype = @reinit_all_upload_type)))
		begin
			select @schemaversion=0
		end

	-- If subscriber missed a preparecleanup and a completecleanup they must be reinitialized
	
	if exists (select * from sysmergeschemachange where 
		pubid=@pubid and schemaversion > @schemaversion and schematype = 17) and
	    exists (select * from sysmergeschemachange where 
		pubid=@pubid and schemaversion > @schemaversion and schematype = 19) 		
		begin
			set @schemaversion=0
		end
		
    if (@schemaversion > 0) 
    begin
        -- Subscriber has already received the snapshot so filter out 
        -- the pre/post-snapshot commands. 
        -- Also filter out the schemtypes for the setlastsentgen (5) and setlastrecgen (6)
        -- This ensures that the subscriber does not apply these schema changes when 
        -- it applies incremental schema - ie the perf optimization that is implemented 
        -- by setting last sent/rec generation should be done only for brand new subscriptions.
        select pubid, artid, schemaversion, schemaguid, schematype, schematext
          from sysmergeschemachange where schemaversion > @schemaversion  
		   and pubid = @pubid
           and schematype not in (40, 45, 50, 51, 52, 53, 54, 55, 56, 57, 58, 25, 5, 6)
      order by schemaversion 
    end
    Else 
    begin
        -- Subscriber requires a snapshot, so carefully sequence the 
        -- pre/post-snapshot commands around the snapshot boundary

        create table #schemachanges 
        (   
            pubid           uniqueidentifier  NOT NULL,
            artid           uniqueidentifier  NULL,
            schemaversion   int               NOT NULL,
            schemaguid      uniqueidentifier  NOT NULL,
            schematype      int               NOT NULL,
            schematext      nvarchar(2000)    collate database_default not null,
            seqno           int identity      NOT NULL
        )
        
        truncate table #schemachanges
        -- Insert snapshot header 

        -- Header begins
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype = 50

        -- Header content
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype in (25, 53, 54, 55, 56, 57, 58) 
        order by schemaversion 

        -- Header ends
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype = 51 

        -- End of snapshot header 
        -- Insert pre command
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype = 40 

        -- Exclude pre-post, but include snapshot only commands
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype in (2, 3, 4, 20, 7, 60, 61, 62, 63, 64)
		 order by schemaversion 

        -- Dynamic BCP commands
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype in (131, 132)
		 order by schemaversion		 
        
        -- DRI/Trg/XPROP
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype in (10, 15, 65)
		 order by schemaversion		 

        -- Insert post command
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype = 45 

        -- Insert snapshot trailer
        insert into #schemachanges
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
		   and pubid = @pubid
           and schematype = 52 
        
        -- Insert other schema changes
        insert into #schemachanges 
	    select pubid, artid, schemaversion, schemaguid, schematype, schematext
		  from sysmergeschemachange where schemaversion > @schemaversion 
           and schematype not in (2, 3, 4, 10, 15, 20, 7, 40, 45, 60)
           and schematype not in (61, 62, 63, 64, 65)
           and schematype not in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58)
           and schematype not in (131, 132) -- dynamic bcp commands
		   and schematype not in (46, 11, 13) -- The on-demand script and schema replication commands should not be enumerated unless 
									  -- we have made sure that it was posted after the current snapshot.
		   and pubid = @pubid
		 order by schemaversion		           

		-- get the schemaversion of the snapshot trailer row
		select @schemaversion_of_snapshottrailer = schemaversion from sysmergeschemachange 
			where schemaversion > @schemaversion 
			and pubid = @pubid
			and schematype = 52 

		if (@schemaversion_of_snapshottrailer is not null)
		begin
			-- insert schema changes for on-demand script and schema replication commands which have schemaversion greater than
			-- schemaversion of the snapshot trailer row
			insert into #schemachanges 
			select pubid, artid, schemaversion, schemaguid, schematype, schematext
			from sysmergeschemachange where schemaversion > @schemaversion_of_snapshottrailer 
			and schematype in (46, 11, 13) -- The on-demand script and schema replication commands only.
			and pubid = @pubid
			order by schemaversion
        end
		    
		declare @endofsnapshot int
        select @endofsnapshot = min(seqno) from #schemachanges 
        where schematype = 52
        delete #schemachanges where seqno > @endofsnapshot
            and (schematype in (2, 3, 4, 10, 15, 20, 7, 40, 45, 65) or 
            schematype in (25, 50, 51, 52, 53, 54, 55, 56, 57, 58))

		--only list the last reinitall command 
		delete schemachanges1 from #schemachanges schemachanges1,#schemachanges schemachanges2 
			where schemachanges1.pubid=@pubid and schemachanges1.schematype=12 and 
				  schemachanges2.pubid=@pubid and schemachanges2.schematype=12 and
				  schemachanges1.schemaversion<schemachanges2.schemaversion
		
		--only list the last reinitall-with-upload command 
		delete schemachanges1 from #schemachanges schemachanges1, #schemachanges schemachanges2 
			where schemachanges1.pubid=@pubid and schemachanges1.schematype=14 and 
				  schemachanges2.pubid=@pubid and schemachanges2.schematype=14 and
				  schemachanges1.schemaversion<schemachanges2.schemaversion

        select pubid, artid, schemaversion, schemaguid, schematype, schematext
          from #schemachanges order by seqno

        drop table #schemachanges
    end

	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumschemachange_80
go
grant exec on dbo.sp_MSenumschemachange_80 to public
go

if exists (select * from sysobjects
            where type = 'P' and 
            name = 'sp_MSregistersubscription')
    drop procedure sp_MSregistersubscription
go
raiserror('Creating procedure sp_MSregistersubscription', 0,1)
go

CREATE PROCEDURE sp_MSregistersubscription (
	@replication_type			int, /* Transactional = 1, Merge = 2 */
    @publisher 					sysname,
    @publisher_db 				sysname,
	@publisher_security_mode	int = NULL,						/* 0 standard; 1 integrated */
	@publisher_login			sysname = NULL,
	@publisher_password	nvarchar(524) = NULL,
    @publication 				sysname,         
	@subscriber 				sysname,
    @subscriber_db 				sysname,
	@subscriber_security_mode	int = NULL,						/* 0 standard; 1 integrated */
	@subscriber_login			sysname = NULL,
	@subscriber_password	    nvarchar(524) = NULL,
	@distributor 				sysname,
	@distributor_security_mode 	int = NULL,
	@distributor_login 			sysname = NULL,
	@distributor_password	    nvarchar(524) = NULL,
    @subscription_id			uniqueidentifier ,
	@independent_agent			int = NULL,
	@subscription_type			int,
	@use_interactive_resolver	int = NULL,
	@failover_mode				int = NULL
    ) AS

    SET NOCOUNT ON

	/* MobileSync Support */
	declare @subscription_name				nvarchar(1000)
	declare @regkey							nvarchar(1000)
    declare @subidstr						nvarchar(38)
    declare @profile_name 					nvarchar(100)
	declare @retcode						int
	
	set @subscription_name = @publisher + ':' + @publisher_db + ':' + @publication + ':' + @subscriber + ':' + @subscriber_db
	/* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */
	set @subscription_name = REPLACE(@subscription_name,'\','/')
	set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
	set @subidstr = '{' + convert ( nchar(36), @subscription_id) + '}'
    set @profile_name = formatmessage(20550) -- SyncMgr Profile

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'ProfileName',
                               'REG_SZ',
                                @profile_name	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'ReplicationType',
                               'REG_DWORD',
                                @replication_type	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriptionType',
                               'REG_DWORD',
                                @subscription_type	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Subid',
                               'REG_SZ',
                                @subidstr	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Publisher',
                               'REG_SZ',
                                @publisher	                                    
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'PublisherDb',
                               'REG_SZ',
                                @publisher_db
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	
	IF @use_interactive_resolver IS NOT NULL
	BEGIN
		EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'UseInteractiveResolver',
                               'REG_DWORD',
                                @use_interactive_resolver
		if @retcode <> 0 OR @@ERROR <> 0
			return 1
	END

	/* If Publisher security mode is NOT NULL, write out the entries */
	if @publisher_security_mode IS NOT NULL
		begin
		   	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
		                               @regkey,
		                               'PublisherSecurityMode',
		                               'REG_DWORD',
		                                @publisher_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
		                               @regkey,
		                               'PublisherLogin',
		                               'REG_SZ',
		                                @publisher_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end
    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Publication',
                               'REG_SZ',
                                @publication
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Subscriber',
                               'REG_SZ',
                                @subscriber
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	/* If Subscriber security mode is NOT NULL, write out the entries */
	if @subscriber_security_mode IS NOT NULL
		begin
		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberSecurityMode',
                               'REG_DWORD',
                                @subscriber_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberLogin',
                               'REG_SZ',
                                @subscriber_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberDb',
                               'REG_SZ',
                                @subscriber_db                                    
	if @retcode <> 0 OR @@ERROR <> 0
		return 1
				
    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Distributor',
                               'REG_SZ',
                                @distributor
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	/* If Distributor security mode is NOT NULL, write out the entries */
	if @distributor_security_mode IS NOT NULL
		begin
		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'DistributorSecurityMode',
                               'REG_DWORD',
                                @distributor_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'DistributorLogin',
                               'REG_SZ',
                                @distributor_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end

    if @independent_agent IS NOT NULL
    	begin
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'IndependentAgent',
                               'REG_DWORD',
                                @independent_agent	
			if @retcode <> 0 OR @@ERROR <> 0
				return 1
		end				

	IF @failover_mode IS NOT NULL
		begin
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'FailoverMode',
                               'REG_DWORD',
                                @failover_mode	
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end			

	-- Mark enabled_for_syncmgr bit if every thing succeeded.
	-- If the row exists in MSreplication_properties table, 
	-- set enabled_for_syncmgr bit
	-- The logic need to be here because UI call this sp directly.
	if exists (select * from sysobjects where name = 'MSsubscription_properties')
	begin
		update MSsubscription_properties set enabled_for_syncmgr = 1 where
			UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
		if @retcode <> 0 OR @@ERROR <> 0
			return 1
	end

	return 0
GO

exec sp_MS_upd_sysobj_category 2
go

exec sp_configure 'allow updates',0
go

reconfigure with override
go
