/*
** repltran.sql            1997/02/12 22:03
**
**
** Copyright Microsoft, Inc. 1998, 1999
** All Rights Reserved.
** Use, duplication, or disclosure by the United States Government
** is subject to restrictions as set forth in subdivision (c) (1) (ii)
** of the Rights in Technical Data and Computer Software clause
** at CFR 252.227-7013. Microsoft, Inc. One Microsoft Way, Redmond WA
** 98052.  SQL-Server 7.0.
*/

use master
go

dump tran master with no_log
go

exec dbo.sp_configure 'update',1
go
reconfigure with override
go

set ANSI_NULLS off
go

-- sp_MS_upd_sysobj_category is obsolete, use sp_MS_marksystemobject instead
-- exec dbo.sp_MS_upd_sysobj_category 1 --Capture time for use at the end
-- go

/* 
** Drop the stored procedures in this script using the old dropping SP 
** and then drop itself
*/
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSdrop_repltran')
begin
    exec dbo.sp_MSdrop_repltran
    drop procedure sp_MSdrop_repltran
end

/*
** Create stored procedures to drop the stored procedures
** created by this script
*/
 

print ''
print 'Creating procedure sp_MSdrop_repl_tran.'
go
create procedure sp_MSdrop_repltran
as

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

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

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

    if exists ( select * from sysobjects 
        where type = 'P '
            and name = 'sp_MSreplsup_table_has_pk' )
        DROP PROC sp_MSreplsup_table_has_pk

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

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

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

    dump tran master with no_log
    

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

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

    dump tran master with no_log
    

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


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

    dump tran master with no_log
    

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

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

    dump tran master with no_log
    

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

    dump tran master with no_log
    

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

    IF EXISTS (SELECT * FROM sysobjects
            WHERE type = 'P '
                AND name = 'sp_changearticle')
        DROP PROCEDURE sp_changearticle
    

    dump tran master with no_log
    

    IF EXISTS (SELECT * FROM sysobjects
            WHERE type = 'P '
                AND name = 'sp_changepublication')
        DROP PROCEDURE sp_changepublication
    


    IF EXISTS (SELECT * FROM sysobjects
            WHERE type = 'P '
                AND name = 'sp_changesubscription')
        DROP PROCEDURE sp_changesubscription
    

    dump tran master with no_log
    

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

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

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

    dump tran master with no_log
    

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

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

    dump tran master with no_log
    

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

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

    dump tran master with no_log
    

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

    dump tran master with no_log
    

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

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

    dump tran master with no_log
    

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

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

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

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

    dump tran master with no_log
    

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

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

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


    if exists (select * from sysobjects
        where type = 'P '
                and name = 'sp_MSdrop_pub_tables')
    begin
        -- Don't drop the system tables here. repltran.sql should not
        -- delete any data in the master database (see bug 34219).
        -- exec dbo.sp_MSdrop_pub_tables
        drop procedure sp_MSdrop_pub_tables
    end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    dump tran master with no_log

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_getarticlepkcolbitmap')
    begin
        drop procedure sp_getarticlepkcolbitmap
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_gettypestring' )
    begin
        drop procedure sp_gettypestring
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_isarticlecolbitset' )
    begin
        drop procedure sp_isarticlecolbitset
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_scriptpkwhereclause' )
    begin
        drop procedure sp_scriptpkwhereclause
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_scriptupdateparams' )
    begin
        drop procedure sp_scriptupdateparams
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_scriptinsproc' )
    begin
        drop procedure sp_scriptinsproc
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_scriptdelproc' )
    begin
        drop procedure sp_scriptdelproc
    end

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_scriptupdproc' )
    begin
        drop procedure sp_scriptupdproc
    end

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

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

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

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

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

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

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

    dump tran master with no_log
go
 
EXEC dbo.sp_MS_marksystemobject sp_MSdrop_repltran
GO

EXEC dbo.sp_MSdrop_repltran
GO

/* Create and execute dbo.sp_MSdrop_pub_tables */

print ''
print 'Creating procedure sp_MSdrop_pub_tables'
go
CREATE PROCEDURE sp_MSdrop_pub_tables
AS
        
    begin tran
    save TRAN sp_drop_central_pub_tables
    
    /* drop 'sysarticles' */
    IF exists (select * from sysobjects where name = 'sysarticles')
    BEGIN
        DROP TABLE sysarticles
        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_drop_central_pub_tables
                commit tran
            end
            RETURN(1)
        END
    END

    /* drop 'syspublications' */
    IF exists (select * from sysobjects where name = 'syspublications')
    BEGIN
        DROP TABLE syspublications
        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_drop_central_pub_tables
                commit tran
            end
            RETURN(1)
        END
    END

    /* drop 'syssubscriptions' */
    IF exists (select * from sysobjects where name = 'syssubscriptions')
    BEGIN
        DROP TABLE syssubscriptions
        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_drop_central_pub_tables
                commit tran
            end
            RETURN(1)
        END
    END

    -- SyncTran
    /* drop 'sysarticleupdates' */
    IF exists (select * from sysobjects where name = 'sysarticleupdates')
    BEGIN
        DROP TABLE sysarticleupdates
        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_drop_central_pub_tables
                commit tran
            end
            RETURN(1)
        END
    END
    -- end SyncTran


    COMMIT TRAN
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSdrop_pub_tables
GO

dump tran master with no_log
go

--print ''
--print 'Executing procedure dbo.sp_MSdrop_pub_tables.'
--go
--exec dbo.sp_MSdrop_pub_tables
--go

--dump tran master with no_log
--go

/* Create and execute dbo.sp_MScreate_pub_tables */

dump tran master with no_log
go

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
        )

        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 '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
        )

        EXEC dbo.sp_MS_marksystemobject 'syspublications'

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

        create unique nonclustered index unc1syspublications
            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), ...
        loopback_detection      bit 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,
        autogen                bit       NOT NULL)     -- ID of sproc handling Delete Sync Transactions

        IF @@ERROR <> 0
        BEGIN
            GOTO ERROR
        END

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

        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

    END
    -- end SyncTran

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

dump tran master with no_log
go

/*
** Create replication stored procedures.
** Part 2:  create all other stored procedures.
*/

create proc sp_MSsetfilterparent @filter_name sysname, @parent_id int
as
   -- SQL SERVER 7.0 ONLY update sysobjects, set parent id = underlying
   -- object id

    declare @retcode int
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

   BEGIN TRAN

   exec dbo.sp_replupdateschema @filter_name 
   update sysobjects set parent_obj = @parent_id where id = object_id( @filter_name )

   COMMIT TRAN

go


EXEC dbo.sp_MS_marksystemobject sp_MSsetfilterparent
GO

create proc sp_MSdoesfilterhaveparent @filter_id int
as
    declare @retcode int
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    if exists ( select * from sysobjects
                where id = @filter_id and
                parent_obj <> 0 )
    BEGIN
        return 1
    END
    ELSE
    BEGIN
        return 0
    END
go

EXEC dbo.sp_MS_marksystemobject sp_MSdoesfilterhaveparent
GO


create proc sp_MSsetfilteredstatus @object_id int
as
    declare @qualified_name nvarchar(512)

    declare @retcode int
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    exec dbo.sp_MSget_qualified_name @object_id, @qualified_name output

   BEGIN TRANSACTION
   
   exec dbo.sp_replupdateschema @qualified_name
        
   if exists( select * from sysobjects where type = 'RF' and parent_obj = @object_id )
      or exists( select * from sysarticles where objid = @object_id and ( upd_cmd like 'CALL%' OR upd_cmd like 'XCALL%' ) )
   begin
       update sysobjects set replinfo = replinfo | 32 where id = @object_id
   end
   else
   begin
       update sysobjects set replinfo = replinfo & ~32 where id = @object_id
   end

   COMMIT TRANSACTION
   
go

EXEC dbo.sp_MS_marksystemobject sp_MSsetfilteredstatus
GO

CREATE PROCEDURE sp_MSreplsup_table_has_pk @tabid INT
as
    IF NOT EXISTS (SELECT * FROM sysobjects
                   WHERE parent_obj = @tabid
                   AND xtype = 'PK')
        RETURN 0
    ELSE
        RETURN 1
go

EXEC dbo.sp_MS_marksystemobject sp_MSreplsup_table_has_pk
GO

CREATE PROCEDURE sp_replsync (
    @publisher sysname,    
    @publisher_db sysname,        
    @publication sysname,    
    @article sysname = '%' 
    ) AS

    SET NOCOUNT ON
    RAISERROR (21023, 16, -1,'sp_replsync')
    RETURN(1)
GO

EXEC dbo.sp_MS_marksystemobject sp_replsync
GO


print ''
print 'Creating procedure sp_enumfullsubscriber'
go

CREATE PROCEDURE sp_enumfullsubscribers (
        @publication sysname = '%'      /* The publication name */
    ) AS

    /*
    ** Declarations.
    */

    DECLARE @retcode int

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

    /*
    ** Parameter Check: @publication.
    ** Check to make sure that the publication exists and that it conforms
    ** to the rules for identifiers.
    */

    IF @publication IS NOT NULL
        BEGIN

            IF @publication <> '%'
                BEGIN
                    EXECUTE @retcode = dbo.sp_validname @publication

                    IF @retcode <> 0
                    RETURN (1)
                END

            IF NOT EXISTS (SELECT * FROM syspublications WHERE name LIKE @publication)
                BEGIN
                    RAISERROR (20026, 11, -1, @publication)
                    RETURN (1)
                END

        END

    ELSE
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END

    /*
    ** Select all subscribers who subscribe to all articles in the desired
    ** publication.
    */

    SELECT DISTINCT 'subscriber' = sv.srvname
      FROM syspublications p,
           sysarticles s,
           syssubscriptions ss,
           master..sysservers sv
     WHERE p.name LIKE @publication
       AND p.pubid = s.pubid
       AND s.artid = ss.artid
       AND ss.srvid = sv.srvid
       AND NOT EXISTS (SELECT *
                         FROM sysarticles s2
                        WHERE s2.pubid = p.pubid
                          AND NOT EXISTS (SELECT *
                                            FROM syssubscriptions ss2,
                                                 master..sysservers sv2
                                           WHERE s2.artid = ss2.artid
                                             AND ss2.srvid = sv2.srvid
                                             AND sv2.srvid = sv.srvid))
go
 

EXEC dbo.sp_MS_marksystemobject sp_enumfullsubscribers
GO

print ''
print 'Creating procedure sp_addpublication.'
go


CREATE PROCEDURE sp_addpublication (
    @publication sysname,                           /* publication name */
    @taskid int = 0,                                /* backward compatible */
    @restricted nvarchar (10) = 'false',            /* publication security */
    @sync_method nvarchar(13) = 'native',           /* (bcp) native, (bcp) character */
    @repl_freq nvarchar(10) = 'continuous',         /* continuous, snapshot */
    @description nvarchar (255) = NULL,             /* publication description */
    @status nvarchar(8) = 'inactive',               /* publication status; 0=inactive, 1=active */
    @independent_agent nvarchar(5) = 'false',       /* true or false */
    @immediate_sync nvarchar(5) = 'false',          /* true or false */
    @enabled_for_internet nvarchar(5) = 'false',    /* true or false */
    @allow_push nvarchar(5) = 'true',               /* true or false */
    @allow_pull nvarchar(5) = 'false',              /* true or false */
    @allow_anonymous nvarchar(5) = 'false',         /* true or false */
    -- SyncTran
    @allow_sync_tran nvarchar(5) = 'false',        /* true or false */
    @autogen_sync_procs nvarchar(5) = 'true',        /* auto gen sync tran procs per article */
    @retention  int = 72                          /* over weekend - 3 days */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode    int         /* return code value for procedure execution */
    DECLARE @rfid tinyint           /* identifier for replication frequency */
    DECLARE @publish_bit smallint   /* publication bit (flag) in sysobjects */
    DECLARE @smid tinyint           /* identifier for sync method */
    DECLARE @statid tinyint         /* status id based on @status */
    DECLARE @subs_type_id tinyint   /* subscription type id based on @subscription_type */
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @agentname nvarchar (40)
    DECLARE @dbname sysname
    DECLARE @mergepublish_bit smallint
    DECLARE @found int
    DECLARE @independent_agent_id bit
    DECLARE @immediate_sync_id bit
    DECLARE @enabled_for_internet_id bit
    DECLARE @allow_push_id bit
    DECLARE @allow_pull_id bit
    DECLARE @allow_anonymous_id bit
    DECLARE @pubid int
    declare @distgroup sysname

    -- SyncTran
    DECLARE @allow_sync_tran_id bit
    DECLARE @autogen_sync_procs_id bit

    select @allow_sync_tran_id = 0, @autogen_sync_procs_id = 0
    -- end SyncTran

    declare @qv_replication varchar(10)
	declare @qv_replication_unlimited integer
	declare @qv_value_replication integer

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

	/*
	** The default value for TRAN publication is always 72 hours
	*/
	if @retention is NULL
	BEGIN
		RAISERROR(20081, 16, -1, 'retention')
		RETURN (1)
	END
	
	if @retention < 0
	BEGIN
		RAISERROR (20050, 16, -1, 1)
        RETURN(1)
	END

	/*
	** Setting retention period to 0 will cause the default value to be used. 
	** This is also the workaround for DMO bug #49491, where a 0 is incorrectly
	** passed to stored procedure.
	*/
	if @retention = 0
		select @retention = 72
	
    SELECT @publish_bit         = 32
    SELECT @mergepublish_bit    = 4

    /*
    ** Security Check
    */

    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** Check to see if the database has been activated for publication.
    */

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0

    BEGIN
        RAISERROR (14013, 16, -1)
        RETURN (1)
    END

    IF @taskid <> 0
    BEGIN
        -- No longer supported
        RAISERROR (21023, 16, -1,'@taskid')
        RETURN(1)
    END

    /*
    ** Parameter Check: @publication.
    ** The @publication name must conform to the rules for identifiers,
    ** and must not be the keyword 'all'.
    */

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

	exec @retcode = dbo.sp_MSreplcheck_name @publication
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    IF LOWER (@publication) = 'all'
        BEGIN
            RAISERROR (14034, 16, -1)
            RETURN (1)
        END

    /*
    **  Check if the publication already exists.
    **  1. Check transaction-level publications
    **  2. Check merge publications
    */

    IF EXISTS (SELECT * FROM syspublications WHERE name = @publication)
        BEGIN
            RAISERROR (14016, 16, -1, @publication)
            RETURN (1)
        END
    
    if (select category & @mergepublish_bit from master..sysdatabases where name = DB_NAME()) <> 0
        begin
            EXEC @retcode = dbo.sp_helpmergepublication @publication, @found output

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                RETURN (1)
            END

            IF @found <> 0 
            BEGIN
                RAISERROR (20025, 16, -1, @publication)
                RETURN (1)
            END
        end

    /*
    ** Get distribution server information for remote RPC
    ** agent verification.
    */
    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


    /*
    ** Parameter Check: @sync_method
    ** The synchronization method must be one of the following:
    **
    **      0  [bcp] native
    **      1  [bcp] character
    */

    SELECT @sync_method = LOWER(@sync_method)
    IF @sync_method IS NULL OR @sync_method NOT IN ('native', 'character', 'bcp native', 'bcp character')
        BEGIN
            RAISERROR (14014, 16, -1)
            RETURN (1)
        END

    IF @sync_method IN ('character', 'bcp character')
        SELECT @smid = 1
    ELSE
        SELECT @smid = 0

    /*
    ** Parameter Check: @repl_freq.
    ** Make sure that the replication frequency is one of the following:
    **
    **  id  frequency
    **  ==  ==========
    **   0  continuous
    **   1  snapshot
    */

    SELECT @repl_freq = LOWER(@repl_freq)
    IF @repl_freq IS NULL OR @repl_freq NOT IN ('continuous', 'snapshot')
        BEGIN
            RAISERROR (14015, 16, -1)
            RETURN (1)
        END

    IF @repl_freq = 'snapshot' SELECT @rfid = 1
    ELSE SELECT @rfid = 0

    -- disable tran publishing on REPLICATION_LIMITED sku
	exec @qv_value_replication = master.dbo.xp_qv @qv_replication 	
	if (@rfid = 0) and ( @qv_value_replication != @qv_replication_unlimited ) 
    begin
        raiserror(21108, 16, -1)
        return (1)
    end

    /*
    ** Parameter Check:  @restricted.
    */

    IF (@restricted IS NULL) OR (LOWER(@restricted) NOT IN ('true', 'false'))
        BEGIN
            RAISERROR (14017, 16, -1)
            RETURN (1)
        END

    /*
    ** Restricted publications are no longer supported
    */
    IF LOWER(@restricted) = 'true'
    BEGIN
        RAISERROR (14147, 16, -1)
        RETURN(1)
    END

    /*
    ** Parameter Check:  @status.
    ** The @status value can be:
    **
    **      statid  status
    **      ======  ========
    **           0  inactive
    **           1  active
    */

    IF @status IS NULL OR LOWER(@status) NOT IN ('inactive', 'active')
        BEGIN
            RAISERROR (14012, 16, -1)
            RETURN (1)
        END

    IF LOWER(@status) = 'active' SELECT @statid = 1
    ELSE SELECT @statid = 0

    /*
    ** Parameter Check:  @independent_agent.
    */

    IF @independent_agent IS NULL OR LOWER(@independent_agent) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@independent_agent')
            RETURN (1)
        END

    IF LOWER(@independent_agent) = 'true' SELECT @independent_agent_id = 1
    ELSE SELECT @independent_agent_id = 0

    /*
    ** Parameter Check:  @immediate_sync.
    */

    IF @immediate_sync IS NULL OR LOWER(@immediate_sync) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@immediate_sync')
            RETURN (1)
        END

    IF LOWER(@immediate_sync) = 'true' SELECT @immediate_sync_id = 1
    ELSE SELECT @immediate_sync_id = 0

    /*
    ** Parameter Check:  @enabled_for_internet.
    */

    IF @enabled_for_internet IS NULL OR LOWER(@enabled_for_internet) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@enabled_for_internet')
            RETURN (1)
        END

    IF LOWER(@enabled_for_internet) = 'true' SELECT @enabled_for_internet_id = 1
    ELSE SELECT @enabled_for_internet_id = 0

    /*
    ** Parameter Check:  @allow_push.
    */

    IF @allow_push IS NULL OR LOWER(@allow_push) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_push')
            RETURN (1)
        END
    IF LOWER(@allow_push) = 'true' SELECT @allow_push_id = 1
    ELSE SELECT @allow_push_id = 0

    /*
    ** Parameter Check:  @allow_pull.
    */

    IF @allow_pull IS NULL OR LOWER(@allow_pull) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_pull')
            RETURN (1)
        END
    IF LOWER(@allow_pull) = 'true' SELECT @allow_pull_id = 1
    ELSE SELECT @allow_pull_id = 0

    /*
    ** Parameter Check:  @allow_anonymous.
    */

    IF @allow_anonymous IS NULL OR LOWER(@allow_anonymous) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_anonymous')
            RETURN (1)
        END
    IF LOWER(@allow_anonymous) = 'true' SELECT @allow_anonymous_id = 1
    ELSE SELECT @allow_anonymous_id = 0

    /* Immediate_sync publications have to be independent_agent */
    IF @immediate_sync_id = 1 AND @independent_agent_id = 0
    BEGIN
            RAISERROR (21022, 16, -1)
            RETURN (1)
    END


    /* 
    ** Non-immediate sync do not support anonymous subscriptions.
    */

    IF @immediate_sync_id = 0 AND @allow_anonymous_id = 1
    BEGIN
            RAISERROR (20011, 16, -1)
            RETURN (1)
    END

    -- SyncTran
    /*
    ** Parameter Check:  @allow_sync_tran
    */

    IF @allow_sync_tran IS NULL OR LOWER(@allow_sync_tran) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@allow_sync_tran')
        RETURN (1)
    END

    IF LOWER(@allow_sync_tran) = 'true' 
    BEGIN
        SELECT @allow_sync_tran_id = 1

        --Parameter Check:  @autogen_sync_procs
        IF @autogen_sync_procs IS NULL OR LOWER(@autogen_sync_procs) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@autogen_sync_procs')
            RETURN (1)
        END

        IF LOWER(@autogen_sync_procs) = 'true' 
            SELECT @autogen_sync_procs_id = 1
        ELSE 
            SELECT @autogen_sync_procs_id = 0

    END
    ELSE 
    BEGIN
        SELECT @allow_sync_tran_id = 0
        SELECT @autogen_sync_procs_id = 0
    END
    -- end SyncTran

    /*
    ** Get distribution server information for remote RPC call.
    */
    EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
       @distribdb   = @distribdb OUTPUT
    IF @@ERROR <> 0 or @retcode <> 0
    BEGIN
        GOTO UNDO
    END

    /*
    **  Add publication to syspublications.
    */
    begin tran
    save TRAN sp_addpublication

    select @dbname = db_name()
    
    /*
    ** Construct Log Reader agent name.
    */

    IF @rfid = 0 and NOT EXISTS (SELECT * FROM syspublications where repl_freq = 0)
    BEGIN
        /*
        ** Schedule Log Reader agent for the database
        */
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSadd_logreader_agent'


        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = 'ALL',  
            @local_job = 1 
        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO
    END            

    INSERT syspublications(description, name, repl_freq,
                           status, sync_method, snapshot_jobid, independent_agent,
                           immediate_sync, enabled_for_internet, 
                           allow_push, allow_pull, allow_anonymous, immediate_sync_ready,
                           -- SyncTran
                           allow_sync_tran, autogen_sync_procs, retention)

    VALUES (@description, @publication, @rfid, @statid, @smid, NULL, 
            @independent_agent_id, 
            @immediate_sync_id, @enabled_for_internet_id, @allow_push_id,
            @allow_pull_id, @allow_anonymous_id, 0,
            -- SyncTran
            @allow_sync_tran_id, @autogen_sync_procs_id, @retention)

    IF @@ERROR <> 0
    BEGIN
        RAISERROR (14018, 16, -1)
        GOTO UNDO
    END

    SELECT @pubid = @@IDENTITY

    DECLARE @false bit
    SELECT @false = 0

    DECLARE @null sysname
    SELECT @null = NULL

    /*
    ** Add the publication to the distributor side
    */
    SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
        '.dbo.sp_MSadd_publication'
    EXECUTE @retcode = @distproc
    @publisher = @@SERVERNAME,
    @publisher_db = @dbname,
    @publication = @publication,
    @publication_type = @rfid,
    @independent_agent = @independent_agent_id,
    @immediate_sync = @immediate_sync_id,
    @allow_push = @allow_push_id,
    @allow_pull = @allow_pull_id,
    @allow_anonymous = @allow_anonymous_id,
    @snapshot_agent = @null,
    @logreader_agent = @agentname,
    @description = @description,
    @retention = @retention

    IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            GOTO UNDO
        END

    -- Populate the initial list.
	exec @retcode = dbo.sp_grant_publication_access 
		@publication = @publication,
		@login = null,
		@reserved = 'init'
	IF @@error <> 0 OR @retcode <> 0
		GOTO UNDO

    COMMIT TRAN

    RETURN(0)

UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_addpublication
        COMMIT TRAN   
    end
    return 1
go
 
EXEC dbo.sp_MS_marksystemobject sp_addpublication
GO

print ''
print 'Creating procedure sp_changepublication'
go

CREATE PROCEDURE sp_changepublication (
    @publication sysname = NULL,        /* Publication name */
    @property nvarchar(20) = NULL,           /* The property to change */
    @value nvarchar(255) = NULL              /* The new property value */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @cmd nvarchar(255)
    DECLARE @cmd2 nvarchar(255)
    DECLARE @pubid int
    DECLARE @replfreqid tinyint
    DECLARE @retcode int
    DECLARE @statusid tinyint
    DECLARE @syncmethodid tinyint
    DECLARE @distributor sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @subscribed int    
    DECLARE @virtual_id smallint
    DECLARE @prev_value_bit bit
    DECLARE @value_bit bit
    DECLARE @allow_anonymous bit
    DECLARE @push int
    DECLARE @pull int
    DECLARE @independent_agent bit
    DECLARE @immediate_sync bit
    DECLARE @distribdb sysname
    DECLARE @dbname sysname
    DECLARE @taskid int
    DECLARE @add_virtual_back bit


    SELECT @add_virtual_back = 0
    SELECT @push = 0
    SELECT @pull = 1

    SELECT @subscribed = 1
    SELECT @virtual_id = -1

    /*
    ** Security Check
    */

    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** Check to see if the database has been activated for publication.
    */

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0

    BEGIN
        RAISERROR (14013, 16, -1)
        RETURN (1)
    END

    
    /*
    ** Parameter Check:  @property.
    ** If the @property parameter is NULL, print the options.
    */

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname NOT NULL)
            INSERT INTO #tab1 VALUES ('description')
            --INSERT INTO #tab1 VALUES ('taskid')
            INSERT INTO #tab1 VALUES ('sync_method')
            INSERT INTO #tab1 VALUES ('status')
            INSERT INTO #tab1 VALUES ('repl_freq')
            INSERT INTO #tab1 VALUES ('independent_agent')
            INSERT INTO #tab1 VALUES ('immediate_sync')
            INSERT INTO #tab1 VALUES ('enabled_for_internet')
            INSERT INTO #tab1 VALUES ('allow_push')
            INSERT INTO #tab1 VALUES ('allow_pull')
            INSERT INTO #tab1 VALUES ('allow_anonymous')
            INSERT INTO #tab1 VALUES ('retention')
            PRINT ''
            SELECT * FROM #tab1
            RETURN (0)
        END

    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

    SELECT @allow_anonymous = allow_anonymous, @pubid = pubid,
        @immediate_sync = immediate_sync,
        @independent_agent = independent_agent
        FROM syspublications 
        WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END
    ELSE

    /*
    ** Parameter Check:  @property.
    ** Check to make sure that @property is a valid property in
    ** syspublications.
    */

    -- Note: must change message 14078 when adding a new property.
    IF LOWER(@property) NOT IN ( 'taskid','description', 'sync_method',
     'status', 'repl_freq','immediate_sync', 'independent_agent', 
     'enabled_for_internet', 'allow_push', 'allow_pull', 'allow_anonymous', 'retention')
        BEGIN
            RAISERROR (14078, 16, -1)
            RETURN (1)
        END

    /*
    ** Change the property.
    */
    begin tran
    save TRAN sp_changepublication

    IF LOWER(@property) ='description'
        BEGIN
            UPDATE syspublications SET description = @value
                WHERE pubid = @pubid
            IF @@ERROR <> 0 GOTO UNDO
        END
        
    IF LOWER(@property) ='retention'
        BEGIN
        	if @value is NULL 
        		BEGIN
        			RAISERROR(20081, 16, -1, @property)
        			GOTO UNDO
        		END
        		
            UPDATE syspublications SET retention = convert(int, @value)
                WHERE pubid = @pubid
            IF @@ERROR <> 0 GOTO UNDO
        END
   

    IF LOWER(@property) = 'taskid'
       BEGIN
            -- No longer supported
            RAISERROR (21023, 16, -1,'@taskid')
            RETURN(1)
       END

    IF LOWER(@property) = 'sync_method'
        BEGIN

            /*
            ** Check for a valid synchronization method.
            */

            IF LOWER(@value) NOT IN ('native', 'character', 'bcp native', 'bcp character')
                BEGIN
                    RAISERROR (14014, 16, -1)
                    GOTO UNDO
                END

            /*
            ** Determine the integer value for the sync_method.
            */

            IF LOWER(@value) IN ('native', 'bcp native')
                SELECT @syncmethodid = 0
            ELSE IF LOWER(@value) IN ('character', 'bcp character')
                SELECT @syncmethodid = 1

            /*
            ** Update the publication with the new synchronization method.
            */

            UPDATE syspublications
               SET sync_method = @syncmethodid
             WHERE pubid = @pubid

            IF @@ERROR <> 0 GOTO UNDO

        END

    IF LOWER(@property) = 'status'
        BEGIN
            
            /*
            ** Check to make sure that we have a valid status.
            */

            IF LOWER(@value) NOT IN ('active', 'inactive')
                BEGIN
                    RAISERROR (14012, 16, -1)
                    GOTO UNDO
                END

            /*
            ** Determine the integer value for the status.
            */

            IF LOWER(@value) = 'active'
                SELECT @statusid = 1
            ELSE
                SELECT @statusid = 0

            /* If status changed */
            IF EXISTS (SELECT * FROM syspublications
                WHERE  pubid = @pubid  AND
                 status <> @statusid)
            BEGIN
    
                /* 
                ** If change the status of the publication,
                ** virtual anonymous subscription have to be recreated.
                **
                */
                IF @allow_anonymous = 1
                BEGIN
                    /* Drop virtual subscriptions */
                    EXEC @retcode = dbo.sp_dropsubscription 
                        @publication = @publication, 
                        @article = 'all', 
                        @subscriber = NULL,
                        @reserved = 'internal'
                    IF @@ERROR <> 0 OR @retcode <> 0
                    BEGIN
                        GOTO UNDO
                    END
                END

                /*
                ** Update the publication with the new status.
                */

                UPDATE syspublications
                   SET status = @statusid
                 WHERE pubid = @pubid

                IF @@ERROR <> 0 
                BEGIN
                    GOTO UNDO                
                END
                
                IF @allow_anonymous = 1
                    SELECT @add_virtual_back = 1
            END
        END

    IF LOWER(@property) = 'repl_freq'
        BEGIN

            /*
            ** Check for a valid replication frequency value.
            */

            IF LOWER(@value) NOT IN ('continuous', 'snapshot')
                BEGIN
                    RAISERROR (14015, 16, -1)
                    GOTO UNDO
                END


            /*
            ** Determine the integer value for the replication frequency.
            */

            IF LOWER(@value) = 'continuous'
                SELECT @replfreqid = 0
            ELSE
                SELECT @replfreqid = 1

            /*
            ** Only unsubscribed publications may have this modified.
            */
            IF EXISTS (SELECT * FROM syssubscriptions
            WHERE 
                status <> @subscribed AND
                srvid >= 0 AND
                artid IN (SELECT artid FROM sysarticles where pubid
               = @pubid))
            BEGIN
                RAISERROR (14033, 11, -1)
                GOTO UNDO
            END


            IF @immediate_sync = 1
            BEGIN
                /* Drop virtual subscriptions */
                EXEC @retcode = dbo.sp_dropsubscription 
                    @publication = @publication, 
                    @article = 'all', 
                    @subscriber = NULL,
                    @reserved = 'internal'
                IF @@ERROR <> 0 OR @retcode <> 0
                BEGIN
                    GOTO UNDO                
                END
            END
            /*
            ** Update the publication with the new replication frequency.
            */

            UPDATE syspublications
               SET repl_freq = @replfreqid
             WHERE pubid = @pubid

            IF @@ERROR <> 0 
            BEGIN
                GOTO UNDO
            END

            IF @immediate_sync = 1
                SELECT @add_virtual_back = 1
        END

    
    IF LOWER(@property) IN ('independent_agent', 'immediate_sync','enabled_for_internet',
            'allow_push', 'allow_pull', 'allow_anonymous')
    BEGIN

    
        /*
        ** Check for a valid  value.
        */

        IF LOWER(@value) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14137, 16, -1)
            GOTO UNDO
        END

        /*
        ** set value bit
        */

        IF LOWER(@value) = 'true'
            SELECT @value_bit = 1
        ELSE 
            SELECT @value_bit = 0


        IF LOWER(@property) = 'independent_agent'
        BEGIN


            SELECT @prev_value_bit = independent_agent
              FROM syspublications 
             WHERE name = @publication

            IF @prev_value_bit <> @value_bit
            BEGIN

               IF @immediate_sync = 1 AND @value_bit = 0
               BEGIN
                    RAISERROR (21022, 16, -1)
                    GOTO UNDO
               END    

               /* 
               ** no subscriptions are allowed
               */
               IF EXISTS (SELECT * FROM syssubscriptions ss, sysarticles sa
                        WHERE ss.artid = sa.artid
                        AND   sa.pubid = @pubid
                        AND   ss.srvid <> @virtual_id )
                BEGIN
                    RAISERROR (20013, 16, -1, @property)
                    GOTO UNDO
                END
            
                /* Update the publication type */
                UPDATE syspublications 
                    SET independent_agent = @value_bit
                    WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END
            END
        END

        IF LOWER(@property) = 'immediate_sync'
        BEGIN


            SELECT @prev_value_bit = immediate_sync
              FROM syspublications 
             WHERE name = @publication

            IF @prev_value_bit <> @value_bit
            BEGIN

               IF @independent_agent = 0 AND @value_bit = 1
               BEGIN
                    RAISERROR (21022, 16, -1)
                    GOTO UNDO
               END    

               /* 
               ** The publication has to be immediate_sync type to
               ** allow anonymous subscriptions
               */
                IF @value_bit = 0 AND
                    EXISTS (SELECT * FROM syspublications
                        WHERE pubid = @pubid
                        AND   allow_anonymous = 1 )
                BEGIN
                    RAISERROR (20011, 16, -1, @property)
                    GOTO UNDO
                END

            
                /* 
                ** If turn on immediate_sync, we need to add virtual subscriptions,
                ** Otherwise, we need to drop them
                ** When adding, we need to change publication bit first
                ** When dropping, we need to change publication bit second
                */
                IF @value_bit = 0
                BEGIN
                    -- Drop virtual subscriptions 
                    EXEC @retcode = dbo.sp_dropsubscription 
                        @publication = @publication, 
                        @article = 'all', 
                        @subscriber = NULL,
                        @reserved = 'internal'
                    IF @@ERROR <> 0 OR @retcode <> 0
                    BEGIN
                        GOTO UNDO
                    END

                    -- Reset the immediate_sync ready bit
                    UPDATE syspublications 
                        SET immediate_sync_ready = 0
                        WHERE pubid = @pubid

                END

                /* Update the publication type */
                UPDATE syspublications 
                    SET immediate_sync = @value_bit
                    WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END


                IF @value_bit = 1
                    SELECT @add_virtual_back = 1
            END
        END

        IF LOWER(@property) = 'allow_anonymous'
        BEGIN

            SELECT @prev_value_bit = allow_anonymous
              FROM syspublications 
             WHERE name = @publication

            IF @prev_value_bit <> @value_bit
            BEGIN
                /* 
                ** The publication has to be immediate_sync type to
                ** allow anonymous subscriptions
                */
                IF @value_bit = 1 AND
                    NOT EXISTS (SELECT * FROM syspublications
                        WHERE pubid = @pubid
                        AND   immediate_sync = 1 )
                BEGIN
                    RAISERROR (20011, 16, -1, @property)
                    GOTO UNDO
                END
                
                

                /* Drop virtual subscriptions */
                EXEC @retcode = dbo.sp_dropsubscription 
                    @publication = @publication, 
                    @article = 'all', 
                    @subscriber = NULL,
                    @reserved = 'internal'
                IF @@ERROR <> 0 OR @retcode <> 0
                BEGIN
                    GOTO UNDO
                END

                /* Update the publication type */
                UPDATE syspublications 
                    SET allow_anonymous = @value_bit
                    WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                   GOTO UNDO
                END

                /* 
                ** add virtual subscriptions back again to enable 
                ** anonymous subscription.
                */
                SELECT @add_virtual_back = 1

            END

        END

        IF LOWER(@property) = 'enabled_for_internet'
        BEGIN

            /* Update the publication type */
            UPDATE syspublications 
                SET enabled_for_internet = @value_bit
                WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

        IF LOWER(@property) = 'allow_push'
        BEGIN

           /* 
           ** If turn it off, make sure there's no push subscriptions left
           */
           IF @value_bit = 0 AND
            EXISTS (SELECT * FROM syssubscriptions ss, sysarticles sa
                    WHERE ss.artid = sa.artid
                    AND   sa.pubid = @pubid
                    AND      ss.subscription_type = @push
                    AND   ss.srvid <> @virtual_id )
            BEGIN
                RAISERROR (20012, 16, -1)
                GOTO UNDO
            END

            
            /* Update the publication type */
            UPDATE syspublications 
                SET allow_push = @value_bit
                WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

        IF LOWER(@property) = 'allow_pull'
        BEGIN
           /* 
           ** If turn it off, make sure there's no pull subscriptions left
           */
           IF @value_bit = 0 AND
            EXISTS (SELECT * FROM syssubscriptions ss, sysarticles sa
                    WHERE ss.artid = sa.artid
                    AND   sa.pubid = @pubid
                    AND      ss.subscription_type = @pull
                    AND   ss.srvid <> @virtual_id )
            BEGIN
                RAISERROR (20013, 16, -1, @property)
                GOTO UNDO
            END
            /* Update the publication type */
            UPDATE syspublications 
                SET allow_pull = @value_bit
                WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    END

    /* Update publication property at the distributor side if necessary */
    IF LOWER(@property) IN ('description', 'repl_freq', 'independent_agent',
        'immediate_sync', 'allow_push',
        'allow_pull', 'allow_anonymous','retention')
    BEGIN
        /* Translate the property names and values  */
        IF LOWER(@property) = 'repl_freq'
        BEGIN
            SELECT @property = 'publication_type'
            SELECT @value = STR(@replfreqid)
        END

        /* Translate values */
        IF LOWER(@value) = 'true'
            SELECT @value = '1'
        ELSE IF LOWER(@value) = 'false'
            SELECT @value = '0'

        /*
        ** Get distribution server information for remote RPC call.
        */
        EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
           @distribdb   = @distribdb OUTPUT
        IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                GOTO UNDO
            END

        SELECT @dbname =  DB_NAME()
        
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
            '.dbo.sp_MSchange_publication'
    
        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = @publication,
            @property = @property,
            @value = @value

        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            GOTO UNDO
        END
    END
    
    IF @add_virtual_back = 1    
    BEGIN
        /* Add virtual subscriptions back*/
        EXEC @retcode = dbo.sp_addsubscription 
            @publication = @publication, 
            @article = 'all',
            @subscriber = NULL,
            @destination_db = 'virtual',
            @sync_type = 'automatic',
            @status = NULL, 
            @reserved = 'internal'
        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            GOTO UNDO                    
        END
    END

    COMMIT TRAN


    /*
    ** Return succeed.
    */

    RAISERROR (14077, 10, -1)
    RETURN (0)

UNDO:
    IF @@TRANCOUNT > 0
    begin 
        ROLLBACK TRAN sp_changepublication
        COMMIT TRAN
    end
GO
 
EXEC dbo.sp_MS_marksystemobject sp_changepublication
GO

print ''
print 'Creating procedure sp_changesubscription'
GO
/* This function should be disallowed */
CREATE PROCEDURE sp_changesubscription (
    @publication sysname = NULL,        /* Publication name */
    @article sysname = NULL,            /* Article name */
    @subscriber sysname,              /* Subscriber name */
    @property nvarchar(15) = NULL,           /* The property to change */
    @value nvarchar(255) = NULL              /* The new property value */
    ) AS

    SET NOCOUNT ON
    RAISERROR (21023, 16, -1,'sp_changesubscription')
    RETURN(1)
go
 
dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_changesubscription
GO


print ''
print 'Creating procedure sp_helparticle'
go

CREATE PROCEDURE sp_helparticle (
    @publication sysname,         /* The publication name */
    @article sysname = '%',       /* The article name */
    @returnfilter bit = 1         /* Return filter flag */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @pubid int
    DECLARE @retcode int
    DECLARE @subscriber_bit smallint
    DECLARE @publish_bit int
    DECLARE @source_object  sysname
    DECLARE @source_owner   sysname
    
    SELECT @publish_bit = 1

    /*
    ** Security Check. To public.
    
    */
    /*
    ** Check if the database is published.
    */
    IF NOT EXISTS (SELECT * FROM master..sysdatabases
        WHERE name = db_name()
        AND (category & @publish_bit) = @publish_bit)
        RETURN(0)

    /*
    ** Initializations.
    */

    SELECT @subscriber_bit = 4

    IF @publication IS NOT NULL
        SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    /*
    ** Create a temporary table to hold all information.
    */

    CREATE TABLE #tab1 (
        artid               int             NOT NULL,
        columns             varbinary(32)   NOT NULL,
        creation_script     nvarchar(255)   NULL,
        del_cmd             nvarchar(255)   NULL,
        description         nvarchar(255)   NULL,
        dest_table          sysname         NULL,
        old_filter          int             NULL,
        ins_cmd             nvarchar(255)   NULL,
        name                sysname         NOT NULL,
        objid               int             NOT NULL,
        pubid               int             NOT NULL,
        status              tinyint         NOT NULL,
        sync_objid          int             NOT NULL,
        type                tinyint         NOT NULL,
        upd_cmd             nvarchar(255)   NULL,
        source_table        nvarchar(257)   NULL,      /* converted from objid */
        filter              nvarchar(257)   NULL,      /* converted from old_filter */
        sync_object         nvarchar(257)   NULL,      /* converted from sync_objid */
        vpartition          bit             NOT NULL,   /* computed */
        pre_creation_cmd    tinyint     NOT NULL,
        filter_clause       ntext           NULL,
        schema_option       binary(8)       NULL,
        dest_owner          sysname         NULL,
        source_owner        sysname         NULL,   /* these two columns are for 7.0 use only */
        unqua_source_object sysname         NULL,   /* column source_table stays due to backward compatibility */
        sync_object_owner   sysname         NULL,
        unqua_sync_object   sysname         NULL,
        filter_owner        sysname         NULL,
        unqua_filter        sysname         NULL
    )

    CREATE UNIQUE INDEX idx1 ON #tab1 (name, pubid)

    /*
    ** Parameter Check:  @publication.
    ** Check to make sure that there are some articles
    ** to display.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    IF NOT EXISTS (SELECT * FROM syspublications WHERE name = @publication)
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

    /*
    ** Parameter Check:  @article.
    ** Check to make sure that the article exists, that it conforms
    ** to the rules for identifiers, and that it isn't NULL.
    */

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

    IF @article <> '%'
        BEGIN

            /*
            EXECUTE @retcode = dbo.sp_validname @article

            IF @retcode <> 0
            RETURN (1)
            */

            IF NOT EXISTS (SELECT *
                             FROM sysarticles
                            WHERE name = @article
                              AND pubid IN (SELECT pubid
                                              FROM syspublications
                                             WHERE name = @publication))
                BEGIN
                    RAISERROR (20027, 11, -1, @article)
                    RETURN (1)
                END

        END

        
    IF @returnfilter = 1
    BEGIN
        INSERT INTO #tab1 (artid, columns, creation_script, del_cmd,
                           description, dest_table, old_filter,
                           ins_cmd, name, objid, pubid, status,
                           sync_objid, type, upd_cmd, source_table,
                           filter, vpartition, pre_creation_cmd,
               filter_clause, schema_option, dest_owner, source_owner, unqua_source_object, 
               sync_object_owner, unqua_sync_object, filter_owner, unqua_filter)
               
         (SELECT artid, columns, creation_script, del_cmd, a.description,
                 dest_table, filter, ins_cmd, a.name, objid, a.pubid,
                 a.status, sync_objid, a.type, upd_cmd, NULL, NULL, 0,
                a.pre_creation_cmd, a.filter_clause, a.schema_option, a.dest_owner, 
                user_name(o.uid), o.name, 
                user_name(sync.uid), sync.name,
                user_name(fltr.uid), fltr.name
            FROM syspublications b, sysobjects o, sysobjects sync, sysarticles a LEFT JOIN sysobjects fltr on a.filter = fltr.id
           WHERE a.name LIKE @article
             AND a.objid = o.id
             AND a.sync_objid = sync.id
             AND a.pubid = b.pubid
             AND b.name = @publication)
    END
    ELSE
    BEGIN
        INSERT INTO #tab1 (artid, columns, creation_script, del_cmd,
                           description, dest_table, old_filter,
                           ins_cmd, name, objid, pubid, status,
                           sync_objid, type, upd_cmd, source_table,
                           filter, vpartition, pre_creation_cmd,
               filter_clause, schema_option, dest_owner, source_owner, unqua_source_object, 
               sync_object_owner, unqua_sync_object, filter_owner, unqua_filter)
         (SELECT artid, columns, creation_script, del_cmd, a.description,
                 dest_table, filter, ins_cmd, a.name, objid, a.pubid,
                 a.status, sync_objid, a.type, upd_cmd, NULL, NULL, 0,
                 a.pre_creation_cmd, NULL, schema_option, dest_owner, 
                 user_name(o.uid), o.name,
                 user_name(sync.uid), sync.name,
                 user_name(fltr.uid), fltr.name
           FROM syspublications b, sysobjects o, sysobjects sync, sysarticles a LEFT JOIN sysobjects fltr on a.filter = fltr.id
           WHERE a.name LIKE @article
             AND a.objid = o.id
             AND a.sync_objid = sync.id
             AND a.pubid = b.pubid
             AND b.name = @publication)
    END

    UPDATE #tab1
       SET source_table = QUOTENAME(u.name) + '.' + QUOTENAME(o.name)
      FROM #tab1, sysobjects o, sysusers u
     WHERE o.id = #tab1.objid
       AND o.uid = u.uid

    UPDATE #tab1
        SET unqua_sync_object = sysobjects.name
        from sysobjects 
        where sysobjects.id = sync_objid

    UPDATE #tab1
       SET sync_object = QUOTENAME(sysusers.name) + '.' + QUOTENAME(sysobjects.name)
      FROM sysobjects, sysusers
     WHERE sysobjects.id = sync_objid
       AND sysobjects.uid = sysusers.uid

    UPDATE #tab1 SET filter = (SELECT sysusers.name + '.' + sysobjects.name
                                 FROM sysobjects, sysusers
                                WHERE sysobjects.id = #tab1.old_filter
                                  AND sysobjects.uid = sysusers.uid)
      FROM #tab1

    DECLARE hC  CURSOR LOCAL FAST_FORWARD FOR SELECT name, pubid FROM #tab1
    OPEN hC
    FETCH hC INTO @article, @pubid
    WHILE (@@fetch_status <> -1)
        BEGIN
            IF EXISTS (SELECT *
                         FROM sysarticles a, syscolumns b
                         WHERE 
                          ( 
                           convert(bit, convert( varbinary, substring( convert( nvarchar, a.columns ), 16 - floor((colid-1)/16),1 )) & power( 2, ((colid-1)%16))) = 0
                           OR convert(bit, convert( varbinary, substring( convert( nvarchar, a.columns ), 16 - floor((colid-1)/16),1 )) & power( 2, ((colid-1)%16))) IS NULL
                          )
                          AND a.objid = b.id
                          AND a.name = @article
                          AND a.pubid = @pubid)

                UPDATE #tab1
                   SET vpartition = 1
                 WHERE name = @article
                   AND pubid = @pubid

            FETCH hC INTO @article, @pubid
        END
    CLOSE hC
    DEALLOCATE hC

    IF @returnfilter = 1
        SELECT 'article id'                = artid,
           'article name'              = name,
           'base object'                = source_table,
           'destination object'         = dest_table,
           'synchronization object'    = sync_object,
           'type'                      = type,
           'status'                    = status,
           'filter'                    = filter,
           'description'               = description,
           'insert_command'            = ins_cmd,
           'update_command'            = upd_cmd,
           'delete_command'            = del_cmd,
           'creation script path'      = creation_script,
           'vertical partition'        = vpartition,
           'pre_creation_cmd'       = pre_creation_cmd,
           'filter_clause'           = filter_clause,
           'schema_option'            = schema_option,
           'dest_owner'             = dest_owner,
           'source_owner'           = source_owner,
           'unqua_source_object'    = unqua_source_object,
           'sync_object_owner'      = sync_object_owner,
           'unqualified_sync_object' = unqua_sync_object,
           'filter_owner'           = filter_owner,
           'unqua_filter'           = unqua_filter
          FROM #tab1
         ORDER BY 2
    ELSE
        SELECT 'article id'                = artid,
           'article name'                   = name,
           'base object'                 = source_table,
           'destination object'          = dest_table,
           'synchronization object'      = sync_object,
           'type'                          = type,
           'status'                     = status,
           'filter'                        = filter,
           'description'                   = description,
           'insert_command'              = ins_cmd,
           'update_command'              = upd_cmd,
           'delete_command'              = del_cmd,
           'creation script path'        = creation_script,
           'vertical partition'          = vpartition,
           'pre_creation_cmd'            = pre_creation_cmd,
           'filter_clause'                = NULL,
           'schema_option'                = schema_option,
           'dest_owner'                 = dest_owner,
           'source_owner'               = source_owner,
           'unqualified_source_object'  = unqua_source_object,
           'sync_object_owner'      = sync_object_owner,
           'unqualified_sync_object' = unqua_sync_object,
           'filter_owner'           = filter_owner,
           'unqualified_filter'         = unqua_filter
           
       FROM #tab1
         ORDER BY 2
    RETURN (0)
go

dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_helparticle
GO

print ''
print 'Creating procedure sp_articlecolumn'
go
CREATE PROCEDURE sp_articlecolumn (
        @publication sysname,           /* The publication name */
        @article sysname,               /* The article name */
        @column sysname = NULL,         /* The column name */
        @operation nvarchar(4) = 'add'      /* Add or delete a column */
        -- synctran
        , @refresh_synctran_procs bit = 1      -- refresh synctran procs or not
		, @ignore_distributor bit = 0
        ) AS

    /*
    ** Declarations.
    */

    DECLARE @bit tinyint                /* Bit offset */
    --DECLARE @byte tinyint               /* Byte offset */
    DECLARE @word tinyint               /* word offset */
    DECLARE @cnt tinyint, @idx tinyint  /* Loop counter, index */
    DECLARE @columns binary(32)         /* Temporary storage for the converted column */
    DECLARE @mask binary(2)              /* Bit mask to set the bit on */
    DECLARE @mval int
--    DECLARE @newbyte binary(1)          /* New byte to replace old byte with */
--    DECLARE @oldbyte binary(1)          /* Temporary storage for original byte */
    DECLARE @newword binary(2)
    DECLARE @oldword binary(2)
    DECLARE @pubid int                  /* Publication identification number */
    DECLARE @retcode int                /* Return code for stored procedures */
--    DECLARE @zero binary(32)            /* Constant:  0 */
    DECLARE @artid int
    DECLARE @inactive tinyint
    DECLARE @objid int            /* Article base table id */    
    DECLARE @tablename  sysname

    select @inactive = 0

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

    /*
    ** Check to see if the database has been activated for publication.
	** Do not check if @ignore_distributor indicates brute force cleanup.
    */

    IF ( (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0 )  and ( @ignore_distributor = 0 )

    BEGIN
            RAISERROR (14013, 16, -1)
        RETURN (1)
    END

    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists and that it conforms to the
    ** rules for identifiers.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
            RETURN (1)

    SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END
    ELSE

    /*
    ** Parameter Check:  @article.
    ** Check to make sure that the article exists in the publication.
    */

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

    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @@ERROR <> 0 OR @retcode <> 0
    RETURN (1)
    */

    /*
    ** Make sure the article exists.
    */
    SELECT @artid = artid FROM sysarticles
       WHERE pubid = @pubid AND name = @article
    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END

    /*
    ** Only unsubscribed articles may be modified. (excluding virtual subscriptions)
    */
    IF EXISTS (SELECT * FROM syssubscriptions WHERE artid = @artid
       AND status <> @inactive
       AND srvid >= 0)
        BEGIN
            RAISERROR (14092, 11, -1)
            RETURN (1)
        END

    /*
    ** Error out if this is a not a table based article
    */
    IF NOT EXISTS ( SELECT * FROM sysarticles WHERE artid = @artid
                      AND pubid = @pubid
                      AND (type & 1) = 1 )
        BEGIN
            RAISERROR (14112, 11, -1 )
            RETURN (1)
        END

    /*
    ** Parameter Check:  @column.
    ** Check to make sure that the column exists and conforms to the rules
    ** for identifiers.
    */

    /*
    IF @column IS NOT NULL
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @column
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END
    */

    /*
    ** Parameter Check:  @operation.
    ** The operation can be either 'add' or 'drop'.
    */

    IF LOWER(@operation) NOT IN ('add', 'drop')
        BEGIN
            RAISERROR (14019, 16, -1)
            RETURN (1)
        END
        
    SELECT @objid = (SELECT objid FROM sysarticles WHERE artid = @artid)
    SELECT @tablename = OBJECT_NAME(@objid)
    
    begin tran
    save TRANSACTION articlecolumn

    /*
    ** Make sure that the columns column is not NULL.
    */

--    SELECT @zero = 0x00

    SELECT @columns = columns
      FROM sysarticles
     WHERE artid = @artid

    IF @columns IS NULL
        UPDATE sysarticles
           SET columns = 0x00
         WHERE artid = @artid

    /*
    ** If no columns are specified, or if NULL is specified, set all
    ** the bits in the 'columns' column so all columns will be included.
    */

    IF @column IS NULL

        BEGIN

            /*
            ** Fetch the number of columns affected.
            */

            SELECT @cnt = COUNT(*), @idx = 1
              FROM syscolumns
             WHERE id = @objid

            SELECT @columns = 0x00

            WHILE @idx <= @cnt
                BEGIN

                    SELECT @word = CONVERT(tinyint, 16 - FLOOR((@idx-1)/16))
                    SELECT @bit = (@idx-1) % 16

                    IF LOWER(@operation) = 'add'
                        SELECT @mval = POWER(2, @bit)
                    ELSE
                        SELECT @mval = ~POWER(2, @bit)

                    SELECT @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )

                    SELECT @oldword = CONVERT( binary(2), SUBSTRING( CONVERT( nvarchar,@columns), @word, 1) )

                    IF @oldword IS NULL SELECT @oldword = 0x0000

                    IF LOWER(@operation) = 'add'
                        SELECT @newword = CONVERT(binary(2), convert(smallint, @oldword) | @mask)
                    ELSE
                        SELECT @newword = CONVERT(binary(2), convert(smallint, @oldword ) & @mask)

                    SELECT @columns = CONVERT(binary(32), STUFF( convert(nchar(16),@columns), @word, 1, convert( nchar(1), @newword)))
                    SELECT @idx = @idx + 1


                END

            IF LOWER(@operation) = 'drop'
           BEGIN
               /* Update Text\Image column status as not published */

               EXECUTE @retcode = dbo.sp_MSarticletextcol @artid, NULL,
                  'publish', @operation
               IF (@@error <> 0 OR @retcode <> 0)
               BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRANSACTION articlecolumn
                        commit tran
                    end
                   RAISERROR (14020, 16, -1)
                   RETURN (1)
               END
           END

            UPDATE sysarticles
               SET columns = @columns
             WHERE name = @article
               AND pubid = @pubid

            IF LOWER(@operation) = 'add'
           BEGIN

               /* Update Text\Image column status as published */
              EXECUTE @retcode = dbo.sp_MSarticletextcol @artid, NULL,
                 'publish', @operation
              IF (@@error <> 0 OR @retcode <> 0)
              BEGIN
                if @@trancount > 0
                begin
                  ROLLBACK TRANSACTION articlecolumn
                  commit tran
                end
                RAISERROR (14020, 16, -1)
                RETURN (1)
              END

           END
        END

    ELSE

        BEGIN
                IF EXISTS (SELECT *
                             FROM sysarticles
                            WHERE name = @article
                              AND pubid = @pubid
                              AND columns IS NULL)

                        UPDATE sysarticles
                          SET columns = 0x00
                        WHERE name = @article
                          AND pubid = @pubid

                DECLARE @columnid smallint   /* Columnid-1 = bit to set */

                /*
                ** Get the column id for this column.  We'll use the column id
                ** to determine the bit in the 'columns' column.  The bit we want
                ** is equal to the columnid - 1.
                */

                SELECT @columnid = colid
                  FROM syscolumns
                 WHERE id = @objid AND name = @column

                IF ((@@error <> 0) OR (@columnid IS NULL))
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION articlecolumn
                            commit tran
                        end
                        RAISERROR (14020, 16, -1)
                        RETURN (1)
                    END

				-- If the publication is allow_sync_tran, we cannot drop the timestamp
				-- column from the partition.
				if exists (select * from syspublications where name = @publication and
					allow_sync_tran = 1) and LOWER(@operation) = 'drop'
				begin
					declare @ts_col sysname
					exec dbo.sp_MSis_col_replicated @publication, @article, 
						'timestamp', @ts_col OUTPUT 
					if @ts_col = @column
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION articlecolumn
                            commit tran
                        end
                        RAISERROR (21080, 16, -1)
                        RETURN (1)
                    END
				end


                /*
                ** Obtain the byte offset and the bit offset, then set the
                ** mask column for the bit we want to turn on.
                */

                SELECT @word = CONVERT(tinyint, 16 - FLOOR((@columnid-1)/16))
                SELECT @bit = (@columnid-1) % 16

                IF LOWER(@operation) = 'add'
                    SELECT @mval = POWER(2, @bit)
                ELSE
                    SELECT @mval = ~POWER(2, @bit)
   
                select @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )

                /*
                ** Save the columns column in a temporary local variable so we
                ** can twiddle the bit and then put it back into the table.
                */

                SELECT @columns = columns
                  FROM sysarticles
                 WHERE name = @article
                   AND pubid = @pubid

                /*
                ** Fish out the byte we're interested in and save it in a
                ** a temporary local variable.  If it's NULL, just set it
                ** to 0.  Then apply the bitwise operator OR to twiddle the
                ** bit in the old byte and save it in another temporary
                ** local variable @newbyte.
                */
                SELECT @oldword = CONVERT( binary(2), SUBSTRING( CONVERT( nvarchar,@columns), @word, 1) )

                IF @oldword IS NULL SELECT @oldword = 0x0000

                IF LOWER(@operation) = 'add'
                    SELECT @newword = CONVERT(binary(2), convert(smallint, @oldword) | @mask)
                ELSE
                    SELECT @newword = CONVERT(binary(2), convert(smallint, @oldword ) & @mask)

                SELECT @columns = CONVERT(binary(32), STUFF( convert(nchar(16),@columns), @word, 1, convert( nchar(1), @newword)))
                SELECT @idx = @idx + 1

               IF LOWER(@operation) = 'drop'
               BEGIN

                   /* Update Text\Image column status as not published */
                  EXECUTE @retcode = dbo.sp_MSarticletextcol @artid, @columnid,
                     'publish', @operation
                  IF (@@error <> 0 OR @retcode <> 0)
                  BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRANSACTION articlecolumn
                        commit tran
                    end
                     RAISERROR (14021, 16, -1)
                     RETURN (1)
                  END



               END

                /*
                ** Update the sysarticles table.  Set the bit to 1 for the
                ** selected column.
                */

                UPDATE sysarticles
                   SET columns = @columns
                 WHERE name = @article
                   AND pubid = @pubid

                IF @@error <> 0
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION articlecolumn
                            commit tran
                        end
                        RAISERROR (14021, 16, -1)
                        RETURN (1)
                    END

               IF LOWER(@operation) = 'add'
               BEGIN

                   /* Update Text\Image column status as not published */
                  EXECUTE @retcode = dbo.sp_MSarticletextcol @artid, @columnid,
                     'publish', @operation
                  IF (@@error <> 0 OR @retcode <> 0)
                  BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRANSACTION articlecolumn
                        commit tran
                    end
                     RAISERROR (14021, 16, -1)
                     RETURN (1)
                  END

               END
        END

    -- Synctran
    /*
    ** If publication is enabled for Synctran and sprocs are auto-generated - regenerate them
    */
    declare @autogen_sync_procs_id bit
    declare @ins_proc_id int, @upd_proc_id int, @del_proc_id int
    declare @ins_proc sysname, @upd_proc sysname, @del_proc sysname, @owner sysname, @objname sysname
    declare @sync_pubid int
    declare @cmd nvarchar(4000)

    select @autogen_sync_procs_id = autogen_sync_procs, @sync_pubid = pubid
    from syspublications where name = @publication

    if  @autogen_sync_procs_id = 1 and @refresh_synctran_procs = 1 
    begin
        -- Drop existing synctran procs
        select @owner = user_name(OBJECTPROPERTY(objid, 'OwnerId')) from sysarticles a, syspublications p
        where a.name = @article and
              p.name = @publication and
              a.pubid = p.pubid

        select @ins_proc_id = sync_ins_proc, @upd_proc_id = sync_upd_proc, @del_proc_id = sync_del_proc
        from sysarticleupdates
        where pubid = @pubid and artid = @artid

        if @ins_proc_id is not null
        begin
            select @objname = object_name(@ins_proc_id)     
            exec @retcode = dbo.sp_MSdrop_object
                @object_name = @objname,
                @object_owner = @owner
            if @@error <> 0 or @retcode <> 0
                return (1)
        end

        if @upd_proc_id is not null
        begin
            select @objname = object_name(@upd_proc_id)     
            exec @retcode = dbo.sp_MSdrop_object
                @object_name = @objname,
                @object_owner = @owner
            if @@error <> 0 or @retcode <> 0
                return (1)
        end

        if @del_proc_id is not null
        begin
            select @objname = object_name(@del_proc_id)     
            exec @retcode = dbo.sp_MSdrop_object
                @object_name = @objname,
                @object_owner = @owner
            if @@error <> 0 or @retcode <> 0
                return (1)
        end

        -- Now generate new ones        
        select @ins_proc = 'sp_MSsync_ins_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @sync_pubid))
        select @upd_proc = 'sp_MSsync_upd_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @sync_pubid))
        select @del_proc = 'sp_MSsync_del_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @sync_pubid))

        -- check uniqueness of names and revert to ugly guid-based name if friendly name already exists
        if exists (select name from sysobjects where name in (@ins_proc, @upd_proc, @del_proc))
        begin
            declare @guid_name nvarchar(36)
            select @guid_name =  convert (nvarchar(36), newid())
            -- remove '-' from guid name because rpc can't handle '-'
            select @guid_name = replace (@guid_name,'-','_')
            select @ins_proc = 'sp_MSsync_ins_' + @guid_name
            select @upd_proc = 'sp_MSsync_upd_' + @guid_name
            select @del_proc = 'sp_MSsync_del_' + @guid_name
        end

        if @ins_proc IS NULL
        begin
            if @@trancount > 0
                ROLLBACK TRANSACTION 
            RAISERROR (14043, 11, -1, '@ins_proc')
            RETURN (1)
        end

        if @upd_proc IS NULL
        begin
            if @@trancount > 0
                ROLLBACK TRANSACTION 
            RAISERROR (14043, 11, -1, '@upd_proc')
            RETURN (1)
        end

        if @del_proc IS NULL
        begin
            if @@trancount > 0
                ROLLBACK TRANSACTION 
            RAISERROR (14043, 11, -1, '@del_proc')
            RETURN (1)
        end

        exec @retcode = dbo.sp_MSgen_sync_tran_procs @publication, @article, @ins_proc, @upd_proc, @del_proc

        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN articlecolumn
                commit tran
            end
            RETURN (1)
        END

        --retrieve sproc id's, fail if they don't exist
        SELECT @ins_proc_id = id FROM sysobjects WHERE name = @ins_proc
        SELECT @upd_proc_id = id FROM sysobjects WHERE name = @upd_proc
        SELECT @del_proc_id = id FROM sysobjects WHERE name = @del_proc

        IF (@ins_proc_id IS NULL) OR (@upd_proc_id IS NULL) OR (@del_proc_id IS NULL)
        BEGIN
            if @ins_proc_id IS NULL RAISERROR (20500, 16, 1, @ins_proc)
            if @upd_proc_id IS NULL RAISERROR (20500, 16, 1, @upd_proc)
            if @del_proc_id IS NULL RAISERROR (20500, 16, 1, @del_proc)
            if @@trancount > 0
            begin
                ROLLBACK tran articlecolumn
                commit tran
            end
            RETURN (1)
        END

        -- perform update in sysarticleupdates
        update sysarticleupdates set sync_ins_proc = @ins_proc_id, sync_upd_proc = @upd_proc_id, 
            sync_del_proc = @del_proc_id
        where pubid = @pubid and artid = @artid

        IF @@ERROR <> 0
        BEGIN
            RAISERROR (20501, 16, -1)
            if @@trancount > 0
            begin
                ROLLBACK tran articlecolumn
                commit tran
            end
            RETURN (1)
         END
    end
    -- end synctran

    /*
    ** Force the article cache to be refreshed with the new definition.
	** Nothing to flush if brute force cleanup.
    */
	if ( @ignore_distributor = 0 )
		EXECUTE dbo.sp_replflush

    COMMIT TRANSACTION
go
 
EXEC dbo.sp_MS_marksystemobject sp_articlecolumn
GO

print ''
print 'Creating procedure sp_helparticlecolumns'
go
CREATE PROCEDURE sp_helparticlecolumns (
    @publication sysname,            /* The publication name */
    @article    sysname              /* The article name */
    ) AS

    /*
    ** Declarations.
    */

    DECLARE @columns binary(32)
    DECLARE @pubid int
    DECLARE @retcode int

    /*
    ** Security Check. To public.
    */

    /*
    ** Parameter Check: @article.
    ** The @article name must conform to the rules for identifiers.
    */

    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END
    
    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @retcode <> 0
    RETURN (1)
    */

    /*
    ** Parameter Check: @publication.
    ** The @publication name must conform to the rules for identifiers.
    */

    IF @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END
    
    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)
    
    /*
    ** Get the pubid.
    */

    SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (14043, 11, -1, '@pubid')
            RETURN (1)
        END

    /*
    ** Parameter Check:  @article, @publication.
    ** Check to make sure that the article exists in this publication.
    */

    IF NOT EXISTS (SELECT *
                     FROM sysarticles
                    WHERE pubid = @pubid
                      AND name = @article)
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END


    /*
    ** Error out if this is a not a table based article
    */
    IF NOT EXISTS ( SELECT * FROM sysarticles WHERE name = @article
                          AND pubid = @pubid
                          AND (type & 1) = 1 )
        BEGIN
            RAISERROR (14112, 11, -1 )
            RETURN (1)
        END


    SELECT @columns = columns
      FROM sysarticles
     WHERE name = @article
       AND pubid = @pubid

    SELECT 'column id' = colid,
           'column'    = name,
       'published' = convert(bit, convert( varbinary, substring( convert( nvarchar, @columns ), 16 - floor((colid-1)/16),1 )) & power( 2, ((colid-1)%16)))
      FROM syscolumns
     WHERE id = (SELECT objid
                   FROM sysarticles
                  WHERE name = @article
                    AND pubid = @pubid)
go
 
EXEC dbo.sp_MS_marksystemobject sp_helparticlecolumns
GO

print ''
print 'Creating procedure sp_helppublication'
go


CREATE PROCEDURE sp_helppublication (
        @publication sysname = '%',     /* The publication name */
        @found int = 23456 OUTPUT            /* a flag indicate returning row */
        ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @pubid      int
    DECLARE @has_subscription bit
    DECLARE @retcode int
    DECLARE @no_row bit
    DECLARE @publish_bit int
    
    SELECT @publish_bit = 1
    
    /*
    ** Check if the database is published.
    */
    IF NOT EXISTS (SELECT * FROM master..sysdatabases
        WHERE name = db_name()
        AND (category & @publish_bit) = @publish_bit)
        RETURN(0)

    /*
    ** Security Check. To public.
    */

    /*
    ** Initializations.
    */
    IF @found = 23456 
    BEGIN
        SELECT @no_row=0
    END
    ELSE
    BEGIN
        SELECT @no_row=1
    END

    /*
    ** Parameter Check:  @publication.
    ** Check to make sure that there are some publications
    ** to display.
    */

    IF @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END
    
    IF @publication <> '%'
        BEGIN
            
            EXECUTE @retcode = dbo.sp_validname @publication

            IF @retcode <> 0
            RETURN (1)
        END

    IF  NOT EXISTS (SELECT * FROM syspublications
        WHERE name like @publication)

    BEGIN
        SELECT @found = 0
        RETURN (0) 
    END
    ELSE
    BEGIN
        SELECT @found = 1
        IF @no_row <>0
            RETURN(0)
    END

    


    SELECT 'pubid'                  = pubid,
           'name'                   = name,
           'restricted'             = 0,
           'status'                 = status,
           -- using 'task' is for backward compatible
           'task'                   = convert(int, 1),
           'replication frequency'  = repl_freq,
           'synchronization method' = sync_method,
           'description'            = description,
           'immediate_sync'            = immediate_sync,
           'enabled_for_internet'    = enabled_for_internet,
           'allow_push'             = allow_push,
           'allow_pull'             = allow_pull,
           'allow_anonymous'        = allow_anonymous,
           'independent_agent'        = independent_agent,
           'immediate_sync_ready'    = immediate_sync_ready,
           -- SyncTran
           'allow_sync_tran'        = allow_sync_tran,
           'autogen_sync_procs'        = autogen_sync_procs,
           'snapshot_jobid'         = snapshot_jobid,
           'retention'              = retention,
           'has subscription'       =  case when EXISTS (select * from syssubscriptions where artid in 
            							(select artid from sysarticles where pubid in 
              						  (select inside.pubid from syspublications inside where inside.name = outter.name))) then 1
                           			else 0 end
      FROM syspublications outter
     WHERE name LIKE @publication
     ORDER BY name

    RETURN (0)
go
 
EXEC dbo.sp_MS_marksystemobject sp_helppublication
GO

-- bug 44359 : sp_helppublication_snapshot not used anymore

print ''
print 'Creating procedure sp_helpsubscription'
go

CREATE PROCEDURE sp_helpsubscription
    @publication sysname = '%',    /* The publication name */
    @article sysname = '%',        /* The article name */
    @subscriber sysname = N'%',      /* The subscriber name */
    @destination_db sysname = '%',
    @found int = 23456 OUTPUT
    AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode int
    DECLARE @subscriber_bit smallint
    DECLARE @no_row bit
    DECLARE @srvid smallint
    DECLARE @pubid int
    DECLARE @artid int
    DECLARE @immediate_sync bit
    DECLARE @subscription_type_id int
    DECLARE @sync_typeid int
    DECLARE @publish_bit int
    
    DECLARE @full_subscription bit

    SELECT @publish_bit = 1


    /* Security check. To public. */

    /*
    ** Check if the database is published.
    */
    IF NOT EXISTS (SELECT * FROM master..sysdatabases
                    WHERE name = db_name()
                      AND (category & @publish_bit) = @publish_bit)
        RETURN(0)

    /*
    ** Initializations of @now_row.
    */
    IF @found = 23456 
    BEGIN
        SELECT @no_row=0
    END
    ELSE
    BEGIN
        SELECT @no_row=1
    END

    /*
    ** Initializations.
    */
    SELECT @subscriber_bit = 4

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

    /*
    ** Parameter Check:  @subscriber.
    ** Check if remote server is defined as a subscription server, and
    ** that the name conforms to the rules for identifiers.
    */

    IF @subscriber <> '%'
        BEGIN

            EXECUTE @retcode = dbo.sp_validname @subscriber
            select @subscriber = UPPER(@subscriber)

            IF @retcode <> 0
        RETURN (1)

            IF NOT EXISTS (SELECT *
                             FROM master..sysservers
                            WHERE UPPER(srvname) = UPPER(@subscriber)
                              AND (srvstatus & @subscriber_bit) <> 0)
                BEGIN
                    RAISERROR (14010, 16, -1)
                    RETURN (1)
                END
        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 @publication <> '%'
        BEGIN

            EXECUTE @retcode = dbo.sp_validname @publication

            IF @retcode <> 0
                RETURN (1)

            IF NOT EXISTS (SELECT * FROM syspublications WHERE name = @publication)
                BEGIN
                   RAISERROR (20026, 11, -1, @publication)
                   RETURN (1)
                END

        END

    /*
    ** Parameter Check:  @article.
    ** If the article name is specified, check to make sure that it
    ** conforms to the rules for identifiers and that the article
    ** actually exists.  Disallow NULL.
    **
    ** If @article is 'all', only return one entry for the whole publication
    ** for full subscriptions (subscriptions inlcluding all the articles in a
    ** publication).
    ** 
    */

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

    IF LOWER(@article) <> 'all' 
    BEGIN
        IF @article <> '%'
            BEGIN
                
                /*
                EXECUTE @retcode = dbo.sp_validname @article

                IF @retcode <> 0
                RETURN (1)
                */

                IF NOT EXISTS (SELECT *
                                 FROM sysarticles
                                WHERE name = @article
                                  AND pubid IN (SELECT pubid
                                                  FROM syspublications
                                                 WHERE name LIKE @publication))
                    BEGIN
                        RAISERROR (20027, 11, -1, @article)
                        RETURN (1)
                    END

            END


        IF EXISTS (SELECT * 
              FROM syssubscriptions sub,
                   master..sysservers ss,
                   syspublications pub,
                   sysarticles art
             WHERE ((@subscriber = N'%') OR (ss.srvname = @subscriber))
               AND sub.srvid = ss.srvid
               AND pub.name LIKE @publication
               AND art.name LIKE @article
               AND art.pubid = pub.pubid
               AND sub.artid = art.artid
               AND sub.dest_db LIKE @destination_db
               AND (sub.login_name = suser_sname(suser_sid()) OR 
                    is_srvrolemember('sysadmin') = 1 OR
                    is_member ('db_owner') = 1)
                )

        BEGIN
            SELECT @found = 1
            IF @no_row <> 0 RETURN (0)
        END
        ELSE
        BEGIN
            SELECT @found = 0
            RETURN(0)
        END
    END

/*
        SELECT 'subscriber'           = ss.srvname,
               'publication'          = pub.name,
               'article'              = art.name,
               'destination database' = sub.dest_db,
               'subscription status'  = sub.status,
               'synchronization type' = sub.sync_type
          FROM syssubscriptions sub,
               master..sysservers ss,
               syspublications pub,
               sysarticles art
         WHERE UPPER(ss.srvname) LIKE UPPER(@subscriber)
           AND sub.srvid = ss.srvid
           AND pub.name LIKE @publication
           AND art.name LIKE @article
           AND art.pubid = pub.pubid
           AND sub.artid = art.artid
           AND (sub.login_name = suser_sname(suser_sid()) OR 
                    is_srvrolemember('sysadmin') = 1 OR
                    is_member ('db_owner') = 1)
                )
         ORDER BY subscriber, publication, article
*/    

    CREATE TABLE #helpsubscription 
    (
    /* Info that will be returned */
    subscriber sysname NOT NULL,
    publication sysname NOT NULL,
    article sysname NOT NULL,
    destination_db sysname NOT NULL,
    status tinyint NOT NULL,
    sync_type tinyint NOT NULL,
    subscription_type int NOT NULL,
    full_subscription bit NOT NULL, /* full subscription or not */
    distribution_jobid binary(16) NULL,
    subscription_name nvarchar(255) NOT NULL,
    -- SyncTran
    update_mode int NOT NULL,
    loopback_detection bit not null
    )


    /* Open a CURSOR LOCAL FOR subscriber/destination_db and publication pair 
    **
    ** Get subscriptions
    ** sa or dbo can see every subscriptions while
    ** others only see their own.
    */

    /* 
    ** Performance Optimization: Eliminate the 'LIKE' clause for publication name.
    **                           Empirical evidence shows almost 50% speed improvement when
    **                           opening the cursor if publication name is provided.
    */
    IF (@publication <> '%')
        DECLARE hChelpsubscription_pub CURSOR LOCAL FAST_FORWARD FOR
            SELECT DISTINCT ss.srvname,
                   pub.name,
                   sub.dest_db,
                   pub.pubid,
                   sub.srvid,
                   pub.immediate_sync
              FROM syssubscriptions sub,
                   master..sysservers ss,
                   syspublications pub,
                   sysarticles art
             WHERE ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
               AND sub.srvid = ss.srvid
               AND pub.name = @publication
               AND art.pubid = pub.pubid
               AND sub.artid = art.artid
               AND sub.dest_db LIKE @destination_db
               AND (sub.login_name = suser_sname(suser_sid()) OR 
                        is_srvrolemember('sysadmin') = 1 OR
                        is_member ('db_owner') = 1)       
               FOR READ ONLY
    ELSE 
        DECLARE hChelpsubscription_pub CURSOR LOCAL FAST_FORWARD FOR
            SELECT DISTINCT ss.srvname,
                   pub.name,
                   sub.dest_db,
                   pub.pubid,
                   sub.srvid,
                   pub.immediate_sync
              FROM syssubscriptions sub,
                   master..sysservers ss,
                   syspublications pub,
                   sysarticles art
             WHERE ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
               AND sub.srvid = ss.srvid
               AND art.pubid = pub.pubid
               AND sub.artid = art.artid
               AND sub.dest_db LIKE @destination_db
               AND (sub.login_name = suser_sname(suser_sid()) OR 
                        is_srvrolemember('sysadmin') = 1 OR
                        is_member ('db_owner') = 1)       
               FOR READ ONLY
 
    OPEN hChelpsubscription_pub
    FETCH hChelpsubscription_pub INTO @subscriber, @publication, 
        @destination_db, @pubid, @srvid, @immediate_sync
        
    WHILE (@@fetch_status <> -1)
    BEGIN

        /* 
        ** Is it a full subscription ? i.e. Does it include all the articles? 
        **
        */

        IF NOT EXISTS (SELECT * FROM sysarticles art WHERE
                art.pubid = @pubid and 
                NOT EXISTS (SELECT * from syssubscriptions sub WHERE
                    sub.artid = art.artid))
        BEGIN
            /* Do all the subscriptions on the publication have same
            ** sync_type and subscription_type ?
            */
  
              /* 
            ** Get subscription type on the publication
            */ 
            SELECT @subscription_type_id = subs.subscription_type,
                @sync_typeid = subs.sync_type 
                FROM 
                sysarticles art, syssubscriptions subs  
                WHERE
                art.pubid = @pubid AND
                subs.srvid = @srvid AND
                subs.dest_db = @destination_db AND
                subs.artid = art.artid


            /* 
            ** if the subscription all have the same subscription type
            ** and sync_type
            */
            IF NOT EXISTS (SELECT * from 
                sysarticles art, syssubscriptions subs where 
                art.pubid = @pubid AND
                subs.srvid = @srvid AND
                subs.dest_db = @destination_db AND
                subs.artid = art.artid AND
                (subscription_type <> @subscription_type_id OR
                sync_type <> @sync_typeid))
                

                SELECT @full_subscription = 1
            ELSE
                SELECT @full_subscription = 0
        END
        ELSE
        BEGIN
            SELECT @full_subscription = 0
        END
            
        /* 
        ** If it is a full subscription and the @article is 'all',
        ** only return one entry for the whole publication.
        ** Bug 22733: Always return one row per publication if @article is 'ALL'
        */
        IF    LOWER(@article) = 'all'
        BEGIN    
            INSERT INTO #helpsubscription 
                SELECT TOP 1 @subscriber, @publication, @article, @destination_db,
                    sub.status, sub.sync_type, sub.subscription_type,
                    @full_subscription, sub.distribution_jobid,
                    @subscriber + ':' + @destination_db  ,
                    -- SyncTran
                    sub.update_mode,
                    sub.loopback_detection
                    -- end SyncTran
                    FROM syssubscriptions sub, sysarticles art 
                    WHERE sub.srvid = @srvid AND
                        sub.dest_db = @destination_db AND
                        sub.artid = art.artid and
                        art.pubid = @pubid
        END
        ELSE
        BEGIN
            /*
            ** Get subscriptions
            ** sa or dbo can see every subscriptions while
            ** others only see their own.
            */

            INSERT INTO #helpsubscription 
                SELECT    @subscriber, @publication, art.name, @destination_db,
                    sub.status, sub.sync_type, sub.subscription_type,
                    @full_subscription, sub.distribution_jobid,
                    @subscriber + ':' + @destination_db + ':' + art.name,
                    -- SyncTran
                    sub.update_mode,
                    sub.loopback_detection
                    -- end SyncTran
                    FROM
                    syssubscriptions sub, sysarticles art WHERE
                        sub.srvid = @srvid AND
                        sub.dest_db = @destination_db AND
                        art.pubid = @pubid AND
                        art.name LIKE @article AND
                        sub.artid = art.artid AND
                        (sub.login_name = suser_sname(suser_sid()) OR 
                         is_srvrolemember('sysadmin') = 1 OR
                         is_member ('db_owner') = 1)     
        END
        FETCH hChelpsubscription_pub INTO @subscriber, @publication, 
            @destination_db, @pubid, @srvid, @immediate_sync
    END

    CLOSE hChelpsubscription_pub
    DEALLOCATE hChelpsubscription_pub

    /*
    ** Get subscriptions
    */
    SELECT 'subscriber'           = subscriber,
           'publication'          = publication,
           'article'              = article,
           'destination database' = destination_db,
           'subscription status'  = status,
           'synchronization type' = sync_type,
           'subscription type'    = subscription_type,
           'full subscription'    = full_subscription,
           'subscription_name'      = subscription_name,
              -- SyncTran
           'update mode'          = update_mode,
           'distribution job id' = distribution_jobid,
           'loopback_detection'  = loopback_detection

      FROM #helpsubscription 
      ORDER BY subscriber, publication, article
go
 
EXEC dbo.sp_MS_marksystemobject sp_helpsubscription
GO

print ''
print 'Creating procedure sp_articlefilter'
go
create procedure sp_articlefilter
    @publication sysname,           /* publication name */
    @article sysname,             /* article name */
    @filter_name nvarchar (386) = NULL,     /* name of filter procedure*/
    @filter_clause ntext = NULL               /* article's filter clause */
        
as
    
    declare @pubid smallint
    declare @table_name sysname
    declare @user_name sysname
    declare @qualified_table_name nvarchar (258)
    declare @filter_id int
    declare @type tinyint        
    declare @previous_proc sysname
    declare @retcode int
    declare @site sysname
    declare @db sysname
    declare @owner sysname
    declare @object sysname
    declare @artid int
    declare @inactive tinyint
    declare @obid int

    select @inactive = 0

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

    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists and that it conforms to the
    ** rules for identifiers.
    */
    if @publication is null
           begin
              RAISERROR (14043, 16, -1, '@publication')
              return (1)
           END
    
    execute @retcode = dbo.sp_validname @publication
    if @retcode <> 0
    RETURN (1)

    select @pubid = pubid from syspublications where name = @publication

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

    /*
    ** Parameter Check:  @article.
    ** Check to make sure that the article exists in the publication.
    */

    if @article is null
       begin
              RAISERROR (14043, 16, -1, '@article')
              return (1)
           end
        /*
        execute @retcode = dbo.sp_validname @article
        if @retcode <> 0
       return (1)
       */

    /*
    ** Get the article information.
    */
    select @artid = art.artid, @table_name = so.name, @type = art.type,
       @filter_id = art.filter, @user_name = USER_NAME(so.uid)
       from sysarticles art, sysobjects so
       where art.pubid = @pubid
       and art.name = @article
       and art.objid = so.id

    /*
    ** Fail if there is no article information.
    */
    if @artid is null
       begin
              RAISERROR (20027, 11, -1, @article)
              return (1)
       end

        /*
        ** Only unsubscribed articles may be modified. (excluding virtual subscriptions)
        */
        if exists (select * from syssubscriptions where artid = @artid
          and status <> @inactive 
          and srvid >= 0)
          begin
         RAISERROR (14092, 11, -1)
             RETURN (1)
          end


        /*
        ** Error out if this is a not a table based article
        */
        IF NOT EXISTS ( SELECT * FROM sysarticles WHERE artid = @artid
                          AND pubid = @pubid
                          AND (type & 1) = 1 )
        BEGIN
            RAISERROR (14112, 11, -1 )
            RETURN (1)
        END



    /*
    ** Make sure a valid @filter_name was provided and it is
    ** a valid name.
    */
    if datalength(@filter_clause) > 0  
    begin

        /*
        ** Make sure a valid @filter_name was provided and it is
        ** a valid name.
        */

        if @filter_name is null
        begin
           RAISERROR (14043, 16, -1, '@filter_name')
           return (1)
        end
        
        select @object = PARSENAME( @filter_name, 1 )
        select @owner  = PARSENAME( @filter_name, 2 )
        select @db     = PARSENAME( @filter_name, 3 )
        select @site   = PARSENAME( @filter_name, 4 )

         if @object IS NULL
               return 1
    end

    /*
    ** If the article has a generated filter (not manually created), then
    ** drop the current filter before creating the new one.
    */
    if ((@type & 0x3) <> 0x3) and @filter_id <> 0
       begin
           select @previous_proc = object_name (@filter_id)
          if @previous_proc is not null and
             exists (select * from sysobjects where name = @previous_proc
                and type = 'RF')
         begin
                exec ('drop procedure ' + @previous_proc)
            if @@error <> 0
               return (1)
         end

       end


    /*
    ** make an owner qualified table name for these operations name
    */

    select @qualified_table_name = @user_name + '.' + @table_name

    -- Drop replication filter if it exists.
    -- Note: upgrade needs this logic
    if datalength(@filter_clause) > 0
        and exists (select * from sysobjects where id = object_id(@object)
                and type = 'RF')
    begin
          exec ('drop procedure ' + @object)
        if @@error <> 0
           return (1)
    end


    /*
    ** If there is a @filter_clause, create the new filter and
    ** update the article filter id and filter_clause.
    **/
    if datalength(@filter_clause) > 0
       begin
        exec ('create procedure ' + @object +
            ' for replication as ' +
            'if exists (select * from ' + @qualified_table_name +
            ' where ' + @filter_clause +
            ') return 1 else return 0')
        if @@error <> 0
           return (1)

        exec ('sp_MS_marksystemobject ''' + @object + '''')
        if @@error <> 0
           return (1)

        select @filter_id = id  from sysobjects where name = @object
            and type = 'RF'
        if @filter_id is null or @filter_id = 0
           begin
              RAISERROR (15001, 11, -1, @object)
              return (1)
           end

        /*
        ** Update article
        */
        update sysarticles set filter = @filter_id,
           filter_clause = @filter_clause
           where pubid = @pubid
              and name = @article

       -------------------------------------------------------------
       -- SQL SERVER 7.0 ONLY: update sysobjects, set parent id = underlying
       -- object id
       -------------------------------------------------------------

        select @obid = object_id( @qualified_table_name )
        EXEC dbo.sp_MSsetfilterparent @object, @obid
        EXEC dbo.sp_MSsetfilteredstatus @obid

       end
    else
    BEGIN
        /*
        ** Clear the filter id and filter_clause.
        */
        update sysarticles set filter = 0,
           filter_clause = NULL
           where pubid = @pubid
              and name = @article

        ---------------------------------------------------
        -- SQL SERVER 7.0 ONLY:  remove parent_id from filter proc
        ---------------------------------------------------

        select @obid = object_id( @qualified_table_name )
        if exists ( select * from sysobjects where name = @object
                and type = 'RF')
            EXEC dbo.sp_MSsetfilterparent @object, 0
        EXEC dbo.sp_MSsetfilteredstatus @obid

    END

    /*
    ** Force the article cache to be refreshed with the new definition.
    */
    EXECUTE dbo.sp_replflush
go
 
dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_articlefilter
GO

print ''
print 'Creating procedure sp_MSarticletextcol'
go
CREATE PROCEDURE sp_MSarticletextcol (
    @artid int,
    @colid smallint = NULL,
    @type nvarchar(10),      /* 'publish', 'nonsqlsub' */
    @operation nvarchar(5))  /* 'add', 'drop' */
    AS

    /*
    ** Declarations.
    */
    DECLARE @cmd nvarchar(255)
    DECLARE @cmd1 nvarchar(255)
    DECLARE @columns binary(32)    /* Temporary storage for the converted column */
    DECLARE @tabid int        /* Article base table id */
    DECLARE @retcode int
    DECLARE @status bit
    DECLARE @image tinyint        /* Constant: 0x22 */
    DECLARE @text tinyint        /* Constant: 0x23 */
    DECLARE @publish smallint        /* Constant: 0x1000 */
    DECLARE @nonsqlsub smallint        /* Constant: 0x2000 */
    DECLARE @tinycolid tinyint        /* hydra compatible colid */

    /* Constants */
    SELECT @image = 0x22
    SELECT @text = 0x23
    SELECT @publish = 0x1000
    SELECT @nonsqlsub = 0x2000

    SELECT @tinycolid = @colid

    SELECT @tabid = objid FROM sysarticles WHERE artid = @artid

    IF @colid IS NULL
    BEGIN
       DECLARE hCarttextcol CURSOR LOCAL FAST_FORWARD FOR
            SELECT colid FROM syscolumns, sysarticles
                WHERE artid = @artid
                AND id = @tabid
                AND (syscolumns.type = 0x22 OR syscolumns.type = 0x23)
                AND convert(bit, convert( varbinary, substring( convert( nvarchar, columns ), 16 - floor((colid-1)/16),1 )) & power( 2, ((colid-1)%16))) = 1
    END
    ELSE
    BEGIN
       DECLARE hCarttextcol CURSOR LOCAL FAST_FORWARD FOR 
            SELECT colid FROM syscolumns WHERE id = @tabid
                AND colid = @colid
                AND (type = 0x22 OR type = 0x23)
    END


    /* Process each Text\Image column in the article */
    OPEN hCarttextcol

    FETCH hCarttextcol INTO @colid

    WHILE (@@fetch_status <> -1)
    BEGIN

       IF LOWER(@operation) = 'add'
       BEGIN
          IF LOWER(@type) = 'publish'
          BEGIN
             UPDATE syscolumns
             SET colstat = colstat | @publish
             WHERE id = @tabid
             AND colid = @colid
          END
          ELSE
          BEGIN
             UPDATE syscolumns
             SET colstat = colstat | @nonsqlsub
             WHERE id = @tabid
             AND colid = @colid
          END
       END
       ELSE /* drop */
       BEGIN
          /*
          ** Is there another non-sql server subscription on the column?
          ** Or another article publishing the column?
          */
          EXEC @retcode = dbo.sp_MStextcolstatus @artid, @tabid, @colid,
          @type, @status OUTPUT

          IF @@error <> 0 OR @retcode <> 0
          BEGIN
             CLOSE hCarttextcol
            DEALLOCATE hCarttextcol
            RETURN (1)
          END

          IF (@status = 0)
          BEGIN
             IF LOWER(@type) = 'publish'
             BEGIN
                /* Clear 'publish' bit */
                UPDATE syscolumns
                SET colstat = colstat & ~@publish
                WHERE id = @tabid
                AND colid = @colid
             END
             ELSE
             BEGIN
                /* Clear 'non-sql server subscription' bit */
                UPDATE syscolumns
                SET colstat = colstat & ~@nonsqlsub
                WHERE id = @tabid
                AND colid = @colid
             END
          END
       END

       FETCH hCarttextcol INTO @colid

    END


    CLOSE hCarttextcol
    DEALLOCATE hCarttextcol

GO

EXEC dbo.sp_MS_marksystemobject sp_MSarticletextcol
GO

print ''
print 'Creating procedure sp_MStextcolstatus'
go
CREATE PROCEDURE sp_MStextcolstatus (
    @artid int,
    @tabid int,
    @colid int,
    @type nvarchar (10),      /* 'publish', 'nonsqlsub' */
    @status bit OUTPUT)
    AS

    /*
    ** Declarations.
    */
    DECLARE @cmd nvarchar(255)
    DECLARE @artid2 int
    DECLARE @columns binary(32)
    DECLARE @image tinyint        /* Constant: 0x22 */
    DECLARE @text tinyint        /* Constant: 0x23 */

    /* Constants */
    SELECT @image = 0x22
    SELECT @text = 0x23

    SELECT @status = 0


    IF LOWER(@type) = 'nonsqlsub'
    BEGIN
    /*
    ** Check all active or subscribed articles for the TEXT/IMAGE column.
    */    
        DECLARE hC4 CURSOR LOCAL FAST_FORWARD FOR
            SELECT sub.artid FROM sysarticles art, syssubscriptions sub
                WHERE art.objid = @tabid
                AND art.artid <> @artid
                AND sub.artid = art.artid
                AND sub.status = 1 OR sub.status = 2
    END
    ELSE
    BEGIN
    /*
    ** Check all articles for the TEXT/IMAGE column.
    */    
        DECLARE hC4 CURSOR LOCAL FAST_FORWARD FOR 
            SELECT artid FROM sysarticles 
                WHERE objid = @tabid
                AND artid <> @artid
    END

    EXECUTE (@cmd)
    OPEN hC4
    FETCH hC4 INTO @artid2
    WHILE (@@fetch_status <> -1)
    BEGIN
       SELECT @columns = columns FROM sysarticles WHERE artid = @artid2

       IF EXISTS (SELECT * FROM syscolumns
          WHERE id = @tabid
          AND colid = @colid
      AND CONVERT(bit, CONVERT( varbinary, SUBSTRING( CONVERT( nvarchar, @columns ), 16 - FLOOR((colid-1)/16),1 )) & POWER(2, ((colid-1)%16))) = 1
      AND (type = @image OR type = @text))
          BEGIN
         SELECT @status = 1    
         GOTO CLEANUP
          END

       FETCH hC4 INTO @artid2
    END

CLEANUP:
    CLOSE hC4
    DEALLOCATE hC4

    RETURN (0)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MStextcolstatus
GO

print ''
print 'Creating procedure sp_articleview'
go
create procedure sp_articleview
    @publication sysname,        /* Publication name */
    @article sysname,          /* Article name */
    @view_name nvarchar (386) = NULL,  /* View name */
    @filter_clause ntext = NULL            /* Article's filter clause */
        
as
    declare @pubid smallint
    declare @table_name sysname
    declare @user_id int
    declare @user_name sysname
    declare @qualified_table_name nvarchar (258)
    declare @columns varbinary (32)
    declare @name sysname
    /* 
    ** NOTE: A column clause of 4000 characters can hold about 27 128- 
    ** characters long column identifiers
    */
    declare @col_clause nvarchar(4000)
    declare @retcode int
    declare @view_id int
    declare @type tinyint
    declare @table_id int
    declare @previous_view sysname
    declare @quoted_prev_view sysname
    declare @colid int
    declare @object sysname
    declare @quoted_object sysname
    declare @artid int
    declare @inactive tinyint

    select @inactive = 0

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

    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists and that it conforms to the
    ** rules for identifiers.
    */
    if @publication is null
           begin
              RAISERROR (14043, 16, -1, '@publication')
              return (1)
           END

    execute @retcode = dbo.sp_validname @publication
    if @retcode <> 0
            RETURN (1)

    select @pubid = pubid from syspublications where name = @publication
        if @pubid is null
           begin
            RAISERROR (20026, 11, -1, @publication)
            return (1)
           end

    /*
    ** Parameter Check:  @article.
    ** Check to make sure that the article exists in the publication.
    */

    if @article is null
       begin
              RAISERROR (14043, 16, -1, '@article')
              return (1)
           end
    
    /*
        execute @retcode = dbo.sp_validname @article
        if @retcode <> 0
       return (1)
       */

    /*
    ** Get the article information.
    */
    select @artid = art.artid, @table_name = so.name,
       @user_id = uid, @user_name = USER_NAME(so.uid),
       @columns = art.columns, @type = art.type,
       @view_id = art.sync_objid, @table_id = art.objid
       from sysarticles art, sysobjects so
       where art.pubid = @pubid
       and art.name = @article
       and art.objid = so.id

    /*
    ** Fail if there is no article information.
    */
    if @artid is null
       begin
              RAISERROR (20027, 11, -1, @article)
              return (1)
       end

        /*
        ** Only unsubscribed articles may be modified. (excluding virtual subscriptions)
        */
        if exists (select * from syssubscriptions where artid = @artid
          and status <> @inactive
          and srvid >= 0)
          begin
         RAISERROR (14092, 11, -1)
             RETURN (1)
          end

        /*
        ** Error out if this is a not a table based article
        */
        IF NOT EXISTS ( SELECT * FROM sysarticles WHERE artid = @artid
                          AND pubid = @pubid
                          AND (type & 1) = 1 )
            BEGIN
                RAISERROR (14112, 11, -1 )
                RETURN (1)
            END

    
    /*
    ** Create a table of all the articles columns.
    */
    create table #tmp (colid int NOT NULL, name sysname NOT NULL, published bit NOT NULL)
    if @@error <> 0
       return (1)

    create unique index ind1 on #tmp (colid)
    if @@error <> 0
       begin
        drop table #tmp
        return (1)
       end

    insert into #tmp select colid, name,
        convert(bit, convert( varbinary, substring( convert( nvarchar(16), @columns ), 16 - floor((colid-1)/16),1 )) & power( 2, ((colid-1)%16)))
        from syscolumns
        where id = (select id from sysobjects where name = @table_name and
           uid = @user_id and type = 'U')
    
    /* Break out the specified view name and get the non-ownerqual'd name, then validate that. */
    select @object = PARSENAME( @view_name, 1 )
    if @object IS NULL
       return 1
	select @quoted_object = QUOTENAME(@object)

    execute @retcode = dbo.sp_validname @object
    if @retcode <> 0
        return (1)

    /* If no non-published columns, we'll select all and avoid the 4000-char limit on column strings. */
    if not exists (select * from #tmp where published = 0) 
    begin
        select @col_clause = null
        goto CreateView
    end

    /*
    ** Construct the column list based on all published columns in the
    ** article.
    */
    declare hC  CURSOR LOCAL FAST_FORWARD FOR select colid, name from #tmp
        where published = 1
            order by colid asc
    open hC
    fetch hC into @colid, @name
    /* 
    ** Warning: A unicode character consists of two bytes!
    */

    while (@@fetch_status <> -1)
        begin

        if @col_clause is null or
           ((len(@name) + len(@col_clause) + 2) <= 4000)
            if @col_clause is null
                select @col_clause = @name
            else
                select @col_clause = @col_clause + ', ' + @name
        else
        /*
        ** The procedure only support ~4000 characters for the column list
        */
          begin
            RAISERROR (14039, 16, -1)
            close hC
            deallocate hC
            drop table #tmp
            return (1)
          end
        fetch hC into @colid, @name
        end            

    close hC
    deallocate hC

CreateView:
	/*
	** If the article has a generated view (not manually created), then
	** drop the current view before creating the new one.
	*/
	if ((@type & 0x5) <> 0x5) and @view_id <> 0
			and @view_id <> @table_id
	begin
		select @previous_view = object_name (@view_id)
		if @previous_view is not null and
				exists (select * from sysobjects where name = @previous_view
				and type = 'V')
		begin
			select @quoted_prev_view = QUOTENAME(@previous_view)
			exec ('drop view ' + @quoted_prev_view)
		end
	end


    /*
    ** If a view is going to be created. Make sure a valid @view_name
    ** was provided.
    */
    if @col_clause is not null
      begin
          if @view_name is null
            begin
              RAISERROR (14043, 16, -1, '@view_name')
              return (1)
            end
      end

    /*
    ** make an owner qualified table name for these operations name
    */

    select @qualified_table_name = QUOTENAME(@user_name) + '.' + QUOTENAME(@table_name)

    /*
    ** Construct and execute the view creation command.
    */
    -- Drop the existing view.
    -- Note: upgrade needs this logic
    if datalength(@filter_clause) > 0 and
        exists (select * from sysobjects where id = object_id(@object)
    and type = 'V') 
    begin
		exec ('drop view ' + @quoted_object)
		if @@error <> 0
			return (1)
    end

    if @col_clause is not null
    begin

        if datalength(@filter_clause) > 0
            exec ('create view ' + @quoted_object + ' as select ' +
                @col_clause + ' from ' +  @qualified_table_name +
                ' where ' + @filter_clause)
        else
            exec ('create view ' + @quoted_object + ' as select ' +
                @col_clause + ' from ' +  @qualified_table_name)
        if @@error <> 0
           return (1)
    end
    else
    begin
        if datalength(@filter_clause) > 0
		begin
            exec ('create view ' + @quoted_object + ' as select * from ' +
                   @qualified_table_name + ' where ' + @filter_clause)
			if @@error <> 0
			  return (1)
		end
		else
		begin
			exec ('create view ' + @quoted_object + ' as select * from ' + @qualified_table_name )
			if @@error <> 0
        	  return (1)
		end

    end

    -----------------------------------------------------------
    -- Update the article's sync_objid with the new view id
    -----------------------------------------------------------

    select @view_id = id from sysobjects where name = @object and type = 'V'
    if @view_id is null or @view_id = 0
    begin
       RAISERROR (15001, 11, -1, @object)
       return (1)    
    end
	else
	begin
	    EXEC dbo.sp_MS_marksystemobject @object
	end

    ---------------------------------------------
	--  Update article definition 
	--  Set new sync_objid and @filter_clause value
    ---------------------------------------------

    if datalength(@filter_clause) > 0
	begin
       update sysarticles set sync_objid = @view_id,
          filter_clause = @filter_clause
          where pubid = @pubid
          and name = @article
	end
    else
	begin
       update sysarticles set sync_objid = @view_id,
          filter_clause = NULL
          where pubid = @pubid
          and name = @article
	end

    drop table #tmp

    /*
    ** Force the article cache to be refreshed with the new definition.
    */
    EXECUTE dbo.sp_replflush
go
 
EXEC dbo.sp_MS_marksystemobject sp_articleview
GO

dump tran master with no_log
go

print ''
print 'Creating procedure sp_MSaddexearticle'
go
CREATE PROCEDURE sp_MSaddexecarticle
    @publication sysname,               /* publication name */
    @article     sysname,             /* article name */
    @source_proc nvarchar (92),                 /* table name */
    @destination_proc sysname = NULL,           /* destination table name */
    @type sysname = NULL,                       /* article type */
    @creation_script nvarchar (127) = NULL,           /* article schema script */
    @description nvarchar (255) = NULL,                 /* article description */
    @pre_creation_cmd nvarchar(10) = 'drop',           /* 'none', 'drop', 'delete', 'truncate' */
    @schema_option binary(8) = NULL,    /* script out stored procedure */
    @destination_owner sysname,
    @article_id int OUTPUT

    AS


    SET NOCOUNT ON

    /* variables for SP_NAMECRACK */

    DECLARE @site sysname
    DECLARE @db sysname
    DECLARE @owner sysname
    DECLARE @object sysname

    DECLARE @retcode   int

    DECLARE @procid    int
    DECLARE @procnum   smallint
    DECLARE @pubid     int
    DECLARE @precmdid  int

    DECLARE @typeid      smallint
    DECLARE @publish_bit smallint
    DECLARE @incompatible_typeid smallint

    DECLARE @cmd nvarchar(255)
    DECLARE @sysobj_colname  sysname

    SELECT  @typeid      = 24


    SELECT @sysobj_colname = 'replinfo'
    SELECT @publish_bit = 1


    /*
    ** Parameter Check: @article.
    ** The @article name cannot be NULL and must conform to the rules
    ** for identifiers.
    */

    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END
    
    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @retcode <> 0
    return(1)
    */

    if LOWER(@article) = 'all'
        BEGIN
            RAISERROR (14032, 16, -1, '@article')
            RETURN (1)
        END

    /*
    ** Parameter Check: @publication.
    ** The @publication name cannot be NULL and must conform to the rules
    ** for identifiers.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    /*
    ** Parameter Check: @source_proc.
    ** Check to see that the @source_proc is local, that it conforms
    ** to the rules for identifiers, and that it is a procedure
    */

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

   select @object = PARSENAME( @source_proc, 1 )
   select @owner  = PARSENAME( @source_proc, 2 )
   select @db     = PARSENAME( @source_proc, 3 )
   select @site   = PARSENAME( @source_proc, 4 )

   if @object IS NULL
         return 1


    IF @source_proc LIKE '%.%.%' AND @db <> DB_NAME()
    BEGIN
        RAISERROR (14004, 16, -1, @source_proc)
		RETURN (1)
    END
    

    /*
    **  Get the id of the @source_proc
    */

    SELECT @procid = id
      FROM sysobjects
     WHERE id = OBJECT_ID(@source_proc)
     AND   type = 'P'

    IF @procid IS NULL
    BEGIN
        RAISERROR (14027, 11, -1, @source_proc)
        RETURN (1)
    END

    IF EXISTS (SELECT * FROM syscomments WHERE
        id = @procid AND
        texttype = 4)
    BEGIN
        RAISERROR (21004, 16, -1, @source_proc)
        RETURN (1)
    END
    /*
    ** Parameter Check:  @destination_proc.
    ** If the destination proc is not specified, assume it's the same
    ** as the source.  Make sure that the name is not qualified.
    */

    IF @destination_proc LIKE '%.%.%'
    BEGIN
            RAISERROR (14001, 16, -1)
        RETURN (1)
    END

    /* Enable owner qualified dest name 
    IF @destination_proc LIKE '%.%'
    BEGIN
            RAISERROR (14044, 16, -1, '@destination_proc')
        RETURN (1)
    END
    */
    
    IF @destination_proc IS NULL
        SELECT @destination_proc = @source_proc

	select @object = PARSENAME( @destination_proc, 1 )
	select @owner  = PARSENAME( @destination_proc, 2 )
	select @db     = PARSENAME( @destination_proc, 3 )
	select @site   = PARSENAME( @destination_proc, 4 )

	if @object IS NULL
		 return 1

    /*
    ** Get the pubid.
    */

    SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (14027, 11, -1, @publication)
            RETURN (1)
        END

    /*
    ** Parameter Check:  @article, @publication.
    ** Check if the article already exists in this publication.
    */

    IF EXISTS (SELECT *
                 FROM sysarticles
                WHERE pubid = @pubid
                  AND name = @article)
        BEGIN
            RAISERROR (14030, 16, -1, @article, @publication)
            RETURN (1)
        END


    /*
    ** Set the precmdid.  The default type is 'drop'.
    **
    **      @precmdid   pre_creation_cmd
    **      =========   ================
    **            0     none
    **          1     drop
    */
    IF LOWER(@pre_creation_cmd) NOT IN ('none', 'drop')
       BEGIN
          RAISERROR (14111, 16, -1)
          RETURN (1)
       END

    /*
    ** Determine the integer value for the pre_creation_cmd.
    */

    IF LOWER(@pre_creation_cmd) = 'none'
       SELECT @precmdid = 0
    ELSE IF LOWER(@pre_creation_cmd) = 'drop'
       SELECT @precmdid = 1

    /*  Determine 'type' value for article.
    **
    **            8     proc exec
    **           24     serializable proc exec
    */

    IF @type IS NULL
    BEGIN
        SELECT @type = 'serializable proc exec'
    END
    ELSE IF LOWER(@type) NOT IN ('proc exec', 'serializable proc exec')
    BEGIN
            RAISERROR (14118, 16, -1)
            RETURN (1)
    END

    IF LOWER(@type) = 'proc exec'
    BEGIN
       SELECT @typeid = 8
       SELECT @incompatible_typeid = 24
    END
    ELSE IF LOWER(@type) = 'serializable proc exec'
    BEGIN
       SELECT @typeid = 24
       SELECT @incompatible_typeid = 8
    END

    -- make sure we haven't already created an article of a different type
    -- on this proc

    IF EXISTS ( select * from sysobjects where id = @procid
                and replinfo & @incompatible_typeid = @incompatible_typeid )
    BEGIN
       RAISERROR (21024, 16, -1, @source_proc )
       RETURN(1)
    END

    /*
    ** Parameter Check:  @creation_script and @schema_option
    ** @schema_option is null, set the default value
    ** If @schema_option is 0, there have to be @creation_script defined.
    */
    IF @schema_option IS NULL
    BEGIN
        SELECT @schema_option = 1
    /* 
        RAISERROR (14043, 16, -1, '@schema_option')
        RETURN (1)
        */
    END

    IF @schema_option <> 0x0000000000000000 AND 
        @schema_option <> 0x0000000000000001
    BEGIN
        RAISERROR (20014, 10, -1)
        RETURN (1)
    END

    /*
    **  Add article to sysarticles and update sysobjects category bit.
    */

    begin tran
    save TRAN sp_MSaddexecarticle
        INSERT sysarticles (columns, creation_script, del_cmd, description,
                            dest_table, filter, filter_clause, ins_cmd, name,
                objid, pre_creation_cmd, pubid,
                            status, sync_objid, type, upd_cmd, schema_option,
                            dest_owner)
        VALUES (0, @creation_script, NULL, @description,
                @destination_proc, 0, '', NULL, @article,
                @procid, @precmdid, @pubid,
                0, @procid, @typeid, NULL, @schema_option,
                @destination_owner)

        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_MSaddexecarticle
                commit tran
            end
            RETURN (1)
        END

        SELECT @article_id = @@IDENTITY

        select @cmd = 'UPDATE sysobjects SET ' + @sysobj_colname
        select @cmd = @cmd + ' = ' + @sysobj_colname + ' | ' + CONVERT( nvarchar, @publish_bit )
        select @cmd = @cmd + ' WHERE id = (SELECT objid FROM sysarticles WHERE name = '''
        select @cmd = @cmd + @article + ''' and pubid = ' + CONVERT( nvarchar, @pubid ) + ')'

        EXEC (@cmd)

        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN sp_MSaddexecarticle
                commit tran
            end
            RETURN (1)
        END


    COMMIT TRAN
go
 
EXEC dbo.sp_MS_marksystemobject sp_MSaddexecarticle
GO

print ''
print 'Creating procedure sp_addarticle'
go
CREATE PROCEDURE sp_addarticle
    @publication sysname,               /* publication name */
    @article sysname,             /* article name */
    @source_table nvarchar (386) = NULL,         /* table name */
    @destination_table sysname = NULL, /* destination table name */
    @vertical_partition nchar(5) = 'false',  /* vertical partition */
    @type sysname = NULL,        /* article type */
    @filter nvarchar (386) = NULL,        /* stored procedure used to filter table */
    @sync_object nvarchar (386) = NULL,        /* view or table used for synchronization */
    @ins_cmd nvarchar (255) = NULL,        /* insert format string */
    @del_cmd nvarchar (255) = NULL,        /* delete format string */
    @upd_cmd nvarchar (255) = NULL,        /* update format string */
    @creation_script nvarchar (127) = NULL,  /* article schema script */
    @description nvarchar (255) = NULL,        /* article description */
    @pre_creation_cmd nvarchar(10) = 'drop', /* 'none', 'drop', 'delete', 'truncate' */
    @filter_clause ntext    = NULL,            /* where clause */
    @schema_option binary(8) = NULL,
	@destination_owner sysname = NULL,
	@status tinyint = 16,						/* Default: binary command format */
	@source_owner	sysname = NULL, 			/* NULL for 6.5 users, not NULL for 7.0 users */
	@sync_object_owner sysname = NULL, 			/* NULL for 6.5 users, not NULL for 7.0 users */
	@filter_owner	sysname = NULL,				/* NULL for 6.5 users, not NULL for 7.0 users */
	@source_object	sysname = NULL				/* if @source_table is NULL, this parameter can not be NULL */
    AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */	
    DECLARE @bak_source sysname
	DECLARE @num_columns int
    DECLARE @accessid smallint
    DECLARE @db sysname
    DECLARE @filterid int
    DECLARE @object sysname
    DECLARE @owner sysname
    DECLARE @pubid int
    DECLARE @publish_bit smallint
    DECLARE @retcode int
    DECLARE @site sysname
    DECLARE @syncid int
    DECLARE @tabid int
    DECLARE @typeid smallint
    DECLARE @pkkey sysname
    DECLARE @i int
    DECLARE @indid int
    DECLARE @precmdid int
    DECLARE @object_type nchar(2)
    DECLARE @push tinyint
    DECLARE @dbname sysname
    DECLARE @cmd nvarchar(255)
    DECLARE @fHasPk int
    DECLARE @no_sync tinyint
    DECLARE @immediate_sync bit
    DECLARE @is_filter_in_use int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @article_id int
    DECLARE @sync_method tinyint
    -- SyncTran
    DECLARE @autogen_sync_procs_id int
    DECLARE @custom_proc_name varchar(32)
	DECLARE @guid varbinary(16)
	declare @allow_sync_tran bit


    SELECT @push = 0
    SELECT @dbname = DB_NAME()

    SELECT @publish_bit = 1

    SELECT @no_sync = 2 /* no sync type in syssubscriptions */

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

    /*
    ** Parameter Check: @article.
    ** The @article name cannot be NULL and must conform to the rules
    ** for identifiers.
    */

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

	exec @retcode = dbo.sp_MSreplcheck_name @article
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    if LOWER(@article) = 'all'
        BEGIN
            RAISERROR (14032, 16, -1, '@article')
            RETURN (1)
        END

    /*
    ** Parameter Check: @publication.
    ** The @publication name cannot be NULL and must conform to the rules
    ** for identifiers.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    /*
    ** Parameter Check: @destination_owner.
    ** The @destination_owner must conform to the rules
    ** for identifiers.
    */

    if @destination_owner is not null
	BEGIN
		-- native bcp mode publications are for odbc subscribers. Destination
		-- owner name is not supported.
		if exists (select * from syspublications where name = @publication and
			sync_method = 1)
		begin
			raiserror(21039,16, -1)
			return(1)
		end
		EXECUTE @retcode = dbo.sp_validname @destination_owner

		IF @retcode <> 0
			RETURN (1)
	END

    /*
    ** Parameter Check: @source_table.
    ** Check to see that the @source_table is local, that it conforms
    ** to the rules for identifiers, and that it is a table, and not
    ** a view or another database object.
    */

    IF @source_table IS NULL
        BEGIN
        	if @source_object is NOT NULL
        		select @source_table = @source_object
        	else
        		begin
            		RAISERROR (14043, 16, -1, '@source_table')
            		RETURN (1)
            	end
        END

	IF @source_owner is NULL -- 6.5 users only
	begin
    	IF @source_table LIKE '%.%.%' AND PARSENAME(@source_table, 3) <> DB_NAME()
       		BEGIN
          		RAISERROR (14004, 16, -1, @source_table)
      			RETURN (1)
       		END
    end

	-- For 7.0 users, @source_owner is not nullable.
	
	select @bak_source = @source_table
	
	IF @source_owner is not NULL
		begin
			select @source_table = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table)
		    IF @destination_table IS NULL
        		SELECT @destination_table = @bak_source
        end
    ELSE IF @destination_table IS NULL
		-- Set destination_table if not provided or default by now.
		-- If @source_table is qualified (6.x behavior) only use table name for destination name.
		SELECT @destination_table = PARSENAME(@source_table, 1)	
        
	select @num_columns=count(*) from syscolumns where id = object_id(@source_table)
	if @num_columns > 255
		begin
			RAISERROR (20068, 16, @source_table, 255)
            RETURN (1)
        end

    /*
    **  Get the id of the @source_table
    */
    SELECT @tabid = id, @object_type = type
    FROM sysobjects
    WHERE id = OBJECT_ID(@source_table)

    IF @tabid IS NULL
        BEGIN
            RAISERROR (14027, 11, -1, @source_table)
            RETURN (1)
        END

    -- at this point, we've done all the common parameter checks.
    -- If this is a procedure, branch to the proc execution publishing
    -- routine, otherwise continue processing as if it were a table

    IF @object_type = 'P'
    BEGIN
		begin tran
        save TRAN sp_addarticle

        EXECUTE @retcode = dbo.sp_MSaddexecarticle @publication,
            @article,
            @source_table,
            @destination_table,
            @type,
            @creation_script,
            @description,
            @pre_creation_cmd,
            @schema_option,
			@destination_owner,
            @article_id OUTPUT

        IF @retcode <> 0
        BEGIN
			if @@trancount > 0
			begin
				ROLLBACK TRAN sp_addarticle
				commit tran
			end
            RETURN (1)
        END
        ELSE
            GOTO DONE
    END

    /*
    ** Make sure that the table name specified is a table and not a view.
    */

    IF NOT EXISTS (SELECT * FROM sysobjects
        WHERE id = (SELECT OBJECT_ID(@source_table))
        AND type = 'U')
    BEGIN
        RAISERROR (14028, 16, -1)
        RETURN (1)
    END

    /*
    ** Parameter Check:  @destination_table.
    ** If the destination table is not specified, assume it's the same
    ** as the source table.  Make sure that the table name is not qualified.
    */

    IF @destination_table LIKE '%.%.%'
    BEGIN
        RAISERROR (14001, 16, -1)
        RETURN (1)
    END

    IF @destination_table LIKE '%.%'
    BEGIN
        RAISERROR (14044, 16, -1, '@destination_table')
        RETURN (1)
    END

    /*
    ** Parameter Check: @vertical_partition
    ** Check to make sure that the vertical partition is either TRUE or FALSE.
    */

    SELECT @vertical_partition = LOWER(@vertical_partition)
    IF @vertical_partition NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14029, 16, -1)
        RETURN (1)
    END

	--
	-- parameter check: @status
	--

	IF (@status & ~24 ) <> 0
	BEGIN
		RAISERROR( 21061, 16, -1, @status, @article )
		RETURN (1)
	END

    /*
    ** Parameter Check: @filter
    ** Make sure that the filter is a valid stored procedure.
    */
    IF @filter IS NOT NULL
    BEGIN
		IF @filter_owner IS NULL
		BEGIN
    		select @object = PARSENAME( @filter, 1 )
    		select @owner  = PARSENAME( @filter, 2 )
	    	select @db     = PARSENAME( @filter, 3 )
    		select @site   = PARSENAME( @filter, 4 )

    		if @object IS NULL
        	  return 1
		END  
		ELSE
		BEGIN
			select @filter = QUOTENAME(@filter_owner) + '.' + QUOTENAME(@filter)
		END

        /*
        ** Get the id of the @filter
        */
        select @filterid = id from sysobjects where
            id = OBJECT_ID(@filter) and type = 'RF'
        IF @filterid IS NULL
        BEGIN
            RAISERROR (14027, 11, -1, @filter)
            RETURN (1)
        END

        EXEC @is_filter_in_use = dbo.sp_MSdoesfilterhaveparent @filterid
        if( @is_filter_in_use <> 0 )
        BEGIN
	        RAISERROR( 21009, 11, -1 )
		    RETURN (1)
        END
    END
    ELSE
        select @filterid = 0


    /*
    ** Get the pubid.
    */

    -- SyncTran
    -- SELECT @pubid = pubid FROM syspublications WHERE name = @publication
    SELECT @pubid = pubid, @autogen_sync_procs_id = autogen_sync_procs, @sync_method = sync_method,
		@allow_sync_tran = allow_sync_tran 
    FROM syspublications WHERE name = @publication
    -- end SyncTran

    IF @pubid IS NULL
        BEGIN
            RAISERROR (14027, 11, -1, @publication)
            RETURN (1)
        END

    /*
    ** Parameter Check:  @article, @publication.
    ** Check if the article already exists in this publication.
    */

    IF EXISTS (SELECT *
                 FROM sysarticles
                WHERE pubid = @pubid
                  AND name = @article)
        BEGIN
            RAISERROR (14030, 16, -1, @article, @publication)
            RETURN (1)
        END

    /*
    ** Set the typeid.  The default type is logbased.  Anything else is
    ** currently undefined (reserved for future use).
    **
    **      @typeid     type
    **      =======     ========
    **          1     logbased
    **          3     logbased manualfilter
    **          5     logbased manualview
    **          7     logbased manualboth
    **          8     proc exec              (valid in dbo.sp_MSaddexecarticle)
    **          24    serializable proc exec (valid in dbo.sp_MSaddexecarticle)
    */


    IF @type IS NULL
    BEGIN
    SELECT @type = 'logbased'
    END
    ELSE IF LOWER(@type) NOT IN ('logbased', 'logbased manualfilter', 'logbased manualview', 'logbased manualboth')
    BEGIN
        RAISERROR (14023, 16, -1)
        RETURN (1)
    END

    IF LOWER(@type) = 'logbased'
        SELECT @typeid = 1
    ELSE IF LOWER(@type) = 'logbased manualfilter'
       SELECT @typeid = 3
    ELSE IF LOWER(@type) = 'logbased manualview'
       SELECT @typeid = 5
    ELSE IF LOWER(@type) = 'logbased manualboth'
        SELECT @typeid = 7

    /*
    ** Set the precmdid.  The default type is 'drop'.
    **
    **      @precmdid   pre_creation_cmd
    **      =========   ================
    **            0     none
    **          1     drop
    **          2     delete
    **          3     truncate
    */
    IF LOWER(@pre_creation_cmd) NOT IN ('none', 'drop', 'delete', 'truncate')
    BEGIN
        RAISERROR (14061, 16, -1)
        RETURN (1)
    END

    /*
    ** Determine the integer value for the pre_creation_cmd.
    */
    IF LOWER(@pre_creation_cmd) = 'none'
        SELECT @precmdid = 0
    ELSE IF LOWER(@pre_creation_cmd) = 'drop'
        SELECT @precmdid = 1
    ELSE IF LOWER(@pre_creation_cmd) = 'delete'
        SELECT @precmdid = 2
    ELSE IF LOWER(@pre_creation_cmd) = 'truncate'
        SELECT @precmdid = 3

    IF @sync_object IS NULL
        select @syncid = @tabid
    ELSE
    BEGIN

    IF @sync_object_owner is NULL  -- 6.5 only
    BEGIN

		/*
		** Parameter Check: @sync_object.
		** Check to see that the sync_object is local and that it
		** conforms to the rules for identifiers.
		*/

		select @object = PARSENAME( @sync_object, 1 )
		select @owner  = PARSENAME(  @sync_object, 2 )
		select @db     = PARSENAME(  @sync_object, 3 )
		select @site   = PARSENAME(  @sync_object, 4 )

		if @object IS NULL
			  return 1


		IF @sync_object LIKE '%.%.%' AND @db <> DB_NAME()
		BEGIN
			RAISERROR (14004, 16, -1, @sync_object)
			RETURN (1)
		END

    END -- end of 65 processing
	else -- for sphinx, @sync_object_owner can not be null
		select @sync_object = QUOTENAME(@sync_object_owner) + '.' + QUOTENAME(@sync_object)
		
        /*
        **  Get the id of the @sync_object
        */

        SELECT @syncid = id FROM sysobjects WHERE id = OBJECT_ID(@sync_object)

        IF @syncid IS NULL
        BEGIN
            RAISERROR (14027, 11, -1, @sync_object)
            RETURN (1)
        END

        /*
        ** Make sure the sync object specified is a table or a view.
        */

        IF NOT EXISTS (SELECT * FROM sysobjects
                WHERE id = (SELECT OBJECT_ID(@sync_object))
                AND (type = 'U' or
                     type = 'V'))
        BEGIN
            RAISERROR (14031, 16, -1)
            RETURN (1)
        END
    END

    /*
    ** If the publication is log-based,
    ** make sure there is a primary key on the source table.
    ** NOTE!  sprok in SPSUP.SQL
    */
    IF EXISTS (SELECT * FROM syspublications 
        WHERE pubid = @pubid AND
            (repl_freq = 0 OR allow_sync_tran = 1)
            )
    BEGIN
        EXEC @fHasPk = dbo.sp_MSreplsup_table_has_pk @tabid

        IF @fHasPk = 0
        BEGIN
            RAISERROR (14088, 16, -1, @source_table)
            RETURN (1)
        END
    END

    /*
    ** Parameter Check:  @creation_script and @schema_option
    ** @schema_option cannot be null
    ** If @schema_option is 0, there have to be @creation_script defined.
    */
    IF @schema_option IS NULL
    BEGIN
        SELECT @schema_option  = 0x0000000000000073
    END

    -- If pub sync_type is character mode bcp(1) 
    if @sync_method = 1
    begin
        select @status = 0
        if @ins_cmd is NULL  select @ins_cmd = 'SQL'
        if @upd_cmd is NULL  select @upd_cmd = 'SQL'
        if @del_cmd is NULL  select @del_cmd = 'SQL'
    end

	/*
	** Parameter Check: @schema_option
	** If Autogeneration of custom procedures is not enabled 
	** then the default commands will be SQL
	*/
	IF ((CONVERT(int, @schema_option) & 0x2) = 0)
	BEGIN
        if @ins_cmd is NULL  select @ins_cmd = 'SQL'
        if @upd_cmd is NULL  select @upd_cmd = 'SQL'
        if @del_cmd is NULL  select @del_cmd = 'SQL'
	END
	 	 
	-- Autogenerate custom procedure names if not provided.
	-- If unable to construct a name because the article name is close to the maximum length, then create a
	-- name based on the database timestamp
	if ((@source_object is not NULL and len(@article) > 119) or
	    (@source_object is NULL and len(@article) > 21))
	begin
		set @guid = CONVERT(varbinary(16), LEFT(NEWID(),8))
        exec @retcode = master.dbo.xp_varbintohexstr @guid, @custom_proc_name OUTPUT
		if @@error <> 0 or @retcode <> 0
			RETURN(1)
	end
	else
		set @custom_proc_name = @article

	-- If no command then construct name 
	if @ins_cmd is NULL
	begin
		if (@status & 16) <> 0 -- parameterized
		begin
			if @source_object is not NULL  -- 7.0 format
				set @ins_cmd = N'CALL ' + convert (sysname, 'sp_MSins_' + @custom_proc_name)
			else -- 6.x compatible
				set @ins_cmd = N'CALL ' + convert(nvarchar(30), 'sp_MSins_' + @custom_proc_name)
		end
		else
			select @ins_cmd = 'SQL'
	end

	if @del_cmd is NULL
	begin
		if (@status & 16) <> 0 -- parameterized
		begin
			if @source_object is not NULL  -- 7.0 format
				set @del_cmd = N'CALL ' + convert (sysname, 'sp_MSdel_' + @custom_proc_name)
			else -- 6.x compatible
				set @del_cmd = N'CALL ' + convert(nvarchar(30), 'sp_MSdel_' + @custom_proc_name)
		end
		else
			select @del_cmd = 'SQL'
	end

	if @upd_cmd is NULL
	begin
		if (@status & 16) <> 0 -- parameterized
		begin
			if @source_object is not NULL  -- 7.0 format
				set @upd_cmd = N'MCALL ' + convert (sysname, 'sp_MSupd_' + @custom_proc_name)
			else -- 6.x compatible
				set @upd_cmd = N'CALL ' + convert(nvarchar(30), 'sp_MSupd_' + @custom_proc_name)
		end
		else
			select @upd_cmd = 'SQL'
	end

    -- SyncTran
	-- Add timestamp column if not exists
	if @allow_sync_tran = 1 and ObjectProperty(@tabid, 'TableHasTimestamp') = 0
	begin
		exec ('alter table ' + @source_table + ' add msrepl_synctran_ts timestamp not null' )
        IF @@ERROR <> 0 
            RETURN (1)
	end

    /*
    **  Add article to sysarticles and update sysobjects category bit.
    */
	begin tran
    save TRAN sp_addarticle
        INSERT sysarticles (columns, creation_script, del_cmd, description,
            dest_table, filter, filter_clause, ins_cmd, name,
            objid, pre_creation_cmd, pubid,
            status, sync_objid, type, upd_cmd, schema_option,
			dest_owner)
        VALUES (0, @creation_script, @del_cmd, @description, @destination_table,
            @filterid, @filter_clause, @ins_cmd, @article, @tabid,
            @precmdid, @pubid, @status, @syncid, @typeid, @upd_cmd, @schema_option, 
			@destination_owner)

        IF @@ERROR <> 0
        BEGIN
			if @@trancount > 0
			begin
				ROLLBACK TRAN sp_addarticle
				commit tran
			end
            RETURN (1)
        END

        SELECT @article_id = @@IDENTITY

        UPDATE sysobjects SET replinfo =  replinfo |  @publish_bit
			WHERE id = (SELECT objid FROM sysarticles WHERE name = @article 
				and pubid =  @pubid)

        IF @@ERROR <> 0
        BEGIN
			if @@trancount > 0
			begin
				ROLLBACK TRAN sp_addarticle
				commit tran
			end
            RETURN (1)
        END

        IF @filter IS NOT NULL
        BEGIN
            EXEC dbo.sp_MSsetfilterparent @filter, @tabid
            IF @@ERROR <> 0
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
                RETURN (1)
            END
        END

        EXEC dbo.sp_MSsetfilteredstatus @tabid
        IF @@ERROR <> 0
        BEGIN
			if @@trancount > 0
			begin
				ROLLBACK TRAN sp_addarticle
				commit tran
			end
            RETURN (1)
        END

        /*
        ** Set all bits to '1' in the columns column to include all columns.
        */

        IF @vertical_partition = 'false'
        BEGIN
            EXECUTE @retcode  = dbo.sp_articlecolumn @publication, @article
			-- synctran
			, @refresh_synctran_procs = 0
            
			IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
                RETURN (1)
            END
        END
        
        /*
        ** 1. Set all bits to '1' for all columns in the primary key.
		** 2. Set timestamp column bit to 1 if the publication is synctran
        */
        ELSE
        BEGIN
            SELECT @indid = indid FROM sysindexes
            WHERE id = @tabid
            AND (status & 2048) <> 0    /* PK index */
        
            /*
            **  First we'll figure out what the keys are.
            */
            SELECT @i = 1

            WHILE (@i <= 16)
            BEGIN
                SELECT @pkkey = INDEX_COL(@source_table, @indid, @i)
                if @pkkey is NULL
                    break

                EXECUTE @retcode  = dbo.sp_articlecolumn @publication,
                    @article, @pkkey, 'add'
					-- synctran
					, @refresh_synctran_procs = 0
                IF @@ERROR <> 0 OR @retcode <> 0
                BEGIN
					if @@trancount > 0
					begin
						ROLLBACK TRAN sp_addarticle
						commit tran
					end
                    RETURN (1)
                END

                select @i = @i + 1
            END

			if @allow_sync_tran = 1 and ObjectProperty(@tabid, 'TableHasTimestamp') = 1
			begin
				declare @ts_col sysname
				-- Get synctran column
				select @ts_col = name from syscolumns 
					where id = @tabid and type_name(xtype) = 'timestamp' 
				if @ts_col is not null
				begin
					EXECUTE @retcode  = dbo.sp_articlecolumn @publication,
						@article, @ts_col, 'add'
						-- synctran
						, @refresh_synctran_procs = 0
					IF @@ERROR <> 0 OR @retcode <> 0
					BEGIN
						if @@trancount > 0
						begin
							ROLLBACK TRAN sp_addarticle
							commit tran
						end
						RETURN (1)
					END
				end
			end
        END
 
		------------------------------------------------------------------------------
		-- if table based article does not use a view for sync, create one and use it
		------------------------------------------------------------------------------

		if @tabid = @syncid 
		begin
			-- generate view name

			declare @viewname varchar(255)

			set @guid = CONVERT(varbinary(16), LEFT(NEWID(),8))
			exec @retcode = master.dbo.xp_varbintohexstr @guid, @viewname OUTPUT
			if @@ERROR <> 0 OR @retcode <> 0
			begin
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
				return 1
			end
			
			set @viewname = 'syncobj_' + @viewname

			-- create view for object synchronization

			exec @retcode = dbo.sp_articleview @publication, @article, @viewname, @filter_clause
			if @@ERROR <> 0 OR @retcode <> 0
			begin
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
				return 1
			end
		end

 DONE:

        /*
        ** Get distribution server information for remote RPC call.
        */
        EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
           @distribdb   = @distribdb OUTPUT
        IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
		        RAISERROR (14071, 16, -1)
                RETURN (1)
            END

        SELECT @dbname =  DB_NAME()
        
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
            '.dbo.sp_MSadd_article'
        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = @publication,
            @article = @article,
            @article_id = @article_id,
			@destination_object = @destination_table,
			@source_owner = @source_owner,
			@source_object = @bak_source,
			@description = @description


        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
			if @@trancount > 0
			begin
				ROLLBACK TRAN sp_addarticle
				commit tran
			end
            RETURN (1)
        END
        
        
        /* If the publication is immediate_sync type
        ** 1. Change the immediate_sync_ready status to false 
        ** 2. Add a virtual subscription on the article 
        ** 3. Add subscriptions for all the subscriber
        ** that have no_sync subscriptions on the publication
        **
        ** Note: Subscriptions for subscribers that have automatic sync subscriptions
        ** on the publication will be added by snasphot agent.
        */
        if EXISTS (SELECT *    FROM syspublications WHERE
            name = @publication    AND
            immediate_sync = 1 )
        BEGIN
            UPDATE syspublications SET immediate_sync_ready = 0
                WHERE name = @publication 
            IF @@ERROR <> 0 
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
                RETURN (1)
            END


            EXECUTE @retcode  = dbo.sp_addsubscription 
                @publication = @publication, 
                @article = @article, 
                @subscriber = NULL, 
                @destination_db = 'virtual', 
                @sync_type = 'automatic', 
                @status = NULL, 
                @reserved = 'internal'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
                RETURN (1)
            END

			-- Note: We have to add the subscriptions to the new article before 
			-- the virtual subscriptions being activated!!!! Otherwise, the snapshot 
			-- transactions may be skipped by dist agents.
            EXECUTE @retcode  = dbo.sp_refreshsubscriptions @publication

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_addarticle
					commit tran
				end
                RETURN (1)
            END 
        END

        /* 
        ** if @autogen_sync_procs_id is 1, autogen the sync tran procs, including name 
        */
        if @tabid > 0 and @autogen_sync_procs_id = 1
        begin
            declare @insproc sysname, @updproc sysname, @delproc sysname

            select @insproc = 'sp_MSsync_ins_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @pubid))
            select @updproc = 'sp_MSsync_upd_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @pubid))
            select @delproc = 'sp_MSsync_del_' + SUBSTRING(RTRIM(@article), 1, 100) + '_' + rtrim(convert(varchar, @pubid))

	        -- check uniqueness of names and revert to ugly guid-based name if friendly name already exists
	        if exists (select name from sysobjects where name in (@insproc, @updproc, @delproc))
            begin
                declare @guid_name nvarchar(36)
                select @guid_name =  convert (nvarchar(36), newid())
				-- remove '-' from guid name because rpc can't handle '-'
			    select @guid_name = replace (@guid_name,'-','_')
		        select @insproc = 'sp_MSsync_ins_' + @guid_name
		        select @updproc = 'sp_MSsync_upd_' + @guid_name
		        select @delproc = 'sp_MSsync_del_' + @guid_name
            end

            if @insproc IS NULL
            begin
				if @@trancount > 0
				begin
					ROLLBACK TRANSACTION sp_addarticle
					commit tran
				end
                RAISERROR (14043, 11, -1, '@insproc')
                RETURN (1)
            end

            if @updproc IS NULL
            begin
				if @@trancount > 0
				begin
					ROLLBACK TRANSACTION sp_addarticle
					commit tran
				end
                RAISERROR (14043, 11, -1, '@updproc')
                RETURN (1)
            end

            if @delproc IS NULL
            begin
				if @@trancount > 0
				begin
					ROLLBACK TRANSACTION sp_addarticle
					commit tran
				end
                RAISERROR (14043, 11, -1, '@delproc')
                RETURN (1)
            end


            exec @retcode = dbo.sp_articlesynctranprocs @publication, @article, @insproc, @updproc, @delproc, true

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRANSACTION sp_addarticle
					commit tran
				end
                RETURN (1)
            END
        end
        -- end SyncTran

    COMMIT TRANSACTION
go
 
/*
** Create replication stored procedures.
** Part 1:  create codependent procedures.
*/

EXEC dbo.sp_MS_marksystemobject sp_addarticle
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
) AS

    SET NOCOUNT ON
    DECLARE @inactive tinyint
    DECLARE @subscribed tinyint
    DECLARE @active 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 @cmd0 nvarchar (255)
    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 @art_change bit
    declare @login_name sysname

    -- 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 @public = 0          /* Const: publication status 'public' */
    SELECT @pub_db = DB_NAME()
    SELECT @virtual_id = -1
    SELECT @art_change = 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 sysarticles 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)
                          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
    */

    IF LOWER(@status) NOT IN ('active', 'subscribed', 'inactive')
        BEGIN
            RAISERROR (14065, 16, -1)
        RETURN (1)
        END

    IF LOWER(@status) IN ('active')
        SELECT @statusid = @active
    ELSE IF LOWER(@status) 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
    */

    IF @previous_status IS NOT NULL
    BEGIN
        IF LOWER(@previous_status) NOT IN ('active', 'subscribed', 'inactive')
        BEGIN
            RAISERROR (14066, 16, -1)
            RETURN (1)
        END

        IF LOWER(@status) = LOWER(@previous_status)
        BEGIN
            RAISERROR (14067, 16, -1)
            RETURN (1)
        END

        IF LOWER(@previous_status) IN ('active')
            SELECT @prevstatid = @active
        ELSE IF LOWER(@previous_status) 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

    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' 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
                          FROM syssubscriptions sub,
                               sysarticles art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication
                           AND art.name LIKE @article
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                            AND sub.status = @prevstatid
                           AND sub.dest_db LIKE @destination_db
                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' 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
                          FROM syssubscriptions sub,
                               sysarticles art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication
                           AND art.name LIKE @article
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND sub.dest_db LIKE @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_MSarticletextcol 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 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

                      FROM syssubscriptions sub,
                           sysarticles 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


            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

                /*
                ** If current status is same as new status, do nothing.
                ** @auto_sync_only is used by snapshot for immediate_sync
                ** publications.
                */
                IF @sub_status = @statusid OR
                    (@from_auto_sync = 1 AND @sync_type <> @automatic)
                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

                    CONTINUE
                END

                /*
                ** Update syssubscription status
                */
                UPDATE syssubscriptions
                       SET status = @statusid
                       FROM syssubscriptions sub,
                           sysarticles 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

                /*
                ** Get timestamp of subscription.
                */
                EXEC @retcode = dbo.sp_replincrementlsn @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 activating subscription, update sysarticles, sysobjects and
                ** MSrepl_subscriptions.
                */
                IF @statusid = @active
                BEGIN
                    
                    /*
                    ** Update status of article to show it has been activated.
                    */
                    IF @repl_freq = 0 and EXISTS (SELECT * FROM sysarticles WHERE artid = @artid
                        AND status & 1 <> 1)
                    BEGIN
                        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
                        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 sysarticles 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 Text\Image 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_MSarticletextcol @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_MSarticletextcol @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 sysarticles, sysobjects and
                ** MSrepl_subscriptions.
                */

                IF @statusid <> @active AND @sub_status = @active
                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 sysarticles WHERE artid = @artid
                            AND status & 1 = 1)
                        BEGIN
                            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
                            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 sysarticles 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 sysarticles 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


                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

                        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 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 = @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 = @active AND
                    NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                    artid IN (SELECT artid FROM sysarticles WHERE
                    objid = @tabid) AND status = @active)
                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

                -- updates done flush in-memory object schema info

                declare @qualified_name nvarchar(512)

                exec dbo.sp_MSget_qualified_name @tabid, @qualified_name output
                exec dbo.sp_replupdateschema @qualified_name

               /*
               ** 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

          
                                    
           END  -- end while for cursor

           CLOSE hCsubstatus
           DEALLOCATE hCsubstatus
        
        END -- end while for virtual and real

        -- force refresh of article cache
        -- Bug 25265: Only do it if necessary
        -- Bug 47732: No need on brute force cleanup
        IF ( @art_change = 1 ) and ( @ignore_distributor = 0 )
            EXECUTE dbo.sp_replflush

    COMMIT TRANSACTION
    RETURN(0)
go
 
EXEC dbo.sp_MS_marksystemobject sp_changesubstatus
GO

print ''
print 'Creating procedure sp_addsubscription'
go
CREATE PROCEDURE sp_addsubscription (
    @publication sysname,                            /* publication name */
    @article sysname = 'all',                        /* article name */
    @subscriber sysname = NULL,                        /* subscriber name */
    @destination_db sysname = NULL,                /* destination database */
    @sync_type nvarchar (15) = 'automatic',                /* subscription sync type */
    @status sysname = NULL,                            /* subscription status */
    @subscription_type nvarchar(4) = 'push',                /* subscription type:
                                                        ** 'push' or 'pull' */
    -- SyncTran
    @update_mode           nvarchar(15)    = 'read only',    -- Can be 'read only', 'sync tran'
    @loopback_detection nvarchar(5) = NULL, -- 'true' or 'false'
    -- end SyncTran

    @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,
    
    @reserved nvarchar(10) = NULL,          /* reserved, used when calling from other system */
                                            /* stored procedures, it will be set to 'internal'.*/
                                            /* It should never be used directly */
    @enabled_for_syncmgr nvarchar(5) = 'false' /* Enabled for SYNCMGR: true or false */
                                        
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @artid int
    DECLARE @pre_creation_cmd tinyint
    DECLARE @none tinyint
    DECLARE @automatic tinyint
    DECLARE @cmd nvarchar(255)
    DECLARE @cmd2 nvarchar(255)
    DECLARE @inactive tinyint
    DECLARE @active tinyint
    DECLARE @subscribed tinyint
    DECLARE @manual tinyint
    DECLARE @pubid int
    DECLARE @retcode int
    DECLARE @srvid smallint
    DECLARE @subscriber_bit smallint
    DECLARE @sync_typeid tinyint
    DECLARE @non_sql_flag bit
    DECLARE @truncate tinyint
    DECLARE @sync_method tinyint
    DECLARE @char_bcp tinyint
    DECLARE @internal nvarchar(10)
    DECLARE @status_id tinyint
    DECLARE @virtual_id smallint
    DECLARE @subscription_type_id int /* 0 push, 1 pull */
    DECLARE @immediate_sync bit    /* publication type */
    DECLARE @count_subs int
    DECLARE @count_arts int
    DECLARE @distribution_jobid binary(16)
    DECLARE @pubstatus tinyint
    DECLARE @allow_anonymous bit
    DECLARE @immediate_sync_ready bit
    declare @loopback_detection_id bit
    declare @independent_agent_id bit
    DECLARE @platform_nt binary

    DECLARE @dsn_dbname sysname

    -- SyncTran
    DECLARE @allow_sync_tran_id bit
    DECLARE @update_mode_id     tinyint -- 0 = read only, 1 = sync tran
    -- end SyncTran

    /*
    ** Initializations.
    */

    SELECT @none = 2            /* Const: synchronization type 'none' */
    SELECT @automatic = 1       /* Const: synchronization type 'automatic' */
    SELECT @manual = 0          /* Const: synchronization type 'manual' */
    SELECT @inactive = 0        /* Const: subscription status 'inactive' */
    SELECT @subscribed = 1        /* Const: subscription status 'subscribed' */
    SELECT @active = 2        /* Const: subscription status 'arctive' */
    SELECT @subscriber_bit = 4  /* Const: subscription server status */
    SELECT @truncate = 3    /* Const: truncate pre-creation command */
    SELECT @char_bcp = 1    /* Const: character bcp sync method */
    SELECT @virtual_id = -1 /* Const: virtual subscriber id */
    SELECT @internal = 'internal' /* Const: Flag of calling internally from system */
                                  /* stored procedures     */


    -- Hardcoded in sqlrepl.h
    SELECT @dsn_dbname = 'DSN'
    SELECT @platform_nt = 0x1
 
    /*
    ** Parameter Check: @publication.
    ** Check to make sure that the publication exists and that it conforms
    ** to the rules for identifiers.
    ** set subscription_type for the publication
    */

    IF @publication IS NOT NULL
        BEGIN
            
            EXECUTE @retcode = dbo.sp_validname @publication

            IF @retcode <> 0
        RETURN (1)

            IF NOT EXISTS (SELECT * FROM syspublications WHERE name = @publication)
                BEGIN
                    RAISERROR (20026, 11, -1, @publication)
                    RETURN (1)
                END

        END

    /*
    ** Parameter Check: @subscription_type
    ** Valid values:
    ** push
    ** pull
    **
    */

    IF LOWER(@subscription_type) NOT IN ('push', 'pull')
        BEGIN
            RAISERROR (14128, 16, -1)    
            RETURN (1)
        END

    IF LOWER(@subscription_type) = 'push'
        SELECT @subscription_type_id = 0
    ELSE 
        SELECT @subscription_type_id = 1

    /*
    ** Security Check.
    */

    IF @subscription_type_id = 0 
    BEGIN
        exec @retcode = dbo.sp_MSreplcheck_publish
        if @@ERROR <> 0 or @retcode <> 0
            return(1)
    END
    ELSE
    BEGIN
        exec @retcode = dbo.sp_MSreplcheck_pull @publication
        if @@ERROR <> 0 or @retcode <> 0
            return(1)
    END

   SELECT @pubid = pubid, @sync_method = sync_method, 
        @immediate_sync = immediate_sync, @pubstatus = status, 
        @allow_anonymous = allow_anonymous, 
        @immediate_sync_ready = immediate_sync_ready,
        -- SyncTran
        @allow_sync_tran_id = allow_sync_tran,
        @independent_agent_id = independent_agent
    FROM syspublications WHERE name = @publication

    select @srvid = srvid from master..sysservers where UPPER(srvname)=UPPER(@subscriber)

    if exists (select name from sysobjects where name='sysmergesubscriptions')
        begin
            IF exists (select name from sysarticles where pubid=@pubid and 
                objid in (select objid from sysmergearticles where 
                    pubid in (select pubid from sysmergesubscriptions where db_name=@destination_db and srvid=@srvid)))
            begin
                RAISERROR(20084, 16, -1, @publication, @destination_db)
                return (1)
            end
        end


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


    /* 
    ** Check to see if the desired subscription type is allowed
    */
    /* 
    ** push 
    ** Virtual subscriptions are always push type
    */
    IF @subscription_type_id = 0 AND @subscriber IS NOT NULL
    BEGIN
        IF NOT EXISTS (SELECT * from syspublications where
            allow_push = 1 AND
            pubid = @pubid)
        BEGIN
            RAISERROR (20012, 16, -1, @subscription_type, @publication)    
            RETURN (1)
        END
    END
        
    /* pull */
    IF @subscription_type_id = 1 AND @subscriber IS NOT NULL
    BEGIN
        IF NOT EXISTS (SELECT * from syspublications where
            allow_pull = 1 AND
            pubid = @pubid)
        BEGIN
            RAISERROR (20012, 16, -1, @subscription_type, @publication)    
            RETURN (1)
        END
    END


 /*
    ** Parameter Check: @subscriber.
    **
    ** Check if the server exists and that it is a subscription server.
    **
    ** @subscriber is NULL represent virtual subscription, which is not allowed
    ** in following case:
    ** 1. Non-immediate-sync publication
    ** 2. the stored procedure is not in the internal usage mode 
    **        (called by system stored procedures)
    ** 3. non push mode
    ** 
    */

    IF  @subscriber IS NULL AND (
        @immediate_sync = 0 OR
        @subscription_type_id <> 0 OR
        @reserved <> @internal)
        BEGIN
            RAISERROR (14043, 16, -1, '@subscriber')
            RETURN (1)
        END


    IF @subscriber IS NULL
        BEGIN
        /* set virtual subscriber ID */
            SELECT @srvid = @virtual_id 
            select @non_sql_flag = 0
        END
    ELSE
        BEGIN
            /* validate name and get subscriber ID  and server status  */
            EXECUTE @retcode = dbo.sp_validname @subscriber

            IF @retcode <> 0
            RETURN (1)

			select @srvid = null
            SELECT @srvid = srvid, @non_sql_flag = 
                case when srvproduct = N'MSREPL-NONSQL' then 1
                else 0 end
              FROM master..sysservers
             WHERE UPPER(srvname) = UPPER(@subscriber)
               AND (srvstatus & @subscriber_bit) <> 0

            IF @srvid IS NULL
                BEGIN
                    RAISERROR (14010, 16, -1)
                   RETURN (1)
                END
        END

    /*
    ** Parameter Check: @destination_db.
    ** @destination_db can not be all. 
    ** Set @destination_db to current database if not specified.  Make
    ** sure that the @destination_db conforms to the rules for identifiers.
    */

    if LOWER(@destination_db) = 'all'
    BEGIN
        RAISERROR (14032, 16, -1, '@destination_db')
        RETURN (1)
    END

    IF @destination_db IS NULL SELECT @destination_db = DB_NAME()
    
    EXECUTE @retcode = dbo.sp_validname @destination_db

    IF @retcode <> 0
    RETURN (1)

    /*
    ** Parameter Check:  @article
    */

    /* @article can not be null     */
    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END

    -- SyncTran
    /*
    ** Parameter check: @update_mode
    */
    IF @update_mode IS NULL OR LOWER(@update_mode) NOT IN ('read only', 'sync tran')
    BEGIN
        RAISERROR (20502, 16, -1, '@update_mode')
        RETURN (1)
    END

    IF LOWER(@update_mode) = 'sync tran' 
    BEGIN
        SELECT @update_mode_id = 1
       
        -- Check if publication allows this option
        IF @allow_sync_tran_id <> 1
        BEGIN
            RAISERROR (20503, 16, -1, '@update_mode', 'sp_addsubscription')
            RETURN (1)
        END

    END
    ELSE 
    BEGIN
        SELECT @update_mode_id = 0
    END
    -- end SyncTran

    /** For immediate_sync publication, @article has to be 'all'     */
    IF NOT @reserved = @internal AND @immediate_sync = 1
        AND NOT LOWER(@article) = 'all'
        BEGIN
            RAISERROR (14122, 16, -1)
            RETURN (1)
        END

    /* For immediate_sync publication,there has to be at least one
    ** article in the publication before the publication can be subscribed.
    */
    IF @immediate_sync = 1 AND not exists ( SELECT * from sysarticles sa, 
        syspublications sp WHERE sa.pubid = sp.pubid AND sp.name = @publication)
        BEGIN
            RAISERROR (14124, 16, -1)
            RETURN(1)
        END

    /* 
    ** For full subscription, check to see if  subscriptions
    ** to ALL the articles exist before expanding parameter @article.
    **
    */
    IF LOWER(@article) = 'all' AND @reserved <> @internal AND
        EXISTS (SELECT * FROM syspublications WHERE pubid = @pubid)
    BEGIN
        SELECT @count_arts = count(*) FROM sysarticles art
            WHERE art.pubid = @pubid 

        SELECT @count_subs = count(*) FROM syssubscriptions sub, 
                  sysarticles art
            WHERE sub.srvid = @srvid
              AND sub.srvid >= 0
              AND sub.dest_db = @destination_db
              AND sub.artid = art.artid
              AND art.pubid = @pubid

        IF (@count_arts = @count_subs)
        BEGIN
              RAISERROR (14058, 16, -1)
              RETURN (1)
        END
    END

    /* 
    ** Real subscription to inactive publicaton is not allowed
    ** Note, subscriptions to the new article will be added automatically
    ** for immediate_sync publications. At that time, the publication may not
    ** be active.
    */

    IF  @srvid <> @virtual_id AND @pubstatus = 0 AND @reserved <> @internal
        BEGIN
            RAISERROR (21000, 16, -1)
            RETURN (1)
        END

    /* 
    ** Do special things for DSN subscribers.
    */
    IF @subscriber IS NOT NULL AND @non_sql_flag <> 0
    BEGIN
        -- DSN subscriber cannot subscribe to native mode publication
        IF @sync_method <> @char_bcp
        BEGIN
            RAISERROR (14095, 16, -1, @publication, @subscriber)
            RETURN (1)
        END

        -- DSN subscriber cannot subscribe with 'Sync Update'
        IF @update_mode_id <> 0
        BEGIN
            RAISERROR (21032, 16, -1, @subscriber)
            RETURN (1)
        END

        -- DSN subscriber cannot subscribe to article using custom procs
        -- or articles using parameterized statements
        -- ( only run this test during execs when the article name is actually specified )
        IF( LOWER( @article ) <> 'all' )
        BEGIN
            --IF EXISTS ( select * from sysarticles sa, syspublications sp
                        --where sa.pubid = sp.pubid 
                        --and sp.name = @publication
                        --and sa.name = @article
                        --and ( ins_cmd like '%call%' or upd_cmd like '%call%' or del_cmd like '%call%' ) )
            --BEGIN
                --RAISERROR(21051, 16, -1, @subscriber)
                --RETURN (1)
            --END

            IF EXISTS ( select * from sysarticles sa, syspublications sp
                        where sa.pubid = sp.pubid 
                        and sp.name = @publication
                        and sa.name = @article
                        and sa.status & 16 = 16 ) 
            BEGIN
                RAISERROR(21060, 16, -1, @subscriber)
                RETURN (1)
            END

        END

        -- bug 24486 subscriber db of DSN subscriber is meaningless
        -- use internal values
        IF @non_sql_flag <> 0 
            SELECT @destination_db = @dsn_dbname

        
    END


    IF LOWER(@article) = 'all' 
    /*
    ** Get all articles in the publication that are not subscribed to
    ** by the @subscriber
    */
    BEGIN
            /*
            ** Make the operation atomic. This is to prevent multiple subscription_type
            ** from one subscriber on an immediate_sync publication
            */
            BEGIN TRAN 

            DECLARE hCx CURSOR LOCAL FAST_FORWARD FOR  SELECT DISTINCT a.name
                FROM sysarticles a, syspublications b  
                WHERE a.pubid = b.pubid 
                AND b.name = @publication
                AND NOT EXISTS (SELECT * from syssubscriptions s 
                    WHERE s.artid = a.artid AND s.status <> 0 AND s.srvid = @srvid
                    AND s.dest_db = @destination_db)
            FOR READ ONLY

            EXECUTE (@cmd + @cmd2)
            OPEN hCx
            FETCH hCx INTO @article

            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE @retcode = dbo.sp_addsubscription 
                                @publication       = @publication,
                                @article        = @article,
                                @subscriber     = @subscriber,
                                @destination_db = @destination_db,
                                @sync_type      = @sync_type,
								@status			= @status,
                                @subscription_type = @subscription_type,
                                @reserved       = @internal,
                                -- SyncTran
                                @update_mode    = @update_mode,      
                                -- end SyncTran
								@loopback_detection = @loopback_detection,
                                @frequency_type  = @frequency_type,
                                @frequency_interval  = @frequency_interval,
                                @frequency_relative_interval  = @frequency_relative_interval,
                                @frequency_recurrence_factor  = @frequency_recurrence_factor,
                                @frequency_subday  = @frequency_subday,
                                @frequency_subday_interval  = @frequency_subday_interval,
                                @active_start_time_of_day  = @active_start_time_of_day,
                                @active_end_time_of_day  = @active_end_time_of_day,
                                @active_start_date  = @active_start_date,
                                @active_end_date  = @active_end_date,
                                @optional_command_line = @optional_command_line
    

                    IF @@error <> 0 OR @retcode <> 0
                    BEGIN
                       CLOSE hCx
                       DEALLOCATE hCx
                       if @@trancount > 0
                            ROLLBACK TRAN 
                       RETURN (1)
                    END
                    FETCH hCx INTO @article
                END
            CLOSE hCx
            DEALLOCATE hCx

            COMMIT TRAN

            RETURN (0)
        END

   
    /* After 'all' being expanded, check to make sure that the article exists, 
    ** is not NULL, and conforms to the rules for identifiers.
    */
    /*
    EXECUTE @retcode = dbo.sp_validname @article
    IF @retcode <> 0
    RETURN (1)
    */

    SELECT @artid = artid, @pre_creation_cmd = pre_creation_cmd
    FROM sysarticles
    WHERE name = @article
    AND pubid = @pubid

    IF NOT EXISTS (SELECT *
                             FROM sysarticles
                            WHERE artid = @artid
                              AND pubid = @pubid)
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END


    /*
    ** If the subscriber is an ODBC DSN, do not allow subscriptions to
    ** articles with a "truncate" pre_creation_cmd.
    */
    IF @non_sql_flag <> 0 AND @pre_creation_cmd = @truncate
        BEGIN
            RAISERROR (14094, 16, -1, @article, @subscriber)
            RETURN (1)
        END

   /*
   ** Parameter Check: @sync_type.
   ** Set sync_typeid based on the @sync_type specified.
   **
   **   sync_typeid     sync_type
   **   ===========     =========
   **             0     manual
   **             1     automatic
   **             2     none
   */


   IF LOWER(@sync_type) NOT IN ('automatic', 'manual', 'none')
       BEGIN
           RAISERROR (14052, 16, -1)
           RETURN (1)
       END

   IF LOWER(@sync_type) = 'manual'
       BEGIN
           RAISERROR (14123, 16, -1)
           RETURN (1)
       END


   IF LOWER(@sync_type) = 'automatic'
   BEGIN
        SELECT @sync_typeid = @automatic
   END
   ELSE
   BEGIN
        SELECT @sync_typeid = @none
   END



    /*
    ** Bug 12850:
    ** Make sure that the creation_script is specified if pre_creation_cmd is "drop"
    ** Note that at this point, @article cannot be 'all'.
    */
    /*  NO LONGER REQUIRED IN 7.0
        if exists (select * from sysarticles where
                name = @article AND
                pre_creation_cmd = 1 AND
                creation_script is null)
            BEGIN
                RAISERROR (14096, 16, -1)    
                RETURN (1)
            END
    */

    /*
    ** Parameter Check: @status
    ** If the publication is immediate_sync type and sync_type is automatic
    ** the status has to be NULL.
    ** Note for 6x backward compatibility, don't do the check for non immediate_sync
    ** publication
    */
    IF @immediate_sync = 1 and @sync_typeid = @automatic AND 
        @status IS NOT NULL
    BEGIN
          RAISERROR (14129, 16, -1)
          RETURN (1)
    END


    /*
    ** Parameter Check:  @loopback_detection
    */
    IF @loopback_detection is not null and LOWER(@loopback_detection) 
        NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@loopback_detection')
        RETURN (1)
    END

    IF  LOWER(@loopback_detection) = 'true'  
        SELECT @loopback_detection_id = 1
    ELSE IF LOWER(@loopback_detection) = 'false' 
        SELECT @loopback_detection_id = 0
    ELSE 
    -- if @loopback_detection is null, we will chose the value
    begin
        if @update_mode_id = 1 
        begin
            declare @tabid int
            select @tabid = objid from sysarticles 
                where artid = @artid
            -- Determine if table has timestamp property
            if ObjectProperty(@tabid, 'TableHasTimestamp') = 1 
            begin
                exec @retcode = dbo.sp_MSis_col_replicated @publication, @article, 'timestamp'
                if @@error <> 0
                    return (1)

                if @retcode = 1
                    select @loopback_detection_id = 1
                else
                    select @loopback_detection_id = 0
            end
            else
                select @loopback_detection_id = 0
        end
        else
            select @loopback_detection_id = 0
    end

    /*
    ** Add subscription to syssubscriptions
    */
    begin tran
    save TRAN addsubscription

    /*
    ** If no subscription exists, add it to syssubscriptions.
    */
    /* (leih) SID: getting around bug( 17371 ) */
    IF NOT EXISTS (SELECT *
                     FROM syssubscriptions
                    WHERE srvid = @srvid
                      AND artid = @artid
                      AND dest_db = @destination_db)
        BEGIN
       INSERT syssubscriptions (artid,
                                    srvid,
                                    dest_db,
                                    login_name,
                                    status,
                                    sync_type,
                                    subscription_type,
                                    distribution_jobid,
                                    -- SyncTran
                                    update_mode,
                                    loopback_detection)
                                 /*  timestamp) */
       VALUES (@artid,
                   @srvid,
                   @destination_db,    
                   suser_sname(suser_sid()),
                   @inactive,
                   @sync_typeid,
                   @subscription_type_id,
                   0,
                   -- SyncTran
                   @update_mode_id,
                   @loopback_detection_id)

           /*  NULL) */

       IF @@ERROR <> 0
           BEGIN
                if @@trancount > 0
                begin
                    ROLLBACK TRAN  addsubscription
                    commit tran
                end
                RAISERROR (14057, 16, -1)
                RETURN (1)
           END
        END
    ELSE
       BEGIN
          RAISERROR (14058, 16, -1)
          if @@trancount > 0
            begin
                ROLLBACK TRAN  addsubscription
                commit tran
            end
          RETURN (1)
       END

    /*
    ** If the @status was not provided determine the default value.
    ** If the @sync_type = 'none' then the subscription defaults to 'active'.
    ** Else the subscription defaults to 'subscribed'.
    */
    IF @status IS NULL
    BEGIN
        IF @sync_typeid = @none    
            SELECT @status = 'active'
        ELSE
            SELECT @status = 'subscribed'
    END

    /*
    ** Set publication subscription status.
    */
    EXEC @retcode = dbo.sp_changesubstatus
    @publication = @publication,
    @article     = @article,
    @subscriber  = @subscriber,
    @status      = @status,
    @destination_db = @destination_db,
    
    @frequency_type  = @frequency_type,
    @frequency_interval  = @frequency_interval,
    @frequency_relative_interval  = @frequency_relative_interval,
    @frequency_recurrence_factor  = @frequency_recurrence_factor,
    @frequency_subday  = @frequency_subday,
    @frequency_subday_interval  = @frequency_subday_interval,
    @active_start_time_of_day  = @active_start_time_of_day,
    @active_end_time_of_day  = @active_end_time_of_day,
    @active_start_date  = @active_start_date,
    @active_end_date  = @active_end_date,
    @optional_command_line = @optional_command_line,
    @distribution_jobid = @distribution_jobid OUTPUT
    IF @@error <> 0 OR @retcode <> 0
    BEGIN
        if @@trancount > 0
        begin
            ROLLBACK TRAN  addsubscription
            commit tran
        end
       RAISERROR (14057, 16, -1)
       RETURN (1)
    END

    UPDATE syssubscriptions SET 
        distribution_jobid = @distribution_jobid where
        artid = @artid AND
        srvid = @srvid AND
        dest_db = @destination_db            

    IF @@error <> 0
    BEGIN
        if @@trancount > 0
        begin
            ROLLBACK TRAN  addsubscription
            commit tran
        end
       RETURN (1)
    END


    /*
    ** If possible, activate the real subscriptions on immediate_sync publication
    ** immediately. Also, activate the virtual subscriptions on 
    ** anonymous publications immediately.
    ** We change the subscription status from 'subscribed' to 'active' so that 
    ** sp_MSupdate_subscription will be called, which will set the subscription's
    ** xactid_ts to the snapshot xactid_ts of virtual subscriptions. This means that
    ** we have to call sp_changesubstatus again here. We can not combine two calls 
    ** into ONE !!!
    **
    ** Activate the subscription immediately if 
    ** 1. The publication is immediate_sync type
    ** 2. sync_type is 'automatic'
    ** AND
    ** 1. The subscription is real
    ** 2. The snapshot has completed once
    ** 3. The subscription is the last subscription added to the publication (subscription for
    ** the last article). This is to guarantee the subscription status of all the articles
    ** in the publication be activate in one transaction at the distributor. This is
    ** to prevent the distribution agent from picking up partial subscriptions. 
    ** Note that this SP will be called with @article = 'all'
    ** OR
    ** 1. The publication is active
    ** 2. The publication is allow_anonymous
    ** 3. The subscription is virtual
    ** 
    */
    
    IF  @sync_typeid = @automatic AND @immediate_sync = 1 AND
        
        ((@srvid <> @virtual_id AND 
        @immediate_sync_ready = 1 AND
        NOT EXISTS (select * from sysarticles art where
                    art.pubid = @pubid and
                    not exists (select * from syssubscriptions sub
                        where sub.artid = art.artid and
                              sub.srvid = @srvid and
                              sub.dest_db = @destination_db))) OR

        (@pubstatus = 1 and @srvid = @virtual_id and @allow_anonymous = 1))
    BEGIN
        DECLARE @article_ex sysname
        IF @srvid <> @virtual_id
            SELECT @article_ex = '%'
        ELSE
            SELECT @article_ex = @article

        /*
        ** Set publication subscription status.
        */
        EXEC @retcode = dbo.sp_changesubstatus
        @publication = @publication,
        @article     = @article_ex,
        @subscriber  = @subscriber,
        @status      = 'active',
        @destination_db = @destination_db

        IF @@error <> 0 OR @retcode <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN  addsubscription
                commit tran
            end
           RAISERROR (14057, 16, -1)
           RETURN (1)
        END
    END

    /* Conditional support for MobileSync */
    if LOWER(@enabled_for_syncmgr) = 'true'
    BEGIN
        /* MobileSync Support */
        declare @distributor_server                 sysname
        declare @distributor_security_mode          int
        declare @distributor_login                  sysname
        declare @distributor_password               sysname
        declare @publisher_db sysname
        
        set @publisher_db = DB_NAME()
        /* 
        ** The registry entry needs to be created only for push subscriptions -  
        ** i.e - need not be called when a pull subscription is created at the 
        ** subscriber and sp_addmergesubscription is being called then.
        */
        IF LOWER(@subscription_type) = 'push'
        BEGIN
            EXECUTE @retcode = dbo.sp_helpdistributor
                @distributor = @distributor_server OUTPUT               /* Distributor RPC server name */

            IF @@ERROR <> 0 or @retcode <> 0
                BEGIN
                    if @@trancount > 0
                        ROLLBACK TRAN  addsubscription
                    RAISERROR (14057, 16, -1)
                    RETURN (1)
                END

            -- Always use integrated security on winNT
            if (@platform_nt = platform() & @platform_nt )
                begin
                    set @distributor_security_mode = 1
                end
            -- For Win9x the dist publisher and distributor are the same machine                
            else
                begin
                    select  @distributor_security_mode = 0,
                        @distributor_login  = login,
                        @distributor_password = [REDACTED]
                    from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername)
                end


            /* Call sp_MSregistersubscription so that the subscription can be synchronized via Onestop etc. */
            declare @subscription_id uniqueidentifier
            set @subscription_id = convert(uniqueidentifier, @distribution_jobid)
            exec @retcode = dbo.sp_MSregistersubscription @replication_type = 1,
                                    @publisher = @@SERVERNAME,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @subscriber = @subscriber,
                                    @subscriber_db = @destination_db,
                                    @distributor = @distributor_server,
                                    @distributor_security_mode = @distributor_security_mode,
                                    @distributor_login = @distributor_login,
                                    @distributor_password = [REDACTED]
                                    @subscription_id = @subscription_id,
                                    @independent_agent = @independent_agent_id,
                                    @subscription_type = @subscription_type_id


            IF @@ERROR <> 0 or @retcode <> 0
                BEGIN
                    if @@trancount > 0
                        ROLLBACK TRAN  addsubscription
                    RAISERROR (14057, 16, -1)
                    RETURN (1)
                END
        END
    END
    COMMIT TRAN
go
 
EXEC dbo.sp_MS_marksystemobject sp_addsubscription
GO

print ''
print 'Creating procedure sp_changearticle'
GO
CREATE PROCEDURE sp_changearticle (
    @publication sysname = NULL,        /* Publication name */
    @article sysname = NULL,            /* Article name */
    @property nvarchar(20) = NULL,           /* The property to change */
    @value nvarchar(255) = NULL              /* The new property value */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @artid int
    DECLARE @cmd1 nvarchar(512)
    DECLARE @cmd2 nvarchar(512)
    DECLARE @db sysname
    DECLARE @filter int
    DECLARE @object sysname
    DECLARE @owner sysname
    DECLARE @pubid int
    DECLARE @retcode int
    DECLARE @site sysname
    DECLARE @sync_objid int
    DECLARE @typeid tinyint
    DECLARE @precmdid tinyint
    DECLARE @active tinyint
    DECLARE @virtual_id smallint

    DECLARE @objid    int
    DECLARE @objtype  nchar(2)
    DECLARE @old_filter_name sysname

    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @dbname sysname
	DECLARE @distproc nvarchar (255)
	DECLARE @article_id int

    select @active = 2
    select @virtual_id = -1

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

    /*
    ** Check to see if the database has been activated for publication.
    */

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0

    BEGIN
            RAISERROR (14013, 16, -1)
            RETURN (1)
        END


    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

    SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END
    ELSE

    /*
    ** Check to see that the article exists in sysarticles.
    ** Fetch the article identification number.
    */

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

    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @retcode <> 0
    RETURN (1)
    */

    SELECT @artid = artid
      FROM sysarticles
     WHERE name = @article
       AND pubid = @pubid
    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END


    /*
    ** Some options on cannot be modified if articles have active subscriptions
	** (excluding virtual subscriptions).
    */
    IF EXISTS (SELECT * FROM syssubscriptions WHERE artid = @artid
       AND status = @active 
       AND srvid >=0
	   AND @property in (N'type', N'filter')  )
        BEGIN
            RAISERROR (14092, 11, -1, @property, @article )
            RETURN (1)
        END

    /*
    ** Get the object id and type from sysobjects
    */

    SELECT @objtype = type
       FROM sysobjects
       WHERE id = ( SELECT  objid
                      FROM  sysarticles
                      WHERE artid = @artid
                      AND   pubid = @pubid )

    IF @objtype IS NULL
    BEGIN
        RAISERROR( 20027, 11, -1, @article )
        RETURN( 1 )
    END

    /*
    ** Parameter Check:  @property.
    ** If the @property parameter is NULL, print the options.
    */

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname NOT NULL)
            INSERT INTO #tab1 VALUES ('description')
            INSERT INTO #tab1 VALUES ('sync_object')
            INSERT INTO #tab1 VALUES ('type')
            INSERT INTO #tab1 VALUES ('ins_cmd')
            INSERT INTO #tab1 VALUES ('del_cmd')
            INSERT INTO #tab1 VALUES ('upd_cmd')
            INSERT INTO #tab1 VALUES ('filter')
            INSERT INTO #tab1 VALUES ('dest_table')
            INSERT INTO #tab1 VALUES ('dest_object')
            INSERT INTO #tab1 VALUES ('creation_script')
            INSERT INTO #tab1 VALUES ('pre_creation_cmd')
            INSERT INTO #tab1 VALUES ('status')
            INSERT INTO #tab1 VALUES ('schema_option')
            INSERT INTO #tab1 VALUES ('destination_owner')
            PRINT ''
            SELECT * FROM #tab1
            RETURN (0)
        END

    IF @objtype = 'U' AND LOWER(@property) NOT IN ('description',
                                                   'sync_object',
                                                   'type',
                                                   'ins_cmd',
                                                   'del_cmd',
                                                   'upd_cmd',
                                                   'filter',
                                                   'dest_table',
                                                   'dest_object',
                                                   'creation_script',
                                                   'pre_creation_cmd',
                                                   'status',
                                                   'schema_option',
                                                   'destination_owner')
        BEGIN
            RAISERROR (14022, 16, -1)
            RETURN (1)
        END

    IF @objtype = 'P' AND LOWER(@property) NOT IN ('description',
                                                   'dest_object',
                                                   'dest_table',
                                                   'creation_script',
                                                   'pre_creation_cmd',
                                                   'schema_option',
                                                   'destination_owner')
        BEGIN
            RAISERROR ( 14110, 16, -1 )
            RETURN (1)
        END

    /* dest_object and 'dest_table' are same */
    IF LOWER(@property) = 'dest_object'
        SELECT @property = 'dest_table' 

    /*
    ** Change the property.
    */

    begin tran
    save TRAN sp_changearticle

        IF LOWER(@property) IN ( 'description', 'ins_cmd', 'del_cmd', 'upd_cmd', 'dest_table', 'creation_script', 'dest_object')
            BEGIN


            /*
            ** Check the validity of the destination object.  NULL should
            ** get converted to the source object name.  Destination object
            ** names can be owner qualified, but not database qualified.
            */

            IF LOWER(@property) = 'dest_table' OR LOWER(@property) = 'dest_object'
                BEGIN
                    IF @value IS NULL
                        SELECT @value = object_name(objid)
                          FROM sysarticles
                         WHERE artid = @artid
                           AND pubid = @pubid
                END

            SELECT @cmd1 = 'UPDATE sysarticles '

            IF @value IS NULL
            BEGIN
                    SELECT @cmd1 = @cmd1 + '   SET ' + LOWER(@property) + ' = NULL'
                SELECT @cmd2 = ' WHERE artid = ' + STR(@artid)
                SELECT @cmd2 = @cmd2 + '   AND pubid = ' + STR(@pubid)
                EXECUTE (@cmd1 + @cmd2)
            END
            ELSE
            BEGIN
                
                SELECT @cmd1 = @cmd1 + '   SET ' + LOWER(@property) + ' = ''' + @value + ''''
                SELECT @cmd2 = ' WHERE artid = ' + STR(@artid)
                SELECT @cmd2 = @cmd2 + '   AND pubid = ' + STR(@pubid)
                EXECUTE (@cmd1 + @cmd2)
            END

            IF LOWER(@property) = 'upd_cmd'
            BEGIN
                IF ( 0 <> ( SELECT PATINDEX( '%[789].[0-9]%', @@version ) ) ) OR
                   ( 0 <> ( SELECT PATINDEX( '%[1-9][0-9].[0-9]%', @@version ) ) )
                BEGIN
                    SELECT @objid = objid FROM sysarticles
                        WHERE artid = @artid
                        AND pubid = @pubid

                    exec dbo.sp_MSsetfilteredstatus @objid
                END

            END

            IF @@ERROR <> 0 
                BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END
            END

        IF LOWER(@property) = 'sync_object'
            BEGIN

                /*
                ** Check for a valid synchronization object.
                */

                IF @value IS NULL
                    BEGIN
                        RAISERROR (14043, 16, -1, '@value')
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                IF @value LIKE '%.%.%' OR @value LIKE '%.%'
                BEGIN
                  select @object = PARSENAME( @value, 1 )
                  select @owner = PARSENAME(  @value, 2 )
                  select @db = PARSENAME(  @value, 3 )
                  select @site = PARSENAME(  @value, 4 )

                  if @object IS NULL
                        return 1
                END


                SELECT @sync_objid = OBJECT_ID(@value)
                IF @sync_objid IS NULL
                    BEGIN
                        RAISERROR (15001, 11, -1, @value)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                IF NOT EXISTS (SELECT *
                                 FROM sysobjects
                                WHERE type IN ('U', 'V')
                                  AND id = @sync_objid)

                    BEGIN
                        RAISERROR (14031, 16, -1)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                /*
                ** Update the article with the new synchronization object.
                */

                UPDATE sysarticles
                   SET sync_objid = @sync_objid
                 WHERE artid = @artid
                   AND pubid = @pubid

                IF @@ERROR <> 0 
                BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END

            END

        IF LOWER(@property) = 'type'
            BEGIN

                /*
                ** Check to make sure that we have a valid type.
                */

            IF LOWER(@value) NOT IN ('logbased', 'logbased manualfilter', 'logbased manualview', 'logbased manualboth')
                    BEGIN
                        RAISERROR (14023, 16, -1)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                /*
                ** Determine the integer value for the type.
                */
            IF LOWER(@value) = 'logbased'
            SELECT @typeid = 1
            ELSE IF LOWER(@value) = 'logbased manualfilter'
            SELECT @typeid = 3
            ELSE IF LOWER(@value) = 'logbased manualview'
            SELECT @typeid = 5
            ELSE IF LOWER(@value) = 'logbased manualboth'
            SELECT @typeid = 7

                /*
                ** Update the article with the new type.
                */

                UPDATE sysarticles
                   SET type = @typeid
                 WHERE artid = @artid
                   AND pubid = @pubid

                IF @@ERROR <> 0 
                BEGIN
                    if @@trancount > 0
                    begin   
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END


            END

        IF LOWER(@property) = 'filter'
            BEGIN

                /*
                ** Check for a valid filter value.
                */

                IF @value IS NOT NULL
                    BEGIN

                        IF @value LIKE '%.%.%' OR @value LIKE '%.%'
                        BEGIN
                           select @object = PARSENAME( @value, 1 )
                           select @owner = PARSENAME(  @value, 2 )
                           select @db = PARSENAME(  @value, 3 )
                           select @site = PARSENAME(  @value, 4 )

                           if @object IS NULL
                                 return 1
                        END

                    END

                SELECT @filter = OBJECT_ID(@value)

                IF @value IS NOT NULL
                    BEGIN

                        IF @filter IS NULL
                            BEGIN
                                RAISERROR (15001, 11, -1, @value)
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRAN sp_changearticle
                                    commit tran
                                end
                                RETURN (1)
                            END

                        IF NOT EXISTS (SELECT *
                                         FROM sysobjects
                                        WHERE type = 'RF'
                                          AND id = @filter)

                            BEGIN
                                RAISERROR (14049, 16, -1)
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRAN sp_changearticle
                                    commit tran
                                end
                                RETURN (1)
                            END

                    END

                IF @value IS NULL SELECT @filter = 0

                -----------------------------
                -- save off the old filter
                -----------------------------

                SELECT @old_filter_name = object_name( filter )
                FROM sysarticles WHERE artid = @artid
                AND pubid = @pubid

                IF @@ERROR <> 0 
                BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END

                --------------------------------------------
                -- Update the article with the new filter.
                --------------------------------------------

                UPDATE sysarticles
                   SET filter = @filter
                 WHERE artid = @artid
                   AND pubid = @pubid

                IF @@ERROR <> 0 
                BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END

                -- SQL SERVER > 7.x ONLY  disassociate old filter with table
                -- and associate new one

                IF ( 0 <> ( SELECT PATINDEX( '%[789].[0-9]%', @@version ) ) ) OR
                   ( 0 <> ( SELECT PATINDEX( '%[1-9][0-9].[0-9]%', @@version ) ) )   
                BEGIN

                    ------------------------------------------
                    -- disassociate table from old filter proc
                    ------------------------------------------

                    EXEC dbo.sp_MSsetfilterparent @old_filter_name, 0

                    IF @@ERROR <> 0
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                    ------------------------------------
                    -- get the table id from sysarticles
                    ------------------------------------

                    SELECT @objid = objid
                    FROM sysarticles
                    WHERE artid = @artid
                    AND pubid = @pubid

                    IF @@ERROR <> 0
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                    ------------------------------------------------------
                    -- set the parent of the filter proc to this object_id
                    ------------------------------------------------------

                    EXEC dbo.sp_MSsetfilterparent @value, @objid

                    IF @@ERROR <> 0
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
                END

            END

        IF LOWER(@property) = 'pre_creation_cmd'
            BEGIN

                /*
                ** Check to make sure that we have a valid pre_creation_cmd.
                */
            IF @objtype = 'P' and LOWER(@value) NOT IN ('none', 'drop')
                BEGIN
                    RAISERROR ( 14111, 16, -1 )
                    if @@trancount > 0
                    begin   
                        ROLLBACK TRAN sp_changearticle
                        commit tran
                    end
                    RETURN (1)
                END

                IF LOWER(@value) NOT IN ('none', 'drop', 'delete', 'truncate')
                    BEGIN
                        RAISERROR (14061, 16, -1)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                /*
                ** Determine the integer value for the type.
                */

                IF LOWER(@value) = 'none'
                    SELECT @precmdid = 0
                ELSE IF LOWER(@value) = 'drop'
                    SELECT @precmdid = 1
                ELSE IF LOWER(@value) = 'delete'
                    SELECT @precmdid = 2
                ELSE IF LOWER(@value) = 'truncate'
                    SELECT @precmdid = 3

                /*
                ** Update the article with the new pre_creation_cmd.
                */
                UPDATE sysarticles
                   SET pre_creation_cmd = @precmdid
                 WHERE artid = @artid
                   AND pubid = @pubid

                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

            END

        IF LOWER(@property) = 'status'
            BEGIN
                /*
                ** Check to make sure that we have a valid type.
                */

                IF LOWER(@value) IN ('not owner qualified', 'owner qualified')
                    BEGIN
                        RAISERROR (21023, 16, -1,@value)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                IF LOWER(@value) NOT IN ('no column names', 'include column names', 'string literals', 'parameters' )
                    BEGIN
                        RAISERROR (14097, 16, -1)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end                        
                        RETURN (1)
                    END

                /*
                ** Determine the integer value for the type.
                */
                IF LOWER(@value) = 'not owner qualified'
                    UPDATE sysarticles 
                    SET status = status & ~4
                    WHERE artid = @artid
                                  AND pubid = @pubid

                ELSE IF LOWER(@value) = 'owner qualified'
                    UPDATE sysarticles 
                    SET status = status | 4
                    WHERE artid = @artid
                                  AND pubid = @pubid
                     
                ELSE IF LOWER(@value) = 'no column names'
                    UPDATE sysarticles 
                    SET status = status & ~8
                    WHERE artid = @artid
                                  AND pubid = @pubid
                     
                ELSE IF LOWER(@value) = 'include column names'
                    UPDATE sysarticles 
                    SET status = status | 8
                    WHERE artid = @artid
                                  AND pubid = @pubid

                ELSE IF LOWER(@value) = 'string literals'
                    UPDATE sysarticles 
                    SET status = status & ~16
                    WHERE artid = @artid
                                  AND pubid = @pubid
                     
                ELSE IF LOWER(@value) = 'parameters'
                    UPDATE sysarticles 
                    SET status = status | 16
                    WHERE artid = @artid
                                  AND pubid = @pubid
                
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
            END

        IF LOWER(@property) = 'schema_option'
            BEGIN
                IF @value IS NULL
                    BEGIN
                        RAISERROR(14146, 16,1)
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                CREATE TABLE #tab_changearticle (value binary(8) NULL)
                                     
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

                EXEC ('insert #tab_changearticle values (' + 
                        @value +')' )
                                     
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
                
                IF @objtype = 'P' AND EXISTS (SELECT * from #tab_changearticle 
                    WHERE value <> 0x0000000000000000 AND
                          value <> 0x0000000000000001 )
                    BEGIN
                        RAISERROR ( 20014, 16, -1 )
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
               

                UPDATE sysarticles SET schema_option = tab.value from 
                    #tab_changearticle tab WHERE artid = @artid
                                  AND pubid = @pubid
                DROP TABLE #tab_changearticle 
                                     
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

            END

        IF LOWER(@property) = 'destination_owner'
            BEGIN
                IF @value IS NOT NULL
                BEGIN
                    /*
                    ** The destination_owner must conform to the rules
                    ** for identifiers.
                    */

                    EXECUTE @retcode = dbo.sp_validname @value

                    IF @retcode <> 0
                    RETURN (1)
                END

                UPDATE sysarticles SET dest_owner = @value from 
                    sysarticles WHERE artid = @artid
                                  AND pubid = @pubid
                                     
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END

            END


		-------------------------------------------------------------------------
		-- some info on articles is also stored at the distributor.
		-- update info at distributor if these properties change
		-------------------------------------------------------------------------

		if @property in ( N'description', N'dest_table', N'dest_object' )
		BEGIN
			/*
			** Get distribution server information for remote RPC call.
			*/
			EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
			   @distribdb   = @distribdb OUTPUT
			IF @@ERROR <> 0 or @retcode <> 0
			BEGIN
				RAISERROR (14071, 16, -1)
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_changearticle
					commit tran
				end
				RETURN (1)
			END

			SELECT @dbname =  DB_NAME()
			SELECT @article_id = artid from sysarticles where name = @article

			SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
				'.dbo.sp_MSchange_article'
			EXECUTE @retcode = @distproc
				@publisher = @@SERVERNAME,
				@publisher_db = @dbname,
				@publication = @publication,
				@article = @article,
				@article_id = @article_id,
				@property = @property,
				@value = @value


			IF @@ERROR <> 0 OR @retcode <> 0
			BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRAN sp_changearticle
					commit tran
				end
				RETURN (1)
			END
		END

    COMMIT TRAN

    /*
    ** Force the article cache to be refreshed with the new definition.
    */
    EXECUTE dbo.sp_replflush

    /*
    ** Return succeed.
    */

    RAISERROR (14025, 10, -1)
    RETURN (0)
go
 
dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_changearticle
GO

print ''
print 'Creating procedure sp_droparticle'
go

CREATE PROCEDURE sp_droparticle(
        @publication sysname,     /* The publication name */
        @article sysname,          /* The article name */
        @ignore_distributor bit = 0
        ) AS

    /*
    ** Declarations.
    */

    DECLARE @cmd nvarchar(255)
    DECLARE @objid int
    DECLARE @pubid int
    DECLARE @publish_bit smallint
    DECLARE @retcode int
    DECLARE @filter_name sysname
    DECLARE @view_name sysname
    DECLARE @type tinyint
    DECLARE @procnum smallint
    DECLARE @virtual_id smallint
    DECLARE @push tinyint
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @dbname sysname
    -- SyncTran
    DECLARE @allow_sync_tran_id bit
    declare @artid int, @insproc_id int, @updproc_id int, @delproc_id int
    declare @insproc sysname, @updproc sysname, @delproc sysname
    declare @filter_id int
    declare @view_id int


    SET NOCOUNT ON

    /*
    ** Initializations.
    */

    SELECT @virtual_id = -1     /* Const: virtual subscriber id */

    SELECT @publish_bit = 1

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

    /*
    ** Parameter Check: @publication.
    ** The @publication name must conform to the rules for identifiers.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    IF NOT EXISTS (SELECT * FROM syspublications WHERE name = @publication)
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END


    /*
    ** Get the @pubid.
    */

    -- SyncTran
    --SELECT @pubid = pubid FROM syspublications WHERE name = @publication
    SELECT @pubid = pubid, @allow_sync_tran_id = allow_sync_tran 
    FROM syspublications WHERE name = @publication

    /*
    ** Parameter Check:  @article.
    ** If the @article is 'all', drop all articles for the specified
    ** publication (@publication).
    */

    IF LOWER(@article) = 'all'
        BEGIN
            DECLARE hC  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT  name FROM sysarticles 
                    WHERE pubid = @pubid
            OPEN hC
            FETCH hC INTO @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_droparticle 
                        @publication = @publication, 
                        @article = @article,
                        @ignore_distributor = @ignore_distributor
                    FETCH hC INTO @article
                END
            CLOSE hC
            DEALLOCATE hC
            RETURN (0)
        END

    /*
    ** Parameter Check: @article.
    ** The @article name must conform to the rules for identifiers.
    */

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

    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @retcode <> 0
    RETURN (1)
    */

    /*
    ** Ascertain the existence of the article.
    */

    IF NOT EXISTS (SELECT *
                     FROM sysarticles
                    WHERE name = @article
                      AND pubid = @pubid)
        BEGIN
            RAISERROR (20027, 11, -1, @article)
        RETURN (1)
        END

    /*
    ** Check to make sure that there are no 'real' subscriptions on the article.
    */

    IF EXISTS (SELECT *
                 FROM syssubscriptions, sysarticles
                WHERE sysarticles.name = @article
                  AND sysarticles.pubid = @pubid
                  AND sysarticles.artid = syssubscriptions.artid
                  AND syssubscriptions.srvid <> @virtual_id)
        BEGIN
            RAISERROR (14046, 16, -1)
            RETURN (1)
        END

    -- SyncTran
    /*
    ** If allow_sync_procs option turned on for the publication, retrieve info from sysarticle updates
    */
    if @allow_sync_tran_id = 1 
    begin
        select @artid = artid from sysarticles where name = @article and pubid = @pubid

        select @insproc_id = sync_ins_proc, @updproc_id = sync_upd_proc, @delproc_id = sync_del_proc
        from sysarticleupdates
        where artid = @artid and pubid = @pubid 
    end
    -- end SyncTran

        /*
        ** Retrieve the object id of the underlying table.
        */

        SELECT @objid = objid, @type = type
          FROM sysarticles
         WHERE name = @article
           AND pubid = @pubid

    begin tran
    save TRAN droparticle

        /* Drop virtual subscription first for @immediate_sync publications
           */
        if EXISTS (SELECT * FROM syspublications WHERE
            name = @publication    AND
            immediate_sync = 1)
        BEGIN
            EXECUTE @retcode  = dbo.sp_dropsubscription 
                @publication = @publication, 
                @article = @article,
                @subscriber = NULL,
                @ignore_distributor = @ignore_distributor,
                @reserved = 'internal'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                if @@trancount > 0
                begin
                    ROLLBACK TRAN droparticle
                    commit tran
                end
                RETURN (1)
            END
        END

        /* Drop article at the distributor side */
        /*
        ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
        */
        if @ignore_distributor = 0
        begin

            /*
            ** Get distribution server information for remote RPC call.
            */
            EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
               @distribdb   = @distribdb OUTPUT
            IF @@ERROR <> 0 or @retcode <> 0
                BEGIN
                    RETURN (1)
                END

            SELECT @dbname =  DB_NAME()
        
            SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
                '.dbo.sp_MSdrop_article'
            EXECUTE @retcode = @distproc
                @publisher = @@SERVERNAME,
                @publisher_db = @dbname,
                @publication = @publication,
                @article = @article

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                if @@trancount > 0
                    ROLLBACK TRAN 
                RETURN (1)
            END
        end
        
        /*
        **  Delete article from sysarticles and clear publish bit in
        **  sysobjects.
        */


        /*
        ** If this article is the only one that references this object,
        ** then we can safely turn off the publish bit in sysobjects.
        */

        IF NOT EXISTS (SELECT *
                         FROM sysarticles
                        WHERE objid = @objid
                          AND NOT (name = @article AND pubid = @pubid))
            BEGIN

            UPDATE sysobjects SET replinfo = replinfo & ~ @publish_bit 
                WHERE id = (SELECT objid FROM sysarticles WHERE name = @article 
                    AND pubid =  @pubid) 

			/*
            EXEC (@cmd)

            IF @@ERROR <> 0
                BEGIN
                    if @@trancount > 0
                        ROLLBACK TRAN
                    RAISERROR (14047, 16, -1, @article)
                    RETURN (1)
                END
			*/

            END

        /*
        ** Drop article view if not logbased manualview (type = 5)
        */
    IF (@type & 5) = 1
       BEGIN    
        SELECT @view_id = sysobjects.id
            FROM sysarticles, sysobjects
         WHERE sysarticles.name = @article
           AND pubid = @pubid
           AND sync_objid = sysobjects.id
           AND sysobjects.type = 'V'
        exec sp_MSget_qualified_name @view_id, @view_name OUTPUT

       END

        /*
        ** Drop article filter if not logbased manualfilter (type = 3)
        */
    IF (@type & 3) = 1
       BEGIN    
        SELECT @filter_id = sysobjects.id
            FROM sysarticles, sysobjects
         WHERE sysarticles.name = @article
           AND pubid = @pubid
           AND filter = sysobjects.id
           AND sysobjects.type = 'RF'

        exec sp_MSget_qualified_name @filter_id, @filter_name OUTPUT
       
       END


        IF( @type & 3 ) = 3
        BEGIN
            select @filter_id =  filter from sysarticles
            where name = @article and pubid = @pubid

            exec sp_MSget_qualified_name @filter_id, @filter_name OUTPUT

            if @filter_name is not null
                EXEC dbo.sp_MSsetfilterparent @filter_name, 0
            
            -- Clear base table dependency on the filter
            EXEC dbo.sp_MSsetfilteredstatus @objid

            -- This is a manual filter, we should not drop it automatically
            -- since it is not created by us.
            -- Set @filter_id to null so the object will not be dropped later.
            select @filter_name = null
 
        END


    /*
    ** If this is a table based article, Drop all article columns.
        ** This is done to force all Text\Image column status to be updated.
    */

        IF (@type & 8) != 8
        BEGIN

	-- propagate @ignore_distributor to sp_articlecolumn to allow forced cleanup
    EXECUTE @retcode  = dbo.sp_articlecolumn @publication, @article,
       @operation = 'drop', @ignore_distributor = @ignore_distributor
       -- synctran
        , @refresh_synctran_procs = 0
        IF @@ERROR <> 0 OR @retcode <> 0
       BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRAN droparticle
                commit tran
            end
            RETURN (1)
       END
        END


        /*
        ** Remove the row from sysarticles.
        */
        DELETE
          FROM sysarticles
         WHERE name = @article
           AND pubid = @pubid

        IF @@ERROR <> 0
        BEGIN
            if @@trancount > 0
                ROLLBACK TRAN 
            RAISERROR (14047, 16, -1, @article)
            RETURN (1)
        END

        -- SyncTran
        /*
        ** Drop associated sync tran procs and entries in sysarticle updates
        */
        if @allow_sync_tran_id = 1
        begin
            exec @retcode = dbo.sp_MSdrop_object 
                @object_id = @insproc_id
            if @retcode <> 0 or @@error <> 0
                goto UNDO

            exec @retcode = dbo.sp_MSdrop_object 
                @object_id = @updproc_id
            if @retcode <> 0 or @@error <> 0
                goto UNDO

            exec @retcode = dbo.sp_MSdrop_object 
                @object_id = @delproc_id
            if @retcode <> 0 or @@error <> 0
                goto UNDO
            
            delete from sysarticleupdates where artid = @artid and pubid = @pubid
            if @@ERROR <> 0 begin
                if @@trancount > 0
                    ROLLBACK TRAN
                RETURN (1)
            end
        end
        -- end SyncTran


    COMMIT TRAN

    IF @view_name IS NOT NULL
	BEGIN
        -- @view_name is already quoted.
		SELECT @cmd = 'drop view ' + @view_name
		exec (@cmd)
	END

    IF @filter_name IS NOT NULL
	BEGIN
        -- @filter_name is already quoted.
		SELECT @cmd = 'drop proc ' + @filter_name
		exec (@cmd)
	END
    /*
    ** Force the article cache to be refreshed; only if needed
    */
	if ( @ignore_distributor = 0 )
		EXECUTE dbo.sp_replflush

    return (0)

UNDO:
    if @@trancount <> 0
        rollback tran

go
 
EXEC dbo.sp_MS_marksystemobject sp_droparticle
GO

print ''
print 'Creating procedure sp_droppublication'
go

CREATE PROCEDURE sp_droppublication(
        @publication sysname,       /* The publication name */
        @ignore_distributor bit = 0
        ) AS

    /*
    ** Declarations.
    */

    DECLARE @article sysname
    DECLARE @cmd nvarchar(255)
    DECLARE @retcode int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @agentname nvarchar (40)
    DECLARE @dbname sysname
    DECLARE @virtual_id smallint

    SELECT @virtual_id = -1
    select @dbname = db_name()

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

    /*
    ** Parameter Check:  @publication.
    ** If the @publication is 'all', drop all publications.  Otherwise,
    ** make sure the @publication is a valid non-null identifier.
    ** Delete the logreader agent after all the publications have been 
    ** removed.
    */

    IF LOWER(@publication) = 'all'
        BEGIN
            DECLARE hC1  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT name FROM syspublications 
                    WHERE pubid NOT IN 
                        (SELECT pubid FROM sysarticles WHERE artid IN 
                            (SELECT artid FROM syssubscriptions WHERE srvid <> @virtual_id))
            OPEN hC1
            FETCH hC1 INTO @publication
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_droppublication @publication,
                        @ignore_distributor = @ignore_distributor
                    FETCH hC1 INTO @publication
                END
            CLOSE hC1
            DEALLOCATE hC1
            RETURN (0)
        END

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    /*
    ** Ascertain the existence of the publication and get the taskid.
    */
    IF NOT EXISTS (SELECT *
                     FROM syspublications
                    WHERE name = @publication)
    BEGIN
        RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
    END

    /*
    ** Check to make sure that there are no subscriptions on the publication.
    */

    IF EXISTS (SELECT *
                 FROM syssubscriptions a, sysarticles b, syspublications c
                WHERE c.name = @publication
                  AND c.pubid = b.pubid
                  AND b.artid = a.artid
                  AND a.srvid <>@virtual_id)
        BEGIN
            RAISERROR (14005, 16, -1)
            RETURN (1)
        END

    /*
    ** Delete all articles from the publication.
    */

    DECLARE hC2  CURSOR LOCAL FAST_FORWARD FOR 
        SELECT DISTINCT name FROM sysarticles 
            WHERE pubid = (SELECT pubid FROM syspublications 
                WHERE name = @publication)
    OPEN hC2
    FETCH hC2 INTO @article
    WHILE (@@fetch_status <> -1)
        BEGIN
            EXECUTE dbo.sp_droparticle @publication = @publication, 
                @article = @article,
                @ignore_distributor = @ignore_distributor
            FETCH hC2 INTO @article
        END
    CLOSE hC2
    DEALLOCATE hC2

    
    BEGIN TRAN

    /*
    ** Delete publication from syspublications.
    */

    DELETE FROM syspublications WHERE name = @publication

    IF @@ERROR <> 0
        GOTO UNDO

    /*
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 0
    begin

        /*
        ** Get distribution server information for remote RPC call.
        */

        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

        /*
        ** Delete sync agent of Publication if it exists.
        */
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_snapshot_agent'
        EXECUTE @retcode = @distproc 
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = @publication

        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO

        IF NOT EXISTS (SELECT * FROM syspublications  where repl_freq = 0)
            BEGIN
                /*
                ** Delete logreader agent, continue if drop is not successful
                */
                SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_logreader_agent'
                EXECUTE @retcode = @distproc @publisher = @@SERVERNAME,
                    @publisher_db = @dbname,
                    -- 'ALL' is used in sp_addpublication.
                    @publication = 'ALL'
                IF @@ERROR <> 0 or @retcode <> 0
                    GOTO UNDO
            END

        /*
        ** Delete the publication at the distribution server
        */
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
            '.dbo.sp_MSdrop_publication'
        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = @publication
        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO
    end

    COMMIT TRAN

    return (0)  
    
UNDO:
    if @@TRANCOUNT = 1
        ROLLBACK TRAN
    else
        COMMIT TRAN
    return(1)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_droppublication
GO

print ''
print 'Creating procedure sp_dropsubscription'
go
CREATE PROCEDURE sp_dropsubscription (
    @publication sysname = NULL,   /* The publication name */
    @article sysname = NULL,       /* The article name */
    @subscriber sysname,           /* The subscriber name */
    @destination_db sysname =NULL,                /* Name of the destination database */
                                        /* If null, all the subscriptions from that
                                            subscriber will be dropped */
    @ignore_distributor bit = 0,

    @reserved nvarchar(10) = NULL            /* reserved, used when calling from other system */
                                            /* stored procedures, it will be set to 'internal'.*/
                                            /* It should never be used directly */
    ) AS

    /*
    ** Declarations.
    */

    DECLARE @subscriber_bit smallint
    DECLARE @cmd nvarchar(255)
    DECLARE @srvid smallint
    DECLARE @artid int
    DECLARE @retcode int
    DECLARE @active tinyint
    DECLARE @internal nvarchar(10)
    DECLARE @expand_article nvarchar(10)
    DECLARE @push tinyint
    DECLARE @virtual_id smallint
    DECLARE @login_name sysname
    DECLARE @immediate_sync bit
    DECLARE @subscription_type int
    DECLARE @qualified_subscription_name nvarchar(512)

    /*
    ** Initializations.
    */
    SET NOCOUNT ON
    SELECT @subscriber_bit = 4  /* Const: subscription server status */
    SELECT @active = 2          /* Const: subscription status 'active' */
    SELECT @push = 0        /* Const: push publication type */
    SELECT @virtual_id = -1 /* Const: virtual subscriber id */
    SELECT @internal = 'internal' /* Const: Flag of calling internally from system */
                                  /* stored procedures     */
    SELECT @expand_article = 'expand_art' 
        /* Const: Flag of calling after expand 'all' for @artcle  */
    
    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

    -- Bug 25691. Test distributor RPC connection before open the cursor
    /*
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 0
    begin
        declare @distributor sysname
        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT
        if @@ERROR <> 0 or @retcode <> 0
            return(1)
    end

    /*
    ** If the @subscriber is 'all', the user wants to cancel all subscriptions
    ** to the specified article(s).
    */

    IF LOWER(@subscriber) = 'all'
        BEGIN
            DECLARE hCdrop_subscription1  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT srvname 
                    FROM master..sysservers a, syssubscriptions b 
                    WHERE srvstatus & @subscriber_bit <> 0 
                    AND a.srvid = b.srvid

    -- With ANSI Defaults ON, the cursor will automatically
    -- be closed on commit.   Since this proc gets called recursively, 
    -- this can happen.  So check before opening. 
    IF CURSOR_STATUS('local','hCdrop_subscription1') = -1
            OPEN hCdrop_subscription1

			-- Bug : 47836 : must owner qual proc invoke to exec inside server on restore/attach cleanup
            FETCH hCdrop_subscription1 INTO @subscriber
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber  = @subscriber,
                        @destination_db = 'all',
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved

        IF CURSOR_STATUS('local','hCdrop_subscription1') = -1
                OPEN hCdrop_subscription1
                FETCH hCdrop_subscription1 INTO @subscriber
                END
            CLOSE hCdrop_subscription1
            DEALLOCATE hCdrop_subscription1
            RETURN (0)
        END

    
    
    /*
    ** Parameter Check: @subscriber.
    **
    ** Check if the server exists and that it is a subscription server.
    **
    */
    IF @subscriber IS NULL
        BEGIN
            SELECT @srvid = @virtual_id 
        END
    ELSE
        BEGIN
            /* validate name and get subscriber ID  and server status  */
            EXECUTE @retcode = dbo.sp_validname @subscriber
            IF @retcode <> 0
            RETURN (1)

            SELECT @srvid = srvid
              FROM master..sysservers
             WHERE UPPER(srvname) = UPPER(@subscriber)
               AND (srvstatus & @subscriber_bit) <> 0

            IF @srvid IS NULL
                BEGIN
                    RAISERROR (14010, 16, -1)
                    RETURN (1)
                END
        END
    /*
    ** If the @publication is 'all', the user wants to cancel all subscriptions
    ** for all publications associated with the specified @subscriber.
    */

    IF LOWER(@publication) = 'all'
        BEGIN
            DECLARE hCdrop_subscription2  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT a.name 
                    FROM syspublications a, sysarticles b,  syssubscriptions c 
                    WHERE c.srvid = @srvid
                    AND a.pubid = b.pubid 
                    AND b.artid = c.artid 
                    
            OPEN hCdrop_subscription2
            FETCH hCdrop_subscription2 INTO @publication
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription @publication = @publication,
                                                @article     = 'all',
                                                @subscriber  = @subscriber,
                                                @destination_db = @destination_db,
                                                @ignore_distributor = @ignore_distributor,
                                                @reserved = @reserved

                    FETCH hCdrop_subscription2 INTO @publication
                END
            CLOSE hCdrop_subscription2
            DEALLOCATE hCdrop_subscription2
            RETURN (0)
        END

    /*
    ** Parameter Check: @publication.
    ** Check to make sure that the publication exists and that it conforms
    ** to the rules for identifiers.
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

    IF NOT EXISTS (SELECT * FROM syspublications WHERE name = @publication)
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

    /* Get subscription type of the publication */
    SELECT @immediate_sync = immediate_sync
        FROM syspublications WHERE name = @publication

    /*
    ** Parameter Check:  @article
    */

    /* @article can not be null     */
    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END

    /** For immediate_sync publication, @article has to be 'all'     */
    -- Relax this constraint since users will need to do this before dropping
    -- an article
    /*
    IF @reserved <> @internal AND @reserved <> @expand_article
        AND @immediate_sync = 1
        AND NOT LOWER(@article) = 'all'
        BEGIN
            RAISERROR (14122, 16, -1)
            RETURN (1)
        END
    */

    /*
    ** If the @article is 'all', the user wants to cancel all
    ** subscriptions on this publisher associated with the given @subscriber
    ** and @publication.
    */

    IF LOWER(@article) = 'all'
        BEGIN

            /* Make the operation automic for immediate_sync publications */
            BEGIN TRAN

            IF @reserved IS NULL
                SELECT @reserved = @expand_article

            DECLARE hCdrop_subscription3  CURSOR LOCAL FAST_FORWARD FOR
                SELECT DISTINCT art.name 
                    FROM sysarticles art, syssubscriptions sub, syspublications pub 
                    WHERE sub.srvid = @srvid
                    AND sub.artid = art.artid
                    AND art.pubid = pub.pubid
                    AND pub.name = @publication 
                    
            OPEN hCdrop_subscription3
            FETCH hCdrop_subscription3 INTO @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE @retcode = dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber = @subscriber,
                        @destination_db = @destination_db,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved
                    IF @@error<>0 OR @retcode <> 0
                    BEGIN
                        CLOSE hCdrop_subscription3
                        DEALLOCATE hCdrop_subscription3
                        GOTO UNDO                        
                    END
                    FETCH hCdrop_subscription3 INTO @article
                END
            CLOSE hCdrop_subscription3
            DEALLOCATE hCdrop_subscription3

            COMMIT TRAN
            RETURN (0)
        END

    /*
    ** Parameter Check: @article
    ** Check if the article exists.
    */

    /*
    EXECUTE @retcode = dbo.sp_validname @article

    IF @retcode <> 0
    RETURN (1)
    */

    SELECT @artid = artid
      FROM sysarticles art, syspublications pub
     WHERE pub.name = @publication
       AND art.name = @article
       AND art.pubid = pub.pubid

    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 11, -1, @article)
        RETURN (1)
        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 IS NULL
    BEGIN
        /*
        ** Check if the subscription exists.
        */

        IF NOT EXISTS (SELECT *
                         FROM syssubscriptions
                        WHERE srvid = @srvid
                          AND artid = @artid)
        BEGIN    
                RAISERROR (14055, 11, -1)
                RETURN (1)
        END
        ELSE

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

    IF LOWER(@destination_db) = 'all' 
        BEGIN
            DECLARE hCdropsub4  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT dest_db
                    FROM syssubscriptions 
                    WHERE srvid = @srvid
                    AND artid = @artid
            OPEN hCdropsub4
            FETCH hCdropsub4 INTO @destination_db
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber = @subscriber,
                        @destination_db = @destination_db,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved
                    FETCH hCdropsub4 INTO @destination_db
                END
            CLOSE hCdropsub4
            DEALLOCATE hCdropsub4
            RETURN (0)
        END

    /*
    ** Dropping virtual subscriptions is not allowed
    ** in following case:
    ** 1. non sa or dbo user
    ** 2. the stored procedure is not in internal usage mode 
    **        (called by system stored procedures)
    **
    ** Note: Only immediate_sync publications have virtual subscriptions
    ** 
    */

    IF  @srvid = @virtual_id  AND  (
        @reserved <> @internal)
        BEGIN
            RAISERROR (14056, 16, -1)
            RETURN (1)
        END

    /*
    ** Check if the subscription exists.
    */

    IF NOT EXISTS (SELECT *
                     FROM syssubscriptions
                    WHERE srvid = @srvid
                      AND artid = @artid
                      AND dest_db = @destination_db)
    BEGIN
            RAISERROR (14055, 11, -1)
            RETURN (1)
    END


    /* Check the current login id. It is valid only when
    ** 1. sa or dbo
    ** 2. same as the one who add the subscription.
    */
    SELECT @login_name = login_name 
         FROM syssubscriptions
        WHERE srvid = @srvid
          AND artid = @artid
          AND dest_db = @destination_db

    IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
        AND is_member ('db_owner') <> 1
    BEGIN
            SELECT @qualified_subscription_name = @subscriber + N':' + @destination_db
            RAISERROR(21120, 11, -1, @qualified_subscription_name, @publication)
            RETURN (1)
    END


    begin tran
    save TRANSACTION dropsubscription

        /* If dropping virtual subscriptions, reset immediate_sync_ready bit */
        IF @srvid = @virtual_id
        BEGIN
            UPDATE syspublications SET immediate_sync_ready = 0
                WHERE
                    name = @publication and
                    immediate_sync = 1 and
                    immediate_sync_ready = 1
            IF @@ERROR <> 0
                goto UNDO
        END

        /*
        ** Change the status of the subscription to 'inactive'.
        */

        EXECUTE @retcode = dbo.sp_changesubstatus @publication = @publication,
                                              @article = @article,
                                              @subscriber = @subscriber,
                                              @status = 'inactive',
                                              @destination_db = @destination_db,
                                              @ignore_distributor = @ignore_distributor
        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRANSACTION dropsubscription
                commit tran
            end
            RETURN (1)
        END

    /* Read the subscription_type befor removing the syssubscriptions row */
    select @subscription_type = subscription_type from syssubscriptions
        WHERE artid = @artid
        AND srvid = @srvid
        AND dest_db = @destination_db
    /*
    ** Remove subscription from syssubscriptions.
    */
    DELETE syssubscriptions
     WHERE artid = @artid
       AND srvid = @srvid
       AND dest_db = @destination_db

    IF @@ERROR <> 0
    BEGIN
        if @@trancount > 0
        begin
            ROLLBACK TRANSACTION dropsubscription
            commit tran
        end
        RETURN (1)
    END

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

            IF @retcode<>0 or @@ERROR<>0
                GOTO UNDO
        end             

    COMMIT TRANSACTION
    RETURN (0)

UNDO:
    IF @@TRANCOUNT = 1
        ROLLBACK TRAN
    ELSE
        COMMIT TRAN
    RETURN(1)
go
 
EXEC dbo.sp_MS_marksystemobject sp_dropsubscription
GO

print ''
print 'Creating procedure sp_subscribe'
go
CREATE PROCEDURE sp_subscribe (
    @publication sysname,          /* publication name */
    @article sysname = 'all',          /* article name */
    @destination_db sysname = NULL,  /* subscriber database */
    @sync_type nvarchar (15) = 'automatic' /* subscription sync type */
    ) AS

    -- New 7.0 sp_addsubscription parameters
    DECLARE @subscriber                  sysname
    DECLARE @status                      sysname
    DECLARE @subscription_type           nvarchar(4)
    DECLARE @update_mode                 nvarchar(15)
    DECLARE @loopback_detection          nvarchar(5)
    DECLARE @enabled_for_syncmgr         nvarchar(5)
    DECLARE @retcode                     int

    SET NOCOUNT ON

    -- sp_subscribe has to be called from a remote subscriber 
    -- If not, we state that it is unsupported
    SELECT @subscriber = @@REMSERVER
    IF @subscriber IS NULL
    BEGIN
      RAISERROR (21023, 16, -1,'sp_subscribe')
      RETURN(1)
    END
    
    SELECT @status = NULL
    SELECT @subscription_type = 'push'
    SELECT @update_mode = 'read only'
    SELECT @loopback_detection = 'false'
    SELECT @enabled_for_syncmgr = 'false'

    -- Call sp_addsubscription to do the actual work
    EXEC @retcode = dbo.sp_addsubscription @publication = @publication,
                                           @article = @article,
                                           @destination_db = @destination_db,
                                           @sync_type = @sync_type,
                                           @subscriber = @subscriber,
                                           @status = @status,
                                           @subscription_type = @subscription_type,
                                           @update_mode = @update_mode,
                                           @loopback_detection = @loopback_detection,
                                           @enabled_for_syncmgr = @enabled_for_syncmgr
                                        
    RETURN @retcode   
go
 
EXEC dbo.sp_MS_marksystemobject sp_subscribe
GO

print ''
print 'Creating procedure sp_unsubscribe'
go
CREATE PROCEDURE sp_unsubscribe (
    @publication sysname = NULL,       /* publication name */
    @article sysname = NULL            /* article name */
    ) AS

    -- New 7.0 sp_dropsubscription parameters
    DECLARE @subscriber     sysname
    DECLARE @destination_db sysname    
    DECLARE @retcode        int 

    SET NOCOUNT ON
    
    -- sp_unsubscribe has to be callled from a remote subscriber
    -- If not, we state that it is unsupported
    SELECT @subscriber = @@REMSERVER
    IF @subscriber IS NULL
    BEGIN
        RAISERROR (21023, 16, -1,'sp_unsubscribe')
        RETURN(1)
    END

    -- 6.5 didn't support having multiple databases on the same subscriber
    -- subscribing to the same publication so here, all subscriptions to the
    -- same publication will be dropped 
    SELECT @destination_db = NULL
    
    -- Call sp_dropsubscription to do the real work
    EXEC @retcode = sp_dropsubscription @publication = @publication,
                                        @article = @article,
                                        @subscriber = @subscriber,
                                        @destination_db = @destination_db
    RETURN @retcode
    
go
 
EXEC dbo.sp_MS_marksystemobject sp_unsubscribe
GO

print ''
print 'Creating procedure sp_refreshsubscriptions'
go

CREATE PROCEDURE sp_refreshsubscriptions (
    @publication sysname       /* Publication name */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @article  sysname 
    DECLARE @subscriber sysname
    DECLARE @dest_db sysname
    DECLARE @retcode int
    DECLARE @pubid int
    DECLARE @immediate_sync bit 
    DECLARE @no_sync tinyint
    DECLARE @subscription_type_id int
    DECLARE @subscription_type nvarchar(4)
    DECLARE @virtual smallint
    DECLARE @srvid smallint
    DECLARE @sync_typeid int
    DECLARE @automatic tinyint
    DECLARE @sync_type nvarchar(9)

    SELECT @no_sync = 2
    SELECT @virtual = -1
    SELECT @automatic = 1
    /*
    ** Security Check
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** Check to see if the database has been activated for publication.
    */

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0

    BEGIN
            RAISERROR (14013, 16, -1)
        RETURN (1)
    END


    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists
    */

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

    SELECT @pubid = pubid
        FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END
    
    
    /* Add real subscription to the new articles  */
    /* Open a cursor on all the pending subscriptions, that is */
    /* All the subscriptions on the publication that */
    /* are not on an article in the publication. */
    /* not including virtual subscriptions */

    DECLARE hCrefreshsubscriptions CURSOR LOCAL FAST_FORWARD FOR
        SELECT DISTINCT art1.name, subs1.dest_db, subs1.srvid
            FROM syssubscriptions subs1, sysarticles art1
            WHERE art1.pubid = @pubid AND
                  subs1.srvid <> @virtual AND
                  EXISTS (SELECT * FROM syssubscriptions subs2, sysarticles art2
                    WHERE subs2.srvid = subs1.srvid AND
                          subs2.dest_db = subs1.dest_db AND
                          subs2.artid = art2.artid AND
                          art2.pubid = @pubid) AND
                  NOT EXISTS ( SELECT * FROM syssubscriptions subs3 
                    WHERE  subs3.artid = art1.artid AND
                           subs3.srvid = subs1.srvid AND
                           subs3.dest_db = subs1.dest_db)
    FOR READ ONLY
    OPEN hCrefreshsubscriptions
    FETCH hCrefreshsubscriptions INTO @article,  @dest_db, @srvid
            
    
    WHILE (@@fetch_status <> -1)
    BEGIN

        /* 
        ** Get subscription type on the publication
        */ 
        SELECT @subscription_type_id = subs.subscription_type,
            @sync_typeid = subs.sync_type
         from 
            sysarticles art, syssubscriptions subs where 
            art.pubid = @pubid AND
            subs.srvid = @srvid AND
            subs.dest_db = @dest_db AND
            subs.artid = art.artid

        /* 
        ** only do it if the subscription all have the same subscription type
        ** and sync_type
        */
        IF NOT EXISTS (SELECT * from 
            sysarticles art, syssubscriptions subs where 
            art.pubid = @pubid AND
            subs.srvid = @srvid AND
            subs.dest_db = @dest_db AND
            subs.artid = art.artid AND
            (subscription_type <> @subscription_type_id OR
            sync_type <> @sync_typeid))
        BEGIN
            IF @subscription_type_id = 0
                SELECT @subscription_type = 'push'
            ELSE
                SELECT @subscription_type = 'pull'

            if @sync_typeid = @automatic
                SELECT @sync_type = 'automatic'
            else
                SELECT @sync_type = 'none'

            /* 
            ** Get the server name
            */
            SELECT @subscriber = srvname FROM master.dbo.sysservers 
                WHERE srvid = @srvid

            EXECUTE @retcode  = dbo.sp_addsubscription 
                        @publication = @publication, 
                        @article = @article, 
                        @subscriber = @subscriber, 
                        @destination_db = @dest_db, 
                        @sync_type = @sync_type, 
                        @status = NULL, 
                        @subscription_type = @subscription_type,
                        @reserved = 'internal'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCrefreshsubscriptions
                DEALLOCATE hCrefreshsubscriptions
                RETURN (1)
            END
        END
        FETCH hCrefreshsubscriptions INTO @article, @dest_db, @srvid
    END
    
    CLOSE hCrefreshsubscriptions
    DEALLOCATE hCrefreshsubscriptions

GO
 
EXEC dbo.sp_MS_marksystemobject sp_refreshsubscriptions
GO

print ''
print 'Creating procedure sp_MSpublishdb'
go

CREATE PROCEDURE sp_MSpublishdb(
      @value     sysname,
      @ignore_distributor bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @quoted_db      sysname
    declare @db_name        sysname
    declare @command        nvarchar(255)
    declare @description    nvarchar(500)
    declare @category_name  nvarchar(100)
    DECLARE @agentname      nvarchar(300)
    DECLARE @dbname         sysname 
    DECLARE @retcode        int
    DECLARE @distributor    sysname
    DECLARE @distribdb      sysname
    DECLARE @distproc       nvarchar (255)
	DECLARE @replicate_bit	smallint

	SELECT @replicate_bit = 2

    /*
    ** Initialization
    */

    SELECT @dbname = DB_NAME()

    /*
    ** Parameter check
    ** @value
    */
    IF LOWER(@value) NOT IN ('true','false')
    BEGIN
      RAISERROR(14137,16,-1)
      RETURN(1)
    END

    /*
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 0
    begin
        /*
        ** Test to see if the distributor is installed and online.
        */
        EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
           @distribdb   = @distribdb OUTPUT

        IF @@ERROR <> 0 or @retcode <> 0 or @distributor IS NULL or @distribdb IS NULL
        BEGIN
            IF LOWER(@value) = 'true'
                RAISERROR (20028, 16, -1)
            ELSE
                RAISERROR (20029, 16, -1)
            RETURN (1)
        END
    end

    /*
    ** Enable the database for publishing.
    */
    IF LOWER(@value) = 'true'
    BEGIN

        /*
        ** Drop and then create central publish tables
        */

        /* 
        ** Drop first if exists
        */

        EXEC @retcode = dbo.sp_MSdrop_pub_tables
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            return (1)
        END

        /*
        ** Create central publish tables
        */

        EXEC @retcode = dbo.sp_MScreate_pub_tables
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            return (1)
        END
    END

    ELSE    /* Disable the database for publishing. */
    BEGIN
        /*
        ** Remove all subscriptions in the database.
		** WARNING : must owner qualify proc calls for these to run inside server on restore/attach
        */
        EXEC @retcode = dbo.sp_dropsubscription @publication = 'all',
            @article = 'all', @subscriber = 'all', 
            @ignore_distributor = @ignore_distributor
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            return (1)
        END

		-- Used for attach and restored db.
		-- sysservers table in master db might be changed so that
		-- sp_dropsubscription won't work. Delete the table directly.
		-- Before dropping the table, we need to unmark repl bits in sysobjects
		-- see below

		delete syssubscriptions where srvid >= 0
        IF @@ERROR <> 0 
        BEGIN
            return (1)
        END

        /*
        ** Remove all publications and articles in the database.
        */
        EXEC @retcode = dbo.sp_droppublication @publication = 'all', 
            @ignore_distributor = @ignore_distributor
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            return (1)
        END
  
        /*
        ** Remove all published database transactions from the distribution
        ** database.
        */
        if @ignore_distributor = 0
        begin
            SELECT  @distproc = RTRIM(@distributor) + '.' +
                    RTRIM(@distribdb) + '.dbo.sp_MSremove_published_jobs '
            EXEC @retcode = @distproc @@SERVERNAME, @dbname
            IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                return (1)
            END
        end

        /*
        ** Publishing shutdown, remove all xacts pending distribution
		** If forced cleanup, no need to flush; may need to mark repldone
        */

		if ( @ignore_distributor = 0 )
		begin

			/* ensure we can get in as logreader */

	        EXEC @retcode = dbo.sp_replflush
	        IF @@ERROR <> 0 or @retcode <> 0
	        BEGIN
				return (1)
	        END

		    /* unmark all xacts marked for replication */

			select @quoted_db = QUOTENAME(@dbname)
	        EXEC ( 'USE ' + @quoted_db + ' exec dbo.sp_repldone NULL, NULL, 0, 0, 1' )
	        IF @@ERROR <> 0 
	        BEGIN
		        return (1)
	        END
        
	        /* release our hold on the db as logreader */
	        EXEC dbo.sp_replflush
            IF @@ERROR <> 0 
			BEGIN
				RETURN(1)
			END

	        /* 
		    ** Drop central publish tables
	        */ 
		    EXEC @retcode = dbo.sp_MSdrop_pub_tables
			IF @@ERROR <> 0 or @retcode <> 0
	        BEGIN
		        return (1)
	        END
		
		end
		    
		-- Used for attached and restored db.
		-- sysservers table in master db might be changed so that
		-- sp_dropsubscription won't work. Unmark repl bits in sysobjects
		-- directly.
        UPDATE sysobjects SET replinfo =  replinfo & ~@replicate_bit
    END
    return (0)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSpublishdb
GO

print ''
print 'Creating procedure sp_MSactivate_auto_sub'
go

CREATE PROCEDURE sp_MSactivate_auto_sub (
    @publication sysname,        /* Publication name */
    @article sysname
    ) AS

    SET NOCOUNT ON

    DECLARE @retcode int

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

    /*
    ** Check to see if the database has been activated for publication.
    */

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME()) = 0

    BEGIN
        RAISERROR (14013, 16, -1)
        RETURN (1)
    END


    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists and the publication is not push type
    */

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

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

    UPDATE syspublications SET immediate_sync_ready = 1 
        WHERE
            name = @publication AND
            immediate_sync = 1 AND
            immediate_sync_ready <> 1
    IF @@ERROR <> 0
    BEGIN
        GOTO UNDO
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_changesubstatus 
        @publication = @publication,
        @article = @article,
        @status = 'active',
        @from_auto_sync = 1

    IF @@ERROR <> 0 OR @retcode <> 0
    BEGIN
        GOTO UNDO
        RETURN (1)
    END
    
    COMMIT TRAN
    RETURN(0)

UNDO:
    IF @@TRANCOUNT = 1
        ROLLBACK TRAN
    ELSE
        COMMIT TRAN

GO

EXEC dbo.sp_MS_marksystemobject sp_MSactivate_auto_sub
GO

raiserror('Creating procedure sp_MSget_synctran_commands', 0,1)
GO
CREATE PROCEDURE sp_MSget_synctran_commands(
    @publication sysname    /* publication name */,
    @article sysname = 'all',
    @command_only bit = 0   /* 0 if called by snapshot agent, 1 if called by sp_script_..., */
) AS

    SET NOCOUNT ON
    DECLARE @artid int
    DECLARE @tabid int
    DECLARE @retcode int
    declare @art_type tinyint        
    declare @filter_id int
    declare @filter_clause nvarchar(4000)
	declare @columns binary(32)

    DECLARE @pubid int,
        @art_name sysname, 
        @posted_synctran_artid int,
        @dest_table sysname, 
		@dest_owner sysname,
        @proc_owner sysname

    /*
    ** Initializations.
    */
    select @posted_synctran_artid = 0 

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    ** Do a relaxed security check here.
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** 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

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

    SELECT @pubid = pubid FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
    BEGIN
        RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
    END

    -- If the publication does not allow sync tran return nothing
    IF NOT EXISTS (SELECT * FROM syspublications WHERE pubid = @pubid and
        allow_sync_tran = 1)
        RETURN(0)

    CREATE TABLE #art_commands (artid int NOT NULL, commands nvarchar(4000) NULL, id int identity NOT NULL)
    
    declare @all_article bit 

    if lower(@article) = 'all'
        select @all_article = 1
    else
        select @all_article = 0

    DECLARE hCsynctran_arts CURSOR LOCAL FAST_FORWARD FOR
        SELECT art.artid,
               art.objid,
               
               art.dest_table,
			   art.dest_owner,
			   art.name,
			   art.type,
			   art.filter,
			   art.columns
          FROM sysarticles art,
               syspublications pub
         WHERE pub.pubid = @pubid and
               pub.pubid = art.pubid and
               (art.type & 0x1) = 1 and
               (art.name = @article or
               @all_article = 1)
    FOR READ ONLY

    OPEN hCsynctran_arts

	FETCH hCsynctran_arts INTO @artid, @tabid, @dest_table, @dest_owner, @art_name, 
		@art_type, @filter_id, @columns
	
    WHILE (@@fetch_status <> -1)
    BEGIN

    /*
    ** Determine conflict detection method 
    */
        declare @ts_col sysname
        -- Determine if table has timestamp property
        select @ts_col = NULL
        if ObjectProperty(@tabid, 'TableHasTimestamp') = 1 
        begin
            exec dbo.sp_MSis_col_replicated @publication, @art_name, 
                'timestamp', @ts_col OUTPUT
        end

        declare @replcmd nvarchar(4000)
        declare @insproc sysname, @updproc sysname, @delproc sysname
        declare @identity_col sysname
        declare @identity_prop tinyint

        select @posted_synctran_artid = @artid

        select @insproc = null, @updproc = null, @delproc = null

        -- Get sproc names and owner name of the sprocs
        -- Note artid is unique
        select @insproc = o.name, @proc_owner = u.name from sysobjects o, sysarticleupdates a, sysusers u
        where a.artid = @artid and a.sync_ins_proc = o.id and
            u.uid = o.uid

        select @updproc = o.name from sysobjects o, sysarticleupdates a
        where a.artid = @artid and a.sync_upd_proc = o.id
        
        select @delproc = o.name from sysobjects o, sysarticleupdates a
        where a.artid = @artid and a.sync_del_proc = o.id 

        if @insproc IS NULL
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@insproc')
            RETURN (1)
        end

        if @updproc IS NULL 
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@updproc')
            RETURN (1)
        end

        if @delproc IS NULL
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@delproc')
            RETURN (1)
        end

        -- Determine if published table has identity  col
        select @identity_col = NULL
        if ObjectProperty(@tabid, 'TableHasIdentity') = 1 
            exec @retcode = dbo.sp_MSis_col_replicated @publication, @art_name, 'identity', @identity_col OUTPUT
                
        -- Horizontal partition
        select @filter_clause = 'null'
        if @filter_id <> 0
        begin
            -- We don't handle manual filters;  allow all updates
            if ((@art_type & 0x3) = 0x3) 
                select @filter_clause = ''
            else
                select @filter_clause = RTRIM(LTRIM(CONVERT(nvarchar(4000), filter_clause)))
                     from sysarticles where artid = @artid
        end
	
		declare @fullname nvarchar(512)
		declare @indkey       int
		declare @indid        int
		declare @key          sysname
		declare @col          sysname
		declare @this_col	  int
		declare @src_cols	  int
		declare @primary_key_bitmap varbinary(4000)
		declare @byte varbinary(1)
		declare @i_byte			int
		declare @num_bytes		int
		declare @i_bit			tinyint	
		declare @bitmap_str	varchar(8000)
		declare @bitmap			varbinary(4000)


		-- Get qualified name
		exec dbo.sp_MSget_qualified_name @tabid, @fullname output
		
        -- Get number of columns in the partition.
        exec dbo.sp_MSget_col_position @tabid, @columns, @key, @col output, 
			@this_col output, 
			1, -- Get num of columns in the partition.
			@src_cols output
		select @num_bytes = @src_cols / 8 + 1
	
		-- Set varbinary length
		set @byte = 0
		set @primary_key_bitmap = @byte
		set @i_byte = 1
		while @i_byte < @num_bytes
		begin
			set @primary_key_bitmap = @primary_key_bitmap + @byte
			set @i_byte = @i_byte + 1
		end
	
		-- get index id
		exec @indid = dbo.sp_MStable_has_unique_index @tabid
		set @indkey = 1
		while @indkey < 16 and index_col(@fullname, @indid, @indkey) is not null
        begin
            set @key = index_col(@fullname, @indid, @indkey)
            exec dbo.sp_MSget_col_position @tabid, @columns, @key, @col output, @this_col output
			set @i_byte = 1 + (@this_col-1) / 8
			set @i_bit  = power(2, (@this_col-1) % 8 )
			set @byte = substring(@primary_key_bitmap, @i_byte, 1 )
			set @byte = @byte | @i_bit
			if @i_byte = 1
			begin
				set @bitmap = @byte
			end
			else
			begin
				set @bitmap = substring(@primary_key_bitmap, 1, @i_byte - 1)
				set @bitmap = @bitmap + @byte
			end

			if @i_byte <> @num_bytes
			begin
				set @primary_key_bitmap = @bitmap + 
					substring(@primary_key_bitmap, @i_byte + 1, @num_bytes - @i_byte)
			end
			else
				set @primary_key_bitmap = @bitmap

			select @indkey = @indkey + 1
		end
		exec @retcode = master..xp_varbintohexstr @primary_key_bitmap, @bitmap_str output
		if @retcode <> 0 or @@error <> 0
			return 1

		if @dest_owner is null 
		begin
			select @dest_owner = N'null'
		end
		select @replcmd = '{call sp_addsynctriggers (N' + 
			quotename(@dest_table,'''') + ', N' + 
			quotename(@dest_owner,'''') + ', N' +  
			quotename(@@SERVERNAME,'''') + ', N' +   
			quotename(db_name(),'''') + ', N' + 
			quotename(@publication,'''') + ', N' +  
			quotename(@insproc,'''') + ', N' +   
			quotename(@updproc,'''') + ', N' +   
			quotename(@delproc,'''') + ', N' +    
			quotename(@proc_owner,'''') + ', N' + 
			ISNULL(quotename(@identity_col,''''),'''null''') + ', N' + 
			ISNULL(quotename(@ts_col,''''), '''null''') + ', N' + 
			quotename(@filter_clause,'''')  + ', ' + 
			@bitmap_str + ')}'

        insert into #art_commands values (@artid, @replcmd)

		FETCH hCsynctran_arts INTO @artid, @tabid, @dest_table, @dest_owner, @art_name, 
			@art_type, @filter_id, @columns
	end

	-- end SyncTran
	if @command_only = 0 
		select * from #art_commands order by id
	else
		select commands from #art_commands order by id

    CLOSE hCsynctran_arts
    DEALLOCATE hCsynctran_arts

go
 
EXEC dbo.sp_MS_marksystemobject sp_MSget_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
    declare @retcode int
    exec @retcode = dbo.sp_MSget_synctran_commands 
        @publication = @publication,
        @article = @article,
        @command_only = 1
    if @retcode <> 0 or @@error <> 0
        return (1)

go
 
dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_script_synctran_commands
GO

print ''
print 'Creating procedure sp_MSaddpub_snapshot'
go
CREATE PROCEDURE sp_MSaddpub_snapshot (
    @publication sysname,    
    @freqtype  int = 4 ,                  /* 4== Daily */
    @freqinterval int  = 1,             /* Every day */
    @freqsubtype int =  4,                 /* Sub interval = Minute */
    @freqsubinterval int = 5,              /* Every five minutes */
    @freqrelativeinterval int = 1, 
    @freqrecurrencefactor int = 0, 
    @activestartdate int = 0,             /* 12:00 am - 11:59 pm */
    @activeenddate int =99991231 ,         /* No start date */    
    @activestarttimeofday int = 0,         
    @activeendtimeofday int = 235959,     /* No end time */       
    @newagentid int = 0 OUTPUT
) AS


    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @retcode            int
    DECLARE @distributor        sysname
    DECLARE @distribdb          sysname
    DECLARE @distproc           nvarchar (255)
    DECLARE @agentname          nvarchar(100)
    DECLARE @database           sysname
    DECLARE @newid              int
    DECLARE @mergepublish_bit   smallint
    DECLARE @centralpublish_bit int
    DECLARE @fFoundPublication  int
    DECLARE @agent_args         nvarchar(4000)
    DECLARE @snapshot_jobid     binary(16)
    DECLARE @dist_rpcname       sysname
    DECLARE @publication_type   int


    /*
    ** Initializations
    */
    select @mergepublish_bit    = 4
    select @centralpublish_bit  = 1
    select @fFoundPublication   = 0
    

    EXEC @retcode = dbo.sp_helppublication @publication, @fFoundPublication output

    IF @@ERROR <> 0 OR @retcode <> 0
    BEGIN
        RETURN (1)
    END
        
    IF @fFoundPublication = 0 
    BEGIN
        SELECT @newagentid = 0
        RETURN (0)
    END

        
    /* 
    ** Make sure the publication does not already have a agent.
    */
    IF EXISTS (SELECT * FROM syspublications WHERE name = @publication and snapshot_jobid <> NULL)
    BEGIN
        RAISERROR (14101, 11, -1, @publication)
        RETURN(1)
    END

    /* Get publication_type */
    SELECT @publication_type = repl_freq from syspublications WHERe name = @publication
    
    /*
    ** Get distributor information
    */
    EXEC @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT, 
        @distribdb = @distribdb OUTPUT,
        @rpcsrvname = @dist_rpcname OUTPUT
    IF @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL
    BEGIN
        RAISERROR (14071, 16, -1)
        RETURN (1)
    END

    SELECT @database = DB_NAME()

    SELECT @distproc = RTRIM(@dist_rpcname) + '.' + @distribdb + '.dbo.sp_MSadd_snapshot_agent'
    
    SELECT @agent_args = '-Publisher ' + QUOTENAME(@@SERVERNAME)
    SELECT @agent_args = @agent_args + ' -PublisherDB ' + QUOTENAME(@database)
    SELECT @agent_args = @agent_args + ' -Distributor ' + QUOTENAME(@distributor)
    SELECT @agent_args = @agent_args + ' -Publication ' + QUOTENAME(@publication)

    BEGIN TRAN

    EXECUTE @retcode = @distproc 
        @publisher = @@SERVERNAME,
        @publisher_db = @database,
        @publication = @publication,  
        @publication_type = @publication_type,
        @local_job = 1,  

        @freqtype = @freqtype, 
        @freqinterval = @freqinterval, 
        @freqsubtype = @freqsubtype, 
        @freqsubinterval = @freqsubinterval, 
        @freqrelativeinterval = @freqrelativeinterval, 
        @freqrecurrencefactor = @freqrecurrencefactor, 
        @activestartdate = @activestartdate, 
        @activeenddate = @activeenddate, 
        @activestarttimeofday = @activestarttimeofday, 
        @activeendtimeofday =  @activeendtimeofday,
        @command = @agent_args,
        @snapshot_jobid = @snapshot_jobid OUTPUT
  
   IF @@ERROR <> 0 or @retcode <> 0
        GOTO UNDO

    -- Legacy, use non zero taskid to indicate agent already created at the distributor.
    UPDATE syspublications set snapshot_jobid =  @snapshot_jobid
        WHERE name =  @publication 

    IF @@ERROR <> 0 
        GOTO UNDO

    -- This is the output parameter to indicate agent created.
    SELECT  @newagentid = 1
 
    COMMIT TRAN

    return (0)  
    
UNDO:
    if @@TRANCOUNT = 1
        ROLLBACK TRAN
    else
        COMMIT TRAN
    return(1)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSaddpub_snapshot
GO

dump tran master with no_log
GO

/*
** SyncTran support procs
*/
print ''
print 'Creating procedure sp_MSis_col_replicated'
go
create proc sp_MSis_col_replicated @publication sysname, 
    @article sysname, 
    @coltype nvarchar(10) = 'timestamp',  -- identity or timestamp
    @colname sysname = NULL OUTPUT 
as
begin
    declare @word tinyint, 
        @bit tinyint, 
        @mask binary(2), 
        @mval int,
        @colword binary(2), 
        @columns binary(32),
        @firstcol tinyint, 
        @colid smallint,
        @tabid int,
        @pubid int
        

    select @colname = NULL

    select @pubid = pubid from syspublications where name = @publication

    select @tabid = objid from sysarticles 
        where name = @article and pubid = @pubid
    
    if @coltype = 'timestamp'
    begin
        if ObjectProperty(@tabid, 'TableHasTimestamp') = 1 
        begin

            select @colname = name, @colid = colid from syscolumns 
                where id = @tabid and type_name(xtype) = 'timestamp' 
            
            if @colname is not NULL
            begin                       
                -- check if  timestamp is replicated
                --  Obtain the byte offset and the bit offset, then set the
                select @columns=columns from sysarticles where name = @article and pubid = @pubid
                select @word = CONVERT(tinyint, 16 - FLOOR((@colid-1)/16))
                select @bit = (@colid-1) % 16
                select @mval = POWER(2, @bit)
                select @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )                                 
    
                -- Fish out the byte we're interested in and save it in a
                -- a temporary local variable.  
                select @colword = convert( binary(2), SUBSTRING( convert(nchar(16),@columns), @word, 1) )
    
                if convert( smallint, @colword ) & convert( smallint, @mask) = 0 
                begin
                    select @colname = NULL
                    return (0)
                end
                else
                    return (1)
            end
            else
            begin
                select @colname = NULL
                return (0)
            end
        end
        else
        begin
            select @colname = NULL
            return (0)
        end
    end
    else if @coltype = 'identity'
    begin
        if ObjectProperty(@tabid, 'TableHasIdentity') = 1 
        begin
            select @colname = name, @colid = colid from syscolumns 
            where id = @tabid and ColumnProperty(@tabid, name, 'IsIdentity') = 1
            
            if @colname is not NULL
            begin                       
                -- check if column is replicated
                --  Obtain the byte offset and the bit offset, then set the
                select @columns=columns from sysarticles where name = @article and pubid = @pubid
                select @word = CONVERT(tinyint, 16 - FLOOR((@colid-1)/16))
                select @bit = (@colid-1) % 16
                select @mval = POWER(2, @bit)
                select @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )                                 

                -- Fish out the byte we're interested in and save it in a
                -- a temporary local variable.  
                select @colword = convert( binary(2), SUBSTRING( convert(nchar(16),@columns), @word, 1) )
                
                if convert( smallint, @colword ) & convert( smallint, @mask) = 0 
                begin
                    select @colname = NULL
                    return (0)
                end
                else
                    return (1)
            end
            else
            begin
                select @colname = NULL
                return (0)
            end
        end
        else
        begin
            select @colname = NULL
            return (0)
        end
    end
    else
    begin
        select @colname = NULL
        return (0)    
    end
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSis_col_replicated
GO

print ''
print 'Creating procedure sp_MSis_pk_col'
go
create proc sp_MSis_pk_col @source_table sysname, @colname sysname, @indid int
as
begin

    declare @indkey int
    select @indkey = 1

    while @indkey < 16 and index_col(@source_table, @indid, @indkey) is not null
    begin
        if index_col(@source_table, @indid, @indkey) = @colname
            return (1)

        select @indkey = @indkey + 1
    end

    return (0)
end

EXEC dbo.sp_MS_marksystemobject sp_MSis_pk_col
GO

print ''
print 'Creating procedure sp_MSmark_proc_norepl'
go

create procedure sp_MSmark_proc_norepl
    @procname sysname
as
    set nocount on

    -- CHECK PERMISSIONS (MUST BE DBO) --
    if not (is_member('db_owner')=1 or is_srvrolemember('sysadmin') = 1) 
    begin
        raiserror(20521,0,1)
        return 1
    end

    -- CHECK THE OBJECT NAME --
    if object_id(@procname, 'local') is null
    begin
        raiserror(20522,0,1,@procname)
        return 1
    end

    -- DO THE UPDATE --
    begin tran
    exec dbo.sp_replupdateschema @procname
    update sysobjects set replinfo = replinfo | 0x40
                        where id = object_id(@procname, 'local')
    commit tran
    return @@error 
go

EXEC dbo.sp_MS_marksystemobject sp_MSmark_proc_norepl
GO

create procedure sp_MSdrop_expired_subscription
AS
/*
** This stored procedure is to periodically check the status of all the subscriptions 
** of every merge publication. If any of them is out-of-date, i.e., has lost contact
** with publisher for a certain length of time, we can declare the death of that replica
** and cleanup their traces at the publisher side
*/
declare @independent_agent  bit
declare @article            sysname
declare @publication        sysname
declare @pubid              int
declare @artid              int
declare @publisher          sysname
declare @subscriber         sysname
declare @subscriber_id      smallint
declare @subscriber_db      sysname
declare @publisher_db       sysname
declare @out_of_date        int
declare @distributor        sysname
declare @distribdb          sysname
declare @retention          int  -- in days         
declare @retcode            smallint
declare @distproc           nvarchar(255)
declare @localproc          nvarchar(255)
declare @msg                nvarchar(255)
declare @open_cursor        nvarchar(400)

    /*
    ** Security Check
    */
EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    /*
    ** Get distribution server information for remote RPC call.
    */
EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
     @distribdb   = @distribdb OUTPUT
IF @@ERROR <> 0 or @retcode <> 0
    BEGIN
        RAISERROR (20036, 16, -1)
        return (1)
    END

    
SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MShelp_subscription_status '
select @publisher = @@SERVERNAME
select @publisher_db = db_name()

declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT name, pubid, independent_agent, retention from syspublications p
    open PC
    fetch PC into @publication, @pubid, @independent_agent, @retention
    WHILE (@@fetch_status <> -1)
        BEGIN
            declare SC CURSOR LOCAL FAST_FORWARD for select s.srvid, s.dest_db, a.name from syssubscriptions s, sysarticles a 
                where a.pubid= @pubid and s.artid = a.artid and s.srvid<>-1 
                for read only
            open SC
            fetch SC into @subscriber_id, @subscriber_db, @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    select @subscriber=srvname from master..sysservers where srvid=@subscriber_id
                    exec @retcode = @distproc @publisher = @publisher, 
                                    @publisher_db = @publisher_db, 
                                    @publication = @publication, 
                                    @subscriber = @subscriber, 
                                    @subscriber_db = @subscriber_db,
                                    @retention = @retention,
                                    @out_of_date = @out_of_date OUTPUT,
                                    @independent_agent = @independent_agent
                    if @retcode<>0 or @@ERROR<>0 
                        begin
                            close SC
                            deallocate SC
                            close PC
                            deallocate PC
                            return (1)
                        end
                    IF (@out_of_date = 1)
                        begin
                            exec @retcode = dbo.sp_dropsubscription   -- publisher_db.dbo.sp_dropsubscription
                                @publication = @publication,
                                @article = @article,
                                @subscriber = @subscriber,
                                @destination_db = @subscriber_db
                            if @retcode <>0 or @@ERROR<>0
                                begin
                                    close SC
                                    deallocate SC
                                    close PC
                                    deallocate PC
                                    return (1)
                                end
                            raiserror(14157, 10, -1, @subscriber, @publication) 
                        end
                    fetch SC into @subscriber_id, @subscriber_db, @article
                END
            CLOSE SC
            DEALLOCATE SC
            fetch PC into @publication, @pubid, @independent_agent, @retention
        END
    CLOSE PC
    DEALLOCATE PC

GO
EXEC dbo.sp_MS_marksystemobject sp_MSdrop_expired_subscription
go


-- synctran supporting procs
raiserror('Creating procedure sp_MSscript_insert_statement', 0,1)
go
create procedure sp_MSscript_insert_statement
    @objid int,
    @columns binary(32)
as
    declare @cmd          nvarchar(4000)
    declare @cmd2         nvarchar(4000)
    declare @qualname     nvarchar(512)
    declare @colname      sysname
    declare @typestring   nvarchar(4000)
    declare @spacer       nvarchar(1)
    declare @ccoltype     sysname
    declare @src_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @rc           int
	declare @num_col	  int
    
    select @src_cols = count(*) from syscolumns where id = @objid

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

    select @cmd2 = N'insert into ' + @qualname + N'( '
    
    -- col names
    select @spacer = N' '
    select @this_col = 1
    select @art_col = 1
    select @cmd = N''

	select @num_col = 0
    while @this_col <= @src_cols
    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' and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
            begin
				select @num_col = @num_col + 1
				if @cmd2 is not null
				begin
					exec dbo.sp_MSflush_command @cmd2 output, 1
					select @cmd2 = null
				end
		        select @cmd = @cmd + @spacer + QUOTENAME(@colname)
                select @spacer = N','
		        exec dbo.sp_MSflush_command @cmd output, 0
            end
        end
        select @this_col = @this_col + 1
    end

	if @num_col > 0
	begin
		-- save off cmd fragment
		exec dbo.sp_MSflush_command @cmd output, 1
		insert into #proctext(procedure_text) values( N') 
		 values (')

		-- col values
		select @spacer = N' '
		select @this_col = 1
		select @art_col = 1
		select @cmd = N''
		while @this_col <= @src_cols
		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' and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
				begin
					select @cmd = @cmd + @spacer + N'@c' + convert(varchar(4), @this_col)
					select @spacer = N','
				end
			end

			exec dbo.sp_MSflush_command @cmd output, 0
			select @this_col = @this_col + 1
		end

		-- save off cmd fragment
		exec dbo.sp_MSflush_command @cmd output, 1
		insert into #proctext(procedure_text) values( N')
	 ')
	end
	else
		-- set the @@rowcount
		insert into #proctext(procedure_text) values( N' select @retcode = @retcode
	')

go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_insert_statement
GO

raiserror('Creating procedure sp_MSscript_update_statement', 0,1)
go
create procedure sp_MSscript_update_statement
    @publication sysname,
    @article     sysname, 
    @objid int,
    @columns binary(32)
as

    declare @cmd          nvarchar(4000)
    declare @cmd2         nvarchar(4000)
    declare @qualname     nvarchar(512)
	declare @colname      sysname
	declare @typestring   nvarchar(4000)
	declare @spacer       nvarchar(1)
	declare @ccoltype     sysname
	declare @src_cols     int
	declare @this_col     int
	declare @rc           int
	declare @column		  nvarchar(100)
	declare @num_col	  int

    select @src_cols = count(*) from syscolumns where id = @objid

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
    select @cmd2 = N'update ' + @qualname + N' set'

    -- col names
    select @spacer = N' '
	select @this_col = 1
	select @cmd = N''

	-- If the table have only identity in pk and a ts col, update statement will be empty 
	-- and the query will fail. Prevent it here.
	select @num_col = 0
    -- script update
    while @this_col <= @src_cols 
    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' and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
            begin
				if @cmd2 is not null
				begin
					exec dbo.sp_MSflush_command @cmd2 output, 1
					select @cmd2 = null
				end

				select @num_col = @num_col + 1
				-- Optimization:
				-- Get null or actual column name
				-- Note: the output is quoted.
				exec dbo.sp_MSget_synctran_column 
						@ts_col = null,
						@op_type = null , -- 'ins, 'upd', 'del'
						@is_new = null,
						@primary_key_bitmap = null,
						@colname = @colname,
						@this_col = @this_col,
						@column = @column output,
						@from_proc = 1

			    select @cmd = @cmd + @spacer + QUOTENAME(@colname) + N' = ' + @column 
			    select @spacer = N','
				-- flush command if necessary
				exec dbo.sp_MSflush_command @cmd output, 0

			end
		end
		
        select @this_col = @this_col + 1
    end

    -- save off cmd fragment
	if @num_col > 0
	begin
		exec dbo.sp_MSflush_command @cmd output, 1
          
		-- Determine method of conflict detection and add where clause
		if ObjectProperty(@objid, 'TableHasTimestamp') = 1
		begin
			exec @rc = dbo.sp_MSis_col_replicated @publication, @article, 'timestamp', @colname OUTPUT 
			if @rc = 1
			begin
				insert into #proctext(procedure_text) values( N'
	') 
				exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd ts', @colname, 4
			end
		end
		else
		begin
			insert into #proctext(procedure_text) values( N'
	')
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd rc', null, 4
		end
	end 
	else
		-- set the @@rowcount
		insert into #proctext(procedure_text) values( N' select @retcode = @retcode
	')
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_update_statement
GO

raiserror('Creating procedure sp_MSscript_delete_statement', 0,1)
go
create procedure sp_MSscript_delete_statement
    @publication sysname,
    @article     sysname, 
    @objid int,
    @columns binary(32)
as
    declare @cmd          nvarchar(4000)
    declare @qualname     nvarchar(512)
    declare @colname      sysname
    declare @typestring   nvarchar(4000)
    declare @spacer       nvarchar(1)
    declare @ccoltype     sysname
    declare @src_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @rc           int

    select @src_cols = count(*) from syscolumns where id = @objid

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
    select @cmd = N'delete ' + @qualname
    exec dbo.sp_MSflush_command @cmd output, 1

    -- Determine method of conflict detection and add where clause
    insert into #proctext(procedure_text) values( N'
')
    if ObjectProperty(@objid, 'TableHasTimestamp') = 1
    begin
        exec @rc = dbo.sp_MSis_col_replicated @publication, @article, 'timestamp', @colname OUTPUT 
        if @rc = 1
            exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd ts', @colname, 4
        else
            exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd rc', null, 4
    end 
    else
        exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd rc', null, 4
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_delete_statement
GO

raiserror('Creating procedure sp_MSscript_beginproc', 0,1)
go
create procedure sp_MSscript_beginproc 
    @publication  sysname, 
    @article      sysname, 
    @procname     sysname,
    @source_objid int        output,
    @columns      binary(32) output
as
    declare @cmd nvarchar(4000)
    declare @source_table sysname
    declare @owner sysname

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

    -- Get the object owner name
    select @owner = u.name from sysusers u, sysobjects o where 
        o.id = @source_objid and
        o.uid = u.uid
            
    if @source_table IS NULL
    begin
        raiserror (20506, 16, 1,  @source_table, 'sp_MSscript_beginproc')
        return 0
    end

    -- Construct proc name
    -- Create proc under the table owner account to preserve the ownership chain
    select @cmd = N'create procedure '+QUOTENAME(@owner)+ N'.'+ QUOTENAME(@procname) + N' @orig_server sysname, @orig_db sysname, '
    exec dbo.sp_MSflush_command @cmd output, 1

    return 1
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_beginproc
GO

raiserror('Creating procedure sp_MSscript_security', 0,1)
go
create procedure sp_MSscript_security 
    @publication sysname
as
    declare @cmd nvarchar(4000)

    -- insert into #proctext(procedure_text) values(N'declare @retcode int')
    insert into #proctext(procedure_text) values(N'exec @retcode = dbo.sp_MSreplcheck_pull')
    insert into #proctext(procedure_text) values(N'@publication = ''' + @publication + '''
' )
    insert into #proctext(procedure_text) values(N'if @retcode <> 0 or @@error <> 0' )
    insert into #proctext(procedure_text) values(N' return -1

')
                    
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_security
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)
as
    declare @cmd nvarchar(4000)
	declare @qualname nvarchar(512)

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

    insert into #proctext(procedure_text) values(N'
 
 if @@ROWCOUNT = 0
 begin
     exec sp_MSreplraiserror 20515
     return -1
 end')
                    
    if @outvars <> null
    begin   
        insert into #proctext(procedure_text) values(N'
 else
 begin 
')
        if @op_type = 'upd'
			-- 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'
')

        select @cmd = N'    select ' + @outvars 
        insert into #proctext(procedure_text) values( @cmd)
        select @cmd = 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

        insert into #proctext(procedure_text) values( N'    return 0
')
        insert into #proctext(procedure_text) values( N'end

')
    end
    else
    begin
        insert into #proctext(procedure_text) values( N'
 else 
     return 0')
    end
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_endproc
GO

raiserror('Creating procedure sp_MStable_not_modifiable', 0,1)
go
create proc sp_MStable_not_modifiable
    @objid   int,
    @columns binary(32)
as
    declare @colname      sysname
    declare @typestring   nvarchar(4000)
    declare @src_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @isset        int
    declare @found int, @repl_columns int

    select @this_col = 1
    select @art_col = 1
    select @found = 0, @repl_columns = 0
    select @src_cols = count(*) from syscolumns where id = @objid

    while @this_col <= @src_cols 
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns

        if @isset != 0 and EXISTS (select name from syscolumns where id=@objid and @this_col=colid and iscomputed<>1)
        begin
            select @repl_columns = @repl_columns + 1
            exec dbo.sp_MSget_type @objid, @this_col, @colname output, @typestring OUTPUT

            if @typestring = N'timestamp' or ColumnProperty(@objid, @colname, 'IsIdentity') = 1
                select @found = 1

        end
        select @this_col = @this_col + 1
    end

    if @found = 1 and @repl_columns = 1
        return 1
    else
        return 0
go


EXEC dbo.sp_MS_marksystemobject sp_MStable_not_modifiable
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
    declare @source_objid int
    declare @colname sysname
    declare @indid int
    declare @cmd          nvarchar(4000)
    declare @ins_cmd      nvarchar(4000)
    declare @columns      binary(32)
    declare @outvars      nvarchar(4000)
    declare @rc           int

    set nocount on
    -- Create temp table
    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) NULL)

    -- preamble common to all synctran procs
    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

    -- construct body of procedure
    insert into #proctext(procedure_text) values( N'
 as
')

    -- set cycle detection
    insert into #proctext(procedure_text) values(N'declare @retcode int

')

    insert into #proctext(procedure_text) values( N'exec @retcode = dbo.sp_replsetoriginator @orig_server, @orig_db
')
    insert into #proctext(procedure_text) values( N'if @retcode <> 0 or @@error <> 0 return -1

')

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

    -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
    exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
    if @rc = 1
        insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
     
    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
            insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
    
        else
        begin
                
            -- script insert statemnt
            exec dbo.sp_MSscript_insert_statement @source_objid, @columns

            -- script closing 
            exec dbo.sp_MSscript_endproc @source_objid, 'ins', @columns, @outvars
        end
    end

    -- send fragments to client
    select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_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
    declare @source_objid int
    declare @colname      sysname
    declare @indid        int
    declare @cmd          nvarchar(4000)
    declare @ins_cmd      nvarchar(4000)
    declare @columns      binary(32)
    declare @outvars      nvarchar(4000)
    declare @rc           int

    set nocount on

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

    -- preamble common to all synctran procs
    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
    insert into #proctext(procedure_text) values( N', 
')
    exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null

	-- Script bitmap parameter
	insert into #proctext(procedure_text) values( N', @bitmap varbinary(4000)')

	-- construct body of procedure
	insert into #proctext(procedure_text) values( N'
 as
')

    -- set cycle detection
    insert into #proctext(procedure_text) values(N'declare @retcode int

')
    insert into #proctext(procedure_text) values( N'exec @retcode = dbo.sp_replsetoriginator @orig_server, @orig_db
')
    insert into #proctext(procedure_text) values( N'if @retcode <> 0 or @@error <> 0 return -1
    
')

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

    -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
    exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
    if @rc = 1
        insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
     
    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
            insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
        else
        begin
            -- script update statemnt
            exec dbo.sp_MSscript_update_statement @publication, @article, @source_objid, @columns

            -- script closing 
            exec dbo.sp_MSscript_endproc @source_objid, 'upd', @columns, @outvars
        end
    end

    -- send fragments to client
    select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_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
    declare @source_objid int
    declare @colname sysname
    declare @indid int
    declare @cmd          nvarchar(4000)
    declare @ins_cmd      nvarchar(4000)
    declare @columns      binary(32)
    declare @outvars      nvarchar(4000)
    declare @rc           int

    set nocount on

    -- Create temp table
    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) NULL)
    
    -- preamble common to all synctran procs
    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
    
    -- construct body of procedure
    insert into #proctext(procedure_text) values( N'
 as
')

    -- set cycle detection
    insert into #proctext(procedure_text) values(N'declare @retcode int

')
    insert into #proctext(procedure_text) values( N'exec @retcode = dbo.sp_replsetoriginator @orig_server, @orig_db
')
    insert into #proctext(procedure_text) values( N'if @retcode <> 0 or @@error <> 0 return -1

')

    -- script out security check
    exec dbo.sp_MSscript_security @publication
    
    -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
    exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
    if @rc = 1
        insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
     
    else
        begin
            exec @indid = dbo.sp_MStable_has_unique_index @source_objid
            if @indid = 0
                -- no delete allowed if  no unique index
                insert into #proctext(procedure_text) values( N'exec sp_MSreplraiserror 20516

')
            else
            begin    
                -- script insert statemnt
                exec dbo.sp_MSscript_delete_statement @publication, @article, @source_objid, @columns

                -- script closing 
                exec dbo.sp_MSscript_endproc @source_objid, 'del', @columns, null
            end
        end

        -- send fragments to client
        select procedure_text from #proctext order by c1 asc
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_del_proc
GO

print ''
print 'Creating procedure sp_MSgen_sync_tran_procs'
go
create procedure sp_MSgen_sync_tran_procs
    @publication    sysname,        -- table name 
    @article        sysname,
    @ins_proc       sysname,
    @upd_proc       sysname,
    @del_proc       sysname

as
    set nocount on

    declare @cmd nvarchar(4000)
    declare @dbname sysname
    declare @owner sysname
    declare @retcode int

    select @owner = user_name(o.uid) from sysobjects o , sysarticles a where o.id=a.objid and a.name=@article

    -- We are now going to create procs, so start a transaction
    begin tran gen_procs
       -- Call out to individual create proc routines
       select @dbname = db_name()
       select @cmd = 'sp_MSscript_sync_ins_proc [' + @publication + '], [' + @article  + '], [' + @ins_proc + ']'
       exec master..xp_execresultset @cmd, @dbname

       select @cmd = 'sp_MSscript_sync_upd_proc [' + @publication + '], [' + @article  + '], [' + @upd_proc + ']'
       exec master..xp_execresultset @cmd, @dbname

       select @cmd = 'sp_MSscript_sync_del_proc  [' + @publication + '], [' + @article  + '], [' + @del_proc  + ']'
       exec master..xp_execresultset @cmd, @dbname

        -- Grant permissions
        select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@ins_proc) + ' to public'
        exec (@cmd)
        select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@upd_proc) + ' to public'
        exec (@cmd)
        select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@del_proc) + ' to public'
        exec (@cmd)

        -- Mark procedures as system procs so they don't show up in the UI
        if @owner in ('dbo','INFORMATION_SCHEMA')
        begin
            select @cmd = 'exec dbo.sp_MS_marksystemobject ''' + quotename(@owner) + '.' + quotename(@ins_proc) + '''' 
            exec (@cmd)
            select @cmd = 'exec dbo.sp_MS_marksystemobject ''' + quotename(@owner) + '.' + quotename(@upd_proc) + ''''
            exec (@cmd)
            select @cmd = 'exec dbo.sp_MS_marksystemobject ''' + quotename(@owner) + '.' + quotename(@del_proc) + ''''
            exec (@cmd)
        end

        -- Mark procedures to set 'NOT FOR REPL' bit
        select @cmd = 'exec dbo.sp_MSmark_proc_norepl ''' + quotename(@owner) + '.' + quotename(@ins_proc) + ''''
        exec (@cmd)
        select @cmd = 'exec dbo.sp_MSmark_proc_norepl ''' + quotename(@owner) + '.' + quotename(@upd_proc) + ''''
        exec (@cmd)
        select @cmd = 'exec dbo.sp_MSmark_proc_norepl ''' + quotename(@owner) + '.' + quotename(@del_proc) + ''''
        exec (@cmd)

    -- Commit tran
    commit tran
go

EXEC dbo.sp_MS_marksystemobject sp_MSgen_sync_tran_procs
GO

print ''
print 'Creating procedure sp_articlesynctranprocs'
go

CREATE PROCEDURE sp_articlesynctranprocs
    @publication sysname,         -- publication name 
    @article sysname,              -- article name 
    @ins_proc sysname,       -- name of sproc supporting Sync Tran inserts associated with this article
    @upd_proc sysname,       -- name of sproc supporting Sync Tran updates associated with this article
    @del_proc sysname,       -- name of sproc supporting Sync Tran deletes associated with this article
    @autogen       nvarchar(5) = 'true' -- indicates wether or not to auto generate sprocs
AS
    SET NOCOUNT ON

    -- Declarations.
    DECLARE @pubid int
    DECLARE @artid int
    DECLARE @retcode int
    DECLARE @autogen_id bit
    DECLARE @ins_proc_id int
    DECLARE @upd_proc_id int
    DECLARE @del_proc_id int
    
    /* 
    ** Security Check.
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)
    
    -- Parameter Check: @article. The @article name cannot be NULL and must conform 
    -- to the rules for identifiers.
    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END

    EXECUTE @retcode = dbo.sp_validname @article
    IF @retcode <> 0
        RETURN(1)
    
    -- Parameter Check: @publication.
    -- The @publication name cannot be NULL and must conform to the rules
    -- for identifiers.
    IF @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END

    EXECUTE @retcode = dbo.sp_validname @publication
    IF @retcode <> 0
        RETURN (1)

    -- Parameter Check: @ins_proc, @upd_proc, @del_proc.
    -- The sproc names cannot be NULL and must conform to the rules
    -- for identifiers

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

    EXECUTE @retcode = dbo.sp_validname @ins_proc
    IF @retcode <> 0
        RETURN (1)

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

    EXECUTE @retcode = dbo.sp_validname @upd_proc
    IF @retcode <> 0
        RETURN (1)

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

    EXECUTE @retcode = dbo.sp_validname @del_proc
    IF @retcode <> 0
        RETURN (1)

    -- Parameter Check:  @autogen
    IF @autogen IS NULL OR LOWER(@autogen) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@autogen')
        RETURN (1)
    END

    IF LOWER(@autogen) = 'true' 
        SELECT @autogen_id = 1
    ELSE 
        SELECT @autogen_id = 0

    -- Retrieve pubid & artid
    SELECT @pubid = a.pubid, @artid = a.artid 
    FROM sysarticles a, syspublications p
    WHERE p.name = @publication AND a.name = @article AND
        a.pubid = p.pubid
    IF @pubid IS NULL OR @artid IS NULL
    BEGIN
        if @pubid IS NULL RAISERROR (20026, 16, 1, @publication)
        if @artid IS NULL RAISERROR (20026, 16, 1, @publication)
        RETURN (1)
    END

       BEGIN TRAN sp_articlesynctranprocs

        -- if @autogen is true, generate the sprocs
        IF @autogen_id = 1
        BEGIN
            EXECUTE @retcode =  dbo.sp_MSgen_sync_tran_procs @publication, @article, 
                @ins_proc, @upd_proc, @del_proc
            IF @retcode <> 0
            BEGIN
                IF @@TRANCOUNT <> 0
                    ROLLBACK tran sp_articlesynctranprocs
                RETURN (1)
            END
        END

        --retrieve sproc id's, fail if they don't exist
        SELECT @ins_proc_id = id FROM sysobjects WHERE name = @ins_proc
        SELECT @upd_proc_id = id FROM sysobjects WHERE name = @upd_proc
        SELECT @del_proc_id = id FROM sysobjects WHERE name = @del_proc

        IF (@ins_proc_id IS NULL) OR (@upd_proc_id IS NULL) OR (@del_proc_id IS NULL)
        BEGIN
            if @ins_proc_id IS NULL RAISERROR (20500, 16, 1, @ins_proc)
            if @upd_proc_id IS NULL RAISERROR (20500, 16, 1, @upd_proc)
            if @del_proc_id IS NULL RAISERROR (20500, 16, 1, @del_proc)
            IF @@TRANCOUNT <> 0
                ROLLBACK tran sp_articlesynctranprocs
            RETURN (1)
        END

        -- perform insert into sysarticleupdates
        -- BUGUBG need to mark this as a system table, so this sproc can live in master db
        INSERT sysarticleupdates(pubid, artid, sync_ins_proc, sync_upd_proc, sync_del_proc, autogen)
            VALUES (@pubid, @artid, @ins_proc_id, @upd_proc_id, @del_proc_id, @autogen_id)

        IF @@ERROR <> 0
            BEGIN
                IF @@TRANCOUNT <> 0
                    ROLLBACK tran sp_articlesynctranprocs
                RETURN (1)
            END

    COMMIT TRAN
go

EXEC dbo.sp_MS_marksystemobject sp_articlesynctranprocs
GO

print ''
print 'Creating procedure sp_reinitsubscription'
go

CREATE PROCEDURE sp_reinitsubscription (
    @publication sysname = 'all',    /* publication name */
    @article sysname = 'all',        /* article name */
    -- Force user to specify the subscriber name
    @subscriber sysname,             /* subscriber name */
    @destination_db sysname = 'all'   /* destination database name */
) AS

    DECLARE @retcode int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    declare @active tinyint
    declare @subscribed tinyint
    declare @automatic tinyint
    DECLARE @artid int
    DECLARE @srvid smallint
    DECLARE @distproc nvarchar (255)
    DECLARE @dbname sysname
    DECLARE @sub_ts binary(10) -- must be binary(10) type.
    DECLARE @sync_type tinyint
    DECLARE @immediate_sync bit
    DECLARE @subscription_type int
    DECLARE @push int
    DECLARE @pub sysname
    DECLARE @dest_db sysname
    DECLARE @sub_name sysname
    DECLARE @art_name sysname
    DECLARE @none tinyint
    declare @login_name sysname


  
    -- Initialization
    select @active = 2
    select @subscribed = 1
    select @dbname = DB_NAME()
    SELECT @none = 2            /* Const: synchronization type 'none' */
    SELECT @automatic = 1       /* Const: synchronization type 'automatic' */
    select @push = 0

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

    /* Validate names */

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

    /* article name can be a quoted name
    EXECUTE @retcode = dbo.sp_validname @article
    IF @@ERROR <> 0 OR @retcode <> 0
        RETURN (1)
    */

    -- Subscriber can be NULL
    IF @subscriber IS NOT NULL
    BEGIN
        EXECUTE @retcode = dbo.sp_validname @subscriber
        IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)

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

    -- Replace 'all' with '%'
    if LOWER(@publication) = 'all'
        SELECT @publication = '%'

    if LOWER(@article) = 'all'
        SELECT @article = '%'

    if LOWER(@subscriber) = 'all'
        SELECT @subscriber = '%'

    if LOWER(@destination_db) = 'all'
        SELECT @destination_db = '%'

    /*
    ** 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 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 NOT EXISTS (SELECT *
                     FROM sysarticles 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

    -- Don't check subscriber and dest_db for virtual subscriptions
    IF @subscriber IS NOT NULL
    BEGIN    
        /*
        ** Parameter Check:  @subscriber
        ** Check to make sure that the subscriber exists
        */
        if @subscriber <> '%' select @subscriber = UPPER(@subscriber)
        
        IF NOT EXISTS (SELECT *
                         FROM master..sysservers
                        WHERE ((@subscriber = N'%') OR (UPPER(srvname) = UPPER(@subscriber)))
                          AND (srvstatus & 4) <> 0)

            BEGIN
                RAISERROR (14063, 11, -1)
                RETURN (1)
            END
    END

    -- Wrong dest_db will be caught by the following query

    -- Check to make sure the subscription exists 
    IF  @publication <> '%' AND
        @subscriber <> '%' AND

        NOT EXISTS (SELECT *
          FROM syssubscriptions sub,
               sysarticles art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication
           AND art.name LIKE @article
           AND ((UPPER(ss.srvname) = UPPER(@subscriber) 
           AND sub.srvid = ss.srvid)
           OR (@subscriber is NULL 
           AND pub.allow_anonymous = 1))
           AND sub.artid = art.artid
           AND art.pubid = pub.pubid
           AND sub.dest_db LIKE @destination_db)
    BEGIN
        RAISERROR (14055, 16, -1)
        RETURN (1)
    END

    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

    DECLARE hCresyncsub CURSOR LOCAL FAST_FORWARD FOR
        -- non immediate_sync pubs
        SELECT pub.name,
               pub.immediate_sync,
               art.name,
               ss.srvname,
               sub.dest_db,
               sub.sync_type,
               sub.subscription_type,
               sub.login_name
          FROM syssubscriptions sub,
               sysarticles art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication
           AND art.name LIKE @article
           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
           AND sub.srvid = ss.srvid
           AND sub.artid = art.artid
           AND art.pubid = pub.pubid
           AND sub.dest_db LIKE @destination_db
           AND sub.status = @active
           AND pub.immediate_sync = 0
        
        UNION
        -- Immediate_sync pubs
        SELECT DISTINCT
               pub.name,
               immediate_sync,
               '%', -- art.name is '%' from immediate_sync pub
               ss.srvname,
               sub.dest_db,
               sub.sync_type,
               sub.subscription_type,
               sub.login_name
          FROM syssubscriptions sub,
               sysarticles art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication -- Ignore @article
           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber)))
           AND sub.srvid = ss.srvid
           AND sub.artid = art.artid
           AND art.pubid = pub.pubid
           AND sub.dest_db LIKE @destination_db
           AND sub.status = @active
           AND pub.immediate_sync = 1
                 
        UNION
        -- For anonymous subscribers
        SELECT pub.name,
               immediate_sync,
               '%', -- art.name is '%' for immediate_sync pub
               CONVERT(sysname, NULL), -- subscriber name (null represent virtual)
               'virtual', -- destination_db for virtual subscription is hardcoded in 
                         -- sp_MSadd_subscription.
               @automatic, -- sub.sync_type is auto tor anonymous subscriber
               @push,      -- virtual subscription is push type,
               'sa'
          FROM syspublications pub
         WHERE pub.name LIKE @publication -- Ignore @article
           AND pub.allow_anonymous = 1 
           AND (@subscriber = '%' OR @subscriber IS NULL) 
                 
    FOR READ ONLY

    OPEN hCresyncsub 

    -- Note: Don't overwrite the variables used in the cursor.
    FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
        @dest_db, @sync_type, @subscription_type, @login_name

    WHILE (@@fetch_status <> -1)
    BEGIN
        -- Security Check
        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

         if @sync_type = @none
         begin
            raiserror(21071, 10, -1, @art_name, @sub_name, @dest_db, @pub)
            FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
                @dest_db, @sync_type, @subscription_type, @login_name
            continue
         end

        -- If @article is not 'all' for immediate_sync publication
        -- report error and skip.
        IF @immediate_sync = 1 AND @article != '%'
        BEGIN
            RAISERROR (14122, 16, -1)
            FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
                @dest_db, @sync_type, @subscription_type, @login_name
            CONTINUE
        END

        begin tran
        save TRAN sp_reinitsubscription

        -- Reset subscription status to subscribed and activate it later.
        -- This is to reset its snapshot transaction ts to the new one.
        -- We don't need to do it for anonymous subscriber since its snapshot
        -- transaction ts will be updated automatically by the snapshot agent.
        IF @sub_name IS NOT NULL
        BEGIN
            EXEC @retcode = dbo.sp_changesubstatus
                @publication = @pub,
                @article = @art_name,
                @subscriber = @sub_name,
                @destination_db = @dest_db,
                @status = 'subscribed'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCresyncsub
                DEALLOCATE hCresyncsub
                RAISERROR (14070, 16, -1)
                GOTO UNDO
            END
        END

        -- Reset the subscription guid at the distributor for immediate_sync publication.
     	-- Reset subscription creation datetime used by retention cleanup.
        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSreset_subscription'
        EXEC @retcode = @distproc 
            @publisher = @@SERVERNAME, 
            @publisher_db = @dbname, 
            @publication = @pub,
            @subscriber = @sub_name, 
            @subscriber_db = @dest_db,
            @subscription_type = @subscription_type

        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            CLOSE hCresyncsub
            DEALLOCATE hCresyncsub
            GOTO UNDO
        END

        -- Activate the subscription again if the publication is immediate_sync or
        -- the subscription is no_sync type.
        -- Otherwise, the snapshot agent will activate the subscription
        IF (@immediate_sync = 1 AND @subscriber IS NOT NULL)
        BEGIN
            -- Set subscription status back to active again.
            EXEC @retcode = dbo.sp_changesubstatus
                @publication = @pub,
                @article = @art_name,
                @subscriber = @sub_name,
                @destination_db = @dest_db,
                @status = 'active'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCresyncsub
                DEALLOCATE hCresyncsub
                RAISERROR (14070, 16, -1)
                GOTO UNDO
            END
        END
    
        COMMIT TRAN 

        FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
            @dest_db, @sync_type, @subscription_type, @login_name
    END

    CLOSE hCresyncsub
    DEALLOCATE hCresyncsub

    RETURN(0)

UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_reinitsubscription
        COMMIT TRAN
    end
    return 1
go

EXEC dbo.sp_MS_marksystemobject sp_reinitsubscription
GO

dump tran master with no_log
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_getarticlepkcolbitmap'
go

create procedure sp_getarticlepkcolbitmap @tabid int, @colbitmap binary(32) output
as
declare @pkindid int
declare @indkey int
declare @colid int
declare @word tinyint
declare @mval    int
declare @mask    binary(2)
declare @wordval binary(2)
declare @objname nvarchar(265)

select @colbitmap = 0x00
select @pkindid = indid from sysindexes where id = @tabid and status & 2048 <> 0
select @indkey = 1
select @objname = QUOTENAME(user_name(OBJECTPROPERTY(@tabid, 'OwnerId'))) + N'.' + QUOTENAME(object_name( @tabid )) 

while @indkey <= 16 and index_col( @objname, @pkindid, @indkey ) is not null
begin
    select @colid = colid from syscolumns where id = @tabid 
           and name = index_col( @objname, @pkindid, @indkey )
    select @word = convert(tinyint, 16 - floor((@colid-1)/16))

    select @mval = power(2, (@colid-1) % 16 )
    select @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )                                 

    select @wordval = convert( binary(2), substring( convert( nchar(16), @colbitmap ), @word, 1 ) )
    select @wordval = convert( binary(2), convert( smallint, @wordval) | convert( smallint, @mask) )

    select @colbitmap = convert(binary(32), STUFF( convert(nchar(16),@colbitmap), @word, 1, convert( nchar(1),@wordval))) 
      
    select @indkey = @indkey + 1
end
go

EXEC dbo.sp_MS_marksystemobject sp_getarticlepkcolbitmap
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_gettypestring'
go

create procedure sp_gettypestring @tabid int, @colid int, @typestring nvarchar(255) output
as
declare @coltypename sysname
declare @coltype  tinyint
declare @colvar   bit
declare @collen   smallint
declare @colprec  tinyint
declare @colscale tinyint

select @coltypename = st.name, @coltype = st.xtype, @colvar = st.variable, 
       @collen = sc.length, @colprec = sc.xprec, @colscale = sc.xscale
from systypes st, syscolumns sc 
where sc.id = @tabid
and sc.colid = @colid
and st.xtype = sc.xtype
and st.xtype = st.xusertype

select @typestring = @coltypename

if @coltypename in (N'char', N'varchar', N'binary', N'varbinary')
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@collen) + N')'
end
else if @coltypename in (N'nchar', N'nvarchar' )
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@collen/2) + N')'
end
else if @coltype = 108 or @coltype = 106
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@colprec) + N',' + convert(nvarchar,@colscale) + N')'
end
else if @coltype = 189
begin
    select @typestring = N'binary(8)'
end
    
go

EXEC dbo.sp_MS_marksystemobject sp_gettypestring
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_isarticlecolbitset'
go

create procedure sp_isarticlecolbitset @colid int, @colbitmap binary(32)
as
declare @word tinyint
declare @mval int
declare @mask  smallint

select @word = convert(tinyint, 16 - floor((@colid-1)/16))
select @mval = power(2, (@colid-1) % 16 )
select @mask = convert( smallint, convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) ) )


if convert( binary(2), substring( convert( nchar(16),@colbitmap), @word, 1 ) ) & @mask = @mask 
begin   
   return 1
end
else
begin
   return 0
end

go

EXEC dbo.sp_MS_marksystemobject sp_isarticlecolbitset
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'sp_scriptpkwhereclause'
go

create procedure sp_scriptpkwhereclause @src_objid int, @src_cols int, @pkcolumns binary(32)
as
declare @this_col int
declare @art_col int
declare @spacer nvarchar(10)
declare @isset int
declare @cmd nvarchar(4000)

-- create WHERE clause

select @this_col = 1
select @art_col = 1
select @spacer = N' '
select @cmd = N'where'

while @this_col <= @src_cols 
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 and iscomputed<>1)
    begin
        select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @pkc' + convert( nvarchar, @art_col ) 
        select @art_col = @art_col + 1
        select @spacer = N' and '

        if len( @cmd ) > 3000
        begin
            insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end
    end
    select @this_col = @this_col + 1
end

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

go

EXEC dbo.sp_MS_marksystemobject sp_scriptpkwhereclause
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Create procedure sp_scriptupdateparams'
go

create procedure sp_scriptupdateparams @src_objid int, @src_cols int, @artcolumns binary(32), @pkcolumns binary(32)
as
declare @this_col int
declare @art_col int
declare @spacer nvarchar(10)
declare @isset int
declare @cmd nvarchar(4000)
declare @typestring nvarchar(255)

-- add colval parameters

select @this_col = 1
select @art_col = 1
select @spacer = N' '
select @cmd = ''

while @this_col <= @src_cols 
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 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','

        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end
   end
   select @this_col = @this_col + 1
end

-- add pkval parameters

select @this_col = 1
select @art_col = 1

while @this_col <= @src_cols 
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 and iscomputed<>1)
   begin
        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','

        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end
   end
   select @this_col = @this_col + 1
end

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

go

EXEC dbo.sp_MS_marksystemobject sp_scriptupdateparams
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_scriptinsproc'
go

create procedure sp_scriptinsproc @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @columns      binary(32)
declare @ins_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @src_cols     int
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(1)

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) NULL)

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @columns = 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


-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd) ) ) 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)

-------- construct parameter list

select @this_col = 1
select @art_col = 1
select @src_cols = count(*) from syscolumns where id = @src_objid
select @spacer = N' '

while @this_col <= @src_cols 
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
   select @this_col = @this_col + 1
end


-- save off cmd fragment

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

insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

select @cmd = N'insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N' values ('
select @this_col = 1
select @art_col = 1
select @spacer = N' '

while @this_col <= @src_cols 
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
    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
    select @this_col = @this_col + 1
end

-- finish up proc body

select @cmd = @cmd + N' )'

-- save off cmd fragement

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

-- send fragements to client

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc
GO

----------------------------------------------------
---------------------------------------------------
print ''
print 'Creating procedure sp_scriptdelproc'
go

create procedure sp_scriptdelproc @artid int
as
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 @src_cols     int
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)

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) 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) ) ) 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)

-------- construct parameter list

select @this_col = 1
select @art_col = 1
select @src_cols = count(*) from syscolumns where id = @src_objid
select @spacer = N' '

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

while @this_col <= @src_cols 
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 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'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   select @this_col = @this_col + 1
end


-- 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, @src_cols, @pkcolumns

-- flush to client

select procedure_text from #proctext order by c1 asc


go

EXEC dbo.sp_MS_marksystemobject sp_scriptdelproc
GO

----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------

print ''
print 'Creating procedure sp_scriptupdproc'
go

create procedure sp_scriptupdproc @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 @pkcolumns    binary(32)
declare @upd_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @src_cols     int
declare @this_col     int
declare @art_col      int
declare @pkart_col    int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)

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) NULL)

-------- get sysarticles information

select @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) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @upd_cmd, 6, len( @upd_cmd ) - 4 )

insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

-------- construct parameter list

select @src_cols = count(*) from syscolumns where id = @src_objid

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

exec dbo.sp_scriptupdateparams @src_objid, @src_cols, @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

if @artcolumns != @pkcolumns
begin
    select @cmd = N'if'

    select @this_col = 1
    select @art_col = 1
    select @pkart_col = 1
    select @spacer = ' '

    while @this_col <= @src_cols
    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
                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
            select @art_col = @art_col + 1
        end
        select @this_col = @this_col + 1
    end

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

    -- construct update if pk hasn't changed

    select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    -- create SET clause

    select @this_col = 1
    select @art_col = 1
    select @spacer = N' '

    while @this_col <= @src_cols
    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
                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
        select @this_col = @this_col + 1
    end

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

    exec dbo.sp_scriptpkwhereclause @src_objid, @src_cols, @pkcolumns

    insert into #proctext(procedure_text) values( N'else' )

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 @this_col = 1
select @art_col = 1
select @spacer = N' '

while @this_col <= @src_cols
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
        select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
        select @art_col = @art_col + 1
        select @spacer = N','

        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end
    end
    select @this_col = @this_col + 1
end

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

exec dbo.sp_scriptpkwhereclause @src_objid, @src_cols, @pkcolumns

-- flush to client

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptupdproc
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_scriptmappedupdproc'
go

create procedure sp_scriptmappedupdproc @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 @pkcolumns    binary(32)
declare @upd_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @src_cols     int
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 @exists_else  bit

select @exists_else	 = 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) )

-------- get sysarticles information

select @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'MCALL', upper(@upd_cmd) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
  

-------- construct parameter list

select @src_cols = count(*) from syscolumns where id = @src_objid

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

exec dbo.sp_scriptupdateparams @src_objid, @src_cols, @artcolumns, @pkcolumns

----- add changed data bitmap

select @this_col = 1
select @art_col = 1

while @this_col <= @src_cols
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
   select @this_col = @this_col + 1
end

-- 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
-- do this only if the article contains columns not included in the pk

if @artcolumns != @pkcolumns
begin
    select @this_col = 1
    select @art_col = 1
    select @spacer = N' '

    select @cmd = N'if'

    while @this_col <= @src_cols
    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
                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
            select @art_col = @art_col + 1
        end
        select @this_col = @this_col + 1
    end

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

end  -- if artcolumns != pkcolumns

-- construct update statement including PK columns

insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )

-- create SET clause consisting of CASE statements

select @this_col = 1
select @art_col = 1
select @spacer = N''

while @this_col <= @src_cols
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 @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 = ',' 

        select @art_col = @art_col + 1
    end
    select @this_col = @this_col + 1
end

-- create where clause

exec dbo.sp_scriptpkwhereclause @src_objid, @src_cols, @pkcolumns


-- 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
begin

    -- create SET clause consisting of CASE statements

    select @this_col = 1
    select @art_col = 1
    select @spacer = N''

    while @this_col <= @src_cols
    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 (@exists_else = 0)
            	begin
            		insert into #proctext(procedure_text) values( N'else' )
			    	insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )
			    	select @exists_else = 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
            select @art_col = @art_col + 1
        end
        select @this_col = @this_col + 1
    end

	if @exists_else=1
		exec dbo.sp_scriptpkwhereclause @src_objid, @src_cols, @pkcolumns
end

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptmappedupdproc
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_fetchshowcmdsinput'
go

create procedure sp_fetchshowcmdsinput @numcmds int
as
create table #rcmds( article_id int NOT NULL, partial_command int NOT NULL, command varbinary(1024) NULL, 
xactid binary(10) NOT NULL, xact_seqno binary(10) NOT NULL, publication_id int NOT NULL, 
command_id int NOT NULL, command_type int NOT NULL, originator_srvname nvarchar(128) NULL, 
originator_db nvarchar(128) NULL)
insert into #rcmds exec dbo.sp_replcmds @numcmds
select convert( varbinary(16), xact_seqno ), 0, 0, article_id, command_type, partial_command, command from #rcmds order by xact_seqno, article_id, command_id asc
drop table #rcmds
go

EXEC dbo.sp_MS_marksystemobject sp_fetchshowcmdsinput
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_replshowcmds'
go

create procedure sp_replshowcmds @maxtrans int = 1
as
declare @query nvarchar(1024)
declare @dbname sysname
select @dbname = db_name()

select @query = 'execute dbo.sp_fetchshowcmdsinput ' + convert( nvarchar, @maxtrans )
execute master..xp_printstatements @query, @dbname
go

EXEC dbo.sp_MS_marksystemobject sp_replshowcmds
GO

print ''
print 'Creating procedure sp_publication_validation'
go

create procedure sp_publication_validation
@publication sysname,
@rowcount_only bit = 1,
@full_or_fast tinyint = 2,  -- full (value 0) does COUNT(*) 
                            -- fast (value 1) uses sysindexes.rows if table (not view); 
                            -- conditional fast (VALUE 2) , first tries fast method, but
                            -- reverts to full if fast method shows differences.
@shutdown_agent bit = 0     -- Set for last article in publication, which will signal subscriber synchronization agent to shutdown
                            -- immediately after successful validation
as

set nocount on

declare @publication_id int
declare @article sysname
declare @article2 sysname
declare @retcode int
declare @publish_bit int

-- Security Check
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)
    
set @publish_bit = 1

-- Check if the database is published for transactional
if not exists (select * from master..sysdatabases where name = db_name() and (category & @publish_bit) = @publish_bit)
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Publication Information
select @publication_id = pubid from syspublications where name = @publication
if @publication_id is null
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

declare hC CURSOR LOCAL FAST_FORWARD for select name from sysarticles where pubid = @publication_id and
(status & 1) <> 0 -- active articles only
open hC
fetch hC into @article
while (@@fetch_status <> -1)
begin
    set @article2 = @article

    -- Look ahead to next article
    fetch hC into @article

    -- If we are at the last article, pass the @shutdown_agent value
    if (@@fetch_status = -1) 
    begin
        exec @retcode = dbo.sp_article_validation @publication, @article2, @rowcount_only = @rowcount_only,
            @full_or_fast = @full_or_fast, @shutdown_agent = @shutdown_agent

    end
    else
        exec @retcode = dbo.sp_article_validation @publication, @article2, @rowcount_only = @rowcount_only,
            @full_or_fast = @full_or_fast
    
    if @retcode <> 0 or @@error <> 0
    begin
        close hC
        deallocate hC
        return 1
    end
end
close hC
deallocate hC
go

EXEC dbo.sp_MS_marksystemobject sp_publication_validation
GO

print ''
print 'Creating procedure sp_article_validation'
go
create procedure sp_article_validation
@publication sysname,
@article sysname,
-- The following are values passed to the sp_table_validation call at the subscriber.
@rowcount_only bit = 1,                     
@full_or_fast tinyint = 2,  -- full (value 0) does COUNT(*) 
                            -- fast (value 1) uses sysindexes.rows if table (not view); 
                            -- conditional fast (VALUE 2) , first tries fast method, but
                            -- reverts to full if fast method shows differences.
@shutdown_agent bit = 0     -- If 1 will raise error 20578, which will signal subscriber synchronization agent to shutdown
                            -- immediately after successful validation
as

declare @publication_guid uniqueidentifier
declare @publication_id int
declare @article_guid uniqueidentifier
declare @article_id int
declare @source_name sysname
declare @destination_table sysname
declare @destination_owner sysname
declare @columns varbinary(32) 
declare @command varchar (4096)
declare @retcode int
declare @actual_rowcount int
declare @actual_checksum numeric
declare @status int
declare @active int
declare @vertical_partition bit
declare @publish_bit int
declare @table_name sysname					-- base table name var to passed to sp_table_validation
    
set nocount on

-- Security Check
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

set @active = 1
set @publish_bit = 1

-- Check if the database is published for transactional
if not exists (select * from master..sysdatabases where name = db_name() and (category & @publish_bit) = @publish_bit)
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Publication Information
select @publication_id = pubid from syspublications where name = @publication
if @publication_id is null
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Article Information
select @article_id = artid, @source_name = OBJECT_NAME(sync_objid),  
    @destination_table = dest_table, @destination_owner = dest_owner, 
	@status = status, @table_name = OBJECT_NAME(objid),
    @columns = columns from sysarticles where name = @article and pubid=@publication_id
if @article_id is null
begin
    raiserror(20027, 16, -1, @article)
    return 1
end

-- Make sure article status is 'active' 
if (@status & @active) <> @active
begin
    -- Article is not active
    raiserror(20523, 16, -1, @article)
    return 1
end

-- Check if table has vertical partition
if exists (select * from sysarticles a, syscolumns b
    where (CONVERT(bit, convert(binary(2), SUBSTRING(convert(nvarchar,a.columns), CONVERT(tinyint, 16 - FLOOR((colid-1)/16)), 1)) & POWER(2, ((colid-1)%16))) = 0
           OR CONVERT(bit, convert(binary(2), SUBSTRING(convert( nvarchar,a.columns), CONVERT(tinyint, 16 - FLOOR((colid-1)/16)), 1)) & POWER(2, ((colid-1)%16))) IS NULL)
           AND a.objid = b.id
           AND a.name = @article
           AND a.pubid = @publication_id)
begin
    set @vertical_partition = 1

    -- partitions only support row count validation, override specified value
    set @rowcount_only = 1
end
else
    set @vertical_partition = 0

begin tran -- The table validation and posting to the log MUST happen with a transaction

-- Get publisher's rowcount and/or checksum for the article
if @rowcount_only = 1
begin
    exec @retcode = dbo.sp_table_validation @table = @source_name, @expected_rowcount = @actual_rowcount OUTPUT,
        @rowcount_only = 1, @full_or_fast = 0, @table_name = @table_name   -- always do full count at publisher
    if @retcode <> 0 or @@error <> 0 
    begin
        commit tran
        return 1
    end
end
else  -- get checksum
begin
    exec @retcode = dbo.sp_table_validation @table = @source_name, @expected_rowcount = @actual_rowcount OUTPUT,
        @expected_checksum = @actual_checksum OUTPUT, @rowcount_only = 0, 
        @full_or_fast = 0, @table_name = @table_name   -- always do full count at publisher
    if @retcode <> 0 or @@error <> 0 
    begin
        commit tran
        return 1
    end
end

-- Post sp_table_validation on behalf of the article and send to subscribers
if @rowcount_only = 1
begin
    select @command = 'exec dbo.sp_table_validation @table = ''' + @destination_table + ''', @expected_rowcount = ' +
        convert(varchar(10), @actual_rowcount) + ', @rowcount_only = 1' +
        ', @full_or_fast = ' + convert(varchar(10), @full_or_fast) +
        ', @shutdown_agent = ' + convert(varchar(10), @shutdown_agent)
end
else
begin
    select @command = 'exec dbo.sp_table_validation @table = ''' + @destination_table + ''', @expected_rowcount = ' +
        convert(varchar(10), @actual_rowcount) + ', @expected_checksum = ' + 
        convert(varchar(100), @actual_checksum) + ', @rowcount_only = 0' + 
        ', @full_or_fast = ' + convert(varchar(10), @full_or_fast) +
        ', @shutdown_agent = ' + convert(varchar(10), @shutdown_agent)
end 

-- Add owner param if destination owner is not NULL
if (@destination_owner IS NOT NULL)
begin
	select @command = @command +
	', @owner = ''' + @destination_owner + ''''
end

-- DEBUG select @command

exec @retcode = dbo.sp_replpostcmd 
    0,              -- partial flag
    @publication_id, 
    @article_id, 
    35,             -- SQL Server Only command type
    @command
if @retcode <> 0 or @@error <> 0
begin
    commit tran
    return 1
end

commit tran

go

EXEC dbo.sp_MS_marksystemobject sp_article_validation
GO

print ''
print 'Creating procedure sp_MSdrop_6x_replication_agent'
go
create procedure sp_MSdrop_6x_replication_agent
@job_id UNIQUEIDENTIFIER,
@category_id int
as
    declare @distbit int
    declare @db_name sysname
    declare @cmd varchar(4000)

    select @distbit = 16

    declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR
        select name from master.dbo.sysdatabases 
            where
            category & @distbit <> 0 
        for read only

    open hCdatabase
    fetch next from hCdatabase into @db_name
    while (@@fetch_status <> -1)
    begin

        if @category_id = 13
        begin
            select @cmd = 'delete from ' + @db_name + '.dbo.MSlogreader_agents where job_id = convert (uniqueidentifier, ''' +
                convert (varchar(100), @job_id) + ''')'
            exec (@cmd)
        end
        else if @category_id = 15   
        begin
            select @cmd = @db_name + '.dbo.sp_MSdrop_6x_publication'
            exec @cmd @job_id = @job_id
        end
        else
            return 0

        if @@ERROR <> 0
            return 1
        
        fetch next from hCdatabase into @db_name
    end
    close hCdatabase
    deallocate hCdatabase
go

EXEC dbo.sp_MS_marksystemobject sp_MSdrop_6x_replication_agent
GO

---------------------------------------------------------------------------
---------------------------------------------------------------------------

grant execute on dbo.sp_enumfullsubscribers to public
go
grant execute on dbo.sp_addpublication to public
go
grant execute on dbo.sp_changepublication to public
go
grant execute on dbo.sp_changesubscription to public
go
grant execute on dbo.sp_articlecolumn to public
go
grant execute on dbo.sp_helparticle to public
go
grant execute on dbo.sp_helparticlecolumns to public
go
grant execute on dbo.sp_helppublication to public
go
grant execute on dbo.sp_publication_validation to public
go
grant execute on dbo.sp_article_validation to public
go
grant execute on dbo.sp_helpsubscription to public
go
grant execute on dbo.sp_articlefilter to public
go
grant execute on dbo.sp_articleview to public
go
grant execute on dbo.sp_addarticle to public
go
grant execute on dbo.sp_changesubstatus to public
go
grant execute on dbo.sp_addsubscription to public
go
grant execute on dbo.sp_changearticle to public
go
grant execute on dbo.sp_droparticle to public
go
grant execute on dbo.sp_droppublication to public
go
grant execute on dbo.sp_dropsubscription to public
go
grant execute on dbo.sp_subscribe to public
go
grant execute on dbo.sp_unsubscribe to public
go
grant execute on dbo.sp_refreshsubscriptions to public
go
grant execute on dbo.sp_reinitsubscription to public
go
-- SyncTran
grant exec on dbo.sp_articlesynctranprocs to public
go
-- custom proc gen.
grant exec on dbo.sp_getarticlepkcolbitmap to public
go
grant exec on dbo.sp_gettypestring to public
go
grant exec on dbo.sp_isarticlecolbitset to public
go
grant exec on dbo.sp_scriptpkwhereclause to public
go
grant exec on dbo.sp_scriptupdateparams to public
go
grant exec on dbo.sp_scriptinsproc to public
go
grant exec on dbo.sp_scriptdelproc to public
go
grant exec on dbo.sp_scriptupdproc to public
go
grant exec on dbo.sp_scriptmappedupdproc to public
go
grant exec on dbo.sp_script_synctran_commands to public
go
grant exec on dbo.sp_MSget_synctran_commands to public
go
grant exec on dbo.sp_MSactivate_auto_sub to public
go
grant execute on dbo.sp_MSscript_insert_statement to public
grant execute on dbo.sp_MSscript_update_statement to public
grant execute on dbo.sp_MSscript_delete_statement to public
grant execute on dbo.sp_MSscript_beginproc  to public
grant execute on dbo.sp_MSscript_security  to public
grant execute on dbo.sp_MSscript_endproc  to public
grant execute on dbo.sp_MSscript_sync_ins_proc  to public
grant execute on dbo.sp_MSscript_sync_upd_proc  to public
grant execute on dbo.sp_MSscript_sync_del_proc  to public
grant execute on dbo.sp_MSmark_proc_norepl to public
go

dump tran master with no_log
go
sp_configure 'allow updates',0
go
reconfigure with override
go

print ''
print 'Checking objects created by repltran.sql.'
go

--obsolete   exec dbo.sp_check_objects 'repl'
-- exec dbo.sp_MS_upd_sysobj_category 2  --set sysobjects.category | 2 based on crdate.
go


print ''
print 'repltran.sql completed successfully.'
go

dump tran master with no_log
go
checkpoint
go
-- - -----
