/*------------------------------------------------------------------------------

sp1_repl.sql
THIS SCRIPT UPDATES REPLICATION SYSTEM STORED PROCEDURES FROM SQL 2000 to SQL 2000  SP1

Changes in this file are organized as follows (please maintain):
	Common system objects (replsys.sql)
	Common repl objects (replcom.sql)
	Tran repl objects (repltran.sql) 
	Merge repl objects (rladmin.sql, rlrecon.sql, rlcore.sql)

Notes:
+ Catalog-updates and sp_MS_upd_sysobj_category are enabled for the entire
	file.  Do not disable or re-enable them.  Please do not change set options.
+ grep for "--.
------------------------------------------------------------------------------*/

--------------------------------------------------------------------------------
-- VERIFY Server is started in single-user-mode (catalog-updates enabled), and
--	start marking of system-objects.
--------------------------------------------------------------------------------
use master
go

dump tran master with no_log
go

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

set ANSI_NULLS off

exec sp_MS_upd_sysobj_category 1
go

--------------------------------------------------------------------------------
--.	Common system objects (replcom.sql)
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
--. sp_MSdrop_replcom
--------------------------------------------------------------------------------
grant exec on xp_mapdown_bitmap to public
go

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

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

create procedure sp_MSdrop_replcom
as
    if exists (select * from sysobjects 
        where type = 'P'
            and name = 'sp_MScreate_distributor_tables')
        drop procedure sp_MScreate_distributor_tables

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

    if exists (select * from sysobjects
            where type = 'P'
                and name = 'sp_helppublicationsync')    /* Remove old version */
        drop procedure sp_helppublicationsync

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if exists (select * from sysobjects
            where type = 'P'
                and name = 'sp_helpdistributor_properties')
        drop procedure sp_helpdistributor_properties
 
    if exists (select * from sysobjects
            where type = 'X'
                and name = 'sp_repldone')
        exec dbo.sp_dropextendedproc 'sp_repldone'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    -- sp_helpsubscriber is removed permanently from the system.
    if exists (select * from sysobjects
        where type = 'P'
                and name = 'sp_helpsubscriber')
        drop procedure sp_helpsubscriber

	-- sp_MSrepl_encrypt obsolete; use xp_repl_encrypt
    if exists (select * from sysobjects
        where type = 'P'
                and name = 'sp_MSrepl_encrypt')
        drop procedure sp_MSrepl_encrypt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	-- Common conflict viewer support procs
    if exists (select * from sysobjects
            where type = 'P'
                and name = 'sp_MShelpconflictpublications')
        drop procedure sp_MShelpconflictpublications

    -- Procs for managing dynamic snapshot views
    if exists (select * from sysobjects
            where type = 'P'
                and name = 'sp_MScleanupdynsnapshotvws')
        drop procedure sp_MScleanupdynsnapshotvws

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

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

    if exists (select * from sysobjects
            where type = 'FN'
                and name = 'fn_replgetagentcommandlinefromjobid')
        drop function system_function_schema.fn_replgetagentcommandlinefromjobid
    
    if exists (select * from sysobjects
            where type = 'P'
                and name = 'sp_replproberemoteserver')
        drop procedure sp_replproberemoteserver

    if exists (select * from sysobjects
            where type = 'FN'
                and name = 'fn_getpersistedservernamecasevariation'
                and user_id('system_function_schema') = uid)
        drop function system_function_schema.fn_getpersistedservernamecasevariation

GO

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

-- This procedure is called to upgrade the MSMQ related entries in 
-- MSdistribution_agents in distribution database - this processing 
-- cannot be done directly inside sp_MScreate_dist_tables or sp_vupgrade_distdb
-- since we need the queue_server column for the processing and we can
-- get a syntax error if the table exists without the column
--
-- Assumption : MSsubscription_agents has been created 
--				and column queue_server exists
--
raiserror('Creating procedure sp_MSupdate_mqserver_distdb', 0,1)
go
create procedure sp_MSupdate_mqserver_distdb
as
begin
	if exists (select * from MSdistribution_agents
		where queue_id IS NOT NULL and queue_id != N'mssqlqueue' and queue_server IS NULL)
	begin
		--
		-- we have entries for active Queued subscriptions using MSMQ that need upgrade
		--
		declare @queue_server sysname

		--
		-- prepare the queue server name
		--
		select @queue_server = @@servername
		if (charindex(N'\', @queue_server) > 0)
			select @queue_server = substring(@queue_server, 1, charindex(N'\', @queue_server) - 1)

		--
		-- update the queue_server column for these entries
		--
		update MSdistribution_agents
		set queue_server = @queue_server
		where queue_id IS NOT NULL and queue_id != N'mssqlqueue' and queue_server IS NULL
	end
end
go


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

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

CREATE PROCEDURE sp_helpreplicationdb
        @dbname sysname = '%', @type sysname = 'pub'
    AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode int, @typebit int

    if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'pub%')
       select @typebit = 1
    else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'sub%')
       select @typebit = 2
    else
    begin
       raiserror(14091,-1,-1)
       return 1
    end

    /*
    ** Parameter Check:  @dbname.
    ** Check to make sure that the database name conforms to the rules
    ** for identifiers.
    */

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

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

    /*
    ** Show databases with this option enabled.
    */

    SELECT name
      FROM master..sysdatabases
     WHERE ((@dbname = N'%') or (name = @dbname collate database_default)) 
       AND (category & @typebit) <> 0
go
 
grant execute on dbo.sp_helpreplicationdb to public
go


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

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

create proc sp_MSUpgradeConflictTable
	@skip_procgen bit = 0 
AS
declare @retcode int
declare @conflict_table sysname
declare @pubid uniqueidentifier 
declare @artid uniqueidentifier 
declare @ins_conflict_proc sysname
declare @conflict_id	int
declare @objid			int
declare @qual_conflict	nvarchar(132)


if exists( select * from sysobjects where name = 'MSmerge_delete_conflicts' ) and 
	not exists (select * from syscolumns where id = object_id('MSmerge_delete_conflicts') and name = 'create_time')
begin
	alter table MSmerge_delete_conflicts add create_time datetime not null default getdate()
end

declare AC CURSOR LOCAL FAST_FORWARD for select conflict_table, objid, ins_conflict_proc, pubid, artid from sysmergearticles 
open AC
fetch AC into @conflict_table, @objid, @ins_conflict_proc, @pubid, @artid
while (@@fetch_status<>-1)
begin
	if @conflict_table is NOT null
	begin
		select @conflict_id = object_id(@conflict_table)
		select @qual_conflict=QUOTENAME(@conflict_table)
		/*
		** Upgrade conflict table so that it can get cleaned up later on
		*/
		if @conflict_id is not NULL and not exists (select name from syscolumns where name='MSrepl_create_time' and id=@conflict_id)
		begin
			exec ('alter table ' + @qual_conflict + ' add MSrepl_create_time datetime not null default getdate() ')
			if @@ERROR<>0
			begin
				close AC
				deallocate AC
				return (1)
			end
			/*
			** use create_time value for the new column before dropping create_time column, after making 
			** sure create_time is not from user table.
			*/
			if exists (select name from syscolumns where name='create_time' and id=@conflict_id) and
				not exists (select name from syscolumns where name='create_time' and id=@objid) 
			begin
				exec ('update ' + @qual_conflict + ' set MSrepl_create_time=create_time')
				if @@ERROR<>0
				begin
					close AC
					deallocate AC
					return (1)
				end
				declare @colid 					int
				declare @default_constraint		sysname
				
				select @colid = colid from syscolumns where name='create_time' and id=@conflict_id
				select @default_constraint=object_name(constid) from sysconstraints where id=@conflict_id and colid=@colid
				/*
				** drop default constrait on create_time column
				*/
				if @default_constraint is not NULL
				begin
					exec ('alter table ' + @qual_conflict + ' drop constraint ' + @default_constraint)
					if @@ERROR<>0
					begin
						close AC
						deallocate AC
						return (1)
					end
				end
				
				exec ('alter table ' + @qual_conflict + ' drop column create_time')
				if @@ERROR<>0
				begin
					close AC
					deallocate AC
					return (1)
				end
			end
			if @ins_conflict_proc is not NULL and object_id(@ins_conflict_proc) is not NULL 
			begin
				exec ('drop procedure ' + @ins_conflict_proc)
				if @@ERROR<>0
		        begin
					close AC
					deallocate AC	        
	    	    	return (1)
	    	    end
				--force to regenerate conflict insert proc to pick up the new column name
				update sysmergearticles set ins_conflict_proc=NULL where artid=@artid and pubid=@pubid
				if @@ERROR<>0
		        begin
					close AC
					deallocate AC	        
	    	    	return (1)
	    	    end

				-- Do not upgrade conflict tables if this is called from sp_restoredbreplication, as 
				-- the entire replication will be striped out.
				if @skip_procgen=0
				begin
					exec @retcode = sp_MSgetconflictinsertproc @artid, @pubid, 0 	
					if @@ERROR<>0 or @retcode<>0
			        begin
						close AC
						deallocate AC	        
		    	    	return (1)
		    	    end
	    	    end
			end
		end

		if not exists (select * from sysindexes where id = @conflict_id and keys is not null)
		begin
			declare @rgcol sysname
			declare @indname sysname
			declare @quotedname sysname
			declare @owner sysname
			
			select @owner=user_name(uid) from sysobjects where id = @objid
			select @rgcol = QUOTENAME(name) from syscolumns where id = @objid and
    	            ColumnProperty(id, name, 'isrowguidcol') = 1
        	select @indname = 'uc_' + @conflict_table
	        set @indname = QUOTENAME(@indname)
    	    set @quotedname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)
        	exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname +
        		' (' + @rgcol + ', origin_datasource)' )
	        if @@ERROR <> 0
	        begin
				close AC
				deallocate AC	        
    	    	return (1)
    	    end
		end
	end
	fetch next from AC into @conflict_table, @objid, @ins_conflict_proc, @pubid, @artid
end
close AC
deallocate AC
return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSUpgradeConflictTable
Go

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

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

CREATE PROCEDURE sp_dropsubscriber (
    @subscriber sysname,        /* The name of the subscriber */
    @reserved nvarchar(50) = NULL,
    @ignore_distributor bit = 0
        ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @db_name sysname
    DECLARE @foundSubscription int
    DECLARE @command nvarchar(255)
    DECLARE @transpublishdb_bit int
    DECLARE @mergepublishdb_bit int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (300)
    DECLARE @retcode int
    DECLARE @type nvarchar(10)

    SELECT @transpublishdb_bit = 1
    SELECT @mergepublishdb_bit = 4


    /*
    ** Parameter Check:  @subscriber.
    ** Check to make sure that the subscriber exists.
    */

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

    EXECUTE @retcode = dbo.sp_validname @subscriber

    IF @retcode <> 0
    RETURN (1)

    IF lower(@subscriber) <> 'all' and NOT EXISTS (SELECT *
                     FROM master..sysservers
                    WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
                      AND srvstatus & 4 <> 0)

        BEGIN
            RAISERROR (14048, 16, -1, @subscriber)
            RETURN (1)
        END

    if lower(@subscriber) = 'all'
    begin
        DECLARE hCdropsubscriber_all CURSOR LOCAL FAST_FORWARD FOR
            SELECT srvname
                     FROM master..sysservers
                    WHERE srvstatus & 4 <> 0
        FOR READ ONLY
        OPEN hCdropsubscriber_all
        FETCH hCdropsubscriber_all INTO @subscriber
    
        WHILE (@@fetch_status <> -1)
        BEGIN
            EXECUTE @retcode  = dbo.sp_dropsubscriber
                @subscriber = @subscriber,    
                @ignore_distributor = @ignore_distributor,
                @reserved = @reserved
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCdropsubscriber_all
                DEALLOCATE hCdropsubscriber_all
                RETURN (1)
            END
            FETCH hCdropsubscriber_all INTO @subscriber
        end
        
        CLOSE hCdropsubscriber_all
        DEALLOCATE hCdropsubscriber_all

        return(0)
    end


    /*
    ** There should be no subscription by the subscriber
    ** Open a cursor the published databases.
    **
    */
    DECLARE hCdropsubscriber CURSOR LOCAL FAST_FORWARD FOR
            SELECT name, N'tran' FROM master..sysdatabases      
                WHERE (category & @transpublishdb_bit) <> 0 
        UNION
            select name, N'merge' from master..sysdatabases      
                WHERE (category & @mergepublishdb_bit) <> 0 
    FOR READ ONLY

    OPEN hCdropsubscriber
    FETCH hCdropsubscriber INTO @db_name, @type
    
    WHILE (@@fetch_status <> -1)
    BEGIN        
		IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = 'drop_subscriptions'
        BEGIN
            if @type = 'tran'
            begin
                SELECT @command = quotename(@db_name) + '.dbo.sp_dropsubscription'
                EXECUTE @retcode  = @command 
                    @publication = 'all', 
                    @article = 'all', 
                    @subscriber = @subscriber,
                    @ignore_distributor = @ignore_distributor
            end
            if @type = 'merge'
            begin
                SELECT @command = quotename(@db_name) + '.dbo.sp_dropmergesubscription'
                EXECUTE @retcode  = @command 
                    @publication = 'all', 
                    @subscriber = @subscriber,
                    @subscription_type = 'both',
                    @ignore_distributor = @ignore_distributor
            end
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCdropsubscriber
                DEALLOCATE hCdropsubscriber
                RETURN (1)
            END
        END
        
		-- Set @foundSubscription to not null so that sp_helpsubscription will not display
		-- result set
		select @foundSubscription = 0

        if @type = 'tran'
        begin
            SELECT @command = quotename(@db_name) + '.dbo.sp_helpsubscription'
            EXECUTE @retcode  = @command @publication = '%', @article = '%', 
                @subscriber = @subscriber,
                @found = @foundSubscription  OUTPUT

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCdropsubscriber
                DEALLOCATE hCdropsubscriber
                RETURN (1)
            END
        end
        else
        begin
            SELECT @command = quotename(@db_name) + '.dbo.sp_helpmergesubscription'
            EXECUTE @retcode  = @command @publication = '%', 
                @subscriber = @subscriber,
                @subscription_type = 'both',
                @found = @foundSubscription  OUTPUT

            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCdropsubscriber
                DEALLOCATE hCdropsubscriber
                RETURN (1)
            END
        end


        IF @foundSubscription <> 0
        BEGIN
            CLOSE hCdropsubscriber
            DEALLOCATE hCdropsubscriber
            RAISERROR ( 14144,  16, -1, @subscriber, @db_name)
            RETURN (1)
        END

        FETCH hCdropsubscriber INTO @db_name, @type

    END
    
    CLOSE hCdropsubscriber
    DEALLOCATE hCdropsubscriber

    /*
    ** Drop the subsubscriber_info in the distribution database
    */
    /*
    ** 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
        ** 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
        
        /*
        ** Insert information into MSsubscriber_info in the distribution db
        */
        if @distribdb is not null
        begin
            SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_subscriber_info'
            EXEC @retcode = @distproc
                 @publisher = @@SERVERNAME,
                 @subscriber = @subscriber

            IF @@error <> 0 OR @retcode <> 0
                BEGIN
                RAISERROR (14042, 16, -1)
                RETURN (1)
            END
        end
    end

    -- We have already validated the existence of the server at this point
    SELECT @subscriber = fn_getpersistedservernamecasevariation(@subscriber) collate database_default

    /*
    ** Turn off the subscriber server option.
    */
    EXECUTE @retcode = dbo.sp_serveroption @subscriber, 'sub', false
    IF @@ERROR <> 0 OR @retcode <> 0
    BEGIN
       RAISERROR (14047, 16, -1, @subscriber)
       RETURN (1)
    END

    RAISERROR (14062, 10, -1)
go


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

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

CREATE PROCEDURE sp_MScreate_dist_tables
AS

   /*
   ** Important:  
   ** We use varbinary(16) for xact_id and xact_seqno, we don't want ending nulls
   ** to be truncated by the server
   **
   ** Also, in MSrepl_commands, we don't want ending space to be truncated.  
   */
   SET ANSI_PADDING ON

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_version' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSrepl_version', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSrepl_version
      (
      major_version int NOT NULL,
      minor_version int NOT NULL,
      revision int NOT NULL,
      db_existed bit NULL
      )
	  CREATE UNIQUE CLUSTERED INDEX ucMSrepl_version ON dbo.MSrepl_version
					(major_version, minor_version, revision)
    
      EXEC dbo.sp_MS_marksystemobject 'MSrepl_version'
      
      INSERT INTO MSrepl_version VALUES (7,0,0,0)
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSpublisher_databases' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSpublisher_databases', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSpublisher_databases(
        publisher_id smallint NOT NULL,
        publisher_db sysname NULL,
        id int identity NOT NULL,                   
    )
      EXEC dbo.sp_MS_marksystemobject 'MSpublisher_databases'

      raiserror('Creating clustered index ucMSpublisher_databases', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSpublisher_databases ON dbo.MSpublisher_databases
     (publisher_id, publisher_db, id)
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSpublications' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSpublications', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSpublications (
        publisher_id smallint NOT NULL,
        publisher_db sysname NULL,
        publication sysname NOT NULL,
        publication_id int identity NOT NULL,   -- This id IS NOT the same as the SQL Server publisher's
        publication_type int NOT NULL,          -- 0 = Snapshot 1 = Transactional
        thirdparty_flag bit NOT NULL,           -- 0 = SQL Server 1 = Third Party
        independent_agent bit NOT NULL,
        immediate_sync bit NOT NULL,
        allow_push bit NOT NULL,
        allow_pull bit NOT NULL,
        allow_anonymous bit NOT NULL,
        description nvarchar(255) NULL,
        vendor_name nvarchar(100) NULL,
        retention	int NULL,
		sync_method int default 0 NOT NULL,
		allow_subscription_copy bit default 0 not null,
		thirdparty_options int null,
		allow_queued_tran bit default 0	not null
		)
      EXEC dbo.sp_MS_marksystemobject 'MSpublications'

	 -- publication_id needs to be the first columns in the index. It
	 -- is used in sp_MSmaximum_cleanup_seqno.
      raiserror('Creating clustered index ucMSpublications', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSpublications ON dbo.MSpublications
     (publication_id,  publication, publisher_db, publisher_id)

   END
   ELSE
   BEGIN
      IF NOT EXISTS (select * from syscolumns
        where name = 'sync_method'
        and id=object_id('MSpublications'))
      BEGIN
         ALTER TABLE MSpublications ADD sync_method int default 0 not null
      END

      IF NOT EXISTS (select * from syscolumns
        where name = 'allow_subscription_copy'
        and id=object_id('MSpublications'))
      BEGIN
         ALTER TABLE MSpublications ADD allow_subscription_copy bit default 0 not null
      END
      IF NOT EXISTS (select * from syscolumns
        where name = 'thirdparty_options'
        and id=object_id('MSpublications'))
      BEGIN
         ALTER TABLE MSpublications ADD thirdparty_options int null
      END

      IF NOT EXISTS (select * from syscolumns
        where name = 'allow_queued_tran'
        and id=object_id('MSpublications'))
      BEGIN
         ALTER TABLE MSpublications ADD allow_queued_tran bit default 0	not null
      END
   END


   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSarticles' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSarticles', 0,1)
      /****************************************************************************/
    CREATE TABLE dbo.MSarticles (
        publisher_id smallint NOT NULL,
        publisher_db sysname NULL,
        publication_id int NOT NULL,
        article sysname NOT NULL,
        article_id int NOT NULL,                            -- This id is the same as a SQL Server Publisher's
        destination_object sysname NULL,
        source_owner    sysname NULL,
        source_object sysname NULL,
        description nvarchar(255) NULL
    )   

      EXEC dbo.sp_MS_marksystemobject 'MSarticles'

      raiserror('Creating clustered index ucMSarticles', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSarticles ON dbo.MSarticles
     (publisher_db, publisher_id, article_id, article, publication_id)
   END

	IF NOT EXISTS( SELECT * FROM sysobjects WHERE name = 'MSsync_states' )
	BEGIN
		CREATE TABLE dbo.MSsync_states
		(
			publisher_id smallint not null,
			publisher_db sysname not null,
			publication_id int not null 
		)
		EXEC dbo.sp_MS_marksystemobject 'MSsync_states'

		CREATE UNIQUE CLUSTERED INDEX ucMSsyncstates on dbo.MSsync_states
		( publisher_id, publisher_db, publication_id )
	END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSsubscriptions' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSsubscriptions', 0,1)
      /****************************************************************************/
       CREATE TABLE dbo.MSsubscriptions
      (
        publisher_database_id int NOT NULL,         -- Used to reference MSrepl_transactions and MSrepl_commands
        publisher_id smallint NOT NULL,
        publisher_db sysname NOT NULL,
        publication_id int NOT NULL,
        article_id int NOT NULL,
        subscriber_id smallint NOT NULL,
        subscriber_db sysname NOT NULL,
        subscription_type int NOT NULL,         -- 0 = push, 1 = pull, 2 = anonymous 
        sync_type tinyint NOT NULL,                 -- 1 = automatic 2 = no sync
        status tinyint NOT NULL,                        -- 0 = inactive, 1 = subscribed, 2 = active 
        subscription_seqno varbinary(16) NOT NULL,  -- publisher's database sequence number 
        snapshot_seqno_flag bit NOT NULL,               -- 1 if subscription_seqno is the snapshot seqno
        independent_agent bit NOT NULL,             -- Value carried over from MSpublications
        subscription_time datetime NOT NULL, 
        loopback_detection bit NOT NULL,  
        agent_id int NOT NULL,
        update_mode tinyint NOT NULL,				-- 0 = read only, 1 = sync tran, 2 = queued tran, 
													-- 3 = failover, 4 = sqlqueued tran, 5 = sqlqueued failover
        publisher_seqno varbinary(16) NOT NULL,
		ss_cplt_seqno   varbinary(16) NOT NULL
      )

      EXEC dbo.sp_MS_marksystemobject 'MSsubscriptions'

      raiserror('Creating clustered index ucMSsubscirptions', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSsubscriptions ON dbo.MSsubscriptions
      (agent_id, article_id)

	  -- Index used by sp_MSdelete_publisherdb_trans
      raiserror('Creating index iMSsubscriptions', 0,1)
      CREATE INDEX iMSsubscriptions ON dbo.MSsubscriptions
      (publisher_database_id, article_id, subscriber_id, subscriber_db, publication_id, publisher_db, publisher_id)
    END
    ELSE
    BEGIN
		if not exists ( select * from syscolumns 
						where id = object_id( N'MSsubscriptions' ) 
						and name = N'ss_cplt_seqno' )
		begin				
			exec ('alter table MSsubscriptions add ss_cplt_seqno varbinary(16) NULL')
			exec ('update MSsubscriptions set ss_cplt_seqno = publisher_seqno')
			exec ('alter table MSsubscriptions alter column ss_cplt_seqno varbinary(16) NOT NULL')
		end
    END

   -- For beta 3 upgrade, we need to create new index here.
   if not exists (select * from sysindexes where name = 'iMSsubscriptions2')
   begin
	  -- Index used by sp_MSdelete_publisherdb_trans
      raiserror('Creating index iMSsubscriptions2', 0,1)
      CREATE INDEX iMSsubscriptions2 ON dbo.MSsubscriptions
      (publisher_database_id, subscription_seqno)
   end

   
   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSmerge_subscriptions' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSmerge_subscriptions', 0,1)
      /****************************************************************************/
       CREATE TABLE dbo.MSmerge_subscriptions
      (
        publisher_id smallint NOT NULL,
        publisher_db sysname NULL,
        publication_id int NOT NULL,
        subscriber_id smallint NOT NULL,
        subscriber_db sysname NULL,
        subscription_type int NULL,         -- 0 = push, 1 = pull, 2 = anonymous 
        sync_type tinyint NOT NULL,                 -- 1 = automatic 2 = no sync
        status tinyint NOT NULL,                        -- 0 = inactive, 1 = subscribed, 2 = active 
        subscription_time datetime NOT NULL
      )

      EXEC dbo.sp_MS_marksystemobject 'MSmerge_subscriptions'

      raiserror('Creating clustered index ucMSmerge_subscriptions', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSmerge_subscriptions ON dbo.MSmerge_subscriptions
     (publisher_id, publisher_db, publication_id, subscriber_id, subscriber_db)
   END


   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_transactions' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSrepl_transactions', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSrepl_transactions
      (
      publisher_database_id int NOT NULL,
      xact_id varbinary(16) NULL,
      xact_seqno varbinary (16 )  NOT NULL,
      entry_time datetime  NOT NULL
      )

      EXEC dbo.sp_MS_marksystemobject 'MSrepl_transactions'

      raiserror('Creating clustered index usMSrepl_transactions', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSrepl_transactions ON dbo.MSrepl_transactions
         (publisher_database_id, xact_seqno)
         WITH STATISTICS_NORECOMPUTE

      CREATE STATISTICS stat_publisher_database_id
         ON MSrepl_transactions (publisher_database_id)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_xact_id
         ON MSrepl_transactions (xact_id)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_xact_seqno
         ON MSrepl_transactions (xact_seqno)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_entry_time
         ON MSrepl_transactions (entry_time)
         WITH NORECOMPUTE

   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_commands' and type = 'U')
   BEGIN

      /****************************************************************************/
      raiserror('Creating table MSrepl_commands', 0,1)
      /****************************************************************************/


      CREATE TABLE dbo.MSrepl_commands (
      publisher_database_id int not null,
      xact_seqno varbinary(16) not null,
      type int not null, 
      article_id int not null,
      originator_id int not null,
      command_id int not null,
      partial_command bit not null,
      command varbinary(1024) NULL
      )


      EXEC dbo.sp_MS_marksystemobject 'MSrepl_commands'

      raiserror('Creating clusterd index ucMSrepl_commands', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSrepl_commands ON dbo.MSrepl_commands
         (publisher_database_id, xact_seqno, command_id)
         WITH STATISTICS_NORECOMPUTE

      CREATE STATISTICS stat_xact_seqno
         ON MSrepl_commands (xact_seqno)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_type
         ON MSrepl_commands (type)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_article_id
         ON MSrepl_commands (article_id)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_originator_id
         ON MSrepl_commands (originator_id)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_command_id
         ON MSrepl_commands (command_id)
         WITH NORECOMPUTE

      CREATE STATISTICS stat_partial_command
         ON MSrepl_commands (partial_command)
         WITH NORECOMPUTE

   END


   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_originators' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSrepl_orginators', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSrepl_originators
      (
      id int identity not null,
      publisher_database_id int not null,
      srvname   sysname not null,
      dbname    sysname not null
      )

      EXEC dbo.sp_MS_marksystemobject 'MSrepl_originators'

      raiserror('Creating clustered index usMSrepl_originators', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSrepl_originators ON dbo.MSrepl_originators
         (publisher_database_id, srvname, dbname)
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSsubscriber_info' and type = 'U')
   BEGIN
      /****************************************************************************/
      raiserror('Creating table MSsubscriber_info', 0,1)
      /****************************************************************************/
      CREATE TABLE dbo.MSsubscriber_info
      (
      publisher  sysname NOT NULL,
      subscriber  sysname NOT NULL,
      type tinyint NOT NULL,           /* 0: MS SQL Server 1: ODBC Data Source */
      login sysname NULL,
      password nvarchar(524) NULL,
      description nvarchar(255) NULL,
      security_mode int NOT NULL
      )

      EXEC dbo.sp_MS_marksystemobject 'MSsubscriber_info'

      raiserror('Creating clustered index ucMSsubscriber_info', 0,1)
      CREATE UNIQUE CLUSTERED INDEX ucMSsubscriber_info ON dbo.MSsubscriber_info
     (publisher, subscriber)
   END
   ELSE
   BEGIN
      IF NOT EXISTS (select * from syscolumns
        where name = 'description'
        and id=object_id('MSsubscriber_info'))
      BEGIN
         
         ALTER TABLE MSsubscriber_info ADD description nvarchar (255) NULL
         UPDATE MSsubscriber_info SET description = 'SQL Server 6.0'
      END
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSsubscriber_schedule' and type = 'U')
   BEGIN
         raiserror('Creating table MSsubscriber_schedule', 0,1)
         
        CREATE TABLE dbo.MSsubscriber_schedule
        (
            publisher  sysname NOT NULL,
            subscriber  sysname NOT NULL,
            agent_type      smallint NOT NULL,   -- 0 for distribution agent, 1 for merge agent
            frequency_type int NOT NULL,
            frequency_interval int NOT NULL,
            frequency_relative_interval int NOT NULL,
            frequency_recurrence_factor int NOT NULL,
            frequency_subday int NOT NULL,
            frequency_subday_interval int NOT NULL,
            active_start_time_of_day int NOT NULL,
            active_end_time_of_day int NOT NULL,
            active_start_date int NOT NULL,
            active_end_date int NOT NULL
        )
      EXEC dbo.sp_MS_marksystemobject 'MSsubscriber_schedule'

        CREATE UNIQUE CLUSTERED INDEX ucMSsubscriber_schedule ON dbo.MSsubscriber_schedule
     (publisher, subscriber, agent_type)
     
    END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSsnapshot_history' and type = 'U')
   BEGIN
        /****************************************************************************/
         raiserror('Creating table MSsnapshot_history', 0,1)
        /****************************************************************************/
        CREATE TABLE dbo.MSsnapshot_history 
        (
        agent_id int NOT NULL,
        runstatus int NOT NULL,
        start_time datetime NOT NULL,        
        time datetime NOT NULL,    
        duration int NOT NULL,            
        comments nvarchar(255) NOT NULL,

        -- Session summary statistics
        delivered_transactions int NOT NULL,
        delivered_commands int NOT NULL,
        delivery_rate float NOT NULL,

        error_id int NOT NULL,
        timestamp NOT NULL
    )

      EXEC dbo.sp_MS_marksystemobject 'MSsnapshot_history'

     raiserror('Creating clustered index ucMSsnapshot_history', 0,1)
    CREATE UNIQUE CLUSTERED INDEX ucMSsnapshot_history ON dbo.MSsnapshot_history
        (agent_id, timestamp, start_time, time)

	if not exists (select * from sysindexes where name = 'nc1MSsnapshot_history')
	begin
		 raiserror('Creating clustered index nc1MSsnapshot_history', 0,1)
		create nonclustered index nc1MSsnapshot_history on MSsnapshot_history(agent_id, start_time) 
	end	

   END
       
   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSlogreader_history' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSlogreader_history', 0,1)
        /****************************************************************************/    
        CREATE TABLE dbo.MSlogreader_history
        (
        agent_id int NOT NULL,
        runstatus int NOT NULL,
        start_time datetime NOT NULL,
        time datetime NOT NULL,
        duration int NOT NULL,
        comments nvarchar(255) NOT NULL,
        xact_seqno varbinary(16) NULL,

        -- Session summary statistics
        delivery_time int NOT NULL,
        delivered_transactions int NOT NULL,
        delivered_commands int NOT NULL,
        average_commands int NOT NULL,
        delivery_rate float NOT NULL,
        delivery_latency int NOT NULL,

        error_id int NOT NULL,
        timestamp NOT NULL
        )

      EXEC dbo.sp_MS_marksystemobject 'MSlogreader_history'

    raiserror('Creating clustered index ucMSlogreader_history', 0,1)
    CREATE UNIQUE CLUSTERED INDEX ucMSlogreader_history ON dbo.MSlogreader_history
        (agent_id, timestamp, runstatus, start_time, time) 

	if not exists (select * from sysindexes where name = 'nc1MSlogreader_history')
	begin
	    raiserror('Creating nonclustered index nc1MSlogreader_history', 0,1)
		create nonclustered index nc1MSlogreader_history on MSlogreader_history(agent_id, start_time) 
	end	

   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSdistribution_history' and type = 'U')
   BEGIN
        /****************************************************************************/
          raiserror('Creating table MSdistribution_history', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSdistribution_history
        (
        agent_id int NOT NULL,
        runstatus int NOT NULL,
        start_time datetime NOT NULL,
        time datetime NOT NULL,
        duration int NOT NULL,
        comments nvarchar(255) NOT NULL,
        xact_seqno varbinary(16) NULL,

        -- Current statistics
        current_delivery_rate float NOT NULL,
        current_delivery_latency int NOT NULL,

        -- Session summary statistics
        delivered_transactions int NOT NULL,
        delivered_commands int NOT NULL,
        average_commands int NOT NULL,
        delivery_rate float NOT NULL,       
        delivery_latency int NOT NULL, 

        -- Summary statistics across all sessions
        total_delivered_commands int NOT NULL, 

        error_id int NOT NULL,
        updateable_row bit NOT NULL,
        timestamp NOT NULL
        )

    EXEC dbo.sp_MS_marksystemobject 'MSdistribution_history'

    raiserror('Creating clustered index ucMSdistribution_history', 0,1)
    CREATE UNIQUE CLUSTERED INDEX ucMSdistribution_history ON dbo.MSdistribution_history
        (agent_id, timestamp, runstatus, start_time, time) 


	if not exists (select * from sysindexes where name = 'nc1MSdistribution_history')
	begin
	    raiserror('Creating clustered index nc1MSdistribution_history', 0,1)
		create nonclustered index nc1MSdistribution_history on MSdistribution_history(agent_id, start_time) 
	end	

   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSmerge_history' and type = 'U')
   BEGIN
        /****************************************************************************/
      raiserror('Creating table MSmerge_history', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSmerge_history
        (
        agent_id                    int             NOT NULL,
        runstatus               int             NOT NULL,
        start_time              datetime        NOT NULL,
        time                    datetime        NOT NULL,
        duration                int             NOT NULL,
        comments                nvarchar(255)   NOT NULL,
        delivery_time               int         NOT NULL,
        delivery_rate               float       NOT NULL,
        publisher_insertcount       int         NULL,
        publisher_updatecount       int         NULL,
        publisher_deletecount       int         NULL,
        publisher_conflictcount     int         NULL,
        subscriber_insertcount      int         NULL,
        subscriber_updatecount      int         NULL,
        subscriber_deletecount      int         NULL,
        subscriber_conflictcount    int         NULL,
        error_id                    int         NOT NULL,
        timestamp                               NOT NULL,
		updateable_row				bit			NOT NULL
        )        

    EXEC dbo.sp_MS_marksystemobject 'MSmerge_history'

    raiserror('Creating clustered index ucMSmerge_history', 0,1)
    CREATE UNIQUE CLUSTERED INDEX ucMSmerge_history ON dbo.MSmerge_history
        (agent_id, timestamp, runstatus) 
        
	if not exists (select * from sysindexes where name = 'nc1MSmerge_history')
		begin
			raiserror('Creating nonclustered index nc1MSmerge_history', 0,1)
			create nonclustered index nc1MSmerge_history on MSmerge_history(agent_id, runstatus, start_time) 
		end
   END
   ELSE
   BEGIN
      IF NOT EXISTS (select * from syscolumns
        where name = 'updateable_row'
        and id=object_id('MSmerge_history'))
      BEGIN 
         ALTER TABLE MSmerge_history ADD updateable_row bit default 1 NOT NULL
      END

	  if not exists (select * from sysindexes where name = 'nc1MSmerge_history' and id=object_id('MSmerge_history'))
	  begin
			raiserror('Creating nonclustered index nc1MSmerge_history', 0,1)
			create nonclustered index nc1MSmerge_history on MSmerge_history(agent_id, runstatus, start_time) 
	  end	
   END


   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_errors' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSrepl_errors', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSrepl_errors
        (
        id                  int NOT NULL,
        time                datetime NOT NULL,
        error_type_id       int NULL,
        source_type_id      int NULL,
        source_name         nvarchar(100) NULL,
        error_code          sysname NULL,
        error_text          ntext NULL,
		xact_seqno			varbinary(16) NULL,
		command_id			int NULL
        )

      EXEC dbo.sp_MS_marksystemobject 'MSrepl_errors'

    raiserror('Creating clustered index ucMSrepl_errors', 0,1)
    CREATE CLUSTERED INDEX ucMSrepl_errors ON dbo.MSrepl_errors
        (id, time) -- WITH ALLOW_DUP_ROW
   END
   ELSE
   BEGIN
      IF NOT EXISTS (select * from syscolumns
        where name = 'xact_seqno'
        and id=object_id('MSrepl_errors'))
         ALTER TABLE MSrepl_errors ADD xact_seqno varbinary(16) NULL

      IF NOT EXISTS (select * from syscolumns
        where name = 'command_id'
        and id=object_id('MSrepl_errors'))
         ALTER TABLE MSrepl_errors ADD command_id int NULL
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSsnapshot_agents' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSsnapshot_agents', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSsnapshot_agents
        (
        id                  int IDENTITY NOT NULL,
        name                nvarchar(100) NOT NULL,
        publisher_id        smallint NOT NULL,
        publisher_db        sysname NOT NULL,
        publication         sysname NOT NULL,
        publication_type    int NOT NULL,       -- 0 transactional 1 snapshot 2 merge
        local_job           bit NOT NULL,
        job_id              binary(16) NULL,
        profile_id  int     NOT NULL
        )

      EXEC dbo.sp_MS_marksystemobject 'MSsnapshot_agents'

    raiserror('Creating clustered index ucMSsnapshot_agents', 0,1)
    CREATE CLUSTERED INDEX ucMSsnapshot_agents ON dbo.MSsnapshot_agents
        (publication, publisher_db, publisher_id) 

    raiserror('Creatingindex iMSsnapshot_agents', 0,1)
    CREATE UNIQUE INDEX iMSsnapshot_agents ON dbo.MSsnapshot_agents
        (id)
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSlogreader_agents' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSlogreader_agents', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSlogreader_agents
        (
        id                  int IDENTITY NOT NULL,
        name                nvarchar(100) NOT NULL,
        publisher_id        smallint NOT NULL,
        publisher_db        sysname NOT NULL,
        publication         sysname NOT NULL,-- Not used for SQL Server publisher
        local_job           bit NOT NULL,
        job_id              binary(16) NULL,
        profile_id  int     NOT NULL
        )

      EXEC dbo.sp_MS_marksystemobject 'MSlogreader_agents'

    raiserror('Creating clustered index ucMSlogreader_agents', 0,1)
    CREATE CLUSTERED INDEX ucMSlogreader_agents ON dbo.MSlogreader_agents
        (publisher_db, publisher_id) 

    raiserror('Creatingindex iMSlogreader_agents', 0,1)
    CREATE UNIQUE INDEX iMSlogreader_agents ON dbo.MSlogreader_agents
        (id)
   END

   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSdistribution_agents' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSdistribution_agents', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSdistribution_agents
        (
		id                  int IDENTITY NOT NULL,
		name                nvarchar(100) NOT NULL,
		publisher_database_id int NOT NULL,
		publisher_id        smallint NOT NULL,
		publisher_db        sysname NOT NULL,
		publication         sysname NOT NULL,
		subscriber_id       smallint NULL, 
		subscriber_db       sysname NULL,
		subscription_type   int NOT NULL,
		local_job           bit NULL,
		job_id              binary(16) NULL,
		subscription_guid   binary(16) NOT NULL,
		profile_id  int     NOT NULL,
		anonymous_subid     uniqueidentifier NULL,
		subscriber_name     sysname NULL,
		virtual_agent_id    int NULL,
		anonymous_agent_id  int NULL,
		creation_date		datetime default (getdate()) not NULL,
		queue_id			sysname null,
        queue_status        int default 0 not null,
        offload_enabled     bit default 0 NOT NULL,
        offload_server      sysname NULL,
		dts_package_name	sysname NULL,
		dts_package_password nvarchar(524) NULL,
		dts_package_location int default 0 not null,
		sid					varbinary(85) default suser_sid() not null,
		queue_server		sysname NULL
        )

        EXEC dbo.sp_MS_marksystemobject 'MSdistribution_agents'

        raiserror('Creating clustered index ucMSdistribution_agents', 0,1)
        CREATE UNIQUE CLUSTERED INDEX ucMSdistribution_agents ON dbo.MSdistribution_agents
            (id)

        raiserror('Creatingindex iMSdistribution_agents', 0,1)
        CREATE INDEX iMSdistribution_agents ON dbo.MSdistribution_agents
            (publication, publisher_db, publisher_id, subscriber_id, subscriber_db, anonymous_subid) 
   END

	if not exists (select * from syscolumns where 
		id = object_id('MSdistribution_agents') and
		name = 'creation_date')
	begin
		alter table MSdistribution_agents add creation_date datetime default (getdate()) not null
	end 

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

	if not exists (select * from syscolumns where 
		id = object_id('MSdistribution_agents') and
		name = 'offload_server')
	begin
		alter table MSdistribution_agents add offload_server sysname null
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSdistribution_agents') and
		name = 'queue_id')
	begin
		alter table MSdistribution_agents add queue_id sysname null
	end 

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

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

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

	if not exists (select * from syscolumns where 
		id = object_id('MSdistribution_agents') and
		name = 'sid')
	begin
		-- set sid to be the upgrade user. db_owner or sysadmin
		-- can drop the agent entry
		alter table MSdistribution_agents add sid varbinary(85) default suser_sid() not null
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSdistribution_agents') and
		name = 'queue_server')
	begin
		alter table MSdistribution_agents add queue_server sysname null
		EXEC dbo.sp_MSupdate_mqserver_distdb
	end 
	
   IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSmerge_agents' and type = 'U')
   BEGIN
        /****************************************************************************/
        raiserror('Creating table MSmerge_agents', 0,1)
        /****************************************************************************/    

        CREATE TABLE dbo.MSmerge_agents
        (
		id                  int IDENTITY NOT NULL,
		name                nvarchar(100) NOT NULL,
		publisher_id        smallint NOT NULL,
		publisher_db        sysname NOT NULL,
		publication         sysname NOT NULL,
		subscriber_id       smallint NULL,
		subscriber_db       sysname NULL,
		local_job           bit NULL,
		job_id              binary(16) NULL,
		profile_id          int NULL,
		anonymous_subid     uniqueidentifier NULL,
		subscriber_name     sysname NULL,
		creation_date		datetime default (getdate()) not NULL,
        offload_enabled     bit default 0 NOT NULL,
        offload_server      sysname NULL,
		sid					varbinary(85) default suser_sid() not null
        )

      EXEC dbo.sp_MS_marksystemobject 'MSmerge_agents'

    raiserror('Creating clustered index ucMSmerge_agents', 0,1)
    CREATE CLUSTERED INDEX ucMSmerge_agents ON dbo.MSmerge_agents
        (publication, publisher_db, publisher_id, subscriber_id, subscriber_db, anonymous_subid) 
    
    raiserror('Creatingindex iMSmerge_agents', 0,1)
    CREATE UNIQUE INDEX iMSmerge_agents ON dbo.MSmerge_agents
        (id)
	END


	-- Need to re_visit the indexing of this table
	if not exists (select * from sysobjects where name = 'MSrepl_identity_range')
		begin		
			raiserror('Creating table MSrepl_identity_range',0,1)
			
			create table dbo.MSrepl_identity_range (
			publisher				sysname not NULL, 
			publisher_db			sysname	not NULL,
			tablename				sysname not NULL,
			identity_support		int NULL,
			next_seed				bigint NULL, --resource control
			pub_range				bigint NULL, --publisher range
			range					bigint NULL, -- set by sp_addmergearticle
			max_identity			bigint NULL, --resource control
			threshold				int	NULL,	--in percentage, set by sp_addmergearticle
			current_max				bigint NULL	--max value for current check constraint,set by sp_addmergearticle
			)
			exec dbo.sp_MS_marksystemobject MSrepl_identity_range

			grant select on MSrepl_identity_range to public
		end

	if not exists (select * from syscolumns where 
		id = object_id('MSmerge_agents') and
		name = 'creation_date')
	begin
		alter table MSmerge_agents add creation_date datetime default (getdate()) not null
	end 

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

	if not exists (select * from syscolumns where 
		id = object_id('MSmerge_agents') and
		name = 'offload_server')
	begin
		alter table MSmerge_agents add offload_server sysname null
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSmerge_agents') and
		name = 'sid')
	begin
		-- set sid to be the upgrade user. db_owner or sysadmin
		-- can drop the agent entry
		alter table MSmerge_agents add sid varbinary(85) default suser_sid() not null
	end 

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSpublication_access' and type = 'U')
	BEGIN
		/****************************************************************************/
		raiserror('Creating table MSpublication_access', 0,1)
		/****************************************************************************/    

		CREATE TABLE dbo.MSpublication_access
		(
		publication_id      int NULL,       -- Publication_id is unique in distribution database.
		login               sysname NOT NULL
											-- Logins in the publication access list, they nust
											-- exist at both publisher and distributor side.            
		)

		EXEC dbo.sp_MS_marksystemobject 'MSpublication_access'

		raiserror('Creating clustered index ucMSpublication_access', 0,1)
		CREATE UNIQUE CLUSTERED INDEX ucMSpublication_access ON dbo.MSpublication_access
			(publication_id, login) 
	END

	-- For b3 upgrade
	if NOT EXISTS (select * from syscolumns where name='retention' and id=object_id('MSpublications'))
	begin
		alter table MSpublications add retention int NULL 
		UPDATE msdb..MSdistributiondbs set max_distretention=72 where
			name = db_name() collate database_default
	end

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

	-- Drop publisher_id column
	if EXISTS (select * from syscolumns where name='publisher_id' and id=object_id('MSpublication_access'))
	begin
		drop index MSpublication_access.ucMSpublication_access

		alter table MSpublication_access drop column publisher_id

		raiserror('Creating clustered index ucMSpublication_access', 0,1)
		CREATE CLUSTERED INDEX ucMSpublication_access ON dbo.MSpublication_access
		(publication_id, login) 
	end

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSqreader_agents' and type = 'U')
	BEGIN
		/****************************************************************************/
		raiserror('Creating table MSqreader_agents', 0,1)
		/****************************************************************************/    

		CREATE TABLE dbo.MSqreader_agents
		(
		id                  int IDENTITY NOT NULL,
		name                nvarchar(100) NULL,
		job_id              binary(16) NULL,
		profile_id  		int NULL
		)

      EXEC dbo.sp_MS_marksystemobject 'MSqreader_agents'

    raiserror('Creating unique index ucMSqreader_agents', 0,1)
    CREATE UNIQUE INDEX ucMSqreader_agents ON dbo.MSqreader_agents
        (id)
   END

	-- add columns for existing table
	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_agents') and
		name = 'profile_id')
	begin
		alter table dbo.MSqreader_agents add profile_id int NULL
	end 
   

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSqreader_history' and type = 'U')
	BEGIN
	/****************************************************************************/
	raiserror('Creating table MSqreader_history', 0,1)
	/****************************************************************************/    

	CREATE TABLE dbo.MSqreader_history
	(
	agent_id int NOT NULL,
	publication_id int NULL,
	runstatus int NOT NULL,
	start_time datetime NOT NULL,
	time datetime NOT NULL,
	duration int NOT NULL,
	comments nvarchar(255) NOT NULL,
	transaction_id nvarchar(40) NULL, 
	transaction_status int NULL,
	transactions_processed int NULL DEFAULT 0,
	commands_processed int NULL DEFAULT 0,
	delivery_rate float NOT NULL DEFAULT 0.0,
	transaction_rate float NOT NULL DEFAULT 0.0,
	subscriber sysname NULL,
	subscriberdb sysname NULL,
	error_id int NULL,    
	timestamp NOT NULL
	)

	EXEC dbo.sp_MS_marksystemobject 'MSqreader_history'

	raiserror('Creating clustered index ucMSqreader_history', 0,1)
	CREATE CLUSTERED INDEX ucMSqreader_history ON dbo.MSqreader_history
	(agent_id, timestamp, runstatus, start_time, time) 
	END

	-- alter column publication_id
	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_history') and
		name = 'publication_id')
	begin
		alter table dbo.MSqreader_history alter column publication_id int NULL
	end

	-- add columns for existing table
	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_history') and
		name = 'error_id')
	begin
		alter table dbo.MSqreader_history add error_id int NULL
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_history') and
		name = 'transactions_processed')
	begin
		alter table dbo.MSqreader_history add transactions_processed int NULL DEFAULT 0
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_history') and
		name = 'delivery_rate')
	begin
		alter table dbo.MSqreader_history add delivery_rate float NOT NULL DEFAULT 0.0
	end 

	if not exists (select * from syscolumns where 
		id = object_id('MSqreader_history') and
		name = 'transaction_rate')
	begin
		alter table dbo.MSqreader_history add transaction_rate float NOT NULL DEFAULT 0.0
	end 

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = 'MSrepl_backup_lsns' and type = 'U')
	BEGIN
		/****************************************************************************/
		raiserror('Creating table MSrepl_backup_lsns', 0,1)
		/****************************************************************************/    

		CREATE TABLE dbo.MSrepl_backup_lsns
		(
		publisher_database_id int NOT NULL,
		valid_xact_id varbinary(16) NULL,
		valid_xact_seqno varbinary (16 ) NULL,
		next_xact_id varbinary(16) NULL,
		next_xact_seqno varbinary (16 )  NULL
		)

		EXEC dbo.sp_MS_marksystemobject 'MSrepl_backup_lsns'

		raiserror('Creating clustered index ucMSrepl_backup_lsns', 0,1)
		CREATE UNIQUE CLUSTERED INDEX ucMSrepl_backup_lsns ON dbo.MSrepl_backup_lsns
			(publisher_database_id)

		if exists (select * from MSpublisher_databases)
		begin
			/****************************************************************************/
			raiserror('Upgrading MSrepl_backup_lsns', 0,1)
			/****************************************************************************/    
			insert into MSrepl_backup_lsns select d.id, 
				NULL, NULL, NULL, NULL from MSpublisher_databases d
			-- No need to set the lsns in the table since the 'sync with backup' option is 
			-- new in 8.0
		end

	END
GO

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

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

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

    declare @retcode int
    declare @new_heartbeat_interval int 

    -- Check to make sure the local server is a distributor
    if not exists (SELECT * FROM master..sysservers
              WHERE  srvstatus & 8 <> 0 and
              UPPER(datasource) = UPPER(@@servername) collate database_default)
    begin
        RAISERROR (14114, 16, -1, @@SERVERNAME)
        return(1)
    end

    -- Return list of properties if @property is NULL
    if @property is NULL
    begin
        create table #tab1 (properties sysname collate database_default not null)
        insert into #tab1 values ('heartbeat_interval')
        select * from #tab1
        return (0)
    end

    if @property is NULL
    begin
        if exists (select name from msdb..sysobjects where name = 'MSdistributor')
        begin
            select property from msdb..MSdistributor
            return 0
        end
        return 1
    end

    -- Check for valid property
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('heartbeat_interval')
    BEGIN
        RAISERROR (14154, 16, -1)
        RETURN (1)
    END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'heartbeat_interval'
    begin
        if exists (select name from msdb..sysobjects where name = 'MSdistributor')  
        begin
            update msdb..MSdistributor set value = @value where property = @property
            if @@error <> 0
                return 1
            select @new_heartbeat_interval = CONVERT(int, @value)
            exec @retcode = dbo.sp_MScreate_replication_checkup_agent @heartbeat_interval = 
                @new_heartbeat_interval
            if @@error <> 0 or @retcode <> 0
                return 1
        end
        else 
            return 1
    end

    return (0)

GO


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


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

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

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @distributor sysname
    DECLARE @min_distretention     int
    DECLARE @max_distretention     int
    DECLARE @retcode             int
    DECLARE @new_min_distretention     int
    DECLARE @new_max_distretention     int
    DECLARE @new_history_retention     int
    DECLARE @agentname nvarchar(100)
    DECLARE @command nvarchar(255)
    DECLARE @security_mode int
    DECLARE @distbit int

    SELECT @distbit = 16

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

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname collate database_default not null)
            INSERT INTO #tab1 VALUES ('min_distretention')
            INSERT INTO #tab1 VALUES ('max_distretention')
            INSERT INTO #tab1 VALUES ('history_retention')
            SELECT * FROM #tab1
            RETURN (0)
        END

    /*
    ** Parameter Check:  @property.
    ** Check to make sure that @property is a valid property in
    ** sysarticles.
    */
    IF @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
                                                    ('min_distretention',
                                                     'max_distretention',
                                                     'history_retention')
             
        BEGIN

            RAISERROR (14115, 16, -1, 
            '''min_distretention'', ''max_distretention'' or ''history_retention''')
            RETURN (1)
        END


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

    /*
    ** Check if database is configured as a distributor database
    */
    IF NOT EXISTS (SELECT * FROM master..sysdatabases
              WHERE name = @database collate database_default
                 AND category & @distbit <> 0)
    BEGIN
        RAISERROR (14117, 16, -1, @database)
        RETURN(1)
    END
    
    /*
    ** Change the property.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'min_distretention'
        BEGIN
            IF @value IS NULL
                BEGIN
                    RAISERROR (14043, 16, -1, '@value') 
                    RETURN (1)
                END

            /*
            ** Set the MinDistRetention registry key value
            */
            SELECT @new_min_distretention = CONVERT(int, @value)

            /*
            ** Get MaxDistRetention value
            */
            SELECT @max_distretention = max_distretention FROM msdb..MSdistributiondbs
                WHERE name = @database collate database_default
                
            /* 
            ** Check for invalid retention values 
            */
            IF @new_min_distretention < 0
                BEGIN
                       RAISERROR(14106, 16, -1)
                    RETURN (1)
                END
            IF @new_min_distretention > @max_distretention
                BEGIN
                    RAISERROR(14107, 16, -1) 
                    RETURN (1)
                END

            UPDATE msdb..MSdistributiondbs SET min_distretention = @new_min_distretention
                WHERE name = @database collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END

            /*
            ** Update Distribution Cleanup agent 
            */
    		select @agentname = name from msdb..sysjobs j, msdb..sysjobsteps s where 
			j.job_id = s.job_id and
			j.category_id = 11 and
			s.database_name = @database collate database_default
        
			SELECT @command =  'EXEC dbo.sp_MSdistribution_cleanup @min_distretention = ' + 
                CONVERT(nvarchar(12), @new_min_distretention) + ', @max_distretention = ' +
                CONVERT(nvarchar(12), @max_distretention)
            EXEC @retcode = msdb.dbo.sp_update_jobstep @job_name = @agentname, @step_id = 1, 
                @command = @command
            IF @@error <> 0 OR @retcode <> 0
               RETURN(1)

        END

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

            /*
            ** Set the MaxDistRetention registry key value
            */
            SELECT @new_max_distretention = CONVERT(int, @value)

            /*
            ** Get MinDistRetention value
            */
            SELECT @min_distretention = min_distretention FROM msdb..MSdistributiondbs
                WHERE name = @database collate database_default

            /* 
            ** Check for invalid retention values 
            */
            IF @new_max_distretention < 0
                BEGIN
                       RAISERROR(14106, 16, -1)
                    RETURN (1)
                END
            IF @new_max_distretention < @min_distretention
                BEGIN
                    RAISERROR(14107, 16, -1) 
                    RETURN (1)
                END

            UPDATE msdb..MSdistributiondbs SET max_distretention = @new_max_distretention
                WHERE name = @database collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END
            /*
            ** Update Distribution Cleanup agent 
            */
			select @agentname = name from msdb..sysjobs j, msdb..sysjobsteps s where 
				j.job_id = s.job_id and
				j.category_id = 11 and
				s.database_name = @database collate database_default
            SELECT @command =  'EXEC dbo.sp_MSdistribution_cleanup @min_distretention = ' + 
                CONVERT(nvarchar(12), @min_distretention) + ', @max_distretention = ' +
                CONVERT(nvarchar(12), @new_max_distretention)
            EXEC @retcode = msdb.dbo.sp_update_jobstep @job_name = @agentname, @step_id = 1, 
                @command = @command
            IF @@error <> 0 OR @retcode <> 0
               RETURN(1)
        END

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

            /*
            ** Set the HistoryRetention registry key value
            */
            SELECT @new_history_retention = CONVERT(int, @value)

            UPDATE msdb..MSdistributiondbs SET history_retention = @new_history_retention
                WHERE name = @database collate database_default
            IF @@error <> 0 
                BEGIN
                    RETURN (1)
                END

            /*
            ** Update History Cleanup agent 
            */
			select @agentname = name from msdb..sysjobs j, msdb..sysjobsteps s where 
				j.job_id = s.job_id and
				j.category_id = 12 and
				s.database_name = @database collate database_default
            SELECT @command =  'EXEC dbo.sp_MShistory_cleanup @history_retention = ' + 
                CONVERT(nvarchar(12), @new_history_retention)
            EXEC @retcode = msdb.dbo.sp_update_jobstep @job_name = @agentname, @step_id = 1, 
                @command = @command
            IF @@error <> 0 OR @retcode <> 0
               RETURN(1)

        END




    /*
    ** Return succeed.
    */
    RAISERROR (14105, 10, -1, @property)
    RETURN (0)
go
 
--------------------------------------------------------------------------------
--. sp_adddistpublisher
--------------------------------------------------------------------------------
if exists (select * from sysobjects
        where type = 'P'
            and name = 'sp_adddistpublisher')
    drop procedure sp_adddistpublisher
go

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

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

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

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

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

    SELECT @distbit = 16
    SELECT @server_added = 0

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

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


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

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

    EXECUTE @retcode = dbo.sp_validname @publisher

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

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

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

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


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

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

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

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

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

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

    /*
    ** Parameter Check:  @trusted
    */

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

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

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

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

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

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

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



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

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


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

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

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

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

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

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


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

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

    IF @server_added = 1
        EXEC dbo.sp_dropserver @publisher

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

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

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

    SET NOCOUNT ON

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        END

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

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

            declare @fExists int

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


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


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

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

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

DONE:    
    RETURN (0)
go


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

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

-- Drop a/all parameter(s) of a/all profile(s) from the MSagent_parameters table
create procedure sp_drop_agent_parameter (
    @profile_id int,
    @parameter_name     sysname = '%'
)
as
    set nocount on

    declare @default            bit
    declare @agent_type         int
    declare @retstatus          int
    select @retstatus = 0

    if @parameter_name is null
    BEGIN
        RAISERROR (14043, 16, -1, '@parameter_name')
        RETURN (1)
    END

    select @agent_type = agent_type, @default=def_profile
    from msdb..MSagent_profiles
    where profile_id = @profile_id

    if @default is null
    BEGIN
        RAISERROR (20066, 16, -1) -- profile not defined
        RETURN (1)
    END
    
    select @parameter_name = lower(@parameter_name collate SQL_Latin1_General_CP1_CS_AS)

    if left(@parameter_name,1) in (N'-', N'/')
        select @parameter_name = right(@parameter_name,len(@parameter_name)-1)

    /* Delete the parameters of the profile */
    delete  msdb..MSagent_parameters 
    where   right(lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS),len(parameter_name)-1) like 
            @parameter_name collate SQL_Latin1_General_CP1_CS_AS
    and     profile_id = @profile_id

    if @@error <> 0
    begin
        select @retstatus = 1
        goto UNDO
    end

UNDO:
    
    return @retstatus
GO


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

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

create procedure sp_generate_agent_parameter(
	@profile_id     int,		-- Fixed profile id used
	@real_profile_id int = NULL -- Used by version upgrade 
)
as
	declare @retcode    int

	-- If real profile id is not passed in. Use the fix profile id.
	if @real_profile_id is NULL
		select @real_profile_id = @profile_id

        /* 
	** Snapshot agent 
	*/
	if (@profile_id = 1)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '2'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxBcpThreads',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        end

        /* 
	** Logreader agent 
	*/
	else if (@profile_id = 2)
        begin
  
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ReadBatchSize',
				@parameter_value = '500'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        end

        /* 
	** Logreader agent - Verbose History Profile
	*/
	else if (@profile_id = 3)
        begin

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '2'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ReadBatchSize',
				@parameter_value = '500'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        end

        /* 
	** Distribution agent 
	*/
	else if (@profile_id = 4)
	  begin

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchSize',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchThreshold',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxBcpThreads',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDeliveredTransactions',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-TransactionsPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-SkipErrors',
				@parameter_value = ''
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

	    end

    /*
	** Distribution Agent Verbose History Profile
	*/
	else if (@profile_id = 5)
	  begin

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchSize',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchThreshold',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '2'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxBcpThreads',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDeliveredTransactions',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-TransactionsPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-SkipErrors',
				@parameter_value = ''
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end
    /* 
	** Merge agent : Default profile for well connected scenarios 
	*/
	else if (@profile_id = 6)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
	** Merge agent : Non default profile for disconnected scenarios ( unreliable link ) 
	*/
	else if (@profile_id = 7)
        begin

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '20'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-KeepAliveMessageInterval',
				@parameter_value = '300'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

        /* 
	** Merge agent : Default profile for well connected scenarios - Verbose history logging 
	*/
	else if (@profile_id = 8)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '50'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
	** Merge agent : (Synchronization Manager Profile)
	*/
	else if (@profile_id = 9)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '50'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
	** Distribution agent (Synchronization Manager Profile)
	*/
	else if (@profile_id = 10)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchSize',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchThreshold',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxBcpThreads',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDeliveredTransactions',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-TransactionsPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-SkipErrors',
				@parameter_value = ''
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end
	
    /* 
	** Queue Reader agent default profile
	*/
	else if (@profile_id = 11)
    begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
	end
	  
    /* 
	** Merge agent : Rowcount Validation profile for well connected scenarios 
	*/
	else if (@profile_id = 12)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE


		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
    ** Merge agent : Rowcount & Checksum Validation profile for well connected scenarios 
    */
	else if (@profile_id = 13)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
			
		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
    ** Distribution agent, skip error profile
    */
	else if (@profile_id = 14)
	  begin

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchSize',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-CommitBatchThreshold',
				@parameter_value = '1000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxBcpThreads',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDeliveredTransactions',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '10'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '300'        -- 5 minutes 
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-TransactionsPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-SkipErrors',
				@parameter_value = '2601:2627:20598'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    /* 
    ** Merge agent : Rowcount Validation profile for high volumn server-to-server
    */
        else if (@profile_id = 15)
        begin
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-PollingInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-StartQueueTimeout',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxDownloadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-MaxUploadChanges',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ValidateInterval',
				@parameter_value = '60'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-LoginTimeout',
				@parameter_value = '15'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-QueryTimeout',
				@parameter_value = '600'        
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadGenerationsPerBatch',
				@parameter_value = '2000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadGenerationsPerBatch',
				@parameter_value = '2000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadReadChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-UploadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-DownloadWriteChangesPerBatch',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-Validate',
				@parameter_value = '0'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-FastRowCount',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE
        
		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-HistoryVerboseLevel',
				@parameter_value = '1'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
				@profile_id = @real_profile_id,
				@parameter_name = '-ChangesPerHistory',
				@parameter_value = '100'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-BcpBatchSize',
				@parameter_value = '100000'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-NumDeadlockRetries',
				@parameter_value = '5'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-SrcThreads',
				@parameter_value = '3'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

		exec @retcode = dbo.sp_add_agent_parameter 
			    @profile_id = @real_profile_id,
				@parameter_name = '-DestThreads',
				@parameter_value = '4'
		if (@retcode = 1 or @@ERROR <> 0)
			goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-KeepAliveMessageInterval',
                @parameter_value = '300'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        exec @retcode = dbo.sp_add_agent_parameter
                @profile_id = @real_profile_id,
                @parameter_name = '-MetadataRetentionCleanup',
                @parameter_value = '1'
        if (@retcode = 1 or @@ERROR <> 0)
            goto FAILURE

        end

    return 0
FAILURE:
    return 1
go


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

raiserror('Creating procedure sp_MSvalidate_agent_parameter', 0,1)
go
create procedure sp_MSvalidate_agent_parameter (
    @profile_id      int,
    @parameter_name  sysname,
    @parameter_value nvarchar(255)
)
as
    declare @agent_type  int
    declare @original_parameter_name sysname
    declare @numeric_value int

    -- Make sure parameters are non-null
    if @profile_id is null
    BEGIN
        RAISERROR (14043, 16, -1, '@profile_id')
        RETURN (1)
    END

    if @parameter_name is null 
    BEGIN
        RAISERROR (14043, 16, -1, '@parameter_name')
        RETURN (1)
    END

    IF @parameter_value is null
    BEGIN
        RAISERROR (14043, 16, -1, '@parameter_value')
        RETURN (1)
    END

    select @original_parameter_name = @parameter_name
    
    select @agent_type = agent_type
    from msdb..MSagent_profiles 
    where profile_id = @profile_id

	-- Parameter name validation
    if (substring(@parameter_name, 1, 1) <> '/' and 
        substring(@parameter_name, 1, 1) <> '-')
    begin
        return 1
    end

    select @parameter_name = lower(substring(@parameter_name, 2, len(@parameter_name) - 1) collate SQL_Latin1_General_CP1_CS_AS)

    -- Snapshot agent - agent_type = 1
    if (@agent_type = 1)
    begin
        if not @parameter_name in ( 
            N'bcpbatchsize',   
            N'historyverboselevel',
            N'logintimeout',
            N'maxbcpthreads',
            N'querytimeout',
            N'startqueuetimeout'
            )    
        begin
            raiserror(21111, 16, -1, @original_parameter_name)
            return 1
        end
    end
    -- Logreader - agent_type = 2
    else if (@agent_type =2)  
    begin
        if not lower(@parameter_name collate SQL_Latin1_General_CP1_CS_AS) in ( 
            N'historyverboselevel',
            N'logintimeout',
            N'pollinginterval',
            N'querytimeout',
            N'readbatchsize'
            )    
        begin
            raiserror(21112, 16, -1, @original_parameter_name)
            return 1
        end
    end
    -- Distribution agent - agent_type = 3
    else if (@agent_type = 3)
    begin
        if not @parameter_name in ( 
            N'bcpbatchsize',   
            N'commitbatchsize',   
            N'commitbatchthreshold',   
            N'historyverboselevel',
            N'logintimeout',
            N'maxbcpthreads',
            N'maxdeliveredtransactions',
            N'pollinginterval',
            N'querytimeout',
            N'transactionsperhistory',
            N'skiperrors',
            N'keepalivemessageinterval',
            N'useinprocloader'            
            )    
        begin
            raiserror(21113, 16, -1, @original_parameter_name)
            return 1
        end
    end
    -- Merge agent - agent_type = 4
    else if (@agent_type = 4)
    begin 
        if not @parameter_name in ( 
            N'startqueuetimeout',
            N'pollinginterval',   
            N'validateinterval',   
            N'logintimeout',   
            N'querytimeout',
            N'maxuploadchanges',
            N'maxdownloadchanges',
            N'uploadgenerationsperbatch',   
            N'downloadgenerationsperbatch',   
            N'uploadreadchangesperbatch',   
            N'downloadreadchangesperbatch',   
            N'uploadwritechangesperbatch',
            N'downloadwritechangesperbatch',
            N'validate',   
            N'fastrowcount',   
            N'historyverboselevel',
            N'changesperhistory',
            N'bcpbatchsize',
            N'numdeadlockretries',
            N'keepalivemessageinterval',
            N'srcthreads',
            N'destthreads',
            N'useinprocloader',
            N'metadataretentioncleanup'
            )    
        begin
            raiserror(21114, 16, -1, @original_parameter_name)
            return 1
        end
    end
    -- Qreader agent - agent_type = 9
    else if (@agent_type = 9)  
    begin
        if not lower(@parameter_name collate SQL_Latin1_General_CP1_CS_AS) in ( 
            N'resolverstate',
            N'sqlqueuemode',
            N'historyverboselevel',
            N'pollinginterval',
            N'logintimeout',
            N'querytimeout'
            )    
        begin
            raiserror(21112, 16, -1, @original_parameter_name)
            return 1
        end
    end
    else if @agent_type is null
    begin
        raiserror (20066, 16, -1)   -- profile not defined
        return 1
    end
    else
    begin
        -- MSagent_parameters table corruption
        return 1
    end

    -- Parameter value validation
    if (@parameter_name = N'bcpbatchsize')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end
    end
    else if (@parameter_name = N'commitbatchsize')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'commitbatchthreshold')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'downloadgenerationsperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end 
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'DownloadGenerationsPerBatch', '1 - 2000') 
			return 1
		end                      
    end
    else if (@parameter_name = N'downloadreadchangesperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end    
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'DownloadReadChangesPerBatch', '1 - 2000') 
			return 1
		end                      
    end
    else if (@parameter_name = N'downloadwritechangesperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end 
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'DownloadWriteChangesPerBatch', '1 - 2000') 
			return 1
		end                         
    end
    else if (@parameter_name = N'fastrowcount')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or not (@numeric_value in (1,2,3))
        begin
            raiserror(21116, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'historyverboselevel')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or not (@numeric_value in (0,1,2,3))
        begin
            raiserror(21117, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'logintimeout')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'maxbcpthreads')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'maxdeliveredtransactions')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 0
        begin
            raiserror(21119, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'pollinginterval')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'querytimeout')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'readbatchsize')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'transactionsperhistory')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value not between 0 and 10000
        begin
            raiserror(211118, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'uploadgenerationsperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end 
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'UploadGenerationsPerBatch', '1 - 2000') 
			return 1
		end                         
    end
    else if (@parameter_name = N'uploadreadchangesperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end     
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'UploadReadChangesPerBatch', '1 - 2000') 
			return 1
		end                     
    end
    else if (@parameter_name = N'uploadwritechangesperbatch')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end 
		if @numeric_value > 2000
		begin
			raiserror(14266, 16, -1, 'UploadWriteChangesPerBatch', '1 - 2000') 
			return 1
		end                         
    end
    else if (@parameter_name = N'validate')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or not (@numeric_value in (0,1,2,3))
        begin
            raiserror(21117, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'validateinterval')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'skiperrors')
    begin
		-- Empty string is valid.
		if @parameter_value <> N''
		begin
			-- Valid format: 11:22:33
			if	@parameter_value like '%[^0-9:]%' or
				@parameter_value like ':%' or
				@parameter_value like '%:' or
				@parameter_value like '%::%'
			begin
				raiserror(20601, 16, -1)
				return 1
			end
			-- cannot has number of errors equals to or more than 11
			if	@parameter_value like '%:%:%:%:%:%:%:%:%:%:%'
			begin
				raiserror(20602, 16, -1)
				return 1
			end
		end
    end
    -- Parameter value validation
    else if (@parameter_name = N'numdeadlockretries')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end
		if @numeric_value > 100
		begin
			raiserror(14266, 16, -1, 'NumDeadlockRetries', '1 - 100') 
			return 1
		end                         
    end
	else if (@parameter_name = N'srcthreads')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
	else if (@parameter_name = N'destthreads')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 1
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'keepalivemessageinterval')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value < 30
        begin
            raiserror(21405, 16, -1, @parameter_value, @original_parameter_name, 30)            
            return 1
        end
    end
    else if (@parameter_name = N'useinprocloader')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value not in (0, 1) or rtrim(@parameter_value) = N''
        begin
            raiserror(21406, 16, -1, @parameter_value, @original_parameter_name)
            return 1
        end
    end
    else if (@parameter_name = N'startqueuetimeout')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or (@numeric_value < 300 and @numeric_value <> 0) or rtrim(@parameter_value) = N''
        begin
            raiserror(21404, 16, -1, @parameter_value, @original_parameter_name)
            return 1
        end
    end
    else if (@parameter_name = N'resolverstate')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value not in (1,2,3)
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    else if (@parameter_name = N'sqlqueuemode')
    begin
        select @numeric_value = convert(int, @parameter_value)
        if @@error <> 0 or @numeric_value not in (0,1,2)
        begin
            raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
            return 1     
        end                        
    end
    
    return 0
go 

EXEC dbo.sp_MS_marksystemobject 'sp_MSvalidate_agent_parameter'
go

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

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

-- Add a row into the "MSagent_parameters" table
create procedure sp_add_agent_parameter (
    @profile_id int,
    @parameter_name         sysname,
    @parameter_value        nvarchar(255)
)
as
    declare @slash_parameter_name sysname
    declare @dash_parameter_name sysname
    declare @retcode int
    
    set nocount on

    select @parameter_name = RTRIM(@parameter_name)

	-- Append leading '-' when not given
    if (substring(@parameter_name, 1, 1) <> '/' and 
        substring(@parameter_name, 1, 1) <> '-')
    BEGIN
		select @parameter_name = N'-' + @parameter_name
	END

    -- Call proc to validate parameter value
    exec @retcode = dbo.sp_MSvalidate_agent_parameter 
                        @profile_id = @profile_id, 
                        @parameter_name = @parameter_name,
                        @parameter_value = @parameter_value
    if @retcode <> 0
        RETURN(1)


    select @slash_parameter_name = lower(stuff(@parameter_name, 1, 1, N'/') collate SQL_Latin1_General_CP1_CS_AS)
    select @dash_parameter_name = lower(stuff(@parameter_name, 1, 1, N'-') collate SQL_Latin1_General_CP1_CS_AS)
     

    /* A parameter may be defined only once per profile */
    if exists ( select * from msdb..MSagent_parameters 
            where profile_id = @profile_id
            and (lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @slash_parameter_name collate SQL_Latin1_General_CP1_CS_AS  
            or lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @dash_parameter_name collate SQL_Latin1_General_CP1_CS_AS))
    BEGIN
        RAISERROR (20067, 16, -1, @parameter_name)  -- The parameter name ''%s'' already exists for the specified profile
        RETURN (1)
    END

    insert into msdb..MSagent_parameters
    values (@profile_id, @parameter_name, @parameter_value) ;

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

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

raiserror('Creating procedure sp_change_agent_parameter', 0,1)
go
-- Change one parameter of a profile from the MSagent_parameters table
create procedure sp_change_agent_parameter(
    @profile_id int,
    @parameter_name         sysname,
    @parameter_value        nvarchar(255)
)AS
    declare @slash_parameter_name sysname
    declare @dash_parameter_name sysname
    declare @retcode int

    select @parameter_name = LTRIM(RTRIM(@parameter_name))
    select @parameter_value = LTRIM(RTRIM(@parameter_value))

    -- DMO sends in empty sting as '(null)'.
	if @parameter_value = N'(null)'
		select @parameter_value = N''

	-- Append leading '-' when not given
    if (substring(@parameter_name, 1, 1) <> '/' and 
        substring(@parameter_name, 1, 1) <> '-')
    BEGIN
		select @parameter_name = N'-' + @parameter_name
	END

	-- Call proc to validate parameter value
    exec @retcode = dbo.sp_MSvalidate_agent_parameter 
                        @profile_id = @profile_id, 
                        @parameter_name = @parameter_name,
                        @parameter_value = @parameter_value
    if @retcode <> 0
        RETURN(1)


    select @slash_parameter_name = lower(stuff(@parameter_name, 1, 1, N'/') collate SQL_Latin1_General_CP1_CS_AS)
    select @dash_parameter_name = lower(stuff(@parameter_name, 1, 1, N'-') collate SQL_Latin1_General_CP1_CS_AS)
   
    IF exists ( select * from msdb..MSagent_parameters 
            where profile_id = @profile_id and 
                (lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @slash_parameter_name collate SQL_Latin1_General_CP1_CS_AS or
                 lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @dash_parameter_name collate SQL_Latin1_General_CP1_CS_AS))
    BEGIN
        update msdb..MSagent_parameters set value = @parameter_value where 
            profile_id = @profile_id and 
            (lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @slash_parameter_name collate SQL_Latin1_General_CP1_CS_AS or
            lower(parameter_name collate SQL_Latin1_General_CP1_CS_AS) = @dash_parameter_name collate SQL_Latin1_General_CP1_CS_AS) 

        if @@error <> 0
            return(1)
    END
GO


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

raiserror('Creating procedure sp_change_agent_profile', 0,1)
go
-- Change one parameter of a profile from the MSagent_profiles table
create procedure sp_change_agent_profile(
    @profile_id         int,
    @property           sysname,
    @value              nvarchar(3000)
)AS

    IF lower(@property collate SQL_Latin1_General_CP1_CS_AS) not in ('description')
    BEGIN
        RAISERROR(21183, 16, -1, @property)
        RETURN (1)
    END

    IF exists ( select * from msdb..MSagent_profiles where profile_id = @profile_id)
    BEGIN
        update msdb..MSagent_profiles set description = @value where profile_id = @profile_id
        if @@error <> 0
            return(1)
    END
GO


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

raiserror('Creating procedure sp_MSfix_6x_tasks', 0,1)
go
CREATE PROCEDURE sp_MSfix_6x_tasks (
	@publisher sysname = NULL
) AS

    SET NOCOUNT ON

    DECLARE @distributor sysname
    DECLARE @distproc nvarchar (255)
	declare @retcode int

	-- If @publisher is null redirect the call to distributor
	if @publisher is null
	begin
		/*
		** Get distribution server information for remote RPC
		** agent verification.
		*/
		EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT

		IF @@error <> 0 OR @retcode <> 0
		BEGIN
			RAISERROR (14071, 16, -1)
			RETURN (1)
		END

		/*
		** RPC distributor
		*/
		SELECT @distproc = RTRIM(@distributor) + '.master.dbo.sp_MSfix_6x_tasks'

		EXECUTE @retcode = @distproc
			@publisher = @@SERVERNAME
		IF @@ERROR <> 0 or @retcode <> 0
			return (1)
	end
	else
	begin

		declare @category_id int
		declare @category_name sysname
		declare @server sysname
		declare @databasename sysname
		declare @name sysname
		declare @distdb sysname
		declare @job_id uniqueidentifier
		declare @sSubsystem sysname

        -- Drop entry in systasks first.
        DECLARE hCtasks CURSOR LOCAL FAST_FORWARD FOR
            SELECT name FROM msdb.dbo.systasks_view st WHERE 
                
                -- drop distribution agents.
                (st.name LIKE @publisher + '_' + '%' + '_' + '%' AND 
                LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'distribution' AND
                server = @@SERVERNAME) OR
                                
                (LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'logreader' AND
                server = @publisher) OR 
                
                (LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot' AND
                server = @publisher) OR

                (st.name LIKE '%' + '_' + '%' + '_Cleanup' AND 
				st.command LIKE '%' + 'sp_replcleanup' + '%' AND
				LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'tsql')
            FOR READ ONLY

        OPEN hCtasks
        FETCH hCtasks INTO @name

        WHILE (@@fetch_status <> -1)
        BEGIN
            
            EXEC @retcode = msdb.dbo.sp_droptask @name = @name
            if @retcode <> 0 or @@error <> 0
                return(1)
            FETCH hCtasks INTO @name
        END

		-- Now spin through each old replication job and fixup categories names
		declare hcJobsToFix CURSOR LOCAL FAST_FORWARD for 
				select distinct j.job_id, j.name, s.subsystem, 
					s.server, s.database_name
					from msdb.dbo.sysjobs j left join msdb.dbo.sysjobsteps s
						on j.job_id = s.job_id
					where j.category_id = 0 and s.step_id = 1 and lower(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) in ( 'snapshot', 'logreader', 'distribution' )
				for read only

		open hcJobsToFix 
		fetch hcJobsToFix into @job_id, @name, @sSubsystem,
			@server,@databasename

		while (@@fetch_status <> -1 )
		begin
			-- Note, have to make it a transaction, once the category_id is changed,
			-- the task will never be picked up again.
			begin tran 

				-- Get Distribution category name (assumes category_id = 10)
				select @category_id =
					case lower(@sSubsystem collate SQL_Latin1_General_CP1_CS_AS) 
						when 'snapshot' then 15
						when 'distribution' then 10
						when 'logreader' then 13
						else 0
					end

				select @category_name = name FROM msdb.dbo.syscategories where category_id = @category_id
				
				-- raiserror( 'Would update %s to category %d based on subsystem value %s', -1, 10, @nJobName, @iCategory, @sSubsystem )
				exec @retcode = msdb.dbo.sp_update_job @job_id = @job_id, 
					@category_name = @category_name
				if @retcode <> 0 or @@error <> 0
					goto UNDO


				-- Add the replication agent for monitoring
				SELECT @distdb = distribution_db from msdb..MSdistpublishers where UPPER(name) = UPPER(@server) collate database_default
				IF (@category_id = 13) -- Logreader
				BEGIN
					SELECT @distproc = @distdb + '.dbo.sp_MSadd_logreader_agent'
					EXECUTE @retcode = @distproc
						@name = @name,
						@publisher = @server,
						@publisher_db = @databasename,
						@publication = '',  
						@local_job = 1,
						@job_existing = 1,
						@job_id = @job_id

					IF (@retcode <> 0 or @@error<>0)
						goto UNDO
				END
				ELSE 
				IF (@category_id = 15) -- Snapshot
				BEGIN
                    DECLARE @publication sysname

                    SELECT @publication = NULL
                    EXECUTE master.dbo.sp_MSget_publication_from_taskname
                                            @taskname = @name,
                                            @publisher = @server,
                                            @publisherdb = @databasename,
                                            @publication = @publication OUTPUT

                    IF (@publication IS NOT NULL )
                    BEGIN    			
					    SELECT @distproc = @distdb + '.dbo.sp_MSadd_publication'
					    EXECUTE @retcode = @distproc
						    @publisher = @server,
						    @publisher_db = @databasename,
						    @publication = @publication,
						    @publication_type = 0 -- Transactional
					    IF (@retcode <> 0 or @@error<>0)
						    goto UNDO

					    SELECT @distproc = @distdb + '.dbo.sp_MSadd_snapshot_agent'
					    EXECUTE @retcode = @distproc
						    @name = @name,
						    @publisher = @server,
						    @publisher_db = @databasename,
						    @publication = @publication,
						    @local_job = 1,
						    @job_existing = 1,
						    @snapshot_jobid = @job_id
					    IF (@retcode <> 0 or @@error<>0)
						    goto UNDO
                    END
				END
			commit tran
			fetch hcJobsToFix into @job_id, @name, @sSubsystem,
				@server,@databasename
		end			
		close hcJobsToFix
		deallocate hcJobsToFix
	end
	return (0)
UNDO:
	if @@trancount <> 0
		rollback tran
	return (1)
GO

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

/*
 * Name :       sp_MShelpconflictpublications
 * Description: This sp returns a list of publications or subscriptions in the current
 *    database that may have conflicts. Results are ordered by publication
 *    name.
 * Parameters:  1. publication_type( sysname; '%'==ALL (default) | 'merge' | 'queued' )
 * Output Result Set has the following structure:
 *  ----------------------------------------------------------------------------------
 *      Name                Datatype                Description
 *  ----------------------------------------------------------------------------------
 *  a. name					(sysname)			Publication name
 *  b. publication_type		(varchar(9))		'merge' | 'queued' | 'immediate' (reserved)
 *  c. merge_pub_id			(uniqueidentifier)	Merge publication identifier
 *  d. queued_pub_id		(integer)			Queued publication identifier (I would prefer to name this as tran_pub_id)
 *  e. sub_agent_id			(integer)			Unique publication identifier on a tran subscriber
 *  NOTE: In case of queued tran publications, either d or e will have a value at any time
 *  and this will also indicate, if we are processing a subscriber of a publication (d 
 *  will be NULL and e will have a value) or if we are processing the publisher side (d
 *  will have a value and e will be NULL)
*/
raiserror('Creating procedure sp_MShelpconflictpublications', 0,1)
GO

CREATE PROCEDURE sp_MShelpconflictpublications ( @publication_type varchar(9) ='%' )
AS 
BEGIN

	SET nocount ON
	
	-- validate publication type
	IF NOT( lower(@publication_type collate SQL_Latin1_General_CP1_CS_AS) IN ('%', 'merge', 'queued') )
	BEGIN
		raiserror( 'invalid publication type', 16, -1 )
		RETURN (1)
	END
	
	-- temp table to store combined result set
	CREATE TABLE #result_list ( publication sysname collate database_default, publication_type VARCHAR(9) DEFAULT 'merge', 
								merge_pub_id UNIQUEIDENTIFIER NULL, 
								queued_pub_id INTEGER NULL, sub_agent_id INTEGER NULL, publisher sysname collate database_default NULL, publisher_db sysname collate database_default NULL)

	-- fetch merge results into temp table; need not affect any rows
	IF ( lower(@publication_type collate SQL_Latin1_General_CP1_CS_AS) IN ('%', 'merge') )
	BEGIN
		IF EXISTS( SELECT * FROM sysobjects WHERE name = 'sysmergepublications' )
			INSERT #result_list ( publication, merge_pub_id, publisher, publisher_db)
				EXEC sp_MShelpmergeconflictpublications

		-- may return 18757 (not merge published) and that is ok if @publication_type = ALL
		IF ( @@ERROR <> 0) AND ( @@ERROR = 18757 AND @publication_type = '%' ) 
			GOTO FAILURE
				
	END

	-- fetch tran results into temp table
	IF ( lower(@publication_type collate SQL_Latin1_General_CP1_CS_AS) IN ('%', 'queued') )
	BEGIN
		INSERT #result_list  ( publication, publication_type, merge_pub_id , queued_pub_id, sub_agent_id )
			EXEC sp_MShelptranconflictpublications
		IF ( @@ERROR <> 0) 
			GOTO FAILURE

	END

	-- return combined result list
	SELECT * FROM #result_list

	IF EXISTS( SELECT * FROM sysobjects WHERE type = 'U' AND name = '#result_list' )
		DROP TABLE #result_list

	RETURN (0)

FAILURE:

	IF EXISTS( SELECT * FROM sysobjects WHERE type = 'U' AND name = '#result_list' )
		DROP TABLE #result_list

	RETURN (1)
	
END
GO

GRANT EXECUTE ON dbo.sp_MShelpconflictpublications TO PUBLIC
GO

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

raiserror('Creating function system_function_schema.fn_replgetagentcommandlinefromjobid',0,1)
go
--
-- Name: fn_replgetagentcommandlinefromjobid
--
-- Description: This function retrieves the command line  
--              of the replication agent with the 
--              specified job_id.
--
-- Parameters: @agenttype nvarchar(16)
--             @job_id uniqueidentifier
-- 
-- Returns: nvarchar(3200) 
--
-- Notes: This function can return null if the 
--        the given job_id doesn't belong to a
--        replication agent of the specified type.
--
-- Security: Admin access only
-- 
create function system_function_schema.fn_replgetagentcommandlinefromjobid (
    @agenttype nvarchar(16),
    @job_id uniqueidentifier
    ) returns nvarchar(3200)
as
begin
    declare @commandline nvarchar(3200)
    select @commandline = null
    select @agenttype = upper(@agenttype collate SQL_Latin1_General_CP1_CS_AS)
    select @commandline = command 
      from msdb.dbo.sysjobsteps
     where job_id = @job_id
       and upper(subsystem collate SQL_Latin1_General_CP1_CS_AS) = @agenttype collate SQL_Latin1_General_CP1_CS_AS

    return @commandline
end
go


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

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

    if @agent_type is null
    begin
        select @agent_type = 'distribution'
    end
    
    -- @remoteservername cannot be null or empty
    select @remoteservername = rtrim(ltrim(@remoteservername))
    if @remoteservername is null or
       @remoteservername = N''
    begin
        raiserror(21263,16,-1,'@remoteservername')
        return 1
    end     
    
    -- @agent_type must be 'distribution' or 'merge'
    if @agent_type not in (N'distribution', N'merge')
    begin
        raiserror(21182,16,-1) 
        return 1
    end

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

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

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

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

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

        return @retcode
    end

    select 'probe_succeeded' = 0

    return 1
end
go
exec sp_MS_marksystemobject sp_replproberemoteserver
go
grant execute on dbo.sp_replproberemoteserver to public
go

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

create procedure sp_MScreate_distributor_tables
as
    declare @profile_id     int
    declare @retcode    int
    declare @profile_name nvarchar(100)
    declare @profile_desc nvarchar(100)

    /* Create MSpublishers table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistpublishers'
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSdistpublishers
        if @@error<> 0 goto FAILURE
    end

    /* Create MSdistributiondbs table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistributiondbs'
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSdistributiondbs
        if @@error<> 0 goto FAILURE
    end

    /* create MSdistributor table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistributor'
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSdistributor
        if @@error<> 0 goto FAILURE
    end

    /* create sysreplicationalerts table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'sysreplicationalerts'
        and xtype = 'U')
    begin
        DROP TABLE msdb..sysreplicationalerts
        if @@error<> 0 goto FAILURE
    end
    
    /* create MSagent_profiles table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSagent_profiles'
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSagent_profiles
        if @@error<> 0 goto FAILURE
    end

    /* create MSagent_parameters table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSagent_parameters' 
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSagent_parameters
        if @@error<> 0 goto FAILURE
    end

    /* create MSdatatype_mappings table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdatatype_mappings' 
        and xtype = 'U')
    begin
        DROP TABLE msdb..MSdatatype_mappings
        if @@error<> 0 goto FAILURE
    end

    
    CREATE TABLE msdb.dbo.MSdistpublishers
    (
        name                sysname     NOT NULL,
        distribution_db     sysname     NOT NULL,
        working_directory   nvarchar(255) NOT NULL,
        security_mode       int         NOT NULL,
        login               sysname     NOT NULL,
        password            nvarchar(524) NULL,
        active              bit         NOT NULL,
        trusted             bit         NOT NULL,
        thirdparty_flag     bit         NOT NULL
    )
    if @@error<> 0 goto FAILURE

	CREATE UNIQUE CLUSTERED INDEX uc1MSdistpublishers 
		ON msdb.dbo.MSdistpublishers(name)
	if @@error<> 0 goto FAILURE


    CREATE TABLE msdb.dbo.MSdistributiondbs
    (
        name            sysname     NOT NULL,
        min_distretention   int     NOT NULL,
        max_distretention   int     NOT NULL,
        history_retention   int     NOT NULL
    )
    if @@error<> 0 goto FAILURE

	CREATE UNIQUE CLUSTERED INDEX uc1MSdistributiondbs 
			ON msdb.dbo.MSdistributiondbs(name)
	if @@error<> 0 goto FAILURE



    CREATE TABLE msdb.dbo.MSdistributor 
    ( 
        property        sysname     NOT NULL, 
        value           nvarchar(3000)  NULL
    )
    if @@error<> 0 goto FAILURE
	
	CREATE UNIQUE CLUSTERED INDEX uc1MSdistributor 
			ON msdb.dbo.MSdistributor(property)
	if @@error<> 0 goto FAILURE

    CREATE TABLE msdb.dbo.sysreplicationalerts
    (
        alert_id            int identity(1,1) NOT NULL,
        status              int NOT NULL,
        agent_type          int NULL,
        agent_id            int NULL,
        error_id            int NULL,
        alert_error_code    int NULL,
        time                datetime NOT NULL,
        publisher           sysname NULL,
        publisher_db        sysname NULL,
        publication         sysname NULL,
        publication_type    int NULL,
        subscriber          sysname NULL,
        subscriber_db       sysname NULL,
        article             sysname NULL,
        destination_object  sysname NULL,
        source_object       sysname NULL,
        alert_error_text    ntext NULL
    )
    if @@error<> 0 goto FAILURE

    CREATE UNIQUE CLUSTERED INDEX ucsysreplicationalerts ON msdb.dbo.sysreplicationalerts(alert_id)
    if @@error<> 0 goto FAILURE

    CREATE TABLE msdb.dbo.MSagent_profiles
    (
        profile_id    int           NOT NULL IDENTITY,
        profile_name  sysname       NOT NULL,
        agent_type          int             NOT NULL, -- 1-Snapshot, 2-Logreader,
                                                      -- 3-Distribution, 4-Merge,
                                                      -- 9-Qreader
        type                int             NOT NULL, -- 0-System, 1-Custom
        description         nvarchar(3000)  NULL,
        def_profile   bit               NOT NULL
    )
    if @@error<> 0 goto FAILURE


    CREATE UNIQUE CLUSTERED INDEX ucMSagent_profiles ON msdb.dbo.MSagent_profiles
        (profile_name, profile_id, agent_type)
    if @@error<> 0 goto FAILURE

    CREATE TABLE msdb.dbo.MSagent_parameters
    (
        profile_id     int          NOT NULL,
        parameter_name       sysname        NOT NULL,
        value                nvarchar(255)  NOT NULL
    )
    if @@error<> 0 goto FAILURE

    CREATE UNIQUE CLUSTERED INDEX ucMSagent_parameters ON msdb.dbo.MSagent_parameters
        (parameter_name, profile_id)
    if @@error<> 0 goto FAILURE

    /* 
	** Create default / non default profiles 
	** for all the agents 
	*/

    /* 
	** Snapshot agent 
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20545) -- Default Snapshot Profile
    set @profile_desc = NULL

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 1,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 1
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

	exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Logreader agent 
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20545) -- Default LogReader Profile
    set @profile_desc = NULL

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 2,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 1
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Logreader agent - Verbose History Profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20546) -- LogReader Verbose History Profile
    set @profile_desc = formatmessage(20547)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 2,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Distribution agent 
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20545) -- Default Distribution Profile
    set @profile_desc = NULL

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 1
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /*
	** Distribution Agent Verbose History Profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20546) -- Distribution Verbose History Profile
    set @profile_desc = formatmessage(20547)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE
 
    /* 
	** Merge agent : Default profile for well connected scenarios 
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20545) -- Default Merge Profile
    set @profile_desc = NULL

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 1

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Merge agent : Non default profile for disconnected scenarios ( unreliable link ) 
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20548) -- Non-Default Merge Profile
    set @profile_desc = formatmessage(20549)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Merge agent : Non default profile for verbose histroy
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20546) -- Verbose Merge Profile
    set @profile_desc = formatmessage(20547)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Merge agent : Synchronization Manager Profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20550) -- SyncMgr Profile
    set @profile_desc = formatmessage(20551)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Distribution agent : Synchronization Manager Profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20550) -- SyncMgr Profile
    set @profile_desc = formatmessage(20551)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

	/* 
	** Qreader agent (default profile)
	*/
	set @profile_id = NULL
	set @profile_name = formatmessage(20545) -- Default QueueReader Profile
    set @profile_desc = formatmessage(20589)

	exec @retcode = dbo.sp_add_agent_profile
			@profile_id = @profile_id OUT,
			@profile_name = @profile_name,
			@agent_type = 9,
			@profile_type = 0, 
			@description = @profile_desc,
			@default = 1
	if (@retcode = 1 or @@ERROR <> 0)
		goto FAILURE

	exec @retcode = dbo.sp_generate_agent_parameter @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		goto FAILURE

    /* 
	** Merge agent : Rowcount Validation profile  
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(21308) -- Rowcount Validation Profile
    set @profile_desc = formatmessage(21309) -- Rowcount Validation Profile Description

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    /* 
	** Merge agent : Rowcount & Checksum Validation profile  
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(21310) -- Rowcount & Checksum Validation Profile
    set @profile_desc = formatmessage(21311) -- Rowcount & Checksum Validation Profile Description

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE


    /* 
	** Distribution agent, skip error profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20599) -- Default Distribution Profile
    set @profile_desc = formatmessage(20600)

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

	/* 
	** Merge agent : High volume server-to-server profile
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(20616) -- High volume server-to-server profile
    set @profile_desc = formatmessage(20617) -- High volume server-to-server profile Description

    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0

    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    exec @retcode = dbo.sp_generate_agent_parameter @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
        goto FAILURE

    create table msdb.dbo.MSdatatype_mappings 
    (
    dbms_name           sysname NOT NULL,
    sql_type            sysname NOT NULL,
    dest_type           sysname NOT NULL,
    dest_prec           int     NOT NULL,
    dest_create_params  int     NOT NULL,
    dest_nullable       bit     NOT NULL
    )

	-- MS Jet
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'binary' , 'binary', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'varbinary' , 'varbinary', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'binary' , 'image', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'varbinary' , 'image', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS Jet', 'sql_variant' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'varchar' , 'varchar', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'varchar' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'nchar' , 'nchar', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'nchar' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'char' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'char' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'nvarchar' , 'nchar varying', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'nvarchar' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'datetime' , 'datetime', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'smalldatetime' , 'datetime', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'decimal' , 'decimal', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'numeric' , 'decimal', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'float' , 'float', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'real' , 'real', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'bigint' , 'decimal', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'int' , 'int', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'smallint' , 'smallint', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'tinyint' , 'byte', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'money' , 'currency', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'smallmoney' , 'currency', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'bit' , 'bit', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'sysname' , 'nchar varying', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'timestamp' , 'binary', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'uniqueidentifier' , 'guid', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'text' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'ntext' , 'longtext', 1073741824, 0, 1
    exec dbo.sp_add_datatype_mapping 'MS Jet', 'image' , 'image', 1073741824, 0, 1

	-- Oracle
    exec dbo.sp_add_datatype_mapping 'Oracle', 'binary' , 'raw', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'varbinary' , 'raw', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'binary' , 'long raw', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'varbinary' , 'long raw', 2147483647, 0, 1
	exec dbo.sp_add_datatype_mapping 'Oracle', 'sql_variant' , 'long', 2147483647, 0, 1
    --exec dbo.sp_add_datatype_mapping 'Oracle', 'varchar' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'varchar' , 'varchar2', 2000, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'varchar' , 'long', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'nchar' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'nchar' , 'varchar2', 2000, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'nchar' , 'long', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'char' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'char' , 'varchar2', 2000, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'char' , 'long', 2147483647, 0, 1
    --exec dbo.sp_add_datatype_mapping 'Oracle', 'nvarchar' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'nvarchar' , 'varchar2', 2000, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'nvarchar' , 'long', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'datetime' , 'date', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'smalldatetime' , 'date', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'decimal' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'numeric' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'float' , 'float', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'real' , 'float', 255, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'bigint' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'int' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'smallint' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'tinyint' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'money' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'smallmoney' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'bit' , 'number', 255, 3, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'sysname' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'timestamp' , 'raw', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'uniqueidentifier' , 'char', 255, 4, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'text' , 'long', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'ntext' , 'long', 2147483647, 0, 1
    exec dbo.sp_add_datatype_mapping 'Oracle', 'image' , 'long raw', 2147483647, 0, 1

	-- MS SSCE
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'binary' , 'binary', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'varbinary' , 'varbinary', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'binary' , 'image', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'varbinary' , 'image', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'sql_variant' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'varchar' , 'national char varying', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'varchar' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'nchar' , 'nchar', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'nchar' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'char' , 'nchar', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'char' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'nvarchar' , 'national char varying', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'nvarchar' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'datetime' , 'datetime', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'smalldatetime' , 'datetime', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'decimal' , 'numeric', 255, 3, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'numeric' , 'numeric', 255, 3, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'float' , 'float', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'real' , 'real', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'bigint' , 'bigint', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'int' , 'int', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'smallint' , 'smallint', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'tinyint' , 'tinyint', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'money' , 'money', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'smallmoney' , 'money', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'bit' , 'bit', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'sysname' , 'national char varying', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'timestamp' , 'binary', 255, 4, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'uniqueidentifier' , 'uniqueidentifier', 255, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'text' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'ntext' , 'ntext', 1073741824, 0, 1
	exec dbo.sp_add_datatype_mapping 'MS SSCE', 'image' , 'image', 1073741824, 0, 1

	--DB2/400
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'bit', 'SMALLINT', 1,  0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'tinyint', 'SMALLINT', 3, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'smallint', 'SMALLINT', 5, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'int', 'INT', 10, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/400', 'char', 'CHAR', 8000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'varchar', 'VARCHAR', 8000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'smalldatetime', 'TIMESTAMP', 26, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'datetime', 'TIMESTAMP', 26, 0, 1
	
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'real', 'REAL', 24, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'decimal', 'DECIMAL', 31, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'double precision', 'DOUBLE', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'float', 'FLOAT', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'numeric', 'NUMERIC', 31, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/400', 'smallmoney', 'DECIMAL', 10, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'money', 'DECIMAL', 19, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/400', 'varbinary', 'VARCHAR () FOR BIT DATA', 8000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'binary', 'CHAR () FOR BIT DATA', 8000, 4, 1

	exec dbo.sp_add_datatype_mapping 'DB2/400', 'timestamp', 'CHAR () FOR BIT DATA', 8, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'uniqueidentifier', 'CHAR', 38, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'image', 'VARCHAR () FOR BIT DATA', 32739, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/400', 'text', 'VARCHAR', 32739, 4, 1

	--DB2/MVS
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'bit', 'SMALLINT', 1,  0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'tinyint', 'SMALLINT', 3, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'smallint', 'SMALLINT', 5, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'int', 'INT', 10, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'char', 'CHAR', 254, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'varchar', 'VARCHAR', 4045, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'char', 'VARCHAR', 4045, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'smalldatetime', 'TIMESTAMP', 26, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'datetime', 'TIMESTAMP', 26, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'real', 'REAL', 24, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'decimal', 'DECIMAL', 31, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'double precision', 'DOUBLE', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'float', 'FLOAT', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'numeric', 'NUMERIC', 31, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'smallmoney', 'DECIMAL', 10, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'money', 'DECIMAL', 19, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'varbinary', 'VARCHAR () FOR BIT DATA', 4045, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'binary', 'CHAR () FOR BIT DATA', 254, 4, 1

	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'timestamp', 'CHAR () FOR BIT DATA', 8, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'uniqueidentifier', 'CHAR', 38, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'image', 'VARCHAR () FOR BIT DATA', 4045, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/MVS', 'text', 'VARCHAR', 4045, 4, 1

	--DB2/NT
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'bit', 'SMALLINT', 1,  0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'tinyint', 'SMALLINT', 3, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'smallint', 'SMALLINT', 5, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'int', 'INT', 10, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'char', 'CHAR', 254, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'varchar', 'VARCHAR', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'char', 'VARCHAR', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'smalldatetime', 'TIMESTAMP', 26, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'datetime', 'TIMESTAMP', 26, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'real', 'REAL', 24, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'decimal', 'DECIMAL', 31, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'double precision', 'DOUBLE', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'float', 'FLOAT', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'numeric', 'NUMERIC', 31, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'smallmoney', 'DECIMAL', 10, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'money', 'DECIMAL', 19, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'varbinary', 'VARCHAR () FOR BIT DATA', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'binary', 'CHAR () FOR BIT DATA', 254, 4, 1

	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'timestamp', 'CHAR () FOR BIT DATA', 8, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'uniqueidentifier', 'CHAR', 38, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'image', 'VARCHAR () FOR BIT DATA', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/NT', 'text', 'VARCHAR', 4000, 4, 1

	--DB2/6000
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'bit', 'SMALLINT', 1,  0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'tinyint', 'SMALLINT', 3, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'smallint', 'SMALLINT', 5, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'int', 'INT', 10, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'char', 'CHAR', 254, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'varchar', 'VARCHAR', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'char', 'VARCHAR', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'smalldatetime', 'TIMESTAMP', 26, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'datetime', 'TIMESTAMP', 26, 0, 1

	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'real', 'REAL', 24, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'decimal', 'DECIMAL', 31, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'double precision', 'DOUBLE', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'float', 'FLOAT', 53, 0, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'numeric', 'NUMERIC', 31, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'smallmoney', 'DECIMAL', 10, 3, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'money', 'DECIMAL', 19, 3, 1

	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'varbinary', 'VARCHAR () FOR BIT DATA', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'binary', 'CHAR () FOR BIT DATA', 254, 4, 1

	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'timestamp', 'CHAR () FOR BIT DATA', 8, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'uniqueidentifier', 'CHAR', 38, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'image', 'VARCHAR () FOR BIT DATA', 4000, 4, 1
	exec dbo.sp_add_datatype_mapping 'DB2/6000', 'text', 'VARCHAR', 4000, 4, 1

    return 0
FAILURE:
    return 1
go

--------------------------------------------------------------------------------
--.	Common system objects (replsys.sql)
--------------------------------------------------------------------------------

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

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

--
-- proc that is invoked by distribution agent to populate
-- MSsubscription_articles with all the necessary article
-- this is done currently only for queued publications 
--
CREATE PROCEDURE sp_addqueued_artinfo (
	@artid				int
	,@article			sysname
	,@publisher 		sysname
	,@publisher_db		sysname
	,@publication		sysname
	,@dest_table		sysname
	,@owner				sysname
	,@cft_table			sysname
	,@columns			binary(32))
AS
BEGIN
	set nocount on
	declare 	@agent_id int
				,@update_mode int
				,@retcode int

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

create procedure sp_setreplfailovermode (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,
    @failover_mode nvarchar (10), 
    @override tinyint = 0)
as
begin
	set nocount on
	declare	@failover_mode_id tinyint, 
			@current_failover_mode_id bit,
			@retcode int,
			@queue_id sysname,
			@fqueue_empty int,
			@update_mode int,
			@queue_server sysname

	if @failover_mode not in (N'immediate', N'sync', N'queued')
	begin
		raiserror (21184, 16, 1, '@failover_mode', 'immediate', 'sync', 'queued')
		return 1			
	end
	else
	begin
		if @failover_mode = 'immediate' or @failover_mode = 'sync'
			select @failover_mode_id = 0
		else if @failover_mode = 'queued'
			select @failover_mode_id = 1
	end

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

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

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

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

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

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

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

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

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

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

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

--
-- sp_MSupdate_mqserver_subdb
--
-- This procedure is called to upgrade the MSMQ related entries in 
-- MSsubscription_agents in subscription database - this processing 
-- cannot be done directly inside sp_MScreate_sub_tables since we need the 
-- queue_server column for the processing and we can get a syntax error 
-- if the table exists without the column
--
-- Assumption : MSsubscription_agents has been created 
--				and column queue_server exists
--
raiserror('Creating procedure sp_MSupdate_mqserver_subdb', 0,1)
GO
create procedure sp_MSupdate_mqserver_subdb
as
begin
	if exists (select * from dbo.MSsubscription_agents
		where queue_id IS NOT NULL and queue_id != N'mssqlqueue' and queue_server IS NULL)
	begin
		--
		-- we have entries for active Queued subscriptions using MSMQ that need upgrade
		--
		declare @queue_server sysname
				,@publisher sysname
				,@publisher_db sysname
				,@publication sysname

		DECLARE hC CURSOR LOCAL FAST_FORWARD FOR 
			select publisher, publisher_db, publication
			from dbo.MSsubscription_agents
			where queue_id IS NOT NULL 
				and queue_id != N'mssqlqueue' 
				and queue_server IS NULL

		OPEN hC
		FETCH hC INTO @publisher, @publisher_db, @publication
		WHILE (@@fetch_status != -1)
		BEGIN
			--
			-- the table MSsubscription_properties has to exist;
			-- prepare the queue server name from distributor name
			-- strip the instance name if necessary
			--
			select @queue_server = ISNULL(distributor, @@servername)
			from dbo.MSsubscription_properties
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			if (charindex(N'\', @queue_server) > 0)
				select @queue_server = substring(@queue_server, 1, charindex(N'\', @queue_server) - 1)

			--
			-- set the queue_server for this entry
			--
			update dbo.MSsubscription_agents
			set queue_server = @queue_server
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			--
			-- get next entry
			--
			FETCH hC INTO @publisher, @publisher_db, @publication
		END
		CLOSE hC
		DEALLOCATE hC
	end
end
go
exec dbo.sp_MS_marksystemobject sp_MSupdate_mqserver_subdb
go

grant exec on dbo.sp_MSupdate_mqserver_subdb to public
go

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

raiserror('Creating function fn_replinttobitstring', 0,1)
go

--
-- Name: fn_replinttobitstring
-- 
-- Description: This function returns the bit pattern in string format for 
--              the specified 32-bit integer. For example, select 
--              fn_replinttobitstring(0x80000001) would yield
--              '10000000000000000000000000000001'
--
-- Parameter:   @number int
--
-- Returns:     char(32)
--
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replinttobitstring(
    @number int
    ) returns char(32)
as
begin

    declare @bitstring nvarchar(32)

    if (@number & 0x80000000) <> 0 select @bitstring = '1' else select @bitstring = '0'
    if (@number & 0x40000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x20000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x10000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x08000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x04000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x02000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x01000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00800000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00400000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00200000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00100000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00080000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00040000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00020000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00010000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00008000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00004000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00002000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00001000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000800) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000400) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000200) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000100) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000080) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000040) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000020) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000010) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000008) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000004) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000002) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000001) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'

    return @bitstring
end
go
grant execute on system_function_schema.fn_replinttobitstring to public
go

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

raiserror('Creating function fn_replbitstringtoint', 0,1)
go

--
-- Name: fn_replbitstringtoint
--
-- Description: This function returns the integer value of the specified
--              32-bit bit pattern in string format.
--
-- Parameter:   @bitstring char(32)
--
-- Notes:
--
-- Returns:     int
--
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replbitstringtoint(
    @bitstring char(32)
    ) returns int
as
begin
    declare @number int 
    select @number = 0
    if (substring(@bitstring,1,1) = '1') select @number = @number | 0x80000000 
    if (substring(@bitstring,2,1) = '1') select @number = @number | 0x40000000 
    if (substring(@bitstring,3,1) = '1') select @number = @number | 0x20000000 
    if (substring(@bitstring,4,1) = '1') select @number = @number | 0x10000000 
    if (substring(@bitstring,5,1) = '1') select @number = @number | 0x08000000 
    if (substring(@bitstring,6,1) = '1') select @number = @number | 0x04000000 
    if (substring(@bitstring,7,1) = '1') select @number = @number | 0x02000000 
    if (substring(@bitstring,8,1) = '1') select @number = @number | 0x01000000 
    if (substring(@bitstring,9,1) = '1') select @number = @number | 0x00800000 
    if (substring(@bitstring,10,1) = '1') select @number = @number | 0x00400000 
    if (substring(@bitstring,11,1) = '1') select @number = @number | 0x00200000 
    if (substring(@bitstring,12,1) = '1') select @number = @number | 0x00100000 
    if (substring(@bitstring,13,1) = '1') select @number = @number | 0x00080000 
    if (substring(@bitstring,14,1) = '1') select @number = @number | 0x00040000 
    if (substring(@bitstring,15,1) = '1') select @number = @number | 0x00020000 
    if (substring(@bitstring,16,1) = '1') select @number = @number | 0x00010000 
    if (substring(@bitstring,17,1) = '1') select @number = @number | 0x00008000 
    if (substring(@bitstring,18,1) = '1') select @number = @number | 0x00004000 
    if (substring(@bitstring,19,1) = '1') select @number = @number | 0x00002000 
    if (substring(@bitstring,20,1) = '1') select @number = @number | 0x00001000 
    if (substring(@bitstring,21,1) = '1') select @number = @number | 0x00000800 
    if (substring(@bitstring,22,1) = '1') select @number = @number | 0x00000400 
    if (substring(@bitstring,23,1) = '1') select @number = @number | 0x00000200 
    if (substring(@bitstring,24,1) = '1') select @number = @number | 0x00000100 
    if (substring(@bitstring,25,1) = '1') select @number = @number | 0x00000080 
    if (substring(@bitstring,26,1) = '1') select @number = @number | 0x00000040 
    if (substring(@bitstring,27,1) = '1') select @number = @number | 0x00000020 
    if (substring(@bitstring,28,1) = '1') select @number = @number | 0x00000010 
    if (substring(@bitstring,29,1) = '1') select @number = @number | 0x00000008 
    if (substring(@bitstring,30,1) = '1') select @number = @number | 0x00000004 
    if (substring(@bitstring,31,1) = '1') select @number = @number | 0x00000002 
    if (substring(@bitstring,32,1) = '1') select @number = @number | 0x00000001 
    return @number
end
go
grant execute on system_function_schema.fn_replbitstringtoint to public
go


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

raiserror('Creating function fn_replrotr', 0,1)
go

--
-- Name: fn_replrotr
--
-- Description: This is just a T-SQL implementation of the C function
--              _rotr().
--
-- Parameter:  @number int
--             @shift  int
--
-- Notes:      The effective shift will the positive remainder of @shift 
--             divided by 32. _rotl() can be implemented by passing in 
--             a negative shift.
--
-- Returns:    int
--
-- Security:   Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replrotr(
    @number int,
    @shift int
    ) returns int
as
begin
    declare @bitstring char(32)
    select @shift = @shift % 32
    if @shift < 0
        select @shift = @shift + 32

    if (@shift != 0)
    begin
        select @bitstring = fn_replinttobitstring(@number)   
        select @bitstring = substring(@bitstring,32-@shift+1,@shift) + substring(@bitstring,1,32-@shift) 
        select @number = fn_replbitstringtoint(@bitstring)
    end
    return @number
end
go
grant execute on system_function_schema.fn_replrotr to public


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

raiserror('Creating function fn_repltrimleadingzerosinhexstr', 0,1)
go

-- 
-- Name: fn_repltrimleadingzerosinhexstr
--
-- Description: This function is used for trimming the leading zeros 
--              of a 32-bit hexadecimal string. For example,
--              select fn_repltrimleadingzerosinhexstr('0000abcd') would 
--              yield 'abcd'. A notable special case would be select
--              fn_repltrimleadingzerosinhexstr('00000000') which yields
--              the string '0' instead of ''.
--
-- Parameter:   @hexstr  nchar(8) - @hexstr is expected to be a full 
--              hexadecimal representation of a 32-bit integer without the
--              0x prefix
--
-- Notes: 
--
-- Returns:     nvarchar(8)
-- 
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_repltrimleadingzerosinhexstr (
    @hexstr nchar(8)
    ) returns nvarchar(8)
as
begin
    declare @trimmed_hexstr nvarchar(8),
            @i int    
    select @i = 1
    while @i < 8
    begin
        if substring(@hexstr,@i,1) <> N'0'
            break;
        select @i = @i + 1
    end    
    select @trimmed_hexstr = substring(@hexstr,@i,8-@i+1)
    return @trimmed_hexstr
end
go
grant execute on system_function_schema.fn_repltrimleadingzerosinhexstr to public
go


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

raiserror('Creating function fn_replgenerateshorterfilenameprefix', 0,1)
go

--
-- Name: fn_replgenerateshorterfilenameprefix
--
-- Description: This function mimics the algorithm used by the snapshot 
--              agent to shorten any overly long component of a publication
--              snapshot folder with "overly long" defined as more than
--              30 characters in length (as specified in the @truncated_len
--              parameter of this function). 
--                
-- Parameters:  @prefix nvarchar(4000)
--              @truncated_len int
--
-- Notes:
--
-- Returns: nvarchar(4000)
--
-- Security: Execute permission on this function is granted to public.
--
create function system_function_schema.fn_replgenerateshorterfilenameprefix(
    @prefix nvarchar(4000),
    @truncated_len int
    ) returns nvarchar(4000)
as
begin
    declare @HashValueIndex int,
            @HashValue int,
            @CurrentByte tinyint,
            @TruncatedString varbinary(8000),
            @i int,
            @TruncatedStringLen int,
            @prefix_to_be_returned nvarchar(4000)

    select @prefix_to_be_returned = @prefix
    if (len(@prefix) > @truncated_len)
    begin
        select @TruncatedString = convert(varbinary(8000),substring(@prefix,@truncated_len-8+1,len(@prefix)-@truncated_len+8))
        select @TruncatedStringLen = len(@TruncatedString)
        select @HashValue = 0
        select @i = 1
        select @HashValueIndex = 0
        while @i <= @TruncatedStringLen
        begin
            select @CurrentByte = convert(tinyint,substring(@TruncatedString,@i,1))
            select @HashValue = @HashValue ^ fn_replrotr(@CurrentByte, -(8*@HashValueIndex))
            select @HashValue = fn_replrotr(@HashValue, @HashValueIndex + 1)
            if @CurrentByte != 0
            begin
                select @HashValueIndex = (@HashValueIndex + 1) % 4
            end
            select @i = @i + 1
        end
        select @prefix_to_be_returned = substring(@prefix,1,@truncated_len-8) 
        select @prefix_to_be_returned = @prefix_to_be_returned + lower(fn_repltrimleadingzerosinhexstr(substring(master.dbo.fn_varbintohexstr(convert(varbinary(4),@HashValue)) collate database_default,3,8)) collate database_default)
    end
    return @prefix_to_be_returned
end
go
grant execute on system_function_schema.fn_replgenerateshorterfilenameprefix to public      
go

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

raiserror('Creating function fn_replcomposepublicationsnapshotfolder', 0,1)
go

--
-- Name: fn_replcomposepublicationsnapshotfolder
--
-- Description: This mimics the algorithm used by the snapshot agent for 
--              composing the name of a publication's snapshot folder.
--
-- Parameters:  @publisher    sysname
--              @publisher_db sysname 
--              @publication  sysname
--
-- Notes: 
--
-- Returns: nvarchar(255)
--
-- Security: Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replcomposepublicationsnapshotfolder(
    @publisher     sysname,
    @publisher_db  sysname,
    @publication   sysname
) returns nvarchar(255)
as
begin
    declare @snapshot_folder_name nvarchar(255)
    
    select @snapshot_folder_name = fn_replgenerateshorterfilenameprefix(@publisher,30) collate database_default + N'_' +
                                   fn_replgenerateshorterfilenameprefix(@publisher_db,30) collate database_default + N'_' +
                                   fn_replgenerateshorterfilenameprefix(@publication,30) collate database_default
    return @snapshot_folder_name
end
go
grant execute on system_function_schema.fn_replcomposepublicationsnapshotfolder to public
go

--------------------------------------------------------------------------------
--. xp_updatelineage (obsolete xp - will be removed)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
		where name = 'xp_updatelineage' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_updatelineage'
go

--------------------------------------------------------------------------------
--. xp_initcolvs (obsolete xp - will be removed)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
		where name = 'xp_initcolvs' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_initcolvs'
go

--------------------------------------------------------------------------------
--. xp_updatecolvbm (obsolete xp - will be removed)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
		where name = 'xp_updatecolvbm' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_updatecolvbm'
go


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

--
-- Name: sp_MSdroparticleconstraints
--
-- Description: This procedure is used by the Distribution Agent to purge all
--              the existing check, PK, UK, and FK constraints on a table
--              article at the Subscriber.
--
-- Parameters:  @destination_object sysname (mandatory)
--              @destination_owner sysname (mandatory)
-- 
-- Returns: 0 - succeeded
--          1 - failed
-- 
-- Security: Procedural security check is done inside this procedure
--           to make sure that the caller is either a member of the db_owner
--           role of the subscriber database or a member of the sysadmin role
--           of the subscription server 
--
create procedure dbo.sp_MSdroparticleconstraints (
    @destination_object sysname,
    @destination_owner sysname
    )
as
begin
    set nocount on
    declare @retcode      int,
            @objid        int,
            @constid      int,
            @drop_command nvarchar(4000),
            @qualified_tablename nvarchar(540),
            @publish_bit  int,
            @mergepublish_bit int

    
    select @retcode             = 0,
           @objid               = null,
           @constid             = null,
           @drop_command        = null,
           @qualified_tablename = null,
           @publish_bit         = 1,
           @mergepublish_bit    = 128

    -- Security check
    exec @retcode = sp_MSreplcheck_subscribe
    if @retcode<>0 or @@error<>0
        return 1

    -- Get object id of the target table
    select @objid = id 
      from sysobjects
     where name = @destination_object
       and (user_name(uid) = @destination_owner 
            or @destination_owner is null 
            or @destination_owner = N'')

    -- If the object is not at the subscriber, there isn't anything we 
    -- can(or need to)  do
    if @objid is null 
        return 0

    select @qualified_tablename = 
            N'['+replace(@destination_object,N']',N']]')+N']'

    if @destination_owner is not null and @destination_owner<>N''
    begin
        select @qualified_tablename = 
            N'['+replace(@destination_owner,N']',N']]')+N'].'+@qualified_tablename
    end

    -- Skip constraint dropping for republished article
    if exists (select * 
                 from sysobjects 
                where id = @objid
                  and ((replinfo & @publish_bit <> 0) or
                       (replinfo & @mergepublish_bit <> 0)))
    begin
        return 0
    end

    declare hConst cursor local fast_forward for
     select constid 
       from sysconstraints 
      where id = @objid
    if @@error<>0
        return 1

    open hConst
    if @@error<>0
        return 1
    
    fetch hConst into @constid 
    while (@@fetch_status<>-1)
    begin
    
        if objectproperty(@constid,N'IsUniqueCnst') = 1 or
           objectproperty(@constid,N'IsPrimaryKey') = 1 or
           objectproperty(@constid,N'IsCheckCnst') = 1 or
           objectproperty(@constid,N'IsForeignKey') = 1
        begin
            select @drop_command = 
                N'alter table '+@qualified_tablename+' drop constraint '+object_name(@constid)
            exec(@drop_command)
            if @@error <> 0
                return 1
        end
        fetch hConst into @constid        
    end
    close hConst
    deallocate hConst

    return @retcode

end
go

exec sp_MS_marksystemobject sp_MSdroparticleconstraints
go

grant execute on sp_MSdroparticleconstraints to public 
go


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

raiserror('Creating function fn_generateparameterpattern', 0,1)
go

--
-- Name: fn_generateparameterpattern
--
-- Description: Given the name of a parameter (excluding the leading / or -), 
--              this function will return the pattern for matching the
--              parameter in a case-insensitive manner. For example
--  
--              select fn_generateparameterpattern(N'Ouptut')
-- 
--              will return
--
--              %[-/][Oo][Uu][Tt][Pp][Uu][Tt]%
--
-- Parameters: @parameter nvarchar(200)
--             
-- Notes: The leading / or - should be omitted from @parameter
--
-- Returns: nvarchar(806)
--
-- Security: Execute permission of this function is granted to public 
--
print 'Creating function fn_generateparameterpattern'
print ''
go
create function system_function_schema.fn_generateparameterpattern(
    @parameter nvarchar(200)
    ) returns nvarchar(806)
begin
    declare @pattern          nvarchar(806)
    declare @parameter_length int
    declare @i                int
    declare @c                nvarchar(1)

    select @pattern = N'%[-/]'
    select @i = 1
    select @parameter_length = len(@parameter)
    
    while @i <= @parameter_length
    begin
    select @c = substring(@parameter, @i, 1)        
    select @pattern = @pattern + N'[' + upper(@c collate SQL_Latin1_General_CP1_CS_AS) + lower(@c collate SQL_Latin1_General_CP1_CS_AS) + N']'
        select @i = @i + 1
    end 
    select @pattern = @pattern + '%'
    return @pattern
end
go

grant execute on system_function_schema.fn_generateparameterpattern to public
go

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

	/* This is to make sure that the varbinary columns do not get padded */

	set ANSI_PADDING off

	DECLARE @exist bit 
	DECLARE @validsubs  int
	select @exist = 1
	
	begin tran
	save transaction MScreate_mergesystables

	exec dbo.sp_MScheckvalidsystables  @validsubs  output
	if @validsubs = 0
		exec dbo.sp_MSdrop_mergesystables
		
	if not exists (select * from sysobjects where name = 'sysmergepublications')
		begin

			raiserror('Creating table sysmergepublications',0,1)
			
			create table dbo.sysmergepublications
			(	publisher				sysname NOT NULL default @@servername,
				publisher_db			sysname NOT NULL default db_name(),
				name					sysname				NOT NULL,
				description				nvarchar(255) 		NULL,
				retention				int					NULL,
				publication_type 		tinyint				NULL,
				pubid 					uniqueidentifier 	NOT NULL,
				designmasterid			uniqueidentifier 	NULL,
				parentid				uniqueidentifier 	NULL,
				sync_mode				tinyint				NULL,
				allow_push				int					NULL,
				allow_pull				int					NULL,
				allow_anonymous			int					NULL,
				centralized_conflicts	int					NULL,
				status					tinyint				NULL,
				snapshot_ready			tinyint				NULL,
		        enabled_for_internet    bit                	NOT NULL default 0,
				dynamic_filters			bit					NOT NULL default 0,
                -- portable snapshot support
                snapshot_in_defaultfolder   bit             NOT NULL default 1,
                alt_snapshot_folder         nvarchar(255)   NULL,
                -- Pre/post - snapshot commands
                pre_snapshot_script         nvarchar(255)   NULL,
                post_snapshot_script        nvarchar(255)   NULL,
                -- Snapshot compression
                compress_snapshot           bit             NOT NULL default 0,
                -- Post 7.0 Ftp support
                ftp_address                 sysname         NULL,
                ftp_port                    int             NOT NULL default 21,
                ftp_subdirectory            nvarchar(255)   NULL,
                ftp_login                   sysname         NULL default N'anonymous',
                ftp_password                nvarchar(524)   NULL,
                conflict_retention			int				NULL,
                keep_before_values			int				NULL default 0,
				allow_subscription_copy		bit 			NULL default 0, 	
				allow_synctoalternate		bit 			NULL default 0,
				validate_subscriber_info	nvarchar(500)	NULL,
				ad_guidname					sysname			NULL,
                backward_comp_level			int				not NULL default 10, --7.0 RTM
				max_concurrent_merge		int				not NULL default 0,
                max_concurrent_dynamic_snapshots int        not NULL default 0
			)
			if @@ERROR <> 0
				goto Error
			
			CREATE UNIQUE NONCLUSTERED INDEX nc1sysmergepublications 
				ON sysmergepublications(pubid)
			if @@ERROR <> 0
				goto Error

			exec dbo.sp_MS_marksystemobject sysmergepublications
			if @@ERROR <> 0
				goto Error
			-- grant select on sysmergepublications to public
		end

	if not exists (select * from sysobjects where name = 'MSmerge_errorlineage')
		begin		
			raiserror('Creating table MSmerge_errorlineage',0,1)
			
			create table dbo.MSmerge_errorlineage (
			tablenick		int NOT NULL,
			rowguid			uniqueidentifier NOT NULL,
			lineage			varbinary(255)
			)
			exec dbo.sp_MS_marksystemobject MSmerge_errorlineage
			if @@ERROR <> 0
				goto Error
			create unique clustered index uc1errorlineage on MSmerge_errorlineage(tablenick, rowguid)
			if @@ERROR <> 0
				goto Error
			
			grant select on MSmerge_errorlineage to public
		end

	-- this table exists at distribution/db and subscriber databse both
	if not exists (select * from sysobjects where name = 'MSrepl_identity_range')
		begin		
			raiserror('Creating table MSrepl_identity_range',0,1)
			
			create table dbo.MSrepl_identity_range (
			objid					int not NULL primary key,
			next_seed				bigint NULL, --resource control
			pub_range				bigint NULL, --publisher range
			range					bigint NULL, -- set by sp_addmergearticle
			max_identity			bigint NULL, --resource control
			threshold				int	NULL,	--in percentage, set by sp_addmergearticle
			current_max				bigint NULL	--max value for current check constraint,set by sp_addmergearticle
			)
			exec dbo.sp_MS_marksystemobject MSrepl_identity_range
			if @@ERROR <> 0
				goto Error

			grant select on MSrepl_identity_range to public
		end

	if not exists (select * from sysobjects where name = 'sysmergearticles')
		begin
		
			raiserror('Creating table sysmergearticles',0,1)

			
			create table dbo.sysmergearticles (
				name					sysname				NOT NULL,
		        type        			tinyint       	 	NULL,
				objid					int					NOT NULL, 
				sync_objid				int					NOT NULL,
				view_type 				tinyint				NULL,
				artid					uniqueidentifier	NOT NULL,
				description    			nvarchar(255)    	NULL,
				pre_creation_command	tinyint				NULL,
				pubid					uniqueidentifier 	NOT NULL,
				nickname				int					NOT NULL,
				column_tracking			int					NOT NULL,
				status					tinyint				NULL,
				conflict_table			sysname				NULL,
				creation_script			nvarchar(255)		NULL,
				conflict_script			nvarchar(255)		NULL,
				article_resolver		nvarchar(255)		NULL,
				ins_conflict_proc		sysname				NULL,
				insert_proc				sysname				NULL,
				update_proc				sysname				NULL,
				select_proc				sysname				NULL,
		        schema_option 			binary(8) 			NULL,
				destination_object		sysname				NOT NULL,
				destination_owner		sysname				NULL,
				resolver_clsid			nvarchar(50)		NULL,
				subset_filterclause    	nvarchar(1000)  	NULL,
				missing_col_count		int					NULL,
				missing_cols			varbinary(128)		NULL,
				excluded_cols			varbinary(128)		NULL,
				excluded_col_count		int					not NULL default 0,
				columns        			varbinary(128)   	NULL,
				resolver_info			nvarchar(255)		NULL,
				view_sel_proc			nvarchar(290)		NULL,
				gen_cur					int					NULL,
				vertical_partition		int					not NULL default 0,
				identity_support		int					not NULL default 0,
				before_image_objid		int					NULL,
				before_view_objid		int					NULL,
				verify_resolver_signature 		int			NULL,
				allow_interactive_resolver		bit			NOT NULL default 0,
				fast_multicol_updateproc		bit			NOT NULL default 0,
				check_permissions		int					NOT NULL default 0,
				maxversion_at_cleanup	int					NOT NULL default 1
                -- Note: Please update sysmergeextendedarticlesview whenever
                -- there is a schema change in sysmergearticles
			)
		
			if @@error<>0
				goto Error
			else
				begin
					
					create unique clustered index uc1sysmergearticles
						on sysmergearticles(artid, pubid) 
					if @@ERROR <> 0
						goto Error
					
					if not exists (select * from sysindexes where name = 'nc1sysmergearticles')
					begin
						create nonclustered index nc1sysmergearticles on sysmergearticles(nickname) 
						if @@ERROR <> 0
						return 1
					end
				end
			exec dbo.sp_MS_marksystemobject sysmergearticles
			if @@ERROR <> 0
				goto Error
			grant select on sysmergearticles to public
			
		end

    if not exists (select * from sysobjects where name = 'sysmergeschemaarticles')
        begin
            
            -- The extended merge articles table is for storing 
            -- schema only article information. 
            -- The current supported schema only articles are
            -- stored procs and views.
            raiserror('Creating table sysmergeschemaarticles',0,1)

            create table dbo.sysmergeschemaarticles 
            (   name                    sysname             NOT NULL,
                type                    tinyint             NULL,
                objid                   int                 NOT NULL,
                artid                   uniqueidentifier    NOT NULL,
                description             nvarchar(255)       NULL,
                pre_creation_command    tinyint             NULL,
                pubid                   uniqueidentifier    NOT NULL,
                status                  tinyint             NULL,
                creation_script         nvarchar(255)       NULL,
                schema_option           binary(8)           NULL,
                destination_object      sysname             NOT NULL,
                destination_owner       sysname             NULL
                -- Note: Please update sysmergeextendedarticlesview whenever
                -- there is a schema change in sysmergeschemaarticles
            )
            
            if @@error<>0
                goto Error
            else
                begin
                    create unique clustered index uc1sysmergeschemaarticles
                        on sysmergeschemaarticles(artid, pubid)
                        if @@ERROR <> 0
                            goto Error
                end

            exec dbo.sp_MS_marksystemobject sysmergeschemaarticles
            if @@ERROR <> 0
                goto Error

        end

    if exists (select * from sysobjects where name = 'sysmergeextendedarticlesview')
    begin
        drop view dbo.sysmergeextendedarticlesview
    end
    exec ('create view dbo.sysmergeextendedarticlesview
               as
           select name, type, objid, sync_objid, view_type, artid, description, pre_creation_command, pubid,
				  nickname, column_tracking, status, conflict_table, creation_script, conflict_script, article_resolver,
				  ins_conflict_proc, insert_proc, update_proc, select_proc, schema_option, destination_object,
				  resolver_clsid, subset_filterclause, missing_col_count, missing_cols, columns, resolver_info,
				  view_sel_proc, gen_cur, excluded_cols, excluded_col_count, vertical_partition, identity_support,
			      destination_owner, before_image_objid, before_view_objid, verify_resolver_signature, 
				  allow_interactive_resolver, fast_multicol_updateproc, check_permissions, maxversion_at_cleanup
		   from sysmergearticles
	       union all
           select name, type, objid, NULL, NULL, artid, description, pre_creation_command, pubid, 
				  NULL, NULL, status, NULL, creation_script, NULL, NULL, 
				  NULL, NULL, NULL, NULL, schema_option, destination_object, 
				  NULL, NULL, NULL, NULL, NULL, NULL, 
				  NULL, NULL, NULL, NULL, NULL, NULL, 
				  destination_owner, NULL, NULL, NULL, 
				  0, 0, 0, NULL
				  from sysmergeschemaarticles
                  go')            
    if @@error <> 0
        goto Error

    exec dbo.sp_MS_marksystemobject sysmergeextendedarticlesview

	if not exists (select * from sysobjects	where name = 'sysmergesubscriptions')
		begin
		
			raiserror('Creating table sysmergesubscriptions',0,1)

			
			create table dbo.sysmergesubscriptions
			(
				subid     			uniqueidentifier 	NOT NULL,
				partnerid 			uniqueidentifier 	NOT NULL,
				datasource_type		int					NOT NULL,
				datasource_path		nvarchar(255)		NULL,
				srvid	     		int					NOT NULL,
				db_name		  		sysname		 		NOT NULL
				constraint 			unique_pubsrvdb 	unique nonclustered (pubid, srvid, db_name),
				pubid				uniqueidentifier 	NULL,
				status    			tinyint     		NOT NULL,
				subscriber_type		int					NOT NULL,
				subscription_type	int					NOT NULL,
				priority			real				NOT NULL,
				sync_type 			tinyint				NOT NULL,	-- 1 = automatic 2 = no sync
				description			nvarchar(255)		NULL,
				login_name			sysname				NOT NULL,
				last_validated		datetime			NULL,
				subscriber_server	sysname				NULL,
				use_interactive_resolver		bit		NOT NULL default 0,
				publication			sysname			 	NULL,
				distributor			sysname			 	NULL,
				validation_level	int					not NULL default 0,
				resync_gen			int					not NULL default -1,
				attempted_validate	datetime			NULL,
				last_sync_date		datetime			NULL,
				last_sync_status	int					NULL,
				last_sync_summary	sysname				NULL
			)
		
			if @@error<>0
				goto Error
			else
				begin
					create unique clustered index uc1sysmergesubscriptions 
						on sysmergesubscriptions (subid) 
					if @@ERROR<>0
						goto Error

					create index nc2sysmergesubscriptions on sysmergesubscriptions (srvid, db_name)
					if @@ERROR<>0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject sysmergesubscriptions
			if @@ERROR <> 0
				goto Error
			grant select on sysmergesubscriptions to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_replinfo')
		begin
			raiserror('Creating table MSmerge_replinfo',0,1)
			
			create table dbo.MSmerge_replinfo
			(
				repid     				uniqueidentifier 	NOT NULL,
				replnickname			int					NOT NULL,
				recgen					int     			NULL,
				recguid					uniqueidentifier 	NULL,
				sentgen					int     			NULL,
				sentguid				uniqueidentifier 	NULL,
				schemaversion			int     			NULL,
				schemaguid				uniqueidentifier 	NULL,
				merge_jobid				binary(16)			NULL,
				snapshot_jobid			binary(16)			NULL
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create unique clustered index uc1MSmerge_replinfo
						on MSmerge_replinfo (repid)
					if @@ERROR <> 0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject MSmerge_replinfo
			if @@ERROR <> 0
				goto Error
			grant select on MSmerge_replinfo to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_tombstone')
		begin
			raiserror('Creating table MSmerge_tombstone',0,1)
			
			create table dbo.MSmerge_tombstone
			(
				rowguid			uniqueidentifier rowguidcol NOT NULL,
				tablenick		int				NOT NULL,
				type			tinyint			NOT NULL,
				lineage			varbinary(249)	NOT NULL,
				generation		int				NOT NULL,
				reason			nvarchar(255)	NOT NULL,
			)

			if @@ERROR <> 0
				goto Error
			else
			begin
				create unique clustered index uc1MSmerge_tombstone
					on MSmerge_tombstone (tablenick DESC, rowguid) 
				if @@ERROR <> 0	goto Error
				
				create index nc2MSmerge_tombstone
					on MSmerge_tombstone (generation) 
				if @@ERROR <> 0	goto Error
			end	
	
			 exec dbo.sp_MS_marksystemobject MSmerge_tombstone
			 if @@ERROR <> 0
				goto Error
			grant select on MSmerge_tombstone to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_contents')
		begin
			raiserror('Creating table MSmerge_contents',0,1)
			
			create table dbo.MSmerge_contents
			(
				tablenick		int					NOT NULL,
				rowguid			uniqueidentifier rowguidcol   NOT NULL,
				generation		int					NOT NULL,
				partchangegen	int					NULL,
				joinchangegen	int					NULL,
				lineage			varbinary(249)		NOT NULL,
				colv1			varbinary(2048)		NULL,
			)
		
			if @@ERROR <> 0
				goto Error
			else
			begin
				create unique clustered index uc1SycContents on MSmerge_contents(tablenick, rowguid)
				if @@ERROR <> 0 goto Error
				create index nc2MSmerge_contents on MSmerge_contents(generation) 
				if @@ERROR <> 0 goto Error
				create index nc3MSmerge_contents on MSmerge_contents(partchangegen) 
				if @@ERROR <> 0 goto Error
				create index nc4MSmerge_contents on MSmerge_contents(rowguid) 
				if @@ERROR <> 0 goto Error
			end
			exec dbo.sp_MS_marksystemobject MSmerge_contents
			if @@ERROR <> 0
				goto Error
			grant select on MSmerge_contents to public
			
		end				

	if not exists (select * from sysobjects	where name = 'MSmerge_genhistory')
		begin
			raiserror('Creating table MSmerge_genhistory',0,1)
			
			create table dbo.MSmerge_genhistory
			(
				guidsrc 		uniqueidentifier 	NOT NULL,
				guidlocal 		uniqueidentifier 	NOT NULL,
				pubid			uniqueidentifier 	NULL,
				generation 		int					NOT NULL,
				art_nick		int					NULL,
				nicknames		varbinary(1000)		NOT NULL,
				coldate 		datetime			NOT NULL
			)
					
			if @@ERROR <> 0
				goto Error

			create clustered index c1MSmerge_genhistory on MSmerge_genhistory(generation) 
			if @@ERROR <> 0
				goto Error

			create unique index unc1MSmerge_genhistory on MSmerge_genhistory(guidsrc, pubid) 
			if @@ERROR <> 0
				goto Error

			create  index nc2MSmerge_genhistory on MSmerge_genhistory(guidlocal) 
			if @@ERROR <> 0
				goto Error

			CREATE INDEX nc4MSmerge_genhistory ON MSmerge_genhistory(coldate)		
			if @@ERROR <> 0
				goto Error

			 exec dbo.sp_MS_marksystemobject MSmerge_genhistory
			 if @@ERROR <> 0
				goto Error
			grant select on MSmerge_genhistory to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_delete_conflicts')
		begin

			raiserror('Creating table MSmerge_delete_conflicts',0,1)
			
			create table dbo.MSmerge_delete_conflicts
			(
				tablenick			int				NOT NULL,
				rowguid				uniqueidentifier rowguidcol NOT NULL,
				origin_datasource	nvarchar(255)	NULL,
				conflict_type		int NULL,
				reason_code			int NULL,
				reason_text			nvarchar(720) 	NULL,
				pubid				uniqueidentifier NULL,
				create_time			datetime not null default getdate()
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create clustered index uc1MSmerge_delete_conflicts on MSmerge_delete_conflicts(tablenick, rowguid) 
					if @@ERROR <> 0
						goto Error
				end					

			CREATE UNIQUE NONCLUSTERED INDEX nc1MSmerge_delete_conflicts 
					ON MSmerge_delete_conflicts(tablenick, rowguid, origin_datasource)
			if @@ERROR <> 0
						goto Error

			exec dbo.sp_MS_marksystemobject MSmerge_delete_conflicts
			if @@ERROR <> 0
				goto Error
			grant select on MSmerge_delete_conflicts to public
			
		end

	if not exists (select * from sysobjects	where name = 'sysmergeschemachange')
		begin
		
			raiserror('Creating table sysmergeschemachange',0,1)
			
			create table dbo.sysmergeschemachange
			(
				pubid			uniqueidentifier 	NOT NULL,
				artid			uniqueidentifier 	NULL,
				schemaversion 	int 	   		NOT NULL,
				schemaguid    	uniqueidentifier 	NOT NULL,
				schematype		int		  		NOT NULL,
				schematext		nvarchar(2000) 	NOT NULL
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create unique clustered index schemachangeversion on sysmergeschemachange(schemaversion, pubid) 
					if @@ERROR <> 0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject sysmergeschemachange
			if @@ERROR <> 0
				goto Error
			grant select on sysmergeschemachange to public
			
		end

	if not exists (select * from sysobjects where name = 'sysmergesubsetfilters')
		begin
			raiserror('Creating table sysmergesubsetfilters',0,1)

			
			create table dbo.sysmergesubsetfilters (
                filtername              sysname		         NOT NULL,
                join_filterid			int					identity NOT NULL,
				pubid					uniqueidentifier	NOT NULL,
				artid					uniqueidentifier	NOT NULL,
				art_nickname			int					NOT NULL,
				join_articlename		sysname NOT NULL,
				join_nickname 			int					NOT NULL,
				join_unique_key			int					NOT NULL,
				expand_proc				sysname					NULL,
				join_filterclause    	nvarchar(1000)  		NULL
			)
			if @@ERROR <> 0
				goto Error

			CREATE UNIQUE NONCLUSTERED INDEX nc1sysmergesubsetfilters 
				ON sysmergesubsetfilters(join_filterid, pubid)
			if @@ERROR <> 0
				goto Error

			exec dbo.sp_MS_marksystemobject sysmergesubsetfilters
			if @@ERROR <> 0
				goto Error
			grant select on sysmergesubsetfilters to public
			
		end

	if @@error <> 0
		goto Error

    if not exists (select * from sysobjects where name = 'MSdynamicsnapshotviews')
        begin
            raiserror('Creating table MSdynamicsnapshotviews',0,1)
            
            create table dbo.MSdynamicsnapshotviews (
                dynamic_snapshot_view_name sysname primary key
            )
            if @@ERROR <> 0
                goto Error
            exec dbo.sp_MS_marksystemobject MSdynamicsnapshotviews
        end

    if not exists (select * from sysobjects where name = 'MSdynamicsnapshotjobs')
        begin
            raiserror('Creating table MSdynamicsnapshotjobs',0,1)
        
            create table dbo.MSdynamicsnapshotjobs (
                id int identity, 
                name sysname not null unique,
                pubid uniqueidentifier not null,
                job_id uniqueidentifier not null,
                dynamic_filter_login sysname null,
                dynamic_filter_hostname sysname null,
                dynamic_snapshot_location nvarchar(255) not null
            )
            if @@ERROR <> 0
                goto Error

            exec dbo.sp_MS_marksystemobject MSdynamicsnapshotjobs

            create unique clustered index uciMSdynamicsnapshotjobs on 
                dbo.MSdynamicsnapshotjobs(job_id, pubid)
            
            if @@ERROR <> 0
                goto Error


        end
    
    if @@error <> 0
        goto Error

    if not exists (select * from sysobjects where name = 'MSmerge_altsyncpartners')
        begin
            raiserror('Creating table MSmerge_altsyncpartners',0,1)
        
            create table dbo.MSmerge_altsyncpartners (
                subid 				uniqueidentifier 	not null,
                alternate_subid 	uniqueidentifier 	not null,
                description			nvarchar(255)		NULL

            )
            if @@ERROR <> 0
                goto Error

            exec dbo.sp_MS_marksystemobject MSmerge_altsyncpartners

            create unique clustered index uciMSmerge_altsyncpartners on 
                dbo.MSmerge_altsyncpartners(subid, alternate_subid)
            
            if @@ERROR <> 0
                goto Error


        end
    

	if exists (select * from master..sysobjects where type='P' and name='sp_MScreatedebuginfrastructure')
	begin
		declare @retval int
		exec @retval= dbo.sp_MScreatedebuginfrastructure
		if @@ERROR <> 0 or @retval <> 0 goto Error
	end
	
	commit transaction
	return (0)
Error:
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION MScreate_mergesystables
		COMMIT TRANSACTION
	end
	RAISERROR (20008, 16, -1)
	return (1)
go

exec dbo.sp_MS_marksystemobject sp_MScreate_mergesystables 
go

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

create procedure sp_MSdeletecontents
	@tablenick int,
	@rowguid uniqueidentifier
AS
	declare @nick int
	declare @reason nvarchar(255)
	declare @lineage varbinary(255)

	/*
	** permission check
	*/
	declare @retcode	int
	declare @objid		int
	declare @owner		sysname
	declare @artid		uniqueidentifier
	declare @guidstr	nvarchar(32)	
	declare @deltrigger	nvarchar(270)
	declare @oldmaxversion int
	
	select @objid = objid, @artid=artid from sysmergearticles where nickname=@tablenick
	select @owner =user_name(uid) from sysobjects where id=@objid
	
	exec @retcode=sp_MSguidtostr @artid, @guidstr out
		if @retcode<>0 or @@ERROR<>0 return (1)

	set @deltrigger = QUOTENAME(@owner) + '.del_' + @guidstr

	if trigger_nestlevel(object_id(@deltrigger)) = 0
		begin
			raiserror(14126, 16, -1)
			return (1) -- current user does not have 'delete' permission to underlying table
		end

	exec dbo.sp_MSgetreplnick @nickname = @nick out
	if (@@error <> 0) or @nick IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

	select @oldmaxversion= maxversion_at_cleanup from sysmergearticles where nickname = @tablenick
	select @lineage = lineage from MSmerge_contents (UPDLOCK ROWLOCK index = 1) 
		where tablenick = @tablenick and rowguid = @rowguid
	set @lineage= { fn UPDATELINEAGE(@lineage, @nick, @oldmaxversion+1) }
	select @reason = 'user delete'

	insert into MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason)
		values (@rowguid, @tablenick, 1, @lineage, 0, @reason)
	if @@error <> 0
		begin
		raiserror (20041, 16, -1)
		return (1)
		end
	delete from MSmerge_contents where
		tablenick = @tablenick and rowguid = @rowguid
	if @@error <> 0
		begin
		raiserror (20041, 16, -1)
		return (1)
		end 
go
exec dbo.sp_MS_marksystemobject sp_MSdeletecontents
go		
grant exec on dbo.sp_MSdeletecontents to public
go


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

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

CREATE PROCEDURE sp_MSadd_repl_job
  @name                   nvarchar(200),
  @subsystem              nvarchar(60)  = 'TSQL',
  @server                 sysname  = NULL,
  @username               sysname  = NULL,
  @databasename           sysname  = NULL,
  @enabled                TINYINT      = 0,
  @freqtype               INT          = 2, -- 2 means OnDemand
  @freqinterval           INT          = 1,
  @freqsubtype            INT          = 1,
  @freqsubinterval        INT          = 1,
  @freqrelativeinterval   INT          = 1,
  @freqrecurrencefactor   INT          = 1,
  @activestartdate        INT          = 0,
  @activeenddate          INT          = 0,
  @activestarttimeofday   INT          = 0,
  @activeendtimeofday     INT          = 0,
  @nextrundate            INT          = 0,
  @nextruntime            INT          = 0,
  @runpriority            INT          = 0,
  @emailoperatorname      nvarchar(100) = NULL,
  @retryattempts          INT          = NULL,
  @retrydelay             INT          = 0,
  @command                nvarchar(4000)= NULL,
  @loghistcompletionlevel INT          = 2,
  @emailcompletionlevel   INT          = 0,
  @description            nvarchar(255) = NULL,
  @tagadditionalinfo      nvarchar(96)  = NULL,
  @tagobjectid            INT          = NULL,
  @tagobjecttype          INT          = NULL,
  @cmdexecsuccesscode     INT          = 0,
  @category_name          sysname = NULL, -- New for 7.0
  @failure_detection	  BIT			= 0,
  @agent_id				  INT			= NULL,
  @job_id BINARY(16) = NULL OUTPUT
AS
BEGIN
  DECLARE	@retval INT
  declare	@step_id int
  declare	@step_name nvarchar(100)
  declare	@step_command nvarchar(1024)
  declare	@on_fail_action tinyint
  declare 	@on_success_action tinyint
  declare	@schedule_name nvarchar(100)
  declare	@comments nvarchar(100)

  SET NOCOUNT ON

  SELECT @retval = 1 -- 0 means success, 1 means failure
  set @step_id = 1
  set @on_fail_action = 2	-- Return failure
  set @on_success_action = 1	-- Return success
  set @step_command = NULL

  /*
  ** Set default retries to every minute for 10 minutes.
  **
  */
  if @retryattempts = NULL and @retrydelay = 0
  begin
     select @retryattempts = 10
     select @retrydelay = 1
  end

  BEGIN TRANSACTION
  save tran sp_MSadd_repl_job

	-- Drop the job if it already exists
	IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @name collate database_default)
	begin
		exec @retval = msdb.dbo.sp_delete_job @job_name=@name
		if @@ERROR<>0 or @retval<>0
			goto UNDO
	end

    -- Add the job
    EXECUTE @retval = msdb.dbo.sp_add_job
      @job_name                   = @name,
      @enabled                    = @enabled,
      @start_step_id              = 1,
      @description                = @description,
      @category_name              = @category_name,
      @notify_level_eventlog      = @loghistcompletionlevel,
      @notify_level_email         = @emailcompletionlevel,
      @notify_email_operator_name = @emailoperatorname,
	  @job_id = @job_id OUTPUT

    IF (@retval <> 0)
    BEGIN
		GOTO UNDO
    END

	-- Add startup message step
	if @failure_detection = 1
	begin

		select @step_name = formatmessage(20528)
		select @comments = formatmessage(20529)

		-- Construct command based on subsystem type
		select @step_command =
			case UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) 
				WHEN 'SNAPSHOT' THEN
				N'sp_MSadd_snapshot_history @perfmon_increment = 0,  @agent_id = ' + 
					convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
					@comments = ''' + @comments + ''''
				WHEN 'LOGREADER' THEN
				N'sp_MSadd_logreader_history @perfmon_increment = 0, @agent_id = ' + 
					convert (nvarchar(10), @agent_id) + N', @runstatus = 1, 
					@comments = ''' + @comments + ''''
				WHEN 'DISTRIBUTION' THEN
				N'sp_MSadd_distribution_history @perfmon_increment = 0, @agent_id = ' + 
					convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
					@comments = ''' + @comments + ''''
				WHEN 'MERGE' THEN
				N'sp_MSadd_merge_history @perfmon_increment = 0, @agent_id = ' + 
					convert (nvarchar(10),@agent_id) + N', @runstatus = 1,  
					@comments = ''' + @comments + ''''
				WHEN 'QUEUEREADER' THEN
				N'sp_MSadd_qreader_history @perfmon_increment = 0, @agent_id = ' + 
					convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
					@comments = ''' + @comments + ''''					
			end
	
		-- Add the job step
		EXECUTE @retval = msdb.dbo.sp_add_jobstep
		  @job_id                = @job_id,
		  @step_id               = @step_id,
		  @step_name             = @step_name,
		  @command               = @step_command,
		  @cmdexec_success_code  = @cmdexecsuccesscode,
		  @on_success_action	 = 3,	-- Goto next step
		  @on_fail_action		 = 3,	-- Goto next step
		  @server                = @server,
		  @database_name         = @databasename,
		  @database_user_name    = @username,
		  @os_run_priority       = @runpriority

		IF (@retval <> 0)
		BEGIN
			GOTO UNDO
		END

		set @step_id = @step_id + 1
		set @on_fail_action = 3			-- Goto next step
	end

    -- Add the job step
 	select @step_name = formatmessage(20530)
    EXECUTE @retval = msdb.dbo.sp_add_jobstep
      @job_id                = @job_id,
      @step_id               = @step_id,
      @step_name             = @step_name,
      @subsystem             = @subsystem,
      @command               = @command,
      @cmdexec_success_code  = @cmdexecsuccesscode,
	  @on_success_action	 = @on_success_action,
	  @on_fail_action		 = @on_fail_action,
	  @server                = @server,
      @database_name         = @databasename,
      @database_user_name    = @username,
      @retry_attempts        = @retryattempts,
      @retry_interval        = @retrydelay,
      @os_run_priority       = @runpriority

    IF (@retval <> 0)
    BEGIN
		GOTO UNDO
    END

	-- Add failure message step
	if @failure_detection = 1
	begin

		set @step_id = @step_id + 1

	 	select @step_name = formatmessage(20531)

		-- Construct command
		select @step_command = N'sp_MSdetect_nonlogged_shutdown @subsystem = ''' + @subsystem +	 N''', @agent_id = ' + convert (nvarchar(10),	@agent_id) 

		-- Add the job step
		EXECUTE @retval = msdb.dbo.sp_add_jobstep
		  @job_id                = @job_id,
		  @step_id               = @step_id,
		  @step_name             = @step_name,
		  @command               = @step_command,
		  @cmdexec_success_code  = @cmdexecsuccesscode,
		  @on_success_action	 = 2,					-- Always quit with failure
		  @server                = @server,
		  @database_name         = @databasename,
		  @database_user_name    = @username,
		  @os_run_priority       = @runpriority

		IF (@retval <> 0)
		BEGIN
			GOTO UNDO
		END
	end

    -- Add the job schedule
    IF (@activestartdate = 0)
      SELECT @activestartdate = NULL
    IF (@activeenddate = 0)
      SELECT @activeenddate = NULL
	
	-- But if @activeenddate is NOT NULL, then @activestartdate cannot be allowed to be NULL either.  Set it to today's date converted to the int format used yyyymmdd

    IF (@activeenddate IS NOT NULL AND @activestartdate IS NULL)
	SELECT @activestartdate=DATEPART(YYYY,getdate()) * 10000 + DATEPART(MM,getdate()) * 100 + DATEPART(DD,getdate())

	-- But never let startdate be > end date
    IF (@activestartdate > @activeenddate)
	SELECT @activestartdate=@activeenddate

    IF (@activestarttimeofday = 0)
      SELECT @activestarttimeofday = NULL
    IF (@activeendtimeofday = 0)
      SELECT @activeendtimeofday = NULL
    IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0
    BEGIN
	  select @schedule_name = formatmessage(20532)

      EXECUTE @retval = msdb.dbo.sp_add_jobschedule
        @job_id                 = @job_id,
        @name                   = @schedule_name,
        @enabled                = 1,
        @freq_type              = @freqtype,
        @freq_interval          = @freqinterval,
        @freq_subday_type       = @freqsubtype,
        @freq_subday_interval   = @freqsubinterval,
        @freq_relative_interval = @freqrelativeinterval,
        @freq_recurrence_factor = @freqrecurrencefactor,
        @active_start_date      = @activestartdate,
        @active_end_date        = @activeenddate,
        @active_start_time      = @activestarttimeofday,
        @active_end_time        = @activeendtimeofday

      IF (@retval <> 0)
      BEGIN
		GOTO UNDO
      END
    END

    -- And finally, add the job server
    EXECUTE @retval = msdb.dbo.sp_add_jobserver @job_id = @job_id, @server_name  = '(local)'

    IF (@retval <> 0)
    BEGIN
      GOTO UNDO
    END

  COMMIT TRANSACTION

  -- If this is an autostart LogReader or Distribution or Merge job, add the [new] '-Continuous' paramter to the command
  IF (@freqtype = 0x40) AND ((UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'LOGREADER') OR (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'DISTRIBUTION') OR 
  			(UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'MERGE') OR (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'QUEUEREADER'))
  BEGIN
	UPDATE msdb.dbo.sysjobsteps
	SET command = command + ' -Continuous'
	WHERE (job_id = @job_id)
	  AND ((@failure_detection = 0 and step_id = 1) or (@failure_detection = 1 and step_id = 2))
  END  

  -- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)
  IF (@freqtype = 0x40)
    EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0

  RETURN(0)

UNDO:
	rollback tran sp_MSadd_repl_job
	commit tran
	return(1)

END
go


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

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

create procedure sp_MSgenreplnickname
	@srcguid	uniqueidentifier,	-- Source Guid
	@repnick	int	output	-- nickname
as
	declare @binguid binary(16)
	declare	@nickname int
	set @binguid = convert(binary(16), @srcguid)
	select @nickname = convert(int, convert(binary(4),substring( convert(nchar(8),@binguid), 1, 2)))
	while exists (select replnickname from MSmerge_replinfo where replnickname = @nickname) or
			(@nickname > 0 and @nickname <= 256)
	begin
		select @nickname = @nickname + 1
	end
	select @repnick = @nickname
go

exec dbo.sp_MS_marksystemobject sp_MSgenreplnickname
go
grant execute on dbo.sp_MSgenreplnickname to public

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

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

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

	DECLARE @install_path nvarchar (255)

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

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

	SELECT @undo_install = 'undo_install'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		END

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

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

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

NO_SCRIPTS:

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

	END
	/* Uninstall replication */
	ELSE
	BEGIN

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

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

	END

	RETURN(0)

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

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

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

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

CREATE PROCEDURE sp_helpreplicationoption (
@optname		sysname = NULL
)
AS
	DECLARE @optbit bit
	DECLARE @retcode int


	IF @optname IS NOT NULL AND LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('transactional','merge')
	BEGIN
		RAISERROR(21014, 16, -1)
		GOTO FAILURE
	END
	
	SELECT optname, value, major_version, minor_version, revision 
		FROM master..MSreplication_options
		WHERE
			optname = @optname OR
			@optname = NULL

	RETURN(0)

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



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

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

create procedure sp_reinitmergepullsubscription
	@publisher		sysname  = 'all',
	@publisher_db	sysname  = 'all',
	@publication	sysname  = 'all',
	@upload_first	nvarchar(5) = 'FALSE'
AS
	declare @schemaversion			int
	declare @schematype				smallint
	declare @schemaguid				uniqueidentifier
	declare @pubname				sysname
	declare @publisher_name			sysname
	declare @retcode				int
	declare @pubdb					sysname
    declare @pubid					uniqueidentifier
    declare @subid					uniqueidentifier
    declare @artid					uniqueidentifier
	/*
	** Replace 'all' with '%'
	*/
	set nocount on
	if LOWER(@publication) = 'all'
		SELECT @publication = '%'

	if LOWER(@publisher) = 'all'
		SELECT @publisher = '%'

	if LOWER(@publisher_db) = 'all'
		SELECT @publisher_db = '%'
	select @retcode = 0
	/*
	** At subscriber side, we need to qualify the publication with server name and database name
	*/
    IF NOT EXISTS (SELECT * FROM sysmergepublications WHERE name LIKE @publication 
    	and ((@publisher = N'%') or (UPPER(publisher) = UPPER(@publisher))) 
    	and ((@publisher_db = N'%') or (publisher_db = @publisher_db)) )
    	
        BEGIN
        IF @publication = '%'
                RAISERROR (14008, 11, -1)
        ELSE
                RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
        END

	if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS) not in ('true', 'false')
	begin
		raiserror(14148, 16, -1, '@upload_first')
		return (1)
	end
	Declare SYN_CUR CURSOR LOCAL FAST_FORWARD FOR 
		select subs.subid, pubs.name, pubs.publisher, pubs.publisher_db
			from sysmergepublications pubs, sysmergesubscriptions subs
				where pubs.name LIKE  @publication
					AND ((@publisher = '%') OR (UPPER(pubs.publisher) = UPPER(@publisher)))
                                        AND ((@publisher_db = N'%') OR (pubs.publisher_db = @publisher_db))
					AND pubs.pubid=subs.pubid
					AND subs.pubid<>subs.subid
	FOR READ ONLY
	open SYN_CUR
	fetch SYN_CUR into @subid, @pubname, @publisher_name, @pubdb
	while (@@fetch_status<>-1)
	BEGIN	
		
		-- do not update schemaversion if the initial snapshot has never been applied.
		update MSmerge_replinfo set schemaversion=-1, recgen = NULL, recguid=NULL, 
			sentgen=NULL, sentguid = NULL where repid=@subid and schemaversion is not null

		if (@@rowcount <> 0)
		begin
			if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS)='true'
				update sysmergesubscriptions set status=5 where subid=@subid
			else
				exec @retcode=sp_MSCleanupForPullReinit @publication=@pubname,
											  @publisher=@publisher_name,
											  @publisher_db=@pubdb
			if @retcode<>0 or @@ERROR<>0
			begin
				return (1)
			end
		end

		fetch next from SYN_CUR into @subid, @pubname, @publisher_name, @pubdb	
			-- so that it won't be treated as a new susbscription	
	END
	close SYN_CUR
	deallocate SYN_CUR
	-- Forget that publisher ever sent us any generations.  They must be resent.
	-- Publication cleanup will remove the genhistory rows.

	if @publication = '%'
		-- get them all
		update MSmerge_replinfo set recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
	else
		begin
		select @pubid = pubid from sysmergepublications where name = @publication
		update MSmerge_replinfo set recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
			where repid in (select subid from sysmergesubscriptions where pubid = @pubid)
		end
GO

exec dbo.sp_MS_marksystemobject sp_reinitmergepullsubscription
go	
grant execute on dbo.sp_reinitmergepullsubscription to public
go


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

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

CREATE PROCEDURE sp_MSmergesubscribedb(
	@value sysname
	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @retcode 				int
	

    /*
    ** Security Check
    */

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


	/*
	** Initialization
	*/


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

	IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		BEGIN		
			execute @retcode = dbo.sp_MScreate_mergesystables
			if @@ERROR <> 0 or @retcode <> 0
				begin
					return (1)
				end
		END
	
	-- We assume we will do nothing about disabling a subscriber
	
GO

exec dbo.sp_MS_marksystemobject sp_MSmergesubscribedb
go

grant execute on dbo.sp_MSmergesubscribedb to public
go 


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

CREATE PROCEDURE sp_MSenumsubscriptions(
@subscription_type	nvarchar(5) = 'push',
@publisher		sysname = '%',
@publisher_db 	sysname = '%'
)AS

	set nocount on
	declare @dbname		sysname
	declare @category 	int
	declare @proc			nvarchar(200)
	declare @retcode	int
	declare @cur_db		sysname
	declare @type_value	int

	select @type_value = 100
	
	if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='push'
		select @type_value = 0
	else
		if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='pull'
			select @type_value = 1
		else
			if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='both'
				select @type_value = 2

	select @cur_db = db_name()
	
	create table #MSenumpushsubscriptions (
						publisher			sysname collate database_default not null,
						publisher_db		sysname collate database_default not null,
						publication			sysname collate database_default null,
						replication_type	nvarchar(15) collate database_default not null,
						subscription_type	nvarchar(5) collate database_default not null,
						last_updated		datetime null,
						subscriber_db		sysname collate database_default not null,
						update_mode			smallint null,
						last_sync_status	int null,
						last_sync_summary	sysname collate database_default null,
						last_sync_time		datetime null
						)

	if exists (select * from sysobjects where name='sysmergesubscriptions')
	begin
		-- return all subscriptions that this database is a subscriber to
		-- suppress all subscriptions that originate from this database.
		insert into #MSenumpushsubscriptions select p.publisher, p.publisher_db, p.name, 'Merge', 
			case s.subscription_type when 0 then 'Push' else 'Pull' end, s.last_sync_date, s.db_name, 
			NULL, s.last_sync_status, s.last_sync_summary, s.last_sync_date
			from sysmergepublications p, sysmergesubscriptions s
			where p.pubid = s.pubid 
			and (s.subscription_type=@type_value OR @type_value=2) 
			and s.pubid <> s.subid 
			and ((@publisher = N'%') or (p.publisher = @publisher))
           	and ((@publisher_db = N'%') or ( p.publisher_db = @publisher_db))
			and s.db_name = @cur_db
			and p.pubid not in 
				(select pubid from sysmergepublications pubs where 
					lower(pubs.publisher) = LOWER(@@servername) AND
					pubs.publisher_db = @cur_db)
	end

	if exists (select * from sysobjects where name='MSreplication_subscriptions')
	begin
		if  exists (select * from sysobjects where name='MSsubscription_properties') and
			exists (select * from sysobjects where name='MSsubscription_agents ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				case isnull(p.publication_type,0) when 0 then 'Transactional' else 'Snapshot' end,
				case s.subscription_type when 0 then 'Push' else 'Pull' end,
				s.time, @cur_db, 
				-- NOTE: For Queued case: we will always return 2/3 for the 4/5 case
				-- since we overload update_mode based on queue_type
				case when isnull(a.update_mode,0) = 4 then 2
				when isnull(a.update_mode,0) = 5 then 3
				else isnull(a.update_mode,0)
				end,
				a.last_sync_status,
				a.last_sync_summary,
				a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_agents a with (NOLOCK) 
					on (UPPER(s.publisher) = UPPER(a.publisher) and 
						s.publisher_db = a.publisher_db and 
						((s.publication = a.publication and 
						s.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and s.independent_agent = 0)) and
						s.subscription_type = a.subscription_type)
				left outer join MSsubscription_properties p with (NOLOCK)
					on (UPPER(s.publisher) = UPPER(p.publisher) and 
						s.publisher_db = p.publisher_db and 
						s.publication = p.publication and
						-- don't use property table for push. 
						s.subscription_type <> 0) 
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
		-- Property table does not exists.
		else if exists (select * from sysobjects where name='MSsubscription_agents ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				-- Property table does not exists. Say transactional.
				'Transactional',
				case s.subscription_type when 0 then 'Push' else 'Pull' end,
				s.time, @cur_db, 
				-- NOTE: For Queued case: we will always return 2/3 for the 4/5 case
				-- since we overload update_mode based on queue_type
				case when isnull(a.update_mode,0) = 4 then 2
				when isnull(a.update_mode,0) = 5 then 3
				else isnull(a.update_mode,0)
				end,
				a.last_sync_status,
				a.last_sync_summary,
				a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_agents a with (NOLOCK) 
					on (UPPER(s.publisher) = UPPER(a.publisher) and 
						s.publisher_db = a.publisher_db and 
						((s.publication = a.publication and 
						s.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and s.independent_agent = 0)) and
						s.subscription_type = a.subscription_type)
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 			
		end
		-- Agents table does not exists.
		else if exists (select * from sysobjects where name='MSsubscription_properties ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				case isnull(p.publication_type,0) when 0 then 'Transactional' else 'Snapshot' end,
				case s.subscription_type when 0 then 'Push' else 'Pull' end,
				s.time, @cur_db, 
				s.update_mode,
				NULL, --a.last_sync_status,
				NULL, --a.last_sync_summary,
				NULL  --a.last_sync_time	
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_properties p with (NOLOCK)
					on (UPPER(s.publisher) = UPPER(p.publisher) and 
						s.publisher_db = p.publisher_db and 
						s.publication = p.publication and
						-- don't use property table for push. 
						s.subscription_type <> 0) 
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
		-- Both table does not exists
		else
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				'Transactional',
				case s.subscription_type when 0 then 'Push' else 'Pull' end,
				s.time, @cur_db, 
				s.update_mode,
				NULL, -- a.last_sync_status,
				NULL, -- a.last_sync_summary
				NULL  -- a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK)
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
	
	end
	select * from #MSenumpushsubscriptions
	--drop table #MSenumpushsubscriptions
	return (0)
GO

grant execute on dbo.sp_MSenumsubscriptions to public
go 
exec dbo.sp_MS_marksystemobject sp_MSenumsubscriptions
GO


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

CREATE PROCEDURE sp_addpullsubscription (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,    /* publication name */
	@independent_agent nvarchar(5) = 'true',  /* true or false */
	@subscription_type nvarchar(9) = 'anonymous',     /* subscription_type, pull or anonymous */
	@description nvarchar(100) = NULL,
	-- SyncTran
	@update_mode          nvarchar(15) = 'read only', -- 'sync tran', 'queued tran', 'failover'
	@immediate_sync		bit = 1
) AS
BEGIN

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode int
    DECLARE @subscription_type_id int   /* 1 = pull, 2 = anonymous */
	DECLARE @independent_agent_id bit
	-- SyncTran
	DECLARE @update_mode_id     tinyint 

	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
	begin
		raiserror(21211, 16, -1)
		return 1
	end

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

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

    /*
    ** Initializations.
    */

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

    IF @publisher = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher

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

    /*
    ** Parameter Check: @publisher_db
    */

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

    IF @publisher_db = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher_db

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

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

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

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

    IF LOWER(@independent_agent collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @independent_agent_id = 1
    ELSE SELECT @independent_agent_id = 0
    /*
    ** Parameter Check:  @subscription_type
    ** The @status value can be:
    **
    **      type_id            type
    **      ======            ========
	**			 0			  push
    **           1            pull
    **           2            anonymous
	**
	**	Note: @subscription_type = push is only used by distribution agents
    */
	
    IF @subscription_type IS NULL OR LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull','anonymous')
    BEGIN
        RAISERROR (20016, 16, -1)
        RETURN (1)
    END


    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'pull'    
		SELECT @subscription_type_id = 1
    ELSE IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'anonymous'  
		SELECT @subscription_type_id = 2
	ELSE
		SELECT @subscription_type_id = 0

	IF @independent_agent_id = 0 AND @subscription_type_id = 2
	BEGIN
		RAISERROR (21026, 16, -1)
		RETURN (1)
	END

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

	-- Anonymous subscriptions should not be allowed to 
	-- subscribe with 'synctran option'	
    IF LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) in ('sync tran', 'queued tran', 'failover') and
        @subscription_type_id = 2 
    begin					  
       	RAISERROR (21057, 16, -1)
		RETURN (1)
	end

	select @update_mode_id = 
	case
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'sync tran' then 1
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'queued tran' then 4
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'failover' then 5
		else 0
    end


	begin tran
    save TRAN addpullsubscription
	
    /* 
	** Check to see if MSreplication_subscriptions and MSsubscription_properties 
	** tables exists.
	** If not, create it.
	*/

	exec @retcode = dbo.sp_MScreate_sub_tables
		@tran_sub_table = 1,
		@property_table = 1
	IF @@ERROR <> 0 or @retcode <> 0
		goto UNDO
	
	/*
    ** Check to make sure that the subscription does not already exist
    */
	declare @sub_type int
	select @sub_type = subscription_type from MSreplication_subscriptions 
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
					  publication = @publication

	-- It is not allowed to subscribe to the same publication twice even with
	-- differnet subscription type. 
	-- Raise special error for push
	if @sub_type is not null
		if @sub_type = 0
		begin
			raiserror (20594, 16, -1)
			GOTO UNDO			
		end
		else
		begin
			RAISERROR (14058, 16, -1)
			GOTO UNDO
		end
  
    /*
    ** Add the subscription
    */

    INSERT MSreplication_subscriptions  (publisher,
                                    publisher_db,
                                    publication,
									independent_agent,
                                    subscription_type,
                                    distribution_agent,
									description,
									time,
									transaction_timestamp,
									-- SyncTran
									update_mode,
									immediate_sync)
       VALUES (@publisher,
                   @publisher_db,
                   @publication,
				   @independent_agent_id,    
                   @subscription_type_id,
                   NULL,
				   @description,
				   getdate(),
				   0,
				   -- SyncTran
				   @update_mode_id,
				   @immediate_sync
				   )
    IF @@ERROR <> 0
    BEGIN
       RAISERROR (14057, 16, -1)
       GOTO UNDO
    END

    COMMIT TRAN

	RETURN (0)

UNDO:
    IF @@TRANCOUNT > 0
	begin
        ROLLBACK TRAN addpullsubscription
        COMMIT TRAN   
	end
	return 1
END
go
 
grant execute on dbo.sp_addpullsubscription to public
go


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

CREATE PROCEDURE sp_MSupdatesharedagentproperties (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @property    sysname,
    @strvalue    nvarchar(256) = NULL,
    @intvalue    int = NULL,
    @subscription_type int     
    )
AS


    -- Note publisher/publisher_db/publication uniquely identifies 
    -- a subscription in MSreplication_subscriptions 
    CREATE TABLE #subscriptions
    (
        publication sysname collate database_default
    )

    -- Compute the list of affected subscriptions
    INSERT INTO #subscriptions SELECT publication FROM
    MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher)
    AND publisher_db = @publisher_db AND publication <> @publication
    AND independent_agent = 0 AND subscription_type = @subscription_type

    IF (SELECT COUNT(*) FROM #subscriptions) > 0
    BEGIN 

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor'
        BEGIN
            UPDATE MSsubscription_properties SET distributor = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_security_mode'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_security_mode = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_login'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_login = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_password'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_password'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_address = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_port = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_login'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_login = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_password'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
        BEGIN
            UPDATE MSsubscription_properties SET alt_snapshot_folder = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'working_directory'
        BEGIN
            UPDATE MSsubscription_properties SET working_directory = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'use_ftp'
        BEGIN
            UPDATE MSsubscription_properties SET use_ftp = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'offload_agent'
        BEGIN
            UPDATE MSsubscription_properties SET offload_agent = @intvalue
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'offload_server'
        BEGIN
            UPDATE MSsubscription_properties SET offload_server = @strvalue
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)
        END
    END

    DROP TABLE #subscriptions

    IF @@ERROR <> 0
        RETURN 1
    ELSE
        RETURN 0
GO 

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

CREATE PROCEDURE sp_replicationdboption (
      @dbname    sysname,
      @optname   sysname,
      @value     sysname,
      @ignore_distributor bit = 0,
	  @from_scripting bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    
    declare @alert_name     sysname
    declare @alert_id       int
    declare @command        nvarchar(255)
    declare @description    nvarchar(500)
    declare @category_name  sysname
    declare @agentname      sysname
    DECLARE @retcode        int
    DECLARE @optbit         int
    DECLARE @optbit_value   int /* Desired value with the optbit mask */
    DECLARE @proc           nvarchar(255)
		, @category int

    /*
    ** Initialization
    */

    /*
    ** Parameter check
    ** @dbname
    */
    SELECT @category = category FROM master.dbo.sysdatabases WHERE
        name = @dbname collate database_default
	if @category is null
    BEGIN
        RAISERROR(15010, 16, -1, @dbname)
        RETURN(1)
    END

    /*
    ** Parameter check
    ** @type
    */
    IF @optname is null or LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('publish',
        'merge publish',
		'subscribe', -- Used by sp_dboption for backward compatibility only.
		'sync with backup',
		'max cmds in tran'
		)
    BEGIN
        RAISERROR(14138,16,-1,@optname)
        RETURN(1)
    END

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

    /*
    ** Security Check
    */
	-- This proc is not granted to public. Only other system proc or sysadmin can use this
	-- sp_dboption will call this and it has its own security check,

    /*
    **  If we're in a transaction, disallow this since it might make recovery
    **  impossible.
    **
    */
    IF @@trancount > 0 
    BEGIN
        RAISERROR(15002,16,-1,'sp_replicationdboption')
        RETURN(1)
    END
    
    IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'publish'
        BEGIN
            SELECT @optbit = 1
            SELECT @proc = QUOTENAME(@dbname) + '.dbo.sp_MSpublishdb'
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish'
        BEGIN
            SELECT @optbit = 4
            SELECT @proc = QUOTENAME(@dbname) + '.dbo.sp_MSmergepublishdb'
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'subscribe'
        BEGIN
            SELECT @optbit = 2
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'sync with backup'
        BEGIN
            SELECT @optbit = 32
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'max cmds in tran'
        BEGIN
            SELECT @optbit = 64
        END

    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        SELECT @optbit_value = @optbit
    ELSE
        SELECT @optbit_value = 0

          
    /*
    ** Check if the option is set as required already
    */
	if (@category & @optbit) = @optbit_value
	BEGIN
		if @optbit_value = 64 -- setting 'max cmds in tran' to the same, do nothing
			RETURN (0)
        if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            RAISERROR (14035, 10, -1, @optname, @dbname)        
        else
            RAISERROR (14037, 10, -1, @optname, @dbname)
        RETURN (1)
    END


	-- If turning on 'sync with backup', make sure 'publish' or 'dist' is turned on already.
	if  @optbit_value = 32 and (@category & 1 = 0 and @category & 16 = 0)
	begin
		raiserror(20019, 16, -1, 'sync with backup')
		return (1)
	end
	if  @optbit_value = 64 and (@category & 16 = 0)
	begin
		raiserror(20019, 16, -1, 'max cmds in tran')
		return (1)
	end

	-- We do not allow turning on sync with backup mode at publishing db if the db is
	-- in simple recovery mode
	if  @optbit_value = 32 and @category & 1 <> 0 and 
		databasepropertyex(@dbname, 'recovery') = 'SIMPLE'
	begin
		raiserror(20622, 16, -1, 'sync with backup')
		return (1)
	end
	
	-- If turning off 'publish', turn off 'sync with backup' as well if the database
	-- is not a distribution database.
	if @optbit = 1 and @optbit_value = 0 and @category & 32 <> 0 and @category & 16 = 0
	begin
		EXEC @retcode =  dbo.sp_replicationdboption   
			@dbname = @dbname,
			@optname = 'sync with backup',
			@value = 'false',
			@ignore_distributor = @ignore_distributor,
			@from_scripting = @from_scripting
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			GOTO UNDO
		END
	end

	-- if turning on 'sync with backup' a distribution database, initialize the backup lsns 
	-- to nulls, this should be done before the category bit is set.
	declare @backup_proc nvarchar(1000)
	if @optbit_value = 32 and @category & 16 <> 0
	begin
        SELECT @backup_proc = QUOTENAME(@dbname) + 
			'.dbo.sp_MSrepl_init_backup_lsns'
		exec @retcode = @backup_proc
        if @@error <> 0 or @retcode <> 0
            goto UNDO
	end

    /*
    ** Prepare the required option
    */
	if @proc is not null
	begin
		EXEC @retcode = @proc @value = @value,
			@ignore_distributor = @ignore_distributor
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			GOTO UNDO
		END
	end


    /*
    ** Preparation succeeded. 
    ** Toggle the category bit in master..sysdatabases
    */
    UPDATE master..sysdatabases SET category = category ^ @optbit
    WHERE name = @dbname
    IF @@ERROR <> 0 
    BEGIN
        GOTO UNDO
    END


    declare @num_mergedb int
    select @num_mergedb = null
    if lower(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish'
    begin
        if lower(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        begin            
            -- Set the 'startup' option for sp_MScleanupmergepublisher if the
            -- database is enabled for merge replication.  
            exec ('use master 
                   exec dbo.sp_procoption ''sp_MScleanupmergepublisher'', ''startup'', ''true''')
        end
        else
        begin
            -- Reset the 'startup' option for sp_MScleanupmergepublisher if
            -- this is the last database that has its 'merge publish' option 
            -- disabled
            select @num_mergedb = count(*) from master..sysdatabases 
             where (category & 4) <> 0
            if @num_mergedb = 0
            begin
                exec ('use master 
                       exec dbo.sp_procoption ''sp_MScleanupmergepublisher'', ''startup'', ''false''')
            end
        end
    end
    

	-- Get expired subscription cleanup agent name
    set @agentname = formatmessage(20569)  

    IF ((LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish') or (LOWER(@optname) = 'publish')) and (LOWER(@value) = 'true')
    BEGIN
        IF NOT EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
						UPPER(originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
            BEGIN
                SELECT @command =  'EXEC dbo.sp_expired_subscription_cleanup'
            
                set @description = formatmessage(20542)
    
                select @category_name = name FROM msdb.dbo.syscategories where category_id = 17   
                
                EXECUTE @retcode = msdb.dbo.sp_MSadd_repl_job @agentname,
                @subsystem = 'TSQL',
                @server = @@SERVERNAME,
                @databasename = @dbname,
                @description = @description,
                @freqtype = 4,        -- daily
                @activestarttimeofday=010000,   -- from 01:00:00 am
                @command = @command,
                @enabled = 1,
                @retryattempts = 0,
                @loghistcompletionlevel = 0,
                @category_name = @category_name
            
                IF @@ERROR <> 0 or @retcode <> 0
                    BEGIN
                         return (1)
                    END
            END

		-- Expired subscription cleanup alert            
        select @category_name = name FROM msdb.dbo.syscategories where category_id = 20
        set @alert_name = formatmessage(20538)  
        set @alert_id = 14157 -- corresponding to formatmessage(20538)
        if not exists (select * from msdb.dbo.sysalerts where message_id = @alert_id)
        begin
            exec @retcode = msdb.dbo.sp_add_alert @enabled = 0, @name = @alert_name, @category_name = @category_name, @message_id = 14157
            if @@error <> 0 or @retcode <> 0
                goto UNDO
        end
    END

    IF ((LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish') or (LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'publish')) and (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false')
    BEGIN
            IF (EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and 
							UPPER(originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))) 
                and (NOT exists (select name from master..sysdatabases where category & 4 =4 ))
                and (NOT exists (select name from master..sysdatabases where category & 1 =1))
        BEGIN
            EXEC @retcode = msdb.dbo.sp_delete_job  @job_name = @agentname
            IF @@ERROR <> 0 or @retcode <> 0
                return (1)            
        END
        
        set @alert_id = 14157 -- cleanup  alert
        set @alert_name = formatmessage(20569)
        if exists (select * from msdb.dbo.sysalerts where message_id=@alert_id)
            and (NOT exists (select name from master..sysdatabases where category & 4 =4 ))
                and (NOT exists (select name from master..sysdatabases where category & 1 =1))
        begin
            select @alert_name=name from msdb.dbo.sysalerts where message_id=@alert_id
            exec @retcode = msdb.dbo.sp_delete_alert @alert_name
            if @@error <> 0 or @retcode <> 0
                return (1)            
        end
    END
    
    /*
    **  ??? 
    ** CHECKPOINT the database that was changed. Make the change
    ** effective immediatly
    */
    CHECKPOINT
    IF @@ERROR <> 0 
    BEGIN
        RETURN(1)
    END

    RETURN(0)

UNDO:
    -- Create system table is not allowed in a multi-statement transactions.
    -- Drop the tables here
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        EXEC dbo.sp_replicationdboption 
          @dbname    = @dbname,
          @optname   = @optname,
          @value     = 'false',
          @ignore_distributor = @ignore_distributor

    return(1)   
GO

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

CREATE PROCEDURE sp_addpullsubscription_agent (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,         /* publication name */
    @subscriber sysname = NULL,
    @subscriber_db sysname = NULL,
    @subscriber_security_mode       int = NULL,                     /* 0 standard; 1 integrated */
    @subscriber_login               sysname = NULL,
    @subscriber_password            sysname = NULL,
    @distributor sysname = @publisher,
    @distribution_db sysname = NULL,
    @distributor_security_mode int = 0,
    @distributor_login sysname = 'sa',
    @distributor_password sysname = NULL,
    @optional_command_line nvarchar(4000) = '',
    @frequency_type  int = 2 ,  /* 2== OnDemand */
    @frequency_interval int = 1, 
    @frequency_relative_interval int = 1, 
    @frequency_recurrence_factor int = 1, 
    @frequency_subday int = 1, 
    @frequency_subday_interval int = 1 ,
    @active_start_time_of_day int = 0, 
    @active_end_time_of_day int = 0,         
    @active_start_date int = 0, 
    @active_end_date int =0,
    @distribution_jobid binary(16) = NULL OUTPUT,
    @encrypted_distributor_password bit = 0,
    @enabled_for_syncmgr nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
    @ftp_address sysname = NULL,
    @ftp_port int = NULL,
    @ftp_login sysname = NULL,
    @ftp_password sysname = NULL,
    @alt_snapshot_folder  nvarchar(255) = NULL,
    @working_directory    nvarchar(255) = NULL,
    @use_ftp              nvarchar(5) = 'false',
    @publication_type     tinyint = 0,-- 0 - Transactional, 1 - Snapshot, 2 - Merge
    @dts_package_name sysname  = NULL,  /* value will be sent and validated at distributor */                                  
    @dts_package_password  sysname = NULL,
    @dts_package_location nvarchar(12) = N'subscriber',
    @reserved nvarchar(100) = N'', -- Not default to null because null problems in conditional expressions.
    @offloadagent          nvarchar(5) = 'false',
    @offloadserver         sysname = NULL,
    @job_name              sysname = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @command nvarchar(4000)
    DECLARE @retcode int
    DECLARE @subscription_type_id int   /* 1 = pull, 2 = anonymous */
    DECLARE @independent_agent_id bit
    DECLARE @distribution_agent nvarchar(100) 
    DECLARE @category_name sysname
    DECLARE @platform_nt binary
    DECLARE @subscriber_enc_password nvarchar(524)
    DECLARE @distributor_enc_password   nvarchar(524)
    DECLARE @use_ftp_bit bit
    DECLARE @offload_agent_bit bit
    
    select @platform_nt = 0x1

    /*
    ** Security Check
    */

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

    /*
    ** Initializations.
    */

    -- Set null @optional_command_line to empty string to avoid string concat problem
    if @optional_command_line is null
        set @optional_command_line = ''
    else
        set @optional_command_line = N' ' + LTRIM( RTRIM(@optional_command_line) ) + N' '

    IF @distributor_password = N''
        select @distributor_password = NULL

    IF @ftp_password = N''
        select @ftp_password = NULL

    IF @dts_package_password = N''
        select @dts_package_password = NULL

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

    EXECUTE @retcode = dbo.sp_validname @publisher

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

    /*
    ** Parameter Check: @publisher_db
    */

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

    EXECUTE @retcode = dbo.sp_validname @publisher_db

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

    /*
    ** Parameter Check: @publication
    ** 
    */
    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)

    /*
    ** Parameter Check: @subscriber and @subscriber_db
    */

    if @subscriber IS NULL or rtrim(@subscriber) = ''
        SELECT @subscriber = @@SERVERNAME

    if @subscriber_db IS NULL or rtrim(@subscriber_db) = ''
        SELECT @subscriber_db = DB_NAME()
    
    EXECUTE @retcode = dbo.sp_validname @subscriber
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
    
    EXECUTE @retcode = dbo.sp_validname @subscriber_db
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)

    /* 
    ** Check to see if MSreplictaion_subscriptions table exists.
    ** If so, copy it into the temp table
    */
    IF  NOT EXISTS (SELECT * FROM sysobjects WHERE 
        type = 'U' AND
        name = 'MSreplication_subscriptions')
    BEGIN
        RAISERROR (20017, 16, -1)
        RETURN (1)
    END 
    
    /*
    ** Check to make sure that the subscription does exist
    */
    IF NOT EXISTS (SELECT * FROM  MSreplication_subscriptions
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
                      publication = @publication)
    BEGIN
        RAISERROR (20017, 16, -1)
        RETURN (1)
    END
    
    declare @update_mode_id int
    SELECT  @distribution_agent = NULL
    SELECT  @independent_agent_id = independent_agent, 
            @subscription_type_id = subscription_type,
            @distribution_agent = distribution_agent,
            @update_mode_id = update_mode
        FROM  MSreplication_subscriptions
        WHERE UPPER(publisher) = UPPER(@publisher) AND
              publisher_db  = @publisher_db AND
              publication = @publication
    /* Distribution agent for push subscriptions is at distributor side */
    IF @subscription_type_id = 0
    BEGIN
        RAISERROR (21001, 16, -1)
        RETURN (1)
    END

    IF @distribution_agent IS NOT NULL
    BEGIN
        RAISERROR (21002, 11, -1, @distribution_agent)
        RETURN (1)
    END

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

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

    if (@subscription_type_id <> 0)
    begin
        if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
        begin
            raiserror(21344, 16, -1, '@subscriber_login')
            return (1)
        end
    end
    
    if (@distributor_security_mode = 0) and (@distributor_login IS NULL or rtrim(@distributor_login) = '')
    begin
        raiserror(3217, 16, -1, '@distributor_login')
        return (1)
    end

    IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
    begin
        exec @retcode = sp_MScreate_sub_tables @property_table = 1
        if @retcode <> 0 or @@error <> 0
        return (1)
    end

    /* 
    ** Parameter check: @alt_snapshot_folder 
    ** @alt_snapshot_folder and @use_ftp are mutually exclusive    
    */

    IF @alt_snapshot_folder <> N'' AND @alt_snapshot_folder IS NOT NULL
       AND LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = N'true'
    BEGIN
        RAISERROR(21146, 16, -1)
        RETURN (1)
    END

    /* 
    ** Parameter check: @use_ftp
    ** Must be 'true' or 'false'
    */
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@use_ftp')
        RETURN (1)
    END
    
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @use_ftp_bit = 1
    END
    ELSE
    BEGIN
        SELECT @use_ftp_bit = 0
    END


    /*
    ** Parameter check: @publication_type
    ** Must be 0 - Transactional or 1 - Snapshot
    */
    IF @publication_type NOT IN (0, 1)
    BEGIN
        RAISERROR (20033, 16, -1)
        RETURN (1)
    END

    /*
    ** Parameter Check: @dts_package_location
    ** Valid values:
    ** distributor
    ** subscriber
    **
    */
    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('distributor', 'subscriber')
    BEGIN
        RAISERROR(21179, 16, -1)    
        RETURN (1)
    END

    declare @dts_package_location_id int

    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = 'distributor'
        SELECT @dts_package_location_id = 0
    ELSE 
        SELECT @dts_package_location_id = 1

    -- Have to be a push, non updatable  subscription to set DTS package name
    if @dts_package_name is not null
    begin
        if  @update_mode_id != 0
        begin
            RAISERROR(21180, 16, -1)    
            RETURN (1)
        end
    end
    
    -- Copy the passwords to new value before attempting to encrypt
    set @distributor_enc_password = @distributor_password
    IF (@encrypted_distributor_password = 0)
        -- Encrypt the password
        BEGIN
            EXEC @retcode = master.dbo.xp_repl_encrypt @distributor_enc_password OUTPUT
            IF @@error <> 0 OR @retcode <> 0
                return 1
        END
	
    declare @dts_package_enc_password nvarchar(524)
    set @dts_package_enc_password = @dts_package_password

    if @dts_package_enc_password is not null
    begin
        EXEC @retcode = master.dbo.xp_repl_encrypt @dts_package_enc_password OUTPUT
        IF @@error <> 0 OR @retcode <> 0
            return 1
    end

    /*
    ** Parameter Check: @offloadserver
    ** 1. If @offloadagent = 'true' then @offloadserver cannot be null.
    ** 2. Similar to the push case, we don't allow "remote" activation
    **    of agent on the local machine.
    */
    SELECT @offloadagent = LOWER(@offloadagent collate SQL_Latin1_General_CP1_CS_AS)
    IF @offloadagent NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@offloadagent')
        RETURN (1)
    END

    IF @offloadagent = 'true'
    BEGIN
        SELECT @offload_agent_bit = 1
    END
    ELSE
    BEGIN
        SELECT @offload_agent_bit = 0
    END

    IF @offload_agent_bit = 1 AND (@offloadserver is NULL or
                               @offloadserver = N'')
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN (1)
    END
    
    IF UPPER(@offloadserver) = UPPER(@@SERVERNAME) AND
       @offload_agent_bit = 1
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END

    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode <> 0 OR @@ERROR <> 0
        RETURN (1)

    /*
    ** Construct unique name
    */
    if @subscriber is NULL select @subscriber = ''
    if @subscriber_db is NULL select @subscriber_db = ''
    
    declare @job_existing bit
    if @job_name is null
    begin
        select @job_existing = 0
        SELECT @job_name = CONVERT(nvarchar(18),@publisher ) + '-' + CONVERT(nvarchar(18),@publisher_db) + '-' + 
                        CONVERT(nvarchar(18),@publication) + '-' + CONVERT(nvarchar(18),@subscriber) + '-' +
                        CONVERT(nvarchar(18),@subscriber_db) + '-' + CONVERT(nvarchar(36),newid())
    end
    else
        select @job_existing = 1

    -- Get property values.
    if @reserved = 'no_change_to_properties'
    begin
        -- Get the distributor value. It will be used in agent command line.
        select @distributor = distributor, 
            @enabled_for_syncmgr = case enabled_for_syncmgr
                when 0 then 'false'
                when 1 then 'true'
                end
        from MSsubscription_properties where
            UPPER(publisher) = UPPER(@publisher)
            and publisher_db =  @publisher_db
            and publication = @publication              
    end

    BEGIN TRAN

    /*
    ** If the publication is independent agent type or it is the first
    ** subscription on the non independent agent publications.
    */

    IF @independent_agent_id = 1 OR 
        NOT EXISTS (SELECT * FROM MSreplication_subscriptions WHERE
                            UPPER(@publisher) = UPPER(publisher) and
                            @publisher_db = publisher_db and
                            agent_id IS NOT NULL and
                            independent_agent = 0)
    BEGIN
        if @job_existing = 0
        begin
            /* Construct agent command */
            SELECT @command = '-Publisher ' + @publisher + ' '
            SELECT @command = @command + '-PublisherDB ' + QUOTENAME(@publisher_db) + ' '
            IF @independent_agent_id = 1
                SELECT @command = @command + '-Publication ' + QUOTENAME(@publication) + ' '

            SELECT @command = @command + '-Distributor ' + QUOTENAME(@distributor)  + ' '

            /*
            Use -Xdatabase to save command line space
            We can not use -Xserver for distribution because SQLExec will validate the server
            to be in sysservers.

            SELECT @command = @command + '-DistributionDB ' + QUOTENAME(@distribution_db)  + ' '
            */
            
            SELECT @command = @command + '-SubscriptionType ' + convert(nvarchar(10),@subscription_type_id)  + ' '
            SELECT @command = @command + '-Subscriber ' + QUOTENAME(@subscriber)  + ' '
        
            select @command = @command + '-SubscriberSecurityMode ' + 
                convert(nvarchar(10),@subscriber_security_mode) + ' '
            if @subscriber_login is not NULL
                select @command = @command + '-SubscriberLogin ' + quotename(@subscriber_login) + ' '
            if @subscriber_password is not NULL
            begin
                set @subscriber_enc_password = @subscriber_password
                exec @retcode = master.dbo.xp_repl_encrypt @subscriber_enc_password OUTPUT
                select @command = @command + '-SubscriberEncryptedPassword ' + quotename(@subscriber_enc_password) + ' '
            end

            SELECT @command = @command + '-SubscriberDB ' + QUOTENAME(@subscriber_db) + ' '

                    
            if @dts_package_name is not null
              select @command = @command + '-UseDTS '

            if @offload_agent_bit = 1 
                select @command = @command + N'-Offload ' + @offloadserver + N' '

            /* 
            ** make sure the command line is not truncated
            */
            /* Use datalength because len doesn't count the last space in @command */
            IF (datalength(@command) + datalength(@optional_command_line)) > 8000
            BEGIN
                RAISERROR(20018, 16, -1)
                RETURN(1)
            END

            SELECT @command = @command + @optional_command_line

            -- Get Distribution category name (assumes category_id = 10)
            select @category_name = name FROM msdb.dbo.syscategories where category_id = 10

            EXEC @retcode = dbo.sp_MSadd_repl_job
                    @name = @job_name,
                    @subsystem = 'Distribution',
                    @server = @@SERVERNAME,
                    @databasename = @distribution_db,
                    @enabled = 1,
                    @freqtype = @frequency_type,
                    @freqinterval = @frequency_interval,
                    @freqsubtype = @frequency_subday,
                    @freqsubinterval = @frequency_subday_interval,
                    @freqrelativeinterval = @frequency_relative_interval,
                    @freqrecurrencefactor = @frequency_recurrence_factor,
                    @activestartdate = @active_start_date,
                    @activeenddate = @active_end_date,
                    @activestarttimeofday = @active_start_time_of_day,
                    @activeendtimeofday = @active_end_time_of_day,
                    @command = @command,
                    @category_name = @category_name,
                    @retryattempts = 10,
                    @retrydelay = 1,
                    @job_id = @distribution_jobid OUTPUT

            IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN   
                RETURN(1)
            END
        end
        else
        begin
            select @distribution_jobid = job_id from msdb..sysjobs_view where 
                name = @job_name collate database_default and
                UPPER(originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
            if @distribution_jobid IS NULL
            begin
                -- Message from msdb.dbo.sp_verify_job_identifiers
                RAISERROR(14262, -1, -1, 'Job', @job_name)          
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN   
                RETURN(1)
            end
        end
    END

    if @reserved <> 'no_change_to_properties' and (@subscription_type_id = 1) OR (@subscription_type_id = 2)
    BEGIN
        IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
              and publisher_db =  @publisher_db
              and publication = @publication) 
        BEGIN
            -- Publication type:
            -- 0  transactional
            -- 1  snapshot
            -- 2  merge (not allowed)

            INSERT INTO MSsubscription_properties 
            (publisher, publisher_db, publication, publication_type, 
             publisher_login,publisher_password, publisher_security_mode, 
             distributor, distributor_login, distributor_password, 
             distributor_security_mode, ftp_address, ftp_port, ftp_login, 
             ftp_password, alt_snapshot_folder, working_directory, use_ftp,
             dts_package_name, dts_package_password, dts_package_location, 
             offload_agent, offload_server, dynamic_snapshot_location)
            values (@publisher, @publisher_db, @publication, @publication_type, NULL, NULL, 1, 
                @distributor, @distributor_login, @distributor_enc_password, 
                @distributor_security_mode, null, null, null,
                null, @alt_snapshot_folder, @working_directory, @use_ftp_bit,
                @dts_package_name, @dts_package_enc_password, 
                @dts_package_location_id, @offload_agent_bit, @offloadserver, null)

            IF @@ERROR <> 0 
            BEGIN
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN           
                RETURN(1)
            END
        END
        ELSE
        BEGIN
            update MSsubscription_properties set
                distributor = @distributor,
                distributor_login = @distributor_login,
                distributor_password = @distributor_enc_password,
                distributor_security_mode = @distributor_security_mode,
                dts_package_name = @dts_package_name,
                dts_package_password = @dts_package_enc_password,
                dts_package_location = @dts_package_location_id
                where UPPER(publisher) = UPPER(@publisher)
                    and publisher_db =  @publisher_db
                    and publication = @publication
        END


        -- For dependent subscriptions we need to fix up all the
        -- shared properties  
        IF @independent_agent_id = 0 
        BEGIN

            EXEC @retcode = sp_MSfixupsharedagentproperties
                   @publisher = @publisher,
                   @publisher_db = @publisher_db,
                   @publication = @publication,
                   @distributor = @distributor,
                   @distributor_security_mode = @distributor_security_mode,
                   @distributor_login = @distributor_login,
                   @distributor_password = @distributor_enc_password,
                   @ftp_address = @ftp_address,
                   @ftp_port = @ftp_port,
                   @ftp_login = @ftp_login,
                   @ftp_password = @ftp_password,
                   @alt_snapshot_folder = @alt_snapshot_folder,
                   @working_directory = @working_directory,
                   @use_ftp = @use_ftp_bit,
                   @offload_agent = @offload_agent_bit,
                   @offload_server = @offloadserver
                    
            IF @retcode <> 0 OR @@ERROR <> 0
            BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
            END
        END

        IF @@ERROR <> 0 
        BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
        END
    END


    /* If we do not have independent agents , i.e. independent_agent=0, but there is
    already a row for that publisher and that publisher database with a NOT null 
    distribution_agent_id, then set the @distribution_jobid to that id.  Note that if
    there are no rows returned, the value of the variable does not change, which is what we want.
    There should never be more than one row ever returned for this query - but will use TOP 1
    to insist that is the case.
    */
    
    IF @independent_agent_id = 0
    BEGIN
        SELECT DISTINCT @distribution_jobid=agent_id, @job_name = distribution_agent 
          FROM MSreplication_subscriptions
         WHERE UPPER(publisher) = UPPER(@publisher) 
           AND publisher_db =  @publisher_db
           AND agent_id IS NOT NULL AND independent_agent=0
    
    END

    UPDATE MSreplication_subscriptions 
       SET distribution_agent = @job_name,
           agent_id = @distribution_jobid
     WHERE UPPER(publisher) = UPPER(@publisher) 
       AND publisher_db =  @publisher_db 
       AND publication =  @publication 
       AND (subscription_type = 1 /* pull*/ OR subscription_type = 2) /*anonymous*/

    IF @@ERROR <> 0 
    BEGIN
        IF @@TRANCOUNT = 1
            ROLLBACK TRAN
        ELSE
            COMMIT TRAN           
        RETURN(1)
    END 

    /* Conditional support for MobileSync */
    if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        /* Call sp_MSregistersubscription so that the subscription can be synchronized via MobileSync etc. */
        declare @subscription_id uniqueidentifier
        declare @failover_mode_id int
        set @subscription_id = convert(uniqueidentifier, @distribution_jobid)

        if @update_mode_id in (3,5) 
            select @failover_mode_id = 1
        else if @update_mode_id in (2,4)
            select @failover_mode_id = 2
        else
            select @failover_mode_id = 0
            
        exec @retcode = dbo.sp_MSregistersubscription @replication_type = 1,
                                    @publisher = @publisher,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @subscriber = @subscriber,
                                    @subscriber_db = @subscriber_db,
                                    @subscriber_security_mode = @subscriber_security_mode,
                                    @subscriber_login = @subscriber_login,
                                    @subscriber_password = @subscriber_password,
                                    @distributor = @distributor,
                                    @subscription_id = @subscription_id,
                                    @independent_agent = @independent_agent_id,
                                    @subscription_type = @subscription_type_id,
                                    @failover_mode = @failover_mode_id
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
        END
    END

    COMMIT TRAN
    RETURN(0)
GO

grant execute on dbo.sp_addpullsubscription_agent to public
go


--------------------------------------------------------------------------------
--. sp_change_subscription_properties 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_change_subscription_properties')
	drop procedure sp_change_subscription_properties
go
raiserror('Creating procedure sp_change_subscription_properties', 0,1)
go
CREATE PROCEDURE sp_change_subscription_properties
        @publisher sysname, 
		@publisher_db sysname, 
		@publication sysname, 
		@property sysname,
		@value nvarchar(1000),
        @publication_type int = NULL
    AS
    SET NOCOUNT ON

	DECLARE @command nvarchar(2000)
	DECLARE @column_to_update nvarchar(64)
	DECLARE @value_string nvarchar(255)
    DECLARE @independent_agent bit
	DECLARE @retcode int
    DECLARE @subscription_type int
    DECLARE @intvalue int
    DECLARE @value_bit bit
    DECLARE @offload_agent bit
    DECLARE @offload_server sysname 
    DECLARE @dbname sysname
    DECLARE @local_publication sysname
    DECLARE @agentid binary(16)
    DECLARE @local_publisher sysname
    DECLARE @cursor_opened bit 
    DECLARE @cursor_allocated bit
    DECLARE @agenttype nvarchar(20)
    DECLARE @commandline nvarchar(3200)

    SELECT @cursor_opened = 0
    SELECT @cursor_allocated = 0
    SELECT @retcode = 0    
	/*
    ** Security Check
    */

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

	IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
	begin
		raiserror(14027, 16, -1, 'The subscription properties table ''MSsubscription_properties''')
		return (1)
	end
	
	if (@publisher is null)
	begin
		raiserror(14043, 16, -1, '@publisher')
		return (1)
	end

	if(@publisher_db is null)
	begin
		raiserror(14043, 16, -1, '@publisher_db')
		return (1)
	end
	
	if (@publication is null) or (@publication = '')
	begin
		select @publication = '%'
	end


    -- Expand '%' into individual subscriptions using a cursor
    IF @publication = N'%'
    BEGIN

        BEGIN TRANSACTION subscription_properties_exp
        DECLARE hsubprop CURSOR LOCAL FAST_FORWARD FOR
            SELECT publication 
              FROM MSreplication_subscriptions
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               -- NOTE:  publication like '%' is implicit
        IF @@ERROR <> 0
            GOTO ExpFailure
        SELECT @cursor_allocated = 1
    
        OPEN hsubprop
        IF @@ERROR <> 0
            GOTO ExpFailure    
        SELECT @cursor_opened = 1

        FETCH hsubprop INTO @local_publication
        WHILE (@@FETCH_STATUS <> 0)
        BEGIN
                            
            EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @local_publication,
                @property = @property,
                @value = @value,
                @publication_type = @publication_type
            IF @retcode <> 0 OR @@ERROR <> 0
                GOTO ExpFailure
            FETCH hsubprop INTO @local_publication
        END

        CLOSE hsubprop
        DEALLOCATE hsubprop
        COMMIT TRANSACTION subscription_properties_exp
        IF @@ERROR <> 0
            GOTO ExpFailure

        RETURN (0)
ExpFailure:

        IF @cursor_opened = 1
            CLOSE hsubprop
        IF @cursor_allocated = 1
            DEALLOCATE hsubprop
        ROLLBACK TRANSACTION subscription_properties_exp        
        RETURN (1)
    END    

    -- Check for existence of the specified pull subscription
    SELECT @agentid = NULL
    SELECT @local_publisher = NULL
    SELECT @dbname = DB_NAME()

    IF @publication_type IN (0,1) OR @publication_type IS NULL
    BEGIN
        IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('MSreplication_subscriptions'))
        BEGIN
            SELECT @local_publisher = publisher, 
                   @agentid = agent_id
              FROM MSreplication_subscriptions
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication = @publication 
        END

    END

    IF @publication_type = 2 OR (@publication_type IS NULL AND
        @local_publisher IS NULL)
    BEGIN
        IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('sysmergepublications'))
        BEGIN

            SELECT @local_publisher = mp.publisher,
                   @agentid = mr.merge_jobid
              FROM sysmergepublications mp
            INNER JOIN sysmergesubscriptions ms
                ON mp.pubid = ms.pubid 
               AND UPPER(mp.publisher) = UPPER(@publisher) 
               AND mp.publisher_db = @publisher_db
               AND mp.name = @publication 
               AND ms.db_name = @dbname
               AND UPPER(ms.subscriber_server) = UPPER(@@SERVERNAME)
            INNER JOIN MSmerge_replinfo mr
                ON ms.subid = mr.repid
        END
    END 

    IF @local_publisher IS NULL
    BEGIN
        RAISERROR(21226, 16, -1, @dbname)
        RETURN (1)
    END

    SELECT @offload_agent = NULL
    SELECT @offload_server = NULL
    SELECT @offload_agent = offload_agent, 
           @offload_server = offload_server,
           @publication_type = publication_type             
      FROM MSsubscription_properties 
     WHERE UPPER(publisher) = UPPER(@publisher)
       AND publisher_db = @publisher_db
       AND publication = @publication
    
    -- If the subscription does not have a corresponding entry in MSsubscription_properties, 
    -- the subscription is probably created by the ActiveX control. In this case there isn't much
    -- we can do about it so we just return 0.
    IF @offload_agent IS NULL
    BEGIN
        RETURN (0)
    END      
    
	IF (@property IS NULL)
	begin
		raiserror(14043, 16, -1, '@property')
		return (1)
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_login')
		select @column_to_update = 'publisher_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_password')
	begin
		select @column_to_update = 'publisher_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode')
		select @column_to_update = 'publisher_security_mode'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor')
		select @column_to_update = 'distributor'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_login')
		select @column_to_update = 'distributor_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_password')
	begin
		select @column_to_update = 'distributor_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_security_mode')
		select @column_to_update = 'distributor_security_mode'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_address')
		select @column_to_update = 'ftp_address'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_port')
		select @column_to_update = 'ftp_port'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_login')
		select @column_to_update = 'ftp_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_password')
		select @column_to_update = 'ftp_password'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'alt_snapshot_folder')
    BEGIN
        select @column_to_update = 'alt_snapshot_folder'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'working_directory')
    BEGIN
        select @column_to_update = 'working_directory'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_ftp')
        select @column_to_update = 'use_ftp'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_name')
        select @column_to_update = 'dts_package_name'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_password')
	begin
        select @column_to_update = 'dts_package_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_location')
        select @column_to_update = 'dts_package_location'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_agent')
    BEGIN
        select @column_to_update = 'offload_agent'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_server')
    BEGIN
        select @column_to_update = 'offload_server'
        exec @retcode = sp_MSreplcheckoffloadserver @value
        if @retcode <> 0 or @@error <> 0
                return(1)
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = N'dynamic_snapshot_location') and @publication_type = 2
    BEGIN
        select @column_to_update = N'dynamic_snapshot_location'
    END
	ELSE
	BEGIN
		raiserror (3217, 16, -1, '@property')
		return(1)
	END

    IF @column_to_update in ('use_ftp', 'offload_agent')
    BEGIN
        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true'
        BEGIN
            SELECT @value_bit = 1
        END
        ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'false'
        BEGIN
            SELECT @value_bit = 0
        END
        ELSE
        BEGIN 
            RAISERROR(14137, 16, -1)
        END
    END

	IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_security_mode') OR (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode') 
	BEGIN
		IF NOT ( @value = 0 or @value = 1 or (@value = 2 and lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode' )) 
		BEGIN
			raiserror(3217, 16, -1, '@value')
			return(1)
		END
        select @value_string = convert(nvarchar(1), @value)
	END
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_location')
	BEGIN
		IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'distributor' 
			select @value_string = '0'
		ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'subscriber' 
			select @value_string = '1'
		ELSE 
		begin
			raiserror(20587, 16, -1, 'dts_package_location', 'sp_change_subscription_properties')
			return(1)
		end

	END
	ELSE
    BEGIN
        IF @value IS NULL
        BEGIN
            select @value_string = 'null'
        END
        ELSE
        BEGIN
		    select @value_string = 'N' + quotename(rtrim(@value),'''')
        END
	END    

    -- Ignore ftp_address, ftp_port, ftp_login, ftp_password on post 7.0 servers
    IF (@column_to_update IN (N'ftp_address', N'ftp_port', N'ftp_login', N'ftp_password'))
    BEGIN
        RETURN (0)
    END

    -- If the 'offload_agent' property is 1, 'offload_server' property must not be
    -- null or empty. Make sure that this is the case
    IF (@column_to_update = N'offload_agent' AND 
        @value_bit = 1 AND 
        (@offload_server IS NULL OR @offload_server = N''))
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN(1)
    END

    -- If we are enabling agent offload for this pull subscription, 
    -- we should make sure that the offload server is different from
    -- the Subscriber's server name
    IF (@column_to_update = N'offload_agent' AND
        @value_bit = 1 AND UPPER(@offload_server) = UPPER(@@SERVERNAME)) OR
       (@column_to_update = N'offload_server' AND
        @offload_agent = 1 AND 
        UPPER(@value) = UPPER(@@SERVERNAME))
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END
    
BEGIN TRANSACTION subscription_properties	
	IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_ftp')
    begin
		update MSsubscription_properties set use_ftp = @value_bit where 
			UPPER(publisher) = UPPER(@publisher) and 
			publisher_db = @publisher_db and
			publication = @publication 
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    end
    else if (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_agent')
    begin
        update MSsubscription_properties set offload_agent = @value_bit where
            UPPER(publisher) = UPPER(@publisher) and
            publisher_db = @publisher_db and
            publication = @publication
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        -- Call helper procedure to add or remove the '-Offload' parameter 
        -- from the agent's command line in msdb. By now, we should 
        -- have the publication type and the agent jodid.

        -- Don't do anything if the offload_agent property hasn't been changed
        IF @offload_agent <> @value_bit
        BEGIN
            IF @publication_type IN (0,1)    
            BEGIN
                SELECT @agenttype = N'distribution'
            END
            ELSE
            BEGIN
                SELECT @agenttype = N'merge'
            END    

            -- Add or remove the Offload parameter based on the new value
            -- of the offload_agent property 
            IF @value_bit = 0
            BEGIN
                EXEC @retcode = sp_MSremoveoffloadparameter
                        @job_id = @agentid,
                        @agenttype = @agenttype

                IF @@ERROR <> 0 OR @retcode <> 0
                    GOTO Failure 
            END
            ELSE
            BEGIN
                EXEC @retcode = sp_MSaddoffloadparameter 
                        @job_id = @agentid,
                        @offloadserver = @offload_server,
                        @agenttype = @agenttype

                IF @@ERROR <> 0 OR @retcode <> 0
                    GOTO Failure 
            END
        END
    end
    else if lower(@property collate SQL_Latin1_General_CP1_CS_AS) = N'dynamic_snapshot_location'
    begin
        select @value = rtrim(ltrim(@value))

        update MSsubscription_properties 
           set dynamic_snapshot_location = @value
         where upper(publisher) = upper(@publisher) 
           and publisher_db = @publisher_db 
           and publication = @publication
        if @@error <> 0 or @retcode <> 0
            goto Failure

        -- Call helper functions to add/update or remove the -DynamicSnapshotLocationParameter
        if @value is null or @value = N''
        begin
            update msdb.dbo.sysjobsteps 
               set command = fn_removeparameterwithargument(command, N'DynamicSnapshotLocation') collate database_default
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge'
        end
        else
        begin

            select @commandline = command 
              from msdb.dbo.sysjobsteps
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge'

            select @commandline = fn_updateparameterwithargument(@commandline, N'DynamicSnapshotLocation', fn_replquotename(@value)) collate database_default

            -- Need to remove existing alternate snapshot folder parameters
            -- and file transfer type parameters

            select @commandline = fn_removeparameterwithargument(@commandline, N'FileTransferType') collate database_default
            
            select @commandline = fn_removeparameterwithargument(@commandline, N'AltSnapshotFolder') collate database_default

            update msdb.dbo.sysjobsteps
               set command = @commandline
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge' 

        end
    end
    else    
	begin
		-- Password is encrypted. Must prefix every string with N' 
		-- otherwise, the chars will be convert to '???'
		select @command = N'update MSsubscription_properties set ' + @column_to_update + '= ' + @value_string
				+ ' where UPPER(publisher) = UPPER(' + quotename(@publisher,'''') 
				+ ') and publisher_db = ' + quotename(@publisher_db, '''')
				+ ' and publication = ' + quotename(@publication,'''')
		EXEC (@command)
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
	end


    -- If the offload_server property is chnaged, we have to modify the agent's
    -- command line if the agent has already been enabled for remote activation 		
    IF @column_to_update = N'offload_server' AND @offload_agent = 1
    BEGIN
        IF @publication_type IN (0,1)
        BEGIN
            SELECT @agenttype = N'distribution'
        END
        ELSE
        BEGIN
            SELECT @agenttype = N'merge'
        END

        EXEC @retcode = sp_MSaddoffloadparameter
            @job_id = @agentid,
            @offloadserver = @value,
            @agenttype = @agenttype        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO Failure
    END

    IF (@publication_type = 0 or @publication_type = 1) AND @publication <> N'%' AND
        @column_to_update IN ('distributor',
                              'distributor_login',
                              'distributor_password',
                              'distributor_security_mode',
                              'ftp_address',
                              'ftp_port',
                              'ftp_login',
                              'ftp_password',
                              'alt_snapshot_folder',
                              'working_dir',
                              'use_ftp',
                              'offload_agent',
                              'offload_server')
    BEGIN
        SELECT @subscription_type = subscription_type
          FROM MSreplication_subscriptions
         WHERE UPPER(publisher) = UPPER(@publisher)
           AND publisher_db = @publisher_db
           AND publication = @publication
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        -- Update the property for all shared subscriptions
        IF @column_to_update IN ('distributor_security_mode', 
                                 'ftp_port')
        BEGIN
            SELECT @intvalue = CONVERT(int, @value)
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @intvalue = @intvalue,
                    @subscription_type = @subscription_type
        END
        ELSE IF @column_to_update IN ('use_ftp', 'offload_agent')
        BEGIN
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @intvalue = @value_bit,
                    @subscription_type = @subscription_type
        END
        ELSE 
        BEGIN
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @strvalue = @value,
                    @subscription_type = @subscription_type
        END  
    
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    -- Ftp and alternate snapshot folder are mutually 
    -- exclusive options but instead of raising an error
    -- when both of them are non-null, nullify the other 
    -- property when either one of them is set to non-null
    -- value since properties can only be set one at a time

    -- 'dynamic_snapshot_location' should also be added to the
    -- list of mutually exclusive properties


    IF (@column_to_update = 'ftp_address') AND (@value <> N''
       AND @value IS NOT NULL)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    IF (@column_to_update = 'use_ftp') AND (@value_bit = 1)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        IF @publication_type = 2
        BEGIN
            EXEC @retcode = sp_change_subscription_properties
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = 'dynamic_snapshot_location',
                    @value = NULL
            IF @@error <> 0 OR @retcode <> 0
                GOTO Failure
        END
    END

    IF (@column_to_update = 'alt_snapshot_folder') AND (@value <> N''
       AND @value IS NOT NULL)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'ftp_address',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'use_ftp',
                @value = 'false'

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        IF @publication_type = 2
        BEGIN
            EXEC @retcode = sp_change_subscription_properties
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = 'dynamic_snapshot_location',
                    @value = NULL
            IF @@error <> 0 OR @retcode <> 0
                GOTO Failure
        END
    END


    IF (@column_to_update = 'dynamic_snapshot_location') AND (@value <> N''
        AND @value IS NOT NULL)
    BEGIN

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'ftp_address',
                @value = NULL
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'use_ftp',
                @value = 'false'
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

    END


    -- Turn off the offload agent bit if the 
    -- the new value of offload server happens to be null
    -- or empty
    IF (@column_to_update = 'offload_server' AND 
        (@value IS NULL OR @value = N'') AND
        @offload_agent = 1)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'offload_agent',
                @value = 'false'
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    IF @@error <> 0 OR @retcode <> 0
        GOTO Failure

    COMMIT TRANSACTION subscription_properties
    RETURN (0)
            
Failure:        
    ROLLBACK TRANSACTION subscription_properties
    RETURN (1)
GO
EXEC dbo.sp_MS_marksystemobject sp_change_subscription_properties
GO
grant execute on dbo.sp_change_subscription_properties to public
go

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


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

CREATE PROCEDURE sp_helppullsubscription (
    @publisher sysname = '%',
    @publisher_db sysname = '%',
    @publication sysname = '%',
	@show_push nvarchar(5) = 'false'
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */


    DECLARE @command nvarchar(255)
    DECLARE @name nvarchar(255)
	DECLARE @retcode int
	DECLARE @show_push_bit bit
	DECLARE @push int
	declare @subscriber			sysname
	declare @subscriber_db		sysname
	declare @publisher_local	sysname
	declare @publisher_db_local	sysname
	declare @publication_local	sysname
	declare @subscription_name 	nvarchar(1000)
	declare @regkey				nvarchar(1000)
	declare @syncmgr_keyexist				int
	declare @helpsubscriptioncursor_open	int


	SELECT @push = 0

	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
		-- The database is attached from a subscription copy file without using
		-- sp_attachsubscription. Return nothing
		return 0

    /*
    ** Security Check
    */

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

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

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

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

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

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

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


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

	IF LOWER(@show_push collate SQL_Latin1_General_CP1_CS_AS) = 'false'				
		SELECT @show_push_bit = 0	
    IF LOWER(@show_push collate SQL_Latin1_General_CP1_CS_AS) = 'true'	
		SELECT @show_push_bit = 1


	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSreplication_subscriptions')
		RETURN (0)

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
		RETURN (0)

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_agents')
		RETURN (0)

				
    /*
    ** Get the result
	**
	** Note: have to return meta data
    */
	    SELECT  'publisher'				= rs.publisher,
            'publisher database'	= rs.publisher_db,
            'publication'			= rs.publication,
			'independent_agent'		= rs.independent_agent,
            'subscription type'     = rs.subscription_type,
            'distribution agent'	= distribution_agent,
			'publication description'   = description,
			'last updating time'		= convert(nvarchar(12), time, 112) + 
                                          substring(convert(nvarchar(24), time, 121), 11,13),
			'subscription_name'	  	= rs.publisher + ':' + rs.publisher_db + ':' + rs.publication,
			'last transaction timestamp' = transaction_timestamp,
			-- SyncTran
			-- For Queued case, we will return 2/3 for values 4/5 so that
			-- SQL-DMO does not have to deal with the overloaded values of update_mode
			'update_mode'         = case 	when rs.update_mode = 4 then 2
											when rs.update_mode = 5 then 3
											else rs.update_mode
									end,
			'distribution agent job_id' = agent_id,
			'enabled for syncmgr' = enabled_for_syncmgr,
    		'subscription guid' = subscription_guid,
			'subid ' = subid,
			'immediate_sync' = immediate_sync,
	        'publisher_login' = publisher_login,
            'publisher_password' = publisher_password,
            'publisher_security_mode' = publisher_security_mode,
            'distributor' = distributor,
            'distributor_login' = distributor_login,
            'distributor_password' = distributor_password,
            'distributor_security_mode' = distributor_security_mode,
            'ftp_address' = ftp_address,
            'ftp_port' = ftp_port,
            'ftp_login' = ftp_login,
            'ftp_password' = ftp_password,
            'alt_snapshot_folder' = alt_snapshot_folder,
            'working_directory' = working_directory,
            'use_ftp' = use_ftp,
            'publication_type' = publication_type,
			'dts_package_name' = dts_package_name,
			'dts_package_location' = dts_package_location,
            'offload_agent' = offload_agent,
            'offload_server' = offload_server,
			a.last_sync_status, 
			a.last_sync_summary,
			'last_sync_time' = convert(nvarchar(12), a.last_sync_time, 112) + 
				substring(convert(nvarchar(24), a.last_sync_time, 121), 11,13)
       from MSreplication_subscriptions rs
       left outer join MSsubscription_properties sp 
                    on (UPPER(rs.publisher) = UPPER(sp.publisher) and rs.publisher_db = sp.publisher_db and rs.publication = sp.publication) 
       left outer join MSsubscription_agents a
                    on (UPPER(rs.publisher) = UPPER(a.publisher) and 
						rs.publisher_db = a.publisher_db and 
						((rs.publication = a.publication and 
						rs.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and rs.independent_agent = 0)) and
						rs.subscription_type = a.subscription_type)
                where ((@publisher = N'%') OR (UPPER(rs.publisher) = UPPER(@publisher))) AND
                      ((@publisher_db = N'%') OR (rs.publisher_db = @publisher_db)) AND
                      ((@publication = N'ALL' AND rs.independent_agent = 0) OR rs.publication LIKE @publication) AND
					  (rs.subscription_type <> @push OR
					   @show_push_bit = 1)
        ORDER BY rs.publisher, rs.publisher_db, rs.publication  
GO

grant execute on dbo.sp_helppullsubscription to public
go

--------------------------------------------------------------------------------
--. sp_addmergepullsubscription 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
	where type = 'P '
			and name = 'sp_addmergepullsubscription')
	drop procedure sp_addmergepullsubscription
go
raiserror('Creating procedure sp_addmergepullsubscription', 0,1)
GO
 
CREATE PROCEDURE sp_addmergepullsubscription (
	@publication 				sysname,	      			/* Publication name */
	@publisher					sysname = @@SERVERNAME,  	/* Publisher server */
	@publisher_db				sysname = NULL,  			/* Publication database */
	@subscriber_type 			nvarchar(15) = 'local',			/* Subscriber type */ 
	@subscription_priority 		real 		= NULL,				/* Subscription priority */
    @sync_type 					nvarchar(15) = 'automatic', /* subscription sync type */
	@description 				nvarchar(255) = NULL			  
 	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @retcode				int
    declare	@subscriber_db			sysname
    declare @subnickname			int
    declare @subscriber_srvid		int 
    declare @publisher_srvid		int 
    declare @priority 				real
    declare @subid	 				uniqueidentifier
    declare @subscriber_typeid 		smallint
    declare @subscription_type	 	smallint
    declare @command 				nvarchar(255)
    declare @inactive				tinyint 
	declare @global 				tinyint		/* subscriber type is global */
	declare @push 					tinyint		/* subscription type is push */
	 
    declare @sync_typeid 			tinyint
	declare @nosync 				tinyint		
	declare @automatic				tinyint			 
	declare @pubid					uniqueidentifier			 
	declare @partnerid				uniqueidentifier			 
    declare @parentid               uniqueidentifier

	/*
    ** Initializations.
    */

    SET @nosync 			= 2       /* Const: synchronization type 'none' */
    SET @automatic 			= 1       /* Const: synchronization type 'automatic' */
	SET @inactive 			= 0
    SET @global 			= 1
	SET @push 				= 0   


	set @pubid 				= newid()
	set @partnerid			= @pubid
	
	set @parentid			= '00000000-0000-0000-0000-000000000000'
	 
	/* 
	** Check if replication components are installed on this server
	*/
	exec @retcode = dbo.sp_MS_replication_installed
	if (@retcode <> 1)
	begin
		return (1)
	end

    /*
    ** Security Check.
    */

	EXEC @retcode = dbo.sp_MSreplcheck_subscribe
	if @@ERROR <> 0 or @retcode <> 0
		return(1)

	/*
	**	Check to see if merge system tables exist. Create them unless they already
	**  exist.
	*/
	IF not exists (select name from sysobjects where name='sysmergesubscriptions')
		BEGIN
			execute @retcode = dbo.sp_MScreate_mergesystables
				if @@ERROR <> 0 or @retcode <> 0
					begin
						return (1)
					end
		END	

	if UPPER(@publisher) = UPPER(@@SERVERNAME) and @publisher_db = db_name()
		begin
			raiserror(21126, 16, -1)
			return (1)
		end

	if exists (select pubid from sysmergepublications where UPPER(publisher) = UPPER(@@SERVERNAME) and publisher_db=db_name()) and @subscriber_type in ('local', 'anonymous')
		begin
            declare @dbname sysname
            select @dbname = DB_NAME()
    	    raiserror(21258, 16, -1, @dbname)
			return (1)
		end
	/* 
	** When adding a pull subscription, if a push subscription for that publication already exists, 
	** we will raise error and fail
	*/
	IF EXISTS (select name from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db)
	BEGIN
		select @pubid=pubid from sysmergepublications 
			where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
		IF EXISTS (select subid from sysmergesubscriptions where pubid=@pubid and subid<>@pubid and subscription_type=0)
			begin
				RAISERROR (21317, 16, -1, @publication)
				return (1)
			end
		ELSE
			begin
				IF EXISTS (select status from sysmergesubscriptions where pubid=@pubid and status =	2)
					begin
						select @subid = subid from sysmergesubscriptions where pubid=@pubid and subid<>pubid
						delete sysmergesubscriptions where pubid=@pubid
						delete MSmerge_replinfo where repid = @subid
					end
				ELSE 
					begin
						RAISERROR (14058, 16, -1)
						return (1)
					end
			end
	END

	set @partnerid = @pubid
     
  	/*
    ** Assign parameter values appropriately for the local server database
	*/
	set @subscriber_db = DB_NAME()
	select @subscriber_srvid = 0

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

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

    EXECUTE @retcode = dbo.sp_validname @publisher
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
	/*
	** Validate that the publisher is a valid server
	*/
	select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
    IF @publisher_srvid IS NULL
		BEGIN
		    EXECUTE @retcode = dbo.sp_addserver @publisher
	        IF @@error <> 0 OR @retcode <> 0
    			BEGIN
		    		RAISERROR (14010, 16, -1)
			       	RETURN (1)
	            END
	        ELSE
	        	select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
		END


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

    IF LOWER(@publisher_db) = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END
	
	/*
	** Check to see if the publication name is already used in the subscription 
	** database - This is the case where we are resubscribing to the same publication.
	** Execute dbo.sp_MSpublicationcleanup to cleanup all all the defunct rows
	
	** if exists (select * from sysmergepublications where name = @publication)
	** begin
	**	exec @retcode = dbo.sp_MSpublicationcleanup 
	**    IF @@ERROR <> 0 OR @retcode <> 0
	**    	BEGIN
	**			RAISERROR (20025, 16, -1, @publication)
	**	    	RETURN (1)
	**		END				    	
	** end
	*/

    /*
    ** Parameter Check: @subscriber_type.
    ** Set subscriber_typeid based on the @subscriber_type specified.
    **
    **   subscriber_type     subscriber_type
    **   =================    ===============
    **             1     		global
    **             2     		local
    **             3     		anonymous
    **             NO support for republisher for B 3
    */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('local', 'global', 'anonymous')
        BEGIN
		  	RAISERROR (20023, 16, -1)
			RETURN (1)
        END

	set @subscription_type = 1 /* pull by default */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('global')
        set @subscriber_typeid = 1
    else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local')
        set @subscriber_typeid = 2
	else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('anonymous')       
		begin
			/* For anonymous subscribers set subscription type appropriately */
	        set @subscriber_typeid = 3
	        set @subscription_type = 2
		end	        

	/* 
	** Assign priority appropriately - choose 0.99 times the minimum priority
	** of the global replicas.
	*/
	if (@subscription_priority > 100.0 or @subscription_priority < 0.0)
		set @subscription_priority = NULL		
	if (@subscription_priority IS NULL)
		begin
			select @priority = 0.99 * min(priority) from sysmergesubscriptions where subscriber_type  = 1 /* global/loopback */
			if (@priority IS NOT NULL)
				select @subscription_priority = @priority
			if (@subscription_priority IS NULL) 
				select @subscription_priority = 0.0
		end
	/*
	** For local and anonymous subscriptions the priority is 0.0
	*/
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local', 'anonymous')
		select @subscription_priority = 0.0

	/*
 	** If the subscription already exists, don't add it.
	
 	** if EXISTS (select db_name, srvid
 	**		FROM sysmergesubscriptions
    ** 		WHERE db_name = @subscriber_db
    ** 		AND srvid = @subscriber_srvid                	       
    **    	AND pubid = @pubid)
	**	BEGIN
	**		RAISERROR (14058, 16, -1)
	**		RETURN (1)
 	**	END
	*/

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


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


   IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
   BEGIN
		SET @sync_typeid = @automatic
   END
   ELSE
   BEGIN
        SET @sync_typeid = @nosync
   END


	/*
	** UNDONE: Validate that the publisher is of type 'republisher'
	*/

	begin tran
    save TRAN addmergepullsubscription
		
		/* Generate a guid for the Subscriber ID */
		set @subid = newid()

		/* Look for existing nickname from any other subscription */
		exec dbo.sp_MSgetreplnick NULL, NULL , NULL,  @subnickname out
		if (@@error <> 0) 
	        begin
            goto FAILURE
	        end                 


		/* Generate a new replica nickname from the @subid */
		if (@subnickname is null)
			EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output

	
		/* 
		** Check to see if MSsubscription_properties table exists.
		** If not, create it.
		*/
		exec @retcode = dbo.sp_MScreate_sub_tables
			@tran_sub_table = 0,
			@property_table = 1,
			@sqlqueue_table = 0

		IF @@ERROR <> 0 or @retcode <> 0
			goto FAILURE

		/*
		** The subscription doesn't exist, so let's add it to sysmergesubscriptions 
		*/
		INSERT sysmergesubscriptions (subid, partnerid, datasource_type, srvid, db_name, 
				pubid, status, subscriber_type, subscription_type, priority, sync_type, 
				description, login_name, subscriber_server, publication)
					VALUES (@subid,
							@partnerid,
							0,
		    				@subscriber_srvid,
		    				@subscriber_db,
		    				@pubid,
		    				@inactive,
		    				@subscriber_typeid,
							@subscription_type, 	/* for a pull/anon subscription */
		    				@subscription_priority,
		    				@sync_typeid,
		    				@description,
		    				suser_sname(suser_sid()),
		    				@@servername,
		    				@publication)			
		if @@ERROR <> 0
			BEGIN
				GOTO FAILURE
			END

		/* Add a self-subscribed subscription to represent the publication */
			
		insert sysmergepublications(publisher, publisher_db, pubid, name, parentid) 
			values(@publisher, @publisher_db, @pubid, @publication, @parentid)
		if @@ERROR <> 0
			begin
				goto FAILURE
			end
		insert sysmergesubscriptions(subid, partnerid, datasource_type, srvid, db_name, 
				pubid, subscriber_type, subscription_type, status, priority, sync_type, description, login_name, subscriber_server, publication, distributor)
			values (@pubid, @pubid, 0, @publisher_srvid, @publisher_db, 
				@pubid, @global, @push, @inactive, 100.0, @sync_typeid, @description, suser_sname(suser_sid()), @publisher, @publication, @publisher)  
						
		if @@ERROR <> 0
			begin
				goto FAILURE
			end
					
		/*
		**  Add row for subscription in MSmerge_replinfo.
		*/
		insert MSmerge_replinfo(repid, replnickname)
				values (@subid, @subnickname)
		if @@ERROR <> 0
			BEGIN
				GOTO FAILURE
			END

    COMMIT TRAN
	return (0)

FAILURE:
	RAISERROR (14057, 16, -1)
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION addmergepullsubscription
		COMMIT TRANSACTION
	end
	RETURN (1)

go
exec dbo.sp_MS_marksystemobject sp_addmergepullsubscription 
go

grant execute on dbo.sp_addmergepullsubscription to public
go
 
--------------------------------------------------------------------------------
--. sp_changemergepullsubscription 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
	where type = 'P '
			and name = 'sp_changemergepullsubscription')
	drop procedure sp_changemergepullsubscription
go
raiserror('Creating procedure sp_changemergepullsubscription', 0,1)
GO

CREATE PROCEDURE sp_changemergepullsubscription (
	@publication 		sysname = '%',	/* Publication name */
	@publisher			sysname = '%',  /* Publisher server */
	@publisher_db		sysname = '%', 	/* Publication database */
    @property 			sysname = NULL, /* The property to change */
    @value 				nvarchar(255) = NULL	/* The new property value */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @subscriber_srvid	 	int
    declare @publisher_srvid	 	int
	declare @retcode 				int
	declare	@pubid 					uniqueidentifier
	declare	@subid 					uniqueidentifier
	declare	@partnerid 				uniqueidentifier
    declare @sync_typeid 			tinyint
    declare @nosync 				tinyint
    declare @automatic 				tinyint
     
    declare @artid					uniqueidentifier
	declare @subscriber				sysname
	declare @subscriber_db			sysname
    declare @schematype				int
	declare @schemaversion			int
	declare @schemaguid				uniqueidentifier
    declare @db_name				sysname
    declare @subscriber_type		int
    declare @schematext				nvarchar(2000)
	declare @use_interactive_bit	bit
	declare @use_interactive_int	int
	declare @enabled_for_syncmgr	int
	declare @regkey					nvarchar(1000)
	declare @snapshot_ready			int
    /*
    ** Initializations.
    */
    SET @subscriber 	= @@SERVERNAME
    SET @subscriber_db	= DB_NAME()
    SET @nosync 		= 2     /* Const: synchronization type 'none' */
    SET @automatic 		= 1     /* Const: synchronization type 'automatic' */

	select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
    IF @subscriber_srvid IS NULL
		BEGIN
		   RAISERROR (14010, 16, -1)
		   RETURN (1)     
		END

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


	/*
	**	Check to see if current database is enabled for subscribing
	*/
	IF not exists (select name from sysobjects where name='sysmergesubscriptions')
		BEGIN
        	RAISERROR (14055, 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 collate database_default not null)
            INSERT INTO #tab1 VALUES ('sync_type')
            INSERT INTO #tab1 VALUES ('priority')
            INSERT INTO #tab1 VALUES ('description') 
            INSERT INTO #tab1 VALUES ('use_interactive_resolver') 			
            -- Properties delegated to sp_change_subscription_properties
            INSERT INTO #tab1 VALUES ('publisher_login')
            INSERT INTO #tab1 VALUES ('publisher_password')
            INSERT INTO #tab1 VALUES ('publisher_security_mode')
            INSERT INTO #tab1 VALUES ('distributor')
            INSERT INTO #tab1 VALUES ('distributor_login')
            INSERT INTO #tab1 VALUES ('distributor_password')
            INSERT INTO #tab1 VALUES ('distributor_security_mode')
            INSERT INTO #tab1 VALUES ('ftp_address')
            INSERT INTO #tab1 VALUES ('ftp_port')
            INSERT INTO #tab1 VALUES ('ftp_login')
            INSERT INTO #tab1 VALUES ('ftp_password')
            INSERT INTO #tab1 VALUES ('alt_snapshot_folder')
            INSERT INTO #tab1 VALUES ('working_directory')
            INSERT INTO #tab1 VALUES ('use_ftp')
            INSERT INTO #tab1 VALUES ('offload_agent')
            INSERT INTO #tab1 VALUES ('offload_server')
            INSERT INTO #tab1 VALUES ('dynamic_snapshot_location')
            select * FROM #tab1
            RETURN (0)
        END

    /*
    ** Parameter Check:  @publisher.
    ** Check to make sure we have a valid publisher.
    ** Should make sure that @publisher is non-null before using it to check whether @publication is valid
    */
    IF @publisher IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publisher')
            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

    select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

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

    /*
    ** Check to see if you have a local / global subscription on this publication
    */
    set @subid = NULL
	select @subid = subs1.subid, 
    @pubid = pubs.pubid, /* identified from publication name */
	@subscriber_type=subs1.subscriber_type,
    	@partnerid = subs2.subid from
		sysmergesubscriptions 	subs1,
	  	sysmergesubscriptions 	subs2,
		sysmergepublications 	pubs
		where subs1.srvid = @subscriber_srvid
			and subs1.db_name = @subscriber_db
			and subs2.srvid = @publisher_srvid
			and subs2.db_name = @publisher_db
			and subs1.pubid = subs2.subid
			and subs2.pubid = pubs.pubid
			and pubs.name = @publication
			and UPPER(pubs.publisher)=UPPER(@publisher)
			and pubs.publisher_db = @publisher_db

	if @subid IS NULL 
     	begin
            RAISERROR (14050, 11, -1)
            RETURN(1)
		end     			

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

	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
                               ('sync_type', 
                                'priority', 
                                'description',
                                'publisher_login',
                                'publisher_password',
                                'publisher_security_mode',
                                'distributor',
                                'distributor_login',
                                'distributor_password',
                                'distributor_security_mode',
                                'ftp_address',
                                'ftp_port',
                                'ftp_login',
                                'ftp_password',
                                'alt_snapshot_folder',
                                'working_directory',
                                'use_ftp',
                                'use_interactive_resolver',
                                'offload_agent',
                                'offload_server',
                                'dynamic_snapshot_location')
        BEGIN
            RAISERROR (21348, 16, -1, @property)
            RETURN (1)
        END

    /*
    ** Change the property.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_type'
        BEGIN

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'none')
                BEGIN
                    RAISERROR (14052, 16, -1)
                    RETURN (1)
                END

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

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
		        SET @sync_typeid = @automatic
	        ELSE
		        SET @sync_typeid = @nosync

            /*
            ** Update the subscription with the new sync_type.
            */

            UPDATE sysmergesubscriptions
               	SET sync_type = @sync_typeid
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END

        END
        
	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'description'
        BEGIN
		UPDATE sysmergesubscriptions
               	SET description = @value
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1) 
              
                    RETURN (1)
                END

        END

	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_interactive_resolver'
        BEGIN

            /* Check to make sure that we have a true/false. */

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

            /* Determine the bit value. */

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		        SET @use_interactive_bit = 1
	        ELSE
		        SET @use_interactive_bit = 0
	
			/* Update the subscription with the new 'use_interactive' value. */

            UPDATE sysmergesubscriptions
               	SET use_interactive_resolver = @use_interactive_bit
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END
			/* If the subscription is enable for Sync Manager, then update the reg value */
			exec sp_MSsubscription_enabled_for_syncmgr
				@publisher, @publisher_db, @publication, @subscriber, @subscriber_db, 
				@enabled_for_syncmgr OUT, @regkey OUT
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END
			if @enabled_for_syncmgr = 1
				begin
			        select @use_interactive_int = convert(int, @use_interactive_bit)
					EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
			                               @regkey,
			                               'UseInteractiveResolver',
			                               'REG_DWORD',
			                                @use_interactive_int
					if @retcode <> 0 OR @@ERROR <> 0
		                BEGIN
		                    RAISERROR (14053, 16, -1)
		                    RETURN (1)
		                END
				end

        END
        

     
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'priority'
    BEGIN

		select @db_name = db_name from sysmergesubscriptions
        	where (pubid=@pubid) and (subid=@pubid)
        IF @db_name <> db_name()
	        BEGIN
    	    	RAISERROR (20047, 16, -1)
        	    RETURN (1)
	        END

	    /* Only the original publisher can change priority of a global subscriptions */

    	IF @subscriber_type<>1  
    	    BEGIN
        	    RAISERROR (20044, 16, -1)  /* Local subscriber does not have priority*/
	            RETURN (1)
    	    END

		 
		BEGIN TRANSACTION
		save tran sp_changemergepullsubscription
        	exec dbo.sp_MSchange_priority @subid,  @value
            select @snapshot_ready=snapshot_ready from sysmergepublications where pubid = @pubid
	    	/* Insert the sp_MSchange_priority schema change only if the publication's snapshot is ready */
			if (@snapshot_ready > 0)
			begin
		     	select @schemaversion = schemaversion from sysmergeschemachange
				if (@schemaversion is NULL)
				set @schemaversion = 1
				else
					select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
				set @schemaguid = newid()
				set @artid = newid()
				set @schematype = 8 /* change priority */
				select @schematext = 'exec dbo.sp_MSchange_priority '+ '''' + convert(nchar(36),@subid) + '''' + ',' + '''' + @value + '''' 
			 	exec dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
                if @@ERROR <> 0 goto Rollback_tran
			end		 	
		COMMIT TRANSACTION

	END
	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN 
                           ('publisher_login',
                            'publisher_password',
                            'publisher_security_mode',
                            'distributor',
                            'distributor_login',
                            'distributor_password',
                            'distributor_security_mode',
                            'ftp_address',
                            'ftp_port',
                            'ftp_login',
                            'ftp_password',
                            'alt_snapshot_folder',
                            'working_directory',
                            'use_ftp',
                            'offload_agent',
                            'offload_server',
                            'dynamic_snapshot_location')
    BEGIN
        EXEC @retcode = sp_change_subscription_properties @publisher = @publisher,
                                                          @publisher_db = @publisher_db,
                                                          @publication = @publication,
                                                          @property = @property,
                                                          @value = @value,
                                                          @publication_type = 2
        IF @retcode <> 0
            RETURN 1
    END


    /*
    ** Return succeed.
    */

    RAISERROR (14054, 10, -1)
    RETURN (0)
Rollback_tran:
	rollback tran sp_changemergepullsubscription
	commit tran
	return(1)
go

exec dbo.sp_MS_marksystemobject sp_changemergepullsubscription 
go

grant execute on dbo.sp_changemergepullsubscription to public
go

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

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

CREATE PROCEDURE sp_helpmergepullsubscription(
	@publication 		sysname = '%',		/* Publication name */
	@publisher			sysname = '%',  	/* Publisher server */
	@publisher_db		sysname = '%',  	/* Publication database */
	@subscription_type	nvarchar(10) = 'pull'	/* Show only pull subscriptions */
	)AS
	
    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    declare @retcode 			int
    declare @srvid	 			int
	declare	@pubid 				uniqueidentifier
	declare	@subid 				uniqueidentifier
	declare	@partnerid 			uniqueidentifier
    declare @cursor_open		int
	declare @subscriber			sysname
	declare @subscriber_db		sysname
    declare @subscription_set 	nvarchar(10)
	declare @publisher_local	sysname
	declare @publisher_db_local	sysname
	declare @publication_local	sysname
	declare @subscription_name 	nvarchar(1000)
	declare @regkey				nvarchar(1000)
	declare @syncmgr_keyexist				int
	declare @helpsubscriptioncursor_open	int
	

    /*
    ** Initializations.
    */
	set @cursor_open 			= 0					

	select @publisher_db = RTRIM(@publisher_db)
	select @publication = RTRIM(@publication)
	
	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
		-- The database is attached from a subscription copy file without using
		-- sp_attachsubscription. Return nothing
		return 0

	/*
	**	Calling sp_help* is all right whether current database is enabled for pub/sub or not
	*/

	IF not exists (select * from sysobjects where name='sysmergesubscriptions')
		RETURN (0)

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

	set @subscriber = @@SERVERNAME	 
	set @subscriber_db = DB_NAME()
 
    /*
    ** Parameter Check: @publisher
    ** Check to make sure that the publisher is defined
    */
    IF @publisher <> '%' AND @publisher IS NOT NULL
    BEGIN
		EXECUTE @retcode = dbo.sp_validname @publisher

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

	/*
    ** Parameter Check: @subscription_type.
    ** Set subscription_typeid based on the @subscription_type specified.
    **
    **   subscription_type    subscription_type
    **   =================    ===============
    **             0     		push
    **             1     		pull
    **			  0,1			both
    */
    if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull', 'both')
        BEGIN
		  	RAISERROR (14128, 16, -1)
			RETURN (1)
        END
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
        set @subscription_set = '(0, 1)'
    else IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        set @subscription_set = '(0)'
    else 
        set @subscription_set = '(1,2)'   -- including pull subscription and pull/anonymous subscription

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
		RETURN (0)

    /*
    ** Get subscriptions
    */
	
	create table #helpmergepullsubscription
				(
					publication				sysname		collate database_default not null,
					publisher				sysname		collate database_default not null,
					publisher_db			sysname		collate database_default not null,
					subscriber				sysname		collate database_default not null,
					subscriber_db		 	sysname		collate database_default not null,
					status    				int     	NOT NULL,
					subscriber_type 		int		    NOT NULL,
					subscription_type 		int		    NOT NULL,
					priority				float(8)	NOT NULL,
					sync_type				tinyint		NOT NULL,
					description				nvarchar(255) 	collate database_default null,
					merge_jobid				binary(16)		NULL,
					enabled_for_syncmgr		int				NULL,
					last_updated	        nvarchar(26) 	collate database_default null,
                    use_interactive_resolver 	int			NULL,
                    subid					uniqueidentifier	not NULL,
                    last_sync_status		int				NULL,
                    last_sync_summary		sysname			collate database_default null
				)

    IF @publisher IS NULL and @publisher_db IS NULL
	    BEGIN
	    	select @subid = subid from sysmergesubscriptions where subid = partnerid
	    	set @partnerid = @subid
			-- show the loopback subscription
		    insert into #helpmergepullsubscription 
				select pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
					subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
					subs1.sync_type, subs1.description, replinfo.merge_jobid, 0, 
					convert(nvarchar(12), subs1.last_sync_date, 112) + substring(convert(nvarchar(24), subs1.last_sync_date, 121), 11,13), 
					subs1.use_interactive_resolver, @subid, subs1.last_sync_status, subs1.last_sync_summary
		    	FROM  	sysmergesubscriptions 	subs1,
		    		  	sysmergesubscriptions 	subs2,
		    		  	MSmerge_replinfo	 	replinfo,
	        			master.dbo.sysservers 	servers1,
	        			master.dbo.sysservers 	servers2,
						sysmergepublications 	pubs
				where subs1.subid = @subid
					and subs2.subid = @partnerid
					and pubs.pubid = subs1.pubid
					and servers1.srvid = subs1.srvid
					and servers2.srvid = subs2.srvid
					and subs1.subid = subs1.partnerid 
					and replinfo.repid = subs1.subid 
	    	
	    END
	else
		begin
			declare #cursor cursor local FAST_FORWARD FOR select DISTINCT sub.subid, sub.partnerid 
	        	FROM sysmergesubscriptions 	sub,
	    	    sysmergesubscriptions 		sub1, 
	            master.dbo.sysservers		ss,  
	            master.dbo.sysservers		ss1, 
	            sysmergepublications 		pub 
	         	WHERE ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default)) 
					AND ((@publisher = N'%') OR (UPPER(ss1.srvname) = UPPER(@publisher) collate database_default)) 
					AND sub1.srvid = ss1.srvid 
	           		AND sub.srvid = ss.srvid  
	           		AND pub.name LIKE  @publication  
	           		AND sub.pubid = pub.pubid 
                                AND ((@subscriber_db = N'%') OR (sub.db_name = @subscriber_db collate database_default))
                                AND ((@publisher_db = N'%') OR (sub1.db_name = @publisher_db collate database_default))
					AND sub1.pubid = pub.pubid 
					AND (sub.subscription_type=1 or sub.subscription_type=2) 
				FOR READ ONLY

			open #cursor
			select @cursor_open = 1					
			fetch next from #cursor into @subid, @partnerid
			while (@@fetch_status <> -1)
				begin
				    insert into #helpmergepullsubscription 
						select pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
							subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
							subs1.sync_type, subs1.description, replinfo.merge_jobid, 0, 
							convert(nvarchar(12), subs1.last_sync_date, 112) + substring(convert(nvarchar(24), subs1.last_sync_date, 121), 11,13), 
							subs1.use_interactive_resolver, @subid, subs1.last_sync_status, subs1.last_sync_summary
				    	FROM  	sysmergesubscriptions 	subs1,
				    		  	sysmergesubscriptions 	subs2,
				    		  	MSmerge_replinfo	 	replinfo,
			        			master.dbo.sysservers	servers1,
			        			master.dbo.sysservers	servers2,
								sysmergepublications 	pubs
						where subs1.subid = @subid
							and subs2.subid = @partnerid
							and pubs.pubid = subs1.pubid
							and servers1.srvid = subs1.srvid
							and servers2.srvid = subs2.srvid
							and @subid <> @partnerid -- do not show the loopback subscription
							and replinfo.repid = subs1.subid 
		
					if @@ERROR <> 0
						begin
							set @retcode = 1
							goto DONE
						end					
				fetch next from #cursor into @subid, @partnerid
			end
		end
		declare #helpsubscriptioncursor CURSOR LOCAL FAST_FORWARD FOR 
			select DISTINCT publisher, publisher_db, publication
       			FROM #helpmergepullsubscription
				FOR READ ONLY
		create table #syncmgr_keyexist (syncmgr_keyexist int)
		open #helpsubscriptioncursor
		select @helpsubscriptioncursor_open = 1					
		fetch next from #helpsubscriptioncursor into @publisher_local, @publisher_db_local, @publication_local
		while (@@fetch_status <> -1)
		begin
			set @subscription_name = @publisher_local + ':' + @publisher_db_local + ':' + @publication_local + ':' + @subscriber + ':' + @subscriber_db
			/* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */
			set @subscription_name = REPLACE(@subscription_name,'\','/')
			set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
			insert into #syncmgr_keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @regkey
			select @syncmgr_keyexist = syncmgr_keyexist from #syncmgr_keyexist
			update #helpmergepullsubscription set enabled_for_syncmgr = @syncmgr_keyexist 
				where UPPER(publisher) = UPPER(@publisher_local)
					and publisher_db = @publisher_db_local
					and publication = @publication_local
			fetch next from #helpsubscriptioncursor into @publisher_local, @publisher_db_local, @publication_local
		end

	select 'subscription_name'= hs.publisher + ':' + hs.publisher_db + ':' + hs.publication collate database_default, hs.publication, hs.publisher,
            hs.publisher_db, hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type, hs.subscription_type,
            hs.priority, hs.sync_type, hs.description, hs.merge_jobid, hs.enabled_for_syncmgr, hs.last_updated, sp.publisher_login,
            sp.publisher_password, sp.publisher_security_mode, sp.distributor, sp.distributor_login, 
            sp.distributor_password, sp.distributor_security_mode, 'ftp_address' = null, 'ftp_port' = 0, 
            'ftp_login' = null, 'ftp_password' = null, sp.alt_snapshot_folder, sp.working_directory, sp.use_ftp, 
            sp.offload_agent, sp.offload_server, hs.use_interactive_resolver, hs.subid, 
            sp.dynamic_snapshot_location, hs.last_sync_status, hs.last_sync_summary
				from #helpmergepullsubscription hs
     left outer join MSsubscription_properties sp
                  on hs.publisher = sp.publisher collate database_default
                 and hs.publisher_db = sp.publisher_db collate database_default
                 and hs.publication = sp.publication collate database_default
			order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
    	 
	select @retcode = 0
DONE:
	if (@cursor_open = 1)
		begin
			close #cursor
			deallocate #cursor
		end			
	--drop table #helpmergepullsubscription

	return @retcode	
go
exec dbo.sp_MS_marksystemobject sp_helpmergepullsubscription
go

grant execute on dbo.sp_helpmergepullsubscription to public
go

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

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

CREATE PROCEDURE sp_addmergepullsubscription_agent (
	@name							sysname = NULL,
	@publisher						sysname,  						/* Publisher server */
	@publisher_db					sysname,  						/* Publisher database */
	@publication 					sysname,	      				/* Publication name */
	@publisher_security_mode		int = 1,
	@publisher_login				sysname = NULL,
	@publisher_password				sysname = NULL,
	@publisher_encrypted_password	bit = 0,
	@subscriber						sysname = NULL,
	@subscriber_db					sysname = NULL,
	@subscriber_security_mode		int = NULL,						/* 0 standard; 1 integrated */
	@subscriber_login				sysname = NULL,
	@subscriber_password			sysname = NULL,
	@distributor					sysname = @@SERVERNAME,
	@distributor_security_mode		int = 0,						/* 0 standard; 1 integrated */
	@distributor_login				sysname = 'sa',
	@distributor_password			sysname = NULL,
	@encrypted_password				bit = 0,			/* distributor password encrypted or not */
    @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(255) = '',			/* Optional command line arguments */
    @merge_jobid					binary(16) = NULL OUTPUT,
    @enabled_for_syncmgr 			nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
	@ftp_address 					sysname = NULL,
	@ftp_port 						int = NULL,
	@ftp_login 						sysname = NULL,
	@ftp_password 					sysname = NULL,
    @alt_snapshot_folder  			nvarchar(255) = NULL,
    @working_directory    			nvarchar(255) = NULL,
    @use_ftp              			nvarchar(5) = 'false',
	@reserved 						nvarchar(100) = N'', -- Not default to null because null problems in conditional expressions.
	@use_interactive_resolver   	nvarchar(5) = 'false',
    @offloadagent         			nvarchar(5) = 'false',
    @offloadserver        			sysname = null,
	-- Used by DMO scripting
	@job_name						sysname = NULL,
    @dynamic_snapshot_location      nvarchar(260) = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @command 				nvarchar(4000)
    declare @retcode 				int
	declare @database				sysname
	declare @repid					uniqueidentifier
	declare @pubid					uniqueidentifier
    declare @subscriber_srvid		int 
    declare @publisher_srvid		int 
	declare @name_id				nvarchar(50)
	declare @subscriber_typeid		int
	declare @subscription_type_id	int
	declare @category_name			sysname
	declare @platform_nt			binary
	DECLARE @subscriber_enc_password 	nvarchar(524)
	DECLARE @publisher_enc_password 	nvarchar(524)
	DECLARE @distributor_enc_password 	nvarchar(524)
    DECLARE @use_ftp_bit            	bit
	declare @use_interactive_bit		bit
    DECLARE @offload_agent_bit      	bit

	select @platform_nt = 0x1

    SELECT @use_ftp_bit = 0

	-- For attach check
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
	begin
		raiserror(21211, 16, -1)
		return 1
	end

	-- Set null @optional_command_line to empty string to avoid string concat problem
	if @optional_command_line is null
		set @optional_command_line = ''
        else
                set @optional_command_line = N' ' + LTRIM( RTRIM(@optional_command_line) ) + N' '

	IF @distributor_password = N''
		select @distributor_password = NULL

	IF @publisher_password = N''
		select @publisher_password = NULL

	IF @ftp_password = N''
		select @ftp_password = NULL

	/*
	** Parameter Check: @subscriber and @subscriber_db
	*/

	if @subscriber IS NULL or rtrim(@subscriber) = ''
		SELECT @subscriber = @@SERVERNAME

	if @subscriber_db IS NULL or rtrim(@subscriber_db) = ''
		SELECT @subscriber_db = DB_NAME()
	
	EXECUTE @retcode = dbo.sp_validname @subscriber
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
	
    EXECUTE @retcode = dbo.sp_validname @subscriber_db
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)

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

    /* 
    ** Parameter check: @alt_snapshot_folder 
    ** @alt_snapshot_folder and @use_ftp are mutually exclusive    
    ** @dynamic_snapshot_location is incompatible with both 
    ** @alt_snapshot_folder and @use_ftp
    */

    IF @alt_snapshot_folder <> N'' AND @alt_snapshot_folder IS NOT NULL
    BEGIN
        IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = N'true'
        BEGIN
            RAISERROR(21146, 16, -1)
            RETURN (1)
        END
        IF @dynamic_snapshot_location <> N'' AND @dynamic_snapshot_location IS NOT NULL
        BEGIN
            RAISERROR(21341, 16, -1)
            RETURN (1)
        END
    END

   	/*
    ** Parameter Check: @use_interactive_resolver  
    */
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@use_interactive_resolver')
            RETURN (1)
        END
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        set @use_interactive_bit = 1
    else 
        set @use_interactive_bit = 0

    /* 
    ** Parameter check: @use_ftp
    ** Must be 'true' or 'false'
    */
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@use_ftp')
        RETURN (1)
    END
    
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        /*
        ** Ftp file transfer is incompatible with @dynamic_snapshot_location
        */
        IF @dynamic_snapshot_location <> N'' AND @dynamic_snapshot_location IS NOT NULL
        BEGIN
            RAISERROR (21342, 16, -1)
            RETURN (1)
        END

        SELECT @use_ftp_bit = 1

    END
    ELSE
    BEGIN
        SELECT @use_ftp_bit = 0
    END

    /*
    ** Parameter Check: @offloadserver
    ** If @offloadagent = 'true' then @offloadserver cannot be null
    */
    SELECT @offloadagent = LOWER(@offloadagent collate SQL_Latin1_General_CP1_CS_AS)
    IF @offloadagent NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@offloadagent')
        RETURN (1)
    END

    IF @offloadagent = 'true'
    BEGIN
        SELECT @offload_agent_bit = 1
    END
    ELSE
    BEGIN
        SELECT @offload_agent_bit = 0
    END

    IF @offload_agent_bit = 1 AND (@offloadserver IS NULL or
                               @offloadserver = N'')
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN (1)
    END

    IF UPPER(@offloadserver) = UPPER(@@SERVERNAME) AND
       @offload_agent_bit = 1
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END

    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode <> 0 OR @@ERROR <> 0
        RETURN (1)

    -- Make sure that there are no leading or trailing blanks
    -- in the dynamic snapshot location
    select @dynamic_snapshot_location = rtrim(ltrim(@dynamic_snapshot_location))

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

	select @subscription_type_id = 1 /* pull agent only */
	/*
	** Set Default schedule values if NULL is specified
	** The default are not implemented during parmeter defintion because this procedure
	** is can be called from sp_addmergesubscription.
	*/
	if @frequency_type is NULL
		set @frequency_type = 4		/* Daily */
	if @frequency_interval is NULL
		set @frequency_interval = 1
	if @frequency_relative_interval is NULL
		set @frequency_relative_interval = 1
	if @frequency_recurrence_factor is NULL
		set @frequency_recurrence_factor = 0
	if @frequency_subday is NULL
		set @frequency_subday = 8	/* Hour */
    if @frequency_subday_interval is NULL
		set @frequency_subday_interval = 1
    if @active_start_time_of_day is NULL
		set @active_start_time_of_day = 0
    if @active_end_time_of_day is NULL
		set @active_end_time_of_day = 235959
    if @active_start_date is NULL
		set @active_start_date = 0
    if @active_end_date is NULL
		set @active_end_date = 99991231

	select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@@SERVERNAME) collate database_default
    IF @subscriber_srvid IS NULL
		BEGIN
		   RAISERROR (14010, 16, -1)
		   RETURN (1)     
		END
			
	select @pubid = pubid from sysmergepublications 
		where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
	IF @pubid is NULL
		begin
			RAISERROR (20026, 16, -1, @publication)
			RETURN (1)
		end
			
	select @repid = subid, @subscriber_typeid = subscriber_type from sysmergesubscriptions
			where srvid = @subscriber_srvid and pubid<>subid and pubid = @pubid and db_name = @subscriber_db

	if @subscriber_typeid = 3 set @subscription_type_id = 2 /* This corresponds to anonymous subscription */

	if (@subscription_type_id <> 0)
	begin
		if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
		begin
			raiserror(3217, 16, -1, '@subscriber_login')
			return (1)
		end
	end

	if (@distributor_security_mode = 0) and (@distributor_login IS NULL or rtrim(@distributor_login) = '')
	begin
		raiserror(3217, 16, -1, '@distributor_login')
		return (1)
	end

	if (@publisher_security_mode = 0) and (@publisher_login IS NULL or rtrim(@publisher_login) = '')
	begin
		raiserror(3217, 16, -1, '@publisher_login')
		return (1)
	end

	IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
	begin
		raiserror(14027, 16, -1, 'The subscription properties table ''MSsubscription_properties''')
		return (1)
	end
	
	declare @job_existing bit
	-- For scripting
	if @job_name is null
		select @job_existing = 0
	else
	begin
		select @job_existing = 1
		select @name = @job_name
	end

	/*
    ** Construct unique task name if @name = NULL
	*/
	IF @name IS NULL
		begin
			 SELECT @name = CONVERT(nvarchar(23),@publisher ) + '-' + CONVERT(nvarchar(23),@publisher_db) + '-' + 
						CONVERT(nvarchar(23),@publication) + '-' + CONVERT(nvarchar(23),@subscriber) + '-' +
						CONVERT(nvarchar(23), @subscriber_db) + '- 0'
		end
	else
	begin
		/*
		** validate name
		*/
		exec @retcode = dbo.sp_MSreplcheck_name @name
		if @@ERROR <> 0 or @retcode <> 0
			return(1)

	end

	-- Get property values.
	if @reserved = 'no_change_to_properties'
	begin
		-- Get the distributor value. It will be used in agent command line.
		select @distributor = distributor, 
			@enabled_for_syncmgr = case enabled_for_syncmgr
				when 0 then 'false'
				when 1 then	'true'
				end
			from MSsubscription_properties where
			UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
	end

	begin tran
	save tran sp_addpullsub_agent

	if @job_existing = 0
	begin
		/* Construct task command */
		select @command = '-Publisher ' + QUOTENAME(@publisher) + ' -PublisherDB ' + QUOTENAME(@publisher_db) + ' '
		select @command = @command + '-Publication ' + QUOTENAME(@publication) + ' '
		select @command = @command + '-Subscriber ' + QUOTENAME(@@SERVERNAME)  + ' '
		select @command = @command + '-SubscriberDB ' + QUOTENAME(db_name()) + ' '
		SELECT @command = @command + '-SubscriptionType ' + convert(nvarchar(10), @subscription_type_id)  + ' '
		
		select @command = @command + '-SubscriberSecurityMode ' + 
			convert(nvarchar(10),@subscriber_security_mode) + ' '
		if @subscriber_login is not NULL
			select @command = @command + '-SubscriberLogin ' + quotename(@subscriber_login) + ' '
		if @subscriber_password is not NULL
		begin
			set @subscriber_enc_password = @subscriber_password
			exec @retcode = master.dbo.xp_repl_encrypt @subscriber_enc_password OUTPUT
			select @command = @command + '-SubscriberEncryptedPassword ' + quotename(@subscriber_enc_password) + ' '
		end
		
		select @command = @command + @optional_command_line
		select @command = @command + ' -Distributor ' + QUOTENAME(@distributor) + ' '

		if @offload_agent_bit = 1
			select @command = @command + N'-Offload ' + @offloadserver + N' '
		
        select @dynamic_snapshot_location = rtrim(ltrim(@dynamic_snapshot_location))
        if @dynamic_snapshot_location is not null and 
           @dynamic_snapshot_location <> N''
            select @command = @command + N'-DynamicSnapshotLocation ' + fn_replquotename(@dynamic_snapshot_location) collate database_default + N' '

		select @database = db_name()

		-- Get Merge category name (assumes category_id = 14)
		select @category_name = name FROM msdb.dbo.syscategories where category_id = 14

		EXEC @retcode = dbo.sp_MSadd_repl_job
				@name = @name,
				@subsystem = 'Merge',
				@server = @@SERVERNAME,
				@databasename = @database,
				@enabled = 1,
				@freqtype = @frequency_type,
				@freqinterval = @frequency_interval,
				@freqsubtype = @frequency_subday,
				@freqsubinterval = @frequency_subday_interval,
				@freqrelativeinterval = @frequency_relative_interval,
				@freqrecurrencefactor = @frequency_recurrence_factor,
				@activestartdate = @active_start_date,
				@activeenddate = @active_end_date,
				@activestarttimeofday = @active_start_time_of_day,
				@activeendtimeofday = @active_end_time_of_day,
				@command = @command,
				@retryattempts = 10,
				@retrydelay = 1,
				@category_name = @category_name,
				@job_id = @merge_jobid OUTPUT

		if @@ERROR <> 0 or @retcode <> 0 goto Rollback_tran
	end
	else
	begin
		select @merge_jobid = job_id from msdb..sysjobs_view where 
			name = @name collate database_default and
			UPPER(originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
		if @merge_jobid IS NULL
		begin
			-- Message from msdb.dbo.sp_verify_job_identifiers
			RAISERROR(14262, -1, -1, 'Job', @name)          
			goto Rollback_tran
		end
	end


	if @reserved <> 'attach_subscription' and (@subscription_type_id = 1) OR (@subscription_type_id = 2)
	begin
		IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication) 
		BEGIN
			
			-- Copy the passwords to new value before attempting to encrypt
			set @distributor_enc_password = @distributor_password
			set @publisher_enc_password = @publisher_password

			IF (@encrypted_password = 0)
			-- Encrypt the password
			BEGIN
				EXEC @retcode = master.dbo.xp_repl_encrypt @distributor_enc_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0 goto Rollback_tran
			END
	
			IF (@publisher_encrypted_password = 0)
			-- Encrypt the password
			BEGIN
				EXEC @retcode = master.dbo.xp_repl_encrypt @publisher_enc_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0 goto Rollback_tran
			END
	
			INSERT INTO MSsubscription_properties 
			(publisher, publisher_db, publication, publication_type, 
			 publisher_login,publisher_password, publisher_security_mode, 
			 distributor, distributor_login, distributor_password, 
			 distributor_security_mode, ftp_address, ftp_port, ftp_login, 
			 ftp_password, alt_snapshot_folder, working_directory, use_ftp,
             offload_agent, offload_server, dynamic_snapshot_location)
			values 
			(@publisher, @publisher_db, @publication, 2, @publisher_login, 
			 @publisher_enc_password, @publisher_security_mode, @distributor, 
			 @distributor_login, @distributor_enc_password, 
			 @distributor_security_mode, null, null, null,
			 null, @alt_snapshot_folder, @working_directory, @use_ftp_bit,
             @offload_agent_bit, @offloadserver, @dynamic_snapshot_location)
		END
	end

		
	/* Update merge joibd for this pull subscription */
	UPDATE MSmerge_replinfo set merge_jobid = @merge_jobid WHERE repid = @repid

	/* Update the distributor column in sysmergesubscriptions */
	UPDATE sysmergesubscriptions set 
			use_interactive_resolver = @use_interactive_bit,
			distributor = @distributor 
				WHERE subid = @repid
	
	/* Conditional support for MobileSync */
    if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
		/* Call sp_MSregistersubscription so that the subscription can be synchronized via MobileSync etc. */
		exec @retcode = dbo.sp_MSregistersubscription @replication_type = 2,
									@publisher = @publisher,
									@publisher_security_mode = @publisher_security_mode,
									@publisher_login = @publisher_login,
									@publisher_password = @publisher_password,
									@publisher_db = @publisher_db,
									@publication = @publication,
								    @subscriber = @subscriber,
								    @subscriber_db = @subscriber_db,
									@subscriber_security_mode = @subscriber_security_mode,
									@subscriber_login = @subscriber_login,
									@subscriber_password = @subscriber_password,
									@distributor = @distributor,
									@distributor_security_mode = @distributor_security_mode,
									@distributor_login = @distributor_login,
									@distributor_password = @distributor_password,
								    @subscription_id = @repid,
									@subscription_type = @subscription_type_id,
									@use_interactive_resolver = @use_interactive_bit

		IF @@ERROR <> 0 or @retcode <> 0 goto Rollback_tran
	END

commit tran
	RETURN (0)
Rollback_tran:
	rollback tran sp_addpullsub_agent
	commit tran
	return(1)
GO

exec dbo.sp_MS_marksystemobject sp_addmergepullsubscription_agent
go

grant exec on dbo.sp_addmergepullsubscription_agent to public
go

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

raiserror('Creating procedure sp_MSscript_where_clause', 0,1)
go
create procedure sp_MSscript_where_clause (
    @objid		  int,
    @columns      binary(32), 
    @clause_type  varchar(15) = 'pk_new', -- 'new pk', 'old pk', 'upd version', 'upd rc', 'trg pk', 'qcft_comp', 'new_pk_q', 'subwins_check'
    @ts_col       sysname = NULL,
    @indent       int = 0,
	@op_type      char(3) = NULL, -- 'ins', 'del', 'upd'
	@primary_key_bitmap varbinary(4000) = null )
as
BEGIN
	declare	@cmd			nvarchar(4000)
			,@colname		sysname
			,@ccoltype		sysname
			,@spacer		nvarchar(20)
			,@indkey		int
			,@indid			int
			,@key			sysname
			,@rc			int
			,@this_col		int
			,@art_col		int
			,@src_cols		int
			,@col			sysname
			,@qualname		nvarchar(512)
			,@curparam		nvarchar(20)
			,@retcode		int

	select @spacer = N' ', @cmd = N'', @indkey = 1, @indid = 0
    exec sp_MSget_qualified_name @objid, @qualname OUTPUT
    select @src_cols = max(colid) from syscolumns where id = @objid
    exec dbo.sp_MSpad_command @cmd output, @indent
    if (@clause_type = 'qcft_comp')
    	select @cmd = @cmd + N' '' where '
    else
    	select @cmd = @cmd + N'where'
    exec dbo.sp_MSflush_command @cmd output, 1, @indent

	if @clause_type in ('new pk','old pk','upd version','trg pk','version pk','qcft_comp','new_pk_q','subwins_check')
    begin
    	if @primary_key_bitmap is null
    	begin
        	exec @indid = dbo.sp_MStable_has_unique_index @objid
			if @indid is null
			begin
				raiserror('Debug: Cannot find unique index', 16, -1)
				return (1)
			end
		end

        while (1=1)
        begin
			--
			-- get the column position
			--
        	if @primary_key_bitmap is null 
        	begin
             	select @key = index_col(@qualname, @indid, @indkey)
             	if @key is null
             		break
             	--exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, @this_col output
             	exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, NULL, 0, NULL, @this_col output
        	end
        	else
        	begin
        		exec dbo.sp_MSget_map_position @primary_key_bitmap, @indkey, @col output, @this_col output
        		if @this_col is null
        			break
        	end

			--
			-- Get column name
			--
			exec @retcode = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @key output, @ccoltype output
			if (@retcode = 1)
			begin
				--
				-- this column not used for replication
				-- continue
				--
				select @indkey = @indkey + 1
				continue
			end
		
            if @clause_type = 'new pk'
            begin
                if ColumnProperty(@objid, @key, 'IsIdentity') = 1
                    select @cmd = @cmd + @spacer + quotename(@key) + N' = @@identity'
                else
                    select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col

                select @spacer = ' and '
            end
            else if @clause_type in ('upd version', 'subwins_check')
            begin
                select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
                select @spacer = ' and '
            end
            else if @clause_type = 'version pk'
            begin
                select @cmd = @cmd + @spacer + @qualname + '.' + quotename(@key) + N' = inserted.' + quotename(@key)
                select @spacer = ' and
     '
            end
            else if @clause_type in ('trg pk', 'old pk')
            begin
				if @op_type = 'ins'
					select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
				else
					-- The vars correspoding to pk were set in sp_MSscript
					-- _pkvar_assignment.
					select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col 

                select @spacer = ' and
     '
			end
			else if (@clause_type = 'qcft_comp')
			begin
				--
				-- Conflict compensation generation
				-- This is a special case - we generate
				-- and exec string for the WHERE clause
				--
				if (@op_type = 'ins')
					select @curparam = N'@' + @col
				else if (@op_type = 'del')
					select @curparam = N'@' + @col + N'_old'
				else
					select @curparam = N'ISNULL(@' + @col + N', @' + @col + N'_old)'
				
				select @cmd = @cmd + @spacer + quotename(@key)
				
				if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
					select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
					select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
					select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
					select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
					select @cmd = @cmd + N' = '' + master.dbo.fn_varbintohexstr(' + @curparam + N') collate database_default ' 
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
					select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
					select @cmd = @cmd + N' = '' + CONVERT(nvarchar(40),' + @curparam + N', 2) '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
					select @cmd = @cmd + N' = '' + '''''''' + CAST(' + @curparam + N' as nvarchar(40)) + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
					select @cmd = @cmd + N' = '' + '''''''' + CONVERT(nvarchar(40), ' + @curparam + N', 121) + '''''''' '	
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
					select @cmd = @cmd + N' = '' + master.dbo.fn_sqlvarbasetostr(' + @curparam + N' ) collate database_default '
				else
					select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
				
				select @spacer = ' + '' and  '
			end
			else if @clause_type = 'new_pk_q'
			begin
				--
				-- new value of primary key, ignore identity
				-- used for scripting in synctran procs
				--
				select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col
				select @spacer = ' and '
			end
			select @indkey = @indkey + 1

			-- flush command if necessary
			exec dbo.sp_MSflush_command @cmd output, 1, @indent
        end
	    
		-- add version col as necessary
		if ((@clause_type in ('upd version','subwins_check')) and (@ts_col is not null))
		begin
			--
			-- @ts_col is version col actually.
			-- check for special cases for queued processing
			--
			exec dbo.sp_MSget_col_position @objid, @columns, @ts_col, @col output
			if (@clause_type = 'subwins_check')
				select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col
			else
				select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col + N'_old'

			--
			-- save off command fragment
			--
			exec dbo.sp_MSflush_command @cmd output, 1, @indent
		end

    end
	-- 'upd rc' is used for column value conflict detection. It is no longer used.
    else if @clause_type = 'upd rc'
    begin
        select @this_col = 1, @art_col = 1

        while @this_col <= @src_cols
        begin
            exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
	    	if @rc = 0
            begin
                select @cmd = @cmd +  @spacer + '(' + @colname + N' = @c' + convert(varchar(4), @this_col) + N'_old or (' 
                select @cmd = @cmd + @colname + ' is null and @c' + convert(varchar(4), @this_col) + N'_old is null)) '
                select @spacer = N' and 
     '
                exec dbo.sp_MSflush_command @cmd output, 0, @indent
            end

            exec dbo.sp_MSflush_command @cmd output, 1, @indent

            select @this_col = @this_col + 1
        end

        -- save off cmd fragment
        exec dbo.sp_MSflush_command @cmd output, 1, @indent
    end
    
END
go

grant execute on dbo.sp_MSscript_where_clause to public
go

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

raiserror('Creating procedure sp_MSscript_begintrig1', 0,1)
go
create procedure sp_MSscript_begintrig1 (
	@trigname      sysname
	,@objid         int
	,@procname      sysname
	,@filter_clause nvarchar(4000)
	,@op_type       char(3) = 'ins' -- ins, upd, del
	,@fisqueued	  bit = 0 -- 1 = Queued subscription
)
as
BEGIN
	declare @cmd       nvarchar(4000)
			,@start     int
			,@sub_len   int
			,@qualname  nvarchar(512)

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	-- construct trigger name
	select @cmd = N'create trigger ' + QUOTENAME(@trigname) + N' on ' + @qualname + N' for '
	select @cmd = case
					when (@op_type = 'ins') then @cmd + N'insert '
					when (@op_type = 'upd') then @cmd + N'update '
					when (@op_type = 'del') then @cmd + N'delete '
				end
	select @cmd = @cmd + N'not for replication
as
'
	insert into #proctext(procedure_text) values (@cmd)

    --
	-- declare common local variables
	--
	--		,@update_mode char(40)
	--		,@failover_mode char(10)
	--
	insert into #proctext(procedure_text) values (N'
	declare 	@rc int
		,@retcode int
		,@connect_string nvarchar(2000)
		,@rpc_proc nvarchar(4000)
		,@rpc_types nvarchar(4000)
		,@update_mode_id int
		,@bitmap varbinary(4000)
		,@version_guid uniqueidentifier
		,@trigger_op char(10) ')

		--
		-- queued specific declarations
		--
	insert into #proctext(procedure_text) values (N'
		,@failover_mode_id int
		,@queue_server sysname
		,@queue_id sysname
		,@tran_id varchar(255)
		,@subscriber sysname
		,@subscriber_db sysname 
		,@partial_cmd bit
		,@start_offset int
		,@end_offset int
		,@vb_buffer varbinary(8000)
		,@vb_bufferlen int		
		')

    -- script variables used to retrieve data from inserted table
    if @op_type in ('ins', 'upd')
    begin
        insert into #proctext(procedure_text) values(N'
	declare ')
        exec dbo.sp_MSscript_params @objid, null, null, 0, null
    end
	insert into #proctext(procedure_text) values(N'
	declare ')
    exec dbo.sp_MSscript_params @objid, null, '_old',  0, null

	-- Set @rc, @subscriber and @subscriber_db
	-- Optimization. Return immediately if no row changed
	select @cmd = N'

	select @rc = @@ROWCOUNT, @subscriber = @@SERVERNAME, @subscriber_db = db_name() 
	if @rc = 0 
		return 
	set nocount on '
	insert into #proctext(procedure_text) values(@cmd)
		
    -- set column update bitmap for update trigger
    if @op_type in ('upd')
    begin
		declare @src_cols       int
				,@num_bytes		int
				,@i_byte			int
				,@i_bit			tinyint
				,@len_before nvarchar(10)
				,@len_after nvarchar(10)
				,@index1 nvarchar(10)
				,@index2 nvarchar(10)
				,@this_col 		int

	    insert into #proctext(procedure_text) values(N'
	select @bitmap = columns_updated() ')

        -- Mark the bit in the bitmap as updated.

	    exec dbo.sp_MSget_col_position @objid, null, 'msrepl_tran_version', @this_col = @this_col output
	    select @src_cols = count(*) from syscolumns where id = @objid
        select @num_bytes = @src_cols / 8 + 1

	    set @i_byte = 1 + (@this_col-1) / 8
	    set @i_bit  = power(2, (@this_col-1) % 8 )

        select @len_before = convert(nvarchar(10), @i_byte -1)
        select @index1 = convert(nvarchar(10), @i_byte)
        select @index2 = convert(nvarchar(10), @i_byte + 1)
        select @len_after = convert(nvarchar(10), @num_bytes - @i_byte)

        select @cmd = 
	        'select @bitmap = substring(@bitmap, 1, ' + @len_before + 
            ') + (convert(binary(1), substring(@bitmap, ' + @index1 + 
            ', 1) | convert(tinyint,' + convert(nvarchar(10), @i_bit) + 
            '))) + substring(@bitmap, ' + @index2 + 
            ', ' + @len_after + 
            ') '
        exec dbo.sp_MSflush_command @cmd, 1
    end

	select @cmd = N'
	select @version_guid = newid() '
	insert into #proctext(procedure_text) values(@cmd) 

	-- Partition check statement
	if @filter_clause IS NOT NULL
	begin
		declare @retcode int
		exec @retcode = sp_MSsubst_filter_names NULL, N'inserted', @filter_clause output
		if @retcode <> 0 or @@error <> 0
			return 1	    
			
		select @cmd = N'
	if exists (select * from inserted where not ('
		insert into #proctext(procedure_text) values(@cmd) 
	    
		-- break filter_clause into chunks of 255
		select @start = 1
		while @start < len(@filter_clause)
		begin
		    if len(@filter_clause) < 255
			    select @sub_len = len(@filter_clause)
			else
				select @sub_len = 255
		    select @cmd = substring(@filter_clause, @start, @sub_len)
			exec dbo.sp_MSflush_command @cmd output, 1
			select @start = @start + @sub_len
		end
			
		select @cmd = N'))
	 begin 
	     exec sp_MSreplraiserror 21034
	     goto FAILURE 
	 end '
		insert into #proctext(procedure_text) values(@cmd) 
	end

	-- trigger nesting checks
	if @op_type in ('upd')
	begin
		select @cmd = N'
	exec @retcode = dbo.sp_check_sync_trigger @@procid, @trigger_op OUTPUT 
	if (@retcode = 1)
		return '
		insert into #proctext(procedure_text) values(@cmd) 
	end
END
go

grant execute on dbo.sp_MSscript_begintrig1 to public
go

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

raiserror('Creating procedure sp_MSscript_begintrig2', 0,1)
go
create procedure sp_MSscript_begintrig2 (
	@publisher   sysname
	,@publisher_db sysname
	,@publication sysname
	,@objid       int
	,@op_type     char(3) = 'ins' -- ins, upd, del
	,@agent_id    int
	,@fisqueued	  bit = 0 -- 1 = Queued subscription
)
as
BEGIN
	declare @cmd nvarchar(4000)
			,@queue_server sysname

	if @op_type = 'ins' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerInsertOrder'') != 1	
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21128, 16, 1, @trigname)
		goto FAILURE
	end ')
	end
	else if @op_type = 'upd' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerUpdateOrder'') != 1	
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21129, 16, 1, @trigname)
		goto FAILURE
	end ')
	end
	else if @op_type = 'del' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerDeleteOrder'') != 1
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21130, 16, 1, @trigname)
		goto FAILURE
	end ')
	end

	--
	-- scripting for debug messages
	--
	select @cmd = N'
	select @update_mode_id = update_mode 
	from dbo.MSsubscription_agents where id = ' + convert(nvarchar(10), @agent_id) + N' '
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- continue with scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- initialize and validate based on update mode
	' + N'--
	if @update_mode_id = 1
	begin
		exec @retcode = dbo.sp_MSget_publisher_rpc @@procid, @connect_string output
		if @retcode <>0 or @@error <> 0 goto FAILURE
	end'
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- continue with scripting
	--
	if (@fisqueued = 1)
	begin
		--
		-- Queued specific scripting
		--
		select @cmd = N'
	else if @update_mode_id in (2,4)
	begin
		select @queue_server = queue_server, @queue_id = queue_id from dbo.MSsubscription_agents where id = ' + convert(nvarchar(10), @agent_id) + N'
		if (@queue_id is NULL) 
			goto FAILURE
	end'
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- continue with scripting
		--
		select @cmd = N'
	else if @update_mode_id in (3,5)
	begin
		select @queue_server = queue_server, @queue_id = queue_id from dbo.MSsubscription_agents 
			where id = ' + convert(nvarchar(10), @agent_id) + N' and failover_mode = 1 '
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- continue with scripting
		--
		select @cmd = N'
		if (@queue_id is NULL)
		begin
			exec @retcode = dbo.sp_MSget_publisher_rpc @@procid, @connect_string output
			if @retcode <>0 or @@error <> 0 
				goto FAILURE
		end
	end'
		insert into #proctext(procedure_text) values (@cmd)
	end
	
	--
	-- continue with scripting
	--
	select @cmd = N'
	else if @update_mode_id = 0
	begin
		raiserror (''read only mode - no updates allowed'', 16, 1)
		goto FAILURE
	end
	else
	begin
		raiserror(''invalid update mode %d'', 16, 1, @update_mode_id)
		goto FAILURE
	end '
	insert into #proctext(procedure_text) values (@cmd)

	if (@fisqueued = 1)
	begin		
		select @cmd = N'
	' + N'--
	' + N'-- set queue prefix for MSMQ cases
	' + N'--
	if (@update_mode_id in (2,3))
	begin
		select @queue_id = N''DIRECT=OS:'' + @queue_server + N''\PRIVATE$\'' + @queue_id 
	end'
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- Get failover mode scripting
		--
	    select @cmd = N'
	' + N'--
	' + N'-- get failover mode
	' + N'--
	if @update_mode_id in (3,5)
	begin
		select @failover_mode_id = failover_mode
		from dbo.MSsubscription_agents where id = '
		+ convert(nvarchar(10), @agent_id) + ' and update_mode in (3,5)
	end'
		insert into #proctext(procedure_text) values (@cmd)
    end
    
    --
	-- Start the distributed tran and get the transaction id as we may use
	-- it for queue sends
	--
    select @cmd = N'
	' + N'--
	' + N'-- begin tran or dist tran based on update mode
	' + N'--
	if (@update_mode_id in (4,5))
		BEGIN TRAN
	else
		BEGIN DISTRIBUTED TRAN
	'
	insert into #proctext(procedure_text) values (@cmd)
		
	if (@fisqueued = 1)
	begin
		select @cmd = N'
	' + N'--
	' + N'-- save the transaction token for later use
	' + N'--
	exec sp_getbindtoken @out_token = @tran_id OUTPUT , @for_xp_flag = 1 '
		insert into #proctext(procedure_text) values (@cmd)
	end

	--
	-- all done with scripting
	--
	return 0
END
go

grant execute on dbo.sp_MSscript_begintrig2 to public
go

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

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

CREATE PROCEDURE sp_helpreplicationdboption (
	@dbname sysname = '%', @type sysname = 'replication allowed'
)
AS
BEGIN
	SET NOCOUNT ON

	/*
	** Declarations.
	*/

	DECLARE @retcode int
			,@typebit int
			,@distbit int -- bit to distinguish distribution databases
			,@dbowner bit
			,@dbreadonly bit
			,@replication_db sysname

	SELECT @distbit = 16
			,@dbowner = 0
			,@dbreadonly = 0

	-- don't do security check.

	if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'publish%')
		select @typebit = 1
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'subscribe%')
		select @typebit = 2
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'merge publish%')
		select @typebit = 4
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'merge subscribe%')
		select @typebit = 8
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'replication allowed%')
		select @typebit = 0
	else        
	begin
		raiserror(14091,-1,-1)
		return 1
	end

	/*
	** Parameter Check:  @dbname.
	** Check to make sure that the database name conforms to the rules
	** for identifiers.
	*/

	IF @dbname <> '%'
	BEGIN
		EXECUTE @retcode = dbo.sp_validname @dbname
		IF @@ERROR <> 0 OR @retcode <> 0
		RETURN (1)
	END

	/*
	** Show databases with this option enabled.
	*/
	CREATE TABLE #replicationdbs (name sysname collate database_default not null, id int identity NOT NULL, transpublish bit not null, mergepublish bit not null, dbowner bit not null, dbreadonly bit not null)
	if @typebit <> 0
	begin
		INSERT INTO #replicationdbs (name, transpublish, mergepublish, dbowner, dbreadonly)
			SELECT name, 
				case when (category & 1) <> 0 then 1 else 0 end,
				case when (category & 4) <> 0 then 1 else 0 end,
				@dbowner,
				DATABASEPROPERTY(name, N'IsReadOnly')
			FROM master.dbo.sysdatabases
			WHERE ((@dbname = N'%') OR (name = @dbname collate database_default))
				AND (category & @typebit) <> 0 
				AND (HAS_DBACCESS ( name ) = 1)

		DECLARE hCdboinfo CURSOR LOCAL FAST_FORWARD FOR
			SELECT name FROM #replicationdbs
			FOR READ ONLY
		OPEN hCdboinfo
		FETCH hCdboinfo INTO @replication_db
		WHILE (@@fetch_status <> -1)
		BEGIN
			EXEC @retcode = sp_MSrepl_isdbowner @replication_db
			IF (@retcode IS NOT NULL) AND (@retcode <> 0)
			BEGIN
				UPDATE #replicationdbs set dbowner = 1 where name = @replication_db
			END
			FETCH hCdboinfo INTO @replication_db
		END
		CLOSE hCdboinfo
		DEALLOCATE hCdboinfo
	end            
	else
	begin
		DECLARE @db_category int

		/* Filter out distribution databases */
		DECLARE hC  CURSOR LOCAL FAST_FORWARD FOR 
			SELECT name, category, DATABASEPROPERTY(name, N'IsReadOnly')
			FROM master.dbo.sysdatabases 
			WHERE ((@dbname = N'%') OR (name = @dbname collate database_default)) 
				AND (category & @distbit) = 0 
				AND (HAS_DBACCESS ( name ) = 1)
			FOR READ ONLY
		OPEN hC
		FETCH hC INTO @replication_db, @db_category, @dbreadonly
		WHILE (@@fetch_status <> -1)
		BEGIN
			if @replication_db NOT IN ('master','model','tempdb','msdb','MSSQLWeb')
			BEGIN
				EXEC @retcode = sp_MSrepl_isdbowner @replication_db
				IF (@retcode IS NOT NULL) AND (@retcode <> 0)
				BEGIN
					SELECT @dbowner = 1
				END
				ELSE
				BEGIN
					SELECT @dbowner = 0
				END
				INSERT INTO #replicationdbs (name, transpublish, mergepublish, dbowner, dbreadonly) 
				VALUES (@replication_db,
						case when (@db_category & 1) <> 0 then 1 else 0 end,
						case when (@db_category & 4) <> 0 then 1 else 0 end,
						@dbowner, @dbreadonly)
			END
			FETCH hC INTO @replication_db, @db_category, @dbreadonly
		END
		CLOSE hC
		DEALLOCATE hC
	end
	SELECT * FROM #replicationdbs
	-- DROP TABLE #replicationdbs
END
go

grant execute on dbo.sp_helpreplicationdboption to public
go


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

CREATE PROCEDURE sp_MSCleanupForPullReinit (
	@publication 		sysname,
	@publisher_db		sysname,
	@publisher     		sysname = @@servername
	) AS
	declare @pubid 		uniqueidentifier
	declare @artid 		uniqueidentifier
	declare @retcode	smallint

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

	/* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)	

	begin transaction
	save tran cleanupforreinit
	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_genhistory where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergesubsetfilters where pubid=@pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergeschemachange where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_contents where tablenick in (select nickname from sysmergearticles where pubid=@pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_tombstone where tablenick in (select nickname from sysmergearticles where pubid=@pubid)
	if @@ERROR<>0 
		goto Error
	commit tran 
	return (0)

Error:
	rollback tran cleanupforreinit
	commit tran 
	return (1)
GO
exec dbo.sp_MS_marksystemobject sp_MSCleanupForPullReinit
go

grant execute on dbo.sp_MSCleanupForPullReinit to public
go

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

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

create procedure sp_MScleanup_conflict
@pubid					uniqueidentifier,
@conflict_retention	int = NULL
AS
	declare @pubname			sysname
	declare @valid_date			datetime
	declare @conflict_table		sysname
	declare @conflict_id		int
	declare @retention_string		nvarchar(100)
	declare @pubidstr			nvarchar(100)
	declare @retcode			int
	
	--if no conflict_retention value is specified, query local table and find out.
	if @conflict_retention is NULL
		select @conflict_retention=conflict_retention from sysmergepublications where pubid=@pubid

	--do not do any cleanup if conflict retention value is 0
	else if @conflict_retention = 0
		return (0)

	select @pubname=name from sysmergepublications where pubid=@pubid
	select @pubidstr = convert(nvarchar(40), @pubid)
	select @valid_date = dateadd(day, -@conflict_retention, getdate())
	select @retention_string = convert(nvarchar, @conflict_retention)
	/*
	** Security Check
	*/
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)


	if exists (select name from syscolumns where name='create_time' and id = object_id('MSmerge_delete_conflicts'))
	begin
		delete from MSmerge_delete_conflicts where create_time < @valid_date and pubid=@pubid
		if @@ERROR<>0
			return (1)
	end
	
	declare AC CURSOR LOCAL FAST_FORWARD for select conflict_table from sysmergearticles where pubid=@pubid
	open AC
	fetch AC into @conflict_table
	while (@@fetch_status<>-1)
	begin
		if @conflict_table is NOT null
			begin

			select @conflict_id = object_id(@conflict_table)
			select @conflict_table=QUOTENAME(@conflict_table)
			/*
			** Upgrade conflict table so that it can get cleaned up later on
			*/
			if @conflict_id is not NULL and not exists (select name from syscolumns where name='MSrepl_create_time' and id=@conflict_id)
					begin
						exec ('alter table ' + @conflict_table + ' add MSrepl_create_time datetime not NULL default getdate() ')
						if @@ERROR<>0
							goto FAILURE
					end

			if @conflict_id is not NULL and @retention_string is not NULL and exists (select name from syscolumns where name='MSrepl_create_time' and id=@conflict_id)
					begin
						exec ('delete from ' + @conflict_table + ' where datediff(dd, MSrepl_create_time, getdate()) > ' + @retention_string + ' and pubid = ''' + @pubidstr + '''')
						if @@ERROR<>0
							goto FAILURE
					end
			end
		fetch next from AC into @conflict_table
	end
	close AC
	deallocate AC
	return (0)
FAILURE:
	close AC
	deallocate AC
	return (1)
GO
exec dbo.sp_MS_marksystemobject sp_MScleanup_conflict
go

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

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

CREATE PROCEDURE sp_MSpublicationcleanup (
	@publication 		sysname,
	@publisher_db		sysname,
	@publisher	       	sysname = @@servername
	) AS
	declare @pubid 		uniqueidentifier
	declare @artid 		uniqueidentifier
	declare @retcode	smallint
    declare @objectname sysname
    declare @objectowner sysname

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

	/* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)

	/* 
	** If we are deleting the last publication in the database, ie there are articles in
	** sysmergearticles with a different pubid then the one being dropped
	** then remove all the rows in MSmerge_genhistory, MSmerge_contents and MSmerge_tombstone 
	** use a truncate table in order to make the operation non logged and hence efficient
	*/
	if not exists (select * from sysmergearticles where pubid <> @pubid)
		begin
			truncate table MSmerge_genhistory
			truncate table MSmerge_contents
			truncate table MSmerge_tombstone
		end

	begin transaction
	save tran MSpublicationcleanup
	/* Clean up the articles for this publication, and delete the row */
	select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
	while @artid is not null
		begin
		if not exists (select * from sysmergearticles WHERE artid = @artid and pubid <> @pubid)
			begin
				exec @retcode=sp_MSarticlecleanup @pubid, @artid
				if @retcode<>0 or @@ERROR<>0 
					goto Error
			end
		delete from sysmergearticles where artid = @artid and pubid = @pubid
		if @@ERROR<>0 
			goto Error
		set @artid = NULL
		select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
		end
		
    /* Unmark all schema articles in this publication */
    if exists (select * from sysobjects where name = 'sysmergeschemaarticles')
    begin
        declare hschemaarticle_cur cursor local fast_forward for
            select destination_object, destination_owner from sysmergeschemaarticles where
            pubid = @pubid 
        for read only
        open hschemaarticle_cur
        fetch hschemaarticle_cur into @objectname, @objectowner
        while (@@fetch_status<>-1)
        begin
                exec  sp_MSunmarkschemaobject @objectname, @objectowner    
				if @retcode<>0 or @@ERROR<>0 
					goto Error
                fetch hschemaarticle_cur into @objectname, @objectowner
        end
        close hschemaarticle_cur
        deallocate hschemaarticle_cur

        /* Delete all schema article rows for this publication*/
        delete from sysmergeschemaarticles where pubid = @pubid
		if @@ERROR<>0 
			goto Error
    end
    
	/* Now clean up any traces in other system tables */

	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_genhistory where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_replinfo where repid in (select subid from sysmergesubscriptions where pubid = @pubid and status <> 2)
	if @@ERROR<>0 
		goto Error
    delete from sysmergesubsetfilters where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergesubscriptions where pubid = @pubid and status <> 2
	if @@ERROR<>0 
		goto Error
	delete from sysmergepublications where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergeschemachange where pubid = @pubid
	if @@ERROR<>0 
		goto Error

	commit tran 
	return (0)

Error:
	rollback tran MSpublicationcleanup
	commit tran 
	return (1)
GO
exec dbo.sp_MS_marksystemobject sp_MSpublicationcleanup
go

grant execute on dbo.sp_MSpublicationcleanup to public
go

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

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

CREATE PROCEDURE sp_mergesubscription_cleanup (
	@publisher		sysname,
	@publisher_db	sysname,
	@publication 	sysname
	) AS
	declare @pubid 				uniqueidentifier
	declare @artid 				uniqueidentifier
	declare @retcode			smallint
	declare @subscription_type  int
    declare @objid              int
    declare @objectname         sysname
    declare @objectowner        sysname

	/*
	** if there is nothing to cleanup, then just return.
	*/
	if not exists (select * from sysobjects where name='sysmergesubscriptions')
		return (0)
		
	/* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)

	select @subscription_type = subscription_type from sysmergesubscriptions where pubid=@pubid and subid<>pubid

	/* This procedure is not intended to be used for cleanning-up pull/anonymous subscriptions */
	if @subscription_type > 0
		begin
			raiserror(20091, 16, -1)
			return (1)
		end

	/* Clean up the articles for this publication, and delete the row */
	select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
	while @artid is not null
		begin
		if not exists (select * from sysmergearticles WHERE artid = @artid and pubid <> @pubid)
			begin
				exec @retcode=sp_MSarticlecleanup @pubid, @artid
				if @retcode<>0 or @@ERROR<>0 return (1)
			end
		delete from sysmergearticles where artid = @artid and pubid = @pubid
		set @artid = NULL
		select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
		end
		
    /* Cleanup the schema articles */

    /* Unmark all schema article objects unconditionally */
    if exists (select * from sysobjects where name = 'sysmergeschemaarticles')
    begin
        declare hschemaarticle_cur cursor local fast_forward for
            select destination_object, destination_owner from sysmergeschemaarticles where
            pubid = @pubid 
        for read only
        open hschemaarticle_cur
        fetch hschemaarticle_cur into @objectname, @objectowner
        while (@@fetch_status<>-1)
        begin
                -- Ignore errors
                exec  sp_MSunmarkschemaobject @objectname, @objectowner    
                fetch hschemaarticle_cur into @objectname, @objectowner
        end
        close hschemaarticle_cur
        deallocate hschemaarticle_cur

        /* Delete all schema article rows for this publication*/
        delete from sysmergeschemaarticles where pubid = @pubid
    end

	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)

	/* Now clean up any traces in other system tables */
	delete from MSmerge_genhistory where pubid = @pubid 
	delete from MSmerge_replinfo where repid in (select subid from sysmergesubscriptions where pubid = @pubid)
	delete from sysmergesubscriptions where pubid = @pubid
	delete from sysmergepublications where pubid = @pubid
	delete from sysmergeschemachange where pubid = @pubid
	/* 
	** If last subscription is dropped and the DB is not enabled for publishing,
	** then remove the merge system tables
	*/
	IF (not exists (select * from sysmergesubscriptions )) 
		AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default )=0
	BEGIN
		execute @retcode = dbo.sp_MSdrop_mergesystables
		if @@ERROR <> 0 or @retcode <> 0
		begin
			return (1)
		end
	END	
GO
exec dbo.sp_MS_marksystemobject sp_mergesubscription_cleanup
go
grant execute on dbo.sp_mergesubscription_cleanup to public
go


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

raiserror('Creating procedure sp_subscription_cleanup', 0,1)
GO
CREATE PROCEDURE sp_subscription_cleanup (
	@publisher		sysname,
	@publisher_db	sysname,
	@publication	sysname = NULL,
	@reserved		nvarchar(10) = NULL
)
AS
BEGIN

	declare @object_name sysname
			,@object_type char(2)
			,@independent_agent bit
			,@retcode int
			,@synctran_bit int
			,@parent_obj int
			,@object_id int
			,@cmd nvarchar(4000)

	select @synctran_bit			= 256

	/*
    ** Security Check
    */

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

	if @publication = '' OR @publication is NULL
		select @independent_agent = 0
	else
		select @independent_agent = 1

	IF exists (select name from sysobjects where name = 'MSreplication_objects')
	BEGIN
		declare object_cursor CURSOR LOCAL FAST_FORWARD for 
			select DISTINCT object_name, object_type from MSreplication_objects o
					where (UPPER(o.publisher) = UPPER(@publisher) and
			  		  o.publisher_db = @publisher_db and
				  	  o.publication = @publication) or
						@reserved = 'drop_all'

		OPEN object_cursor
    	FETCH object_cursor INTO @object_name, @object_type
 	    WHILE (@@fetch_status <> -1)
    	      BEGIN
        	      IF @object_type = 'T' 
				  begin
					select @parent_obj = NULL
					select @parent_obj = parent_obj, @object_id = id from
						sysobjects where name = @object_name 
					if @parent_obj is not null
					begin
						-- Unmark synctran bit
						update sysobjects set replinfo = replinfo & ~@synctran_bit where 
							id = @parent_obj and
							(replinfo & @synctran_bit) <> 0
						IF @@ERROR <> 0 
							GOTO UNDO
						exec @retcode = dbo.sp_MSdrop_object 
							@object_id = @object_id
						if @retcode <> 0 or @@error <> 0
							goto UNDO

						-- Clean up identity range entry
						-- Since we only support one trigger per subscriber table
						-- we assume identity range row can not be reused by multiple
						-- subscriptions.
						IF EXISTS(select * from sysobjects where type='U' and name = 'MSsub_identity_range')
						BEGIN
							if exists (select * from MSsub_identity_range where objid = @parent_obj)
							begin
								-- Drop the identity range constraits.
								exec @retcode = dbo.sp_MSreseed
									@objid =  @parent_obj,
									-- range or seed can be anything
									@next_seed = 10,
									@range = 10,
									@is_publisher = -1,
									@check_only = 1,
									@drop_only = 1
								IF @retcode <> 0 or @@ERROR <> 0 
									GOTO UNDO

								delete MSsub_identity_range where objid = @parent_obj
								IF @@ERROR <> 0 
									GOTO UNDO
							end

							IF NOT EXISTS (SELECT * FROM MSsub_identity_range)
							BEGIN
								DROP TABLE MSsub_identity_range
								IF @@ERROR <> 0 
									GOTO UNDO
							END
						END
					end
				  end
        	      delete from MSreplication_objects where object_name=@object_name
            	  FETCH object_cursor INTO @object_name, @object_type
         	 END
    	CLOSE object_cursor
    	DEALLOCATE object_cursor
    	
		if not exists (select * from MSreplication_objects) 
		begin
    		drop table MSreplication_objects
			IF @@ERROR <> 0 
				GOTO UNDO
		end
    	
	END

	--
	-- cleanup queued conflict tables
	--
	IF exists (select name from dbo.sysobjects where name = 'MSsubscription_agents')
	BEGIN
		declare		@agent_id int
					,@cft_table sysname
					,@owner sysname

		--
		-- first get the agent(s) for this queued subscription(s) and 
		-- 
		declare #agent_cursor CURSOR LOCAL FAST_FORWARD for 
			select id from dbo.MSsubscription_agents 
			where ((UPPER(publisher) = UPPER(@publisher) and 
					publisher_db = @publisher_db and 
					publication = @publication) or (@reserved = 'drop_all')) and
					update_mode in (2,3,4,5)

		open #agent_cursor
		fetch #agent_cursor into @agent_id
		while (@@fetch_status != -1)
		begin
			--
			-- drop the conflict table for each article in this subscription
			--
			if exists (select name from dbo.sysobjects where name = 'MSsubscription_articles')
			begin
			
				declare #object_cursor CURSOR LOCAL FAST_FORWARD for 
					select owner, cft_table from dbo.MSsubscription_articles
					where agent_id = @agent_id

				OPEN #object_cursor
				FETCH #object_cursor INTO @owner, @cft_table
				WHILE (@@fetch_status != -1)
				BEGIN
					--
					-- drop the conflict table(s) for this article - ignore errors
					--
					select @cmd = case 
						when (@owner IS NULL) then
							N'if exists (select * from dbo.sysobjects where name = N''' + 
							master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
							quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
						else
							N'if exists (select * from dbo.sysobjects where name = N''' + 
							master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
							quotename(master.dbo.fn_MSgensqescstr(@owner)) collate database_default + N'.' +
							quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
						end
					execute ( @cmd )

					-- get next row
					FETCH #object_cursor INTO @owner, @cft_table
				END
				CLOSE #object_cursor
				DEALLOCATE #object_cursor

				--
				-- delete entries from MSsubscription_articles for this agent id
				--
				delete dbo.MSsubscription_articles where agent_id = @agent_id

				--
				-- drop MSsubscription_articles if empty (should we do it)
				-- 
				IF NOT EXISTS (SELECT * FROM dbo.MSsubscription_articles)
				BEGIN
					DROP TABLE dbo.MSsubscription_articles
					IF @@ERROR != 0 
						GOTO UNDO
				END
			end

			--
			-- get the next agent
			--
			fetch #agent_cursor into @agent_id
		end
		close #agent_cursor
		deallocate #agent_cursor
	END

	--
	-- clean discarded queued transactions
	--
	if exists (select name from dbo.sysobjects where name = 'MSreplication_queue')
	begin
		delete dbo.MSreplication_queue
		where (UPPER(publisher) = UPPER(@publisher) and 
				publisher_db = @publisher_db and 
				publication = @publication) or 
				@reserved = 'drop_all'
	end
	
	IF exists (select name from sysobjects where name = 'MSreplication_subscriptions')
	BEGIN
	delete from MSreplication_subscriptions 
		where (UPPER(publisher) = UPPER(@publisher) AND
			  publisher_db = @publisher_db AND
			  -- Drop the subscription as long as the publication name matches even if
			  -- the publication is not independent agent
			  -- This behaviour is expected by sp_droppullsubscription
			  -- -- independent_agent = @independent_agent and 
			  ((@independent_agent=0 and independent_agent = 0) or 
			  publication = @publication))
			  or @reserved = 'drop_all'
 
		IF NOT EXISTS (SELECT * FROM MSreplication_subscriptions)
		BEGIN
			DROP TABLE MSreplication_subscriptions
			IF @@ERROR <> 0 
				GOTO UNDO
		END
	END


	IF exists (select name from sysobjects where name = 'MSsubscription_agents')
	BEGIN
		delete from MSsubscription_agents
		where (UPPER(publisher) = UPPER(@publisher) AND
			  publisher_db = @publisher_db AND
			  -- Drop the subscription as long as the publication name matches even if
			  -- the publication is not independent agent
			  -- This behaviour is expected by sp_droppullsubscription
			  (publication = @publication or
			   (@independent_agent=0 and publication = N'ALL')))
			  or @reserved = 'drop_all'

		-- Delete the agent entry if no corresponding rows found in MSreplication_subscription
		-- table.
		-- This is to cleanup share agent entry.
		-- This behaviour is expected by sp_droppullsubscription
		if object_id('MSreplication_subscriptions') is not null
		begin
			if not exists (select * from MSreplication_subscriptions s where
					s.publisher = @publisher and
					s.publisher_db = @publisher_db and
					s.independent_agent = 0)
				delete from MSsubscription_agents where
					publisher = @publisher and
					publisher_db = @publisher_db and
					publication = N'ALL'
		end
		else
			delete  MSsubscription_agents

		IF NOT EXISTS (SELECT * FROM MSsubscription_agents)
		BEGIN
			DROP TABLE MSsubscription_agents
			IF @@ERROR <> 0 
				GOTO UNDO
		END
	END

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

		IF @@ERROR <> 0 
			GOTO UNDO

		IF NOT EXISTS (SELECT * FROM MSsubscription_properties)
		BEGIN
			exec @retcode = dbo.sp_MSsub_cleanup_prop_table
			IF @@ERROR <> 0 or @retcode <> 0
				GOTO UNDO
		END
	END

    -- Ignore errors.
    exec dbo.sp_MSsub_cleanup_orphans
	
    return (0)
            
UNDO:
	return(1)
END
GO
exec dbo.sp_MS_marksystemobject sp_subscription_cleanup 
go

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

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

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

	set nocount on 

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

	select @db_distbit = 16
    select @platform_nt = 0x1

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

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

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

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

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

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

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

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

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

					select @osql_cmd = @osql_cmd + ' -l30 -t120 '
					select @osql_cmd = @osql_cmd + ' -b ' + ' -d' + @dbname
					select @osql_cmd = @osql_cmd +	' -i' + '"' + @install_path + '\install\instdist.sql"' + 
													' -o' + '"' + @install_path + '\install\instdist.out"'			

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

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

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

					select @dbname = quotename(@dbname)
					exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_distdb')
					if @@error <> 0
						return(1)
				end
				else
				begin
					-- all distribution databases must be upgraded before continuing
					raiserror( 21378, 16, 1, @dbname) with nowait
				end
				
				fetch next from cur_distdb into @dbname, @has_dbaccess
			end
			close cur_distdb
			deallocate cur_distdb
		end

	
		-- Update subscription database schema
		exec @retcode = dbo.sp_vupgrade_subscription_databases
		if @retcode <> 0 or @@error <> 0
			return (1)


	end

	return (0)

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_replication
go

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

raiserror('Creating procedure sp_vupgrade_distdb', 0,1)
go
create procedure sp_vupgrade_distdb 
as
begin
/* 
 * Process schema and metadata changes specific to a distribution database. Some schema modifications
 * may have already been made by the apply of instdist.sql against the distribution database. Both steps
 * are needed for a complete distribution database upgrade.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_distdb
*/

	set nocount on

	declare @table_name sysname
	declare @retcode integer

	-- raiserror('sp_vupgrade_publisher', 0,1) with nowait
	/*
	 * MSdistribution_agents
	*/
	if exists (select name from sysobjects where name='MSdistribution_agents')
	begin
		if not exists (select * from syscolumns where id = object_id('MSdistribution_agents') and name = 'queue_server')
		begin
			alter table MSdistribution_agents add queue_server sysname null
			EXEC dbo.sp_MSupdate_mqserver_distdb
		end
	end

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_distdb
go


--------------------------------------------------------------------------------
--. sp_vupgrade_subscription_databases 
--------------------------------------------------------------------------------
if exists (select * from sysobjects 
		where name = 'sp_vupgrade_subscription_databases' 
				and type = 'P')
	  drop procedure sp_vupgrade_subscription_databases
go
raiserror('Creating procedure sp_vupgrade_subscription_databases', 0,1)
GO
create procedure sp_vupgrade_subscription_databases
as
begin
/* 
 * Process schema and metadata changes common to all databases. This proc loops
 * through each database and upgrades MSsubscription_properties, transactional tables
 * and merge tables.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases
*/
	set nocount on

	-- raiserror('sp_vupgrade_subscription_databases', 0,1) with nowait
	declare @dbname nvarchar(270), @has_dbaccess bit

	declare current_db CURSOR LOCAL FAST_FORWARD for 
		select N'[' + replace(name, N']', N']]') + N']', has_dbaccess(name) from master..sysdatabases 
			WHERE name <> N'master' collate database_default
			AND name <> N'tempdb' collate database_default
			AND name <> N'msdb' collate database_default
		for read only

	-- Note: dbname is quoted!
	open current_db
	fetch current_db into @dbname, @has_dbaccess
	while ( @@fetch_status <> -1 )
	begin

		-- upgrade repl tables in sub dbs if needed - sub dbs are not marked with subscribed status 
		-- skip any database in an offline state and write warning to upgrade log
		if ( @has_dbaccess = 1 )
		begin
			--
			-- NOTE : there are several things to process here
			-- for each upgrade - all these steps may NOT be necessary
			-- and should be commented/uncommented out as required for each upgrade
			-- 
			-- Current setting : SQL 2000 SP1 upgrade
			--
			raiserror( 21377, 0, 1, @dbname) with nowait
			-- exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_MSsubscription_properties')
			exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_subscription_tables')
			exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_mergetables')
			-- exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_subpass')
		end
		else
		begin
			raiserror( 21373, 11, 1, @dbname) with nowait
		end

		fetch next from current_db into @dbname, @has_dbaccess
	end
	close current_db
	deallocate current_db
end
go


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

raiserror('Creating procedure sp_vupgrade_mergetables', 0,1)
GO
create procedure sp_vupgrade_mergetables( @skip_procgen bit = 0 )
as
begin
/* 
 * Process schema and metadata changes common to transactional pub/sub databases.
 *
 * @skip_procgen is set by sp_restoredbreplication when calling this proc directly to update
 * system tables during restore of a down-level (e.g. - SQL7.0) database to current version
 * 
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_mergetables
*/

	set nocount on 

	declare @artnick int
	declare @objid  int
	declare @col_track int
	declare @article sysname
	declare @pubname sysname
	declare @artid uniqueidentifier
	declare @pubid uniqueidentifier
    declare @qualified_name         nvarchar(257)
    declare @source_owner           sysname
    declare @source_object			sysname
	declare @table_name				sysname
	declare @retcode				integer
	declare @snapshot_ready			int
	declare @cmd 					nvarchar(4000)

	-- raiserror('sp_vupgrade_mergetables', 0,1)

	/*
	 * sysmergearticles
	*/
	if (exists (select * from sysobjects where name = 'sysmergearticles'))
	begin

        -- Set all invalid sysmergearticles.sync_objid to the corresponding 
        -- objid, this will allow regeneration of article procs to succeed
        update dbo.sysmergearticles 
           set sync_objid = objid 
         where object_name(sync_objid) is null

        if @@ERROR<>0
            return(1)

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

		if not exists (select * from syscolumns where id = object_id('sysmergearticles') and
						name = 'maxversion_at_cleanup')
		begin
			alter table sysmergearticles add maxversion_at_cleanup int NOT NULL default 1
			if @@ERROR <> 0 return 1
		end

		-- create view now that sysmergearticles is altered and sysmergeextendedarticles is created
		if exists (select * from sysobjects where name='sysmergeextendedarticlesview')
		begin
            drop view dbo.sysmergeextendedarticlesview
		end    

		-- cannot create view directly in proc
		exec ('create view dbo.sysmergeextendedarticlesview
		    	   as
               select name, type, objid, sync_objid, view_type, artid, description, pre_creation_command, pubid,
			   nickname, column_tracking, status, conflict_table, creation_script, conflict_script, article_resolver,
			   ins_conflict_proc, insert_proc, update_proc, select_proc, schema_option, destination_object,
			   resolver_clsid, subset_filterclause, missing_col_count, missing_cols, columns, resolver_info,
			   view_sel_proc, gen_cur, excluded_cols, excluded_col_count, vertical_partition, identity_support,
			   destination_owner, before_image_objid, before_view_objid, verify_resolver_signature, 
			   allow_interactive_resolver, fast_multicol_updateproc, check_permissions, maxversion_at_cleanup				   
			   from sysmergearticles
	           union all
               select name, type, objid, NULL, NULL, artid, description, pre_creation_command, pubid, 
			   NULL, NULL, status, NULL, creation_script, NULL, NULL, 
			   NULL, NULL, NULL, NULL, schema_option, destination_object, 
			   NULL, NULL, NULL, NULL, NULL, NULL, 
			   NULL, NULL, NULL, NULL, NULL, NULL, 
			   destination_owner, NULL, NULL, NULL, 
			   0, 0, 0, NULL 
			   from sysmergeschemaarticles
			   go')

	    exec dbo.sp_MS_marksystemobject sysmergeextendedarticlesview

		-- Do not regenerate views, procs if this is called from sp_restoredbreplication. Restore only
		-- needs to update schema, then it can call existing system procs to remove db replication cleanly
		if @skip_procgen = 0
		begin
			select @artnick = min(a.nickname) from sysmergearticles a inner join sysmergepublications p on p.pubid = a.pubid where p.snapshot_ready =1
			while @artnick is not null
			begin
				-- find base table to compute number of columns
				select @objid = objid, @col_track = column_tracking
					from sysmergearticles where nickname = @artnick

				-- regenerate the triggers
				select @source_owner = user_name(uid), @source_object = name from sysobjects where id = @objid
				select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_object)
				exec dbo.sp_MSaddmergetriggers @qualified_name, NULL, @col_track

				/* Loop through all articles that this table is involved in and regenerate the article procs */
	            declare hcArtCursor CURSOR LOCAL FAST_FORWARD FOR select artid, pubid from sysmergearticles where nickname = @artnick order by artid, pubid
	            
    	        OPEN hcArtCursor
        	    FETCH hcArtCursor INTO @artid, @pubid
                WHILE (@@fetch_status <> -1)
                    BEGIN
                        select @pubname = name, @snapshot_ready = snapshot_ready from sysmergepublications where pubid = @pubid
                        -- regenerate procs, triggers, and views only for articles with snapshot ready
                        if @snapshot_ready>0
                            begin
                            	declare @rgcol nvarchar(270)
								declare @indname nvarchar(270)
								declare @quotedname nvarchar(270)
								declare @conflict_table sysname
								declare @conflict_table_id int
								declare @owner sysname
                                select @article = name, @conflict_table=conflict_table, @conflict_table_id=object_id(conflict_table)  
                                	from sysmergearticles where artid = @artid and pubid = @pubid

								--make sure conflict table has already got the indexes needed for performance enhancement
								--if not there we will add it up
 								if ( @conflict_table_id is not null) and not exists 
 									(select * from sysindexes where id = @conflict_table_id and keys is not null)
 								begin
							        select @owner=user_name(uid) from sysobjects where id= @conflict_table_id
									select @rgcol = QUOTENAME(name) from syscolumns 
										where id = @objid and ColumnProperty(id, name, 'isrowguidcol') = 1
							        select @indname = 'uc_' + @conflict_table
							        if len(@indname) > 128
        							begin
							            select @indname = substring(@indname,1,92) + convert(nvarchar(36), newid())
        							end
						        	set @indname = QUOTENAME(@indname)
						        	set @quotedname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)
						        	exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname +
        								' (' + @rgcol + ', origin_datasource)' )
	        						if @@error <> 0
    	    							return (1)
								end
                                
                                -- remake the articles procs
                                exec @retcode = dbo.sp_MSsetartprocs @publication = @pubname,   @article = @article, @force_flag = 1
                                if @@ERROR <>0 OR @retcode <>0 
                                    return (1)
                            END
                        FETCH hcArtCursor INTO @artid, @pubid
                    END                         
                CLOSE hcArtCursor
                DEALLOCATE hcArtCursor

				-- we no longer try to delete metadata rows that might have truncated colv1
				--  deleting can cause non-convergence problems where they previously didn't
				--  exist, so we will try to patch up any truncated colv1 values in the merge agent.
				
				-- find next article
				select @artnick = min(a.nickname) from sysmergearticles a inner join sysmergepublications p on p.pubid = a.pubid where p.snapshot_ready > 0 and a.nickname > @artnick
			end -- end colv metadata fixup, article proc and trigger re-gen

			-- Loop over publications and recreate the views, skipping publications where snapshot is not ready
			select @pubname = min(name) from sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() and snapshot_ready > 0
			while @pubname is not null
			begin
				-- remake the publication views
				exec dbo.sp_MSpublicationview @pubname, 1
				select @pubname = min(name) from sysmergepublications where name > @pubname and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() and snapshot_ready > 0

			end
		end -- end @skip_procgen
	end -- end sysmergearticles modifications


	SELECT @table_name = N'MSmerge_tombstone'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSmerge_tombstone' )
	BEGIN
		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'unc3MSmerge_tombstone' AND id = OBJECT_ID('MSmerge_tombstone'))
			drop index MSmerge_tombstone.unc3MSmerge_tombstone
		
	END

	SELECT @table_name = N'MSmerge_contents'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSmerge_contents' )
	BEGIN
		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc2MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc2MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc3MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc3MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc4MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc4MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'unc3SycContents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.unc3SycContents
		
		create index nc2MSmerge_contents on MSmerge_contents(generation)
		if @@ERROR <> 0 return 1

		create index nc3MSmerge_contents on MSmerge_contents(partchangegen)
		if @@ERROR <> 0 return 1

		create index nc4MSmerge_contents on MSmerge_contents(rowguid)
		if @@ERROR <> 0 return 1
	END

	-- before image tables
	declare @binames table (biname sysname)
	insert into @binames select name from sysobjects where xtype='U' and name like 'MS_bi%'
	declare @biname sysname
	set @biname= (select top 1 biname from @binames)
	while @biname is not null
	begin
		set @cmd= 'drop index ' + @biname + '.' + @biname + '_gen'
		exec dbo.sp_executesql @cmd
		set @cmd= 'create clustered index ' + @biname + '_gen on ' + @biname + '(generation)'
		exec dbo.sp_executesql @cmd
		delete from @binames where biname=@biname
		set @biname= (select top 1 biname from @binames)
	end

end

GO
exec sp_MS_marksystemobject 'sp_vupgrade_mergetables'
go

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

-- This proc is invoked on subscriber.
raiserror('Creating procedure sp_MSreset_queue', 0,1)
GO
CREATE PROCEDURE sp_MSreset_queue (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. 
    @publication	sysname,    			    -- publication name,
	@artid 		int)
as
begin
	declare @subserver sysname
			,@subdbname sysname
			,@queue_id  sysname
			,@update_mode int
			,@retcode smallint
			,@vbartid varbinary(20)
			,@queue_server sysname

	set nocount on

	select 	@subserver = @@servername, 
			@subdbname = db_name(),
			@update_mode = update_mode, 
			@queue_id = queue_id,
			@queue_server = queue_server
	from MSsubscription_agents
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication

	if (@update_mode in (2,3))
	begin
		--
		-- MSMQ processing
		-- prefix the queue_id with queue server in direct format
		-- and then perform the queue reset
		--						
		select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
		
		begin distributed tran
		exec @retcode = master.dbo.xp_resetqueue @queue_id, @subserver, 
							@subdbname, @publication, @artid
		if (@retcode != 0 or @@error != 0)
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
	end
	else if (@update_mode in (4,5))
	begin
		begin tran
		
		select @retcode = 0
		if (exists (select * from sysobjects 
			where name = 'MSreplication_queue'))
		begin
			--
			-- Strictly speaking we do no need
			-- to delete but, makes it easy for
			-- the queue reader agent
			-- Do not delete any reset messages
			--
			delete dbo.MSreplication_queue
				where publisher = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication
				and tranid != N'sub-reset'
		end
		else
		begin
			--
			-- first queue subscription is being initialized
			-- create queue if necessary
			--
			exec @retcode = sp_MScreate_sub_tables
				@tran_sub_table = 0,
				@property_table = 0,
				@sqlqueue_table = 1
		end

		--
		-- for subscription reinitialization we
		-- need to insert a RESYNC command message
		--
		select @vbartid = cast(@artid as varbinary(20))
		insert into dbo.MSreplication_queue (publisher, publisher_db,
			publication,tranid, commandtype, data, datalen)
		values (UPPER(@publisher), @publisher_db, 
			@publication, N'sub-reset', 2, @vbartid, datalength(@vbartid))

		if ((@@error != 0) or (@retcode != 0))
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
	end

	commit tran
	return 0
end            
GO
exec dbo.sp_MS_marksystemobject sp_MSreset_queue
go
grant execute on dbo.sp_MSreset_queue to public
go

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

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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSset_subscription_properties (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int,
	@allow_subscription_copy bit,
	@queue_id sysname,
	@update_mode int,
	@attach_version binary(16),
	@queue_server sysname = NULL
)
AS
BEGIN
    set nocount on
	declare @retcode int

	--  Security Check
    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
    IF @@ERROR <> 0 or @retcode <> 0
		RETURN(1)
	
    -- For non independent agent publications
	if @publication is null or @publication = ''
        set @publication = 'ALL'

	if @queue_server = N''
		select @queue_server = NULL
		
	if @queue_id = N''
		select @queue_id = NULL

	update MSsubscription_agents set      
        allow_subscription_copy = @allow_subscription_copy,
		update_mode = @update_mode,
		queue_id = @queue_id,
		queue_server = @queue_server,
		attach_version = @attach_version
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type

	--
	-- for queued pull subscriptions 
	-- update column update_mode in MSreplication_subscriptions
	-- as we never know the right update_mode until initialization
	--
	if ((@subscription_type = 1) and (@queue_id IS NOT NULL) and
		exists (select * from MSreplication_subscriptions 
			WHERE UPPER(publisher) = UPPER(@publisher) AND
				publisher_db  = @publisher_db AND
				publication = @publication AND
				subscription_type = @subscription_type))
	begin
		update MSreplication_subscriptions 
		set update_mode = @update_mode
		WHERE UPPER(publisher) = UPPER(@publisher) AND
			publisher_db  = @publisher_db AND
			publication = @publication AND
			subscription_type = @subscription_type
	end
END
go

exec dbo.sp_MS_marksystemobject sp_MSset_subscription_properties
go
grant execute on dbo.sp_MSset_subscription_properties to public
go


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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSset_sub_guid (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int,
	@subscription_guid binary(16),
	@queue_id		sysname,
	@queue_server	sysname = NULL
)
AS
BEGIN
    set nocount on
	declare @retcode int
	declare @independent_agent bit

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

    -- For non independent agent publications
	if @publication is null or @publication = ''
	begin
        set @publication = 'ALL'
		set @independent_agent = 0
	end
	else
		set @independent_agent = 1

	if @queue_id = N''
		select @queue_id = NULL

	if @queue_server = N''
		select @queue_server = NULL

	update MSsubscription_agents set      
        queue_id = @queue_id
        ,queue_server = @queue_server
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type

	update MSreplication_subscriptions set      
        [time] = getdate(),
		subscription_guid = @subscription_guid
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and (@independent_agent = 0 or publication = @publication)
            and subscription_type = @subscription_type
			and independent_agent = @independent_agent
END
go

exec dbo.sp_MS_marksystemobject sp_MSset_sub_guid
go
grant execute on dbo.sp_MSset_sub_guid to public
go

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

CREATE PROCEDURE sp_MScreate_sub_tables (
@tran_sub_table bit = 0,
@property_table bit = 1,
@sqlqueue_table bit = 0
)
as
BEGIN
	set nocount on
	declare @retcode int

	IF @tran_sub_table = 1 and
		(NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND name = 'MSreplication_subscriptions')) 
	BEGIN
		CREATE TABLE dbo.MSreplication_subscriptions
		(
		publisher sysname NOT NULL,
        publisher_db sysname NOT NULL, 
        publication sysname NULL, 
		independent_agent bit NOT NULL,
        subscription_type int NOT NULL,
        distribution_agent sysname NULL, 
		time smalldatetime NOT NULL,
		description nvarchar(255) NULL,
        transaction_timestamp varbinary(16) NOT NULL,
		-- SyncTran
		update_mode tinyint NOT NULL,
		agent_id binary(16) NULL,
		subscription_guid binary(16) NULL,
		subid binary(16) NULL,
		immediate_sync bit NOT NULL default 1 -- sync_mode with a default of 1
		)
		IF @@ERROR <> 0
			GOTO UNDO
		CREATE UNIQUE CLUSTERED INDEX uc1MSReplication_subscriptions ON
				MSreplication_subscriptions(publication, publisher_db, publisher, subscription_type)
		IF @@ERROR <> 0
			GOTO UNDO

		EXEC dbo.sp_MS_marksystemobject 'MSreplication_subscriptions'
		 IF @@ERROR <> 0
			GOTO UNDO
	END	


	IF @tran_sub_table = 1
	BEGIN
		IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
			type = 'U' AND name = 'MSsubscription_agents') 
		BEGIN
			CREATE TABLE dbo.MSsubscription_agents
			(
			id int identity,
			publisher sysname NOT NULL,
			publisher_db sysname NOT NULL, 
			publication sysname NOT NULL, 
			subscription_type int NOT NULL,
			queue_id sysname NULL,
			update_mode tinyint default 0 not null, -- 0 = read only, 1 = sync/immediate, 2 = queued, 3 = failover, 4 = sqlqueued, 5 = sqlqueued failover
			failover_mode bit default 0 not null, -- 0 - sync/immediate, 1 = queued
			spid int NOT NULL,
			login_time datetime NOT NULL,
			allow_subscription_copy bit default 0 not null,
			attach_state int default 0 not null,	-- 0: not attached 1 attached but not processed 2 attached and processed.
			attach_version binary(16) default newid() not null,
			last_sync_status int NULL, -- allow null for upgrade
			last_sync_summary sysname NULL, -- allow null for upgrade
			last_sync_time datetime NULL, -- allow null for upgrade
			queue_server sysname NULL -- only used for MSMQ based updating subscribers
			)
			IF @@ERROR <> 0
				GOTO UNDO

			CREATE unique CLUSTERED INDEX ucMSsubscription_agents ON dbo.MSsubscription_agents
				(publication, publisher_db, publisher, subscription_type)

			CREATE INDEX ucMSsubscription_agents_id ON dbo.MSsubscription_agents
				(id)

			EXEC dbo.sp_MS_marksystemobject 'MSsubscription_agents'
			IF @@ERROR <> 0
				GOTO UNDO

			grant select on dbo.MSsubscription_agents to public
			IF @@ERROR <> 0
				GOTO UNDO
		END
		ELSE
		BEGIN
			--
			-- table exists - add new columns
			--
			if not exists (select * from dbo.syscolumns where 
				id = object_id('MSsubscription_agents') and
				name = 'queue_server')
			begin
				alter table dbo.MSsubscription_agents add queue_server sysname NULL
				exec dbo.sp_MSupdate_mqserver_subdb
			end
		END
 	END

	IF @property_table = 1 and
		NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
	BEGIN
		BEGIN TRAN

		CREATE TABLE dbo.MSsubscription_properties
		(
		publisher						sysname		NOT NULL,
		publisher_db					sysname		NOT NULL,
		publication						sysname		NOT NULL,
		publication_type				int			NOT NULL,
		publisher_login					sysname		NULL,
		publisher_password				nvarchar(524) NULL,
		publisher_security_mode			int			NOT NULL,
		distributor						sysname		NULL,
		distributor_login				sysname		NULL,
		distributor_password			nvarchar(524) NULL,
		distributor_security_mode		int			NOT NULL,
		ftp_address						sysname		NULL,
		ftp_port						int			NULL,
		ftp_login						sysname		NULL,
		ftp_password					nvarchar(524) NULL,
        alt_snapshot_folder             nvarchar(255) NULL,
        working_directory               nvarchar(255) NULL,
        use_ftp		                    bit default 0 NOT NULL,
		dts_package_name				sysname NULL,
		dts_package_password			nvarchar(524) NULL,
		-- default to be at the subscriber
		dts_package_location			int	default 1 NOT NULL,
		enabled_for_syncmgr				bit default 0 NOT NULL,
        offload_agent                   bit default 0 NOT NULL,
        offload_server                  sysname     NULL,
        dynamic_snapshot_location       nvarchar(255) NULL
		)
		IF @@ERROR <> 0
			GOTO UNDO

		CREATE UNIQUE CLUSTERED INDEX uc1MSsubscription_properties ON
				MSsubscription_properties(publication, publisher_db, publisher)
		IF @@ERROR <> 0
			GOTO UNDO
		
		EXEC @retcode = dbo.sp_MS_marksystemobject 'MSsubscription_properties'
		if @retcode <> 0 or @@error <> 0
			GOTO UNDO

		COMMIT TRAN
	END

	IF @sqlqueue_table = 1
	BEGIN
		declare @folddata bit

		BEGIN TRAN	
		if EXISTS (SELECT * FROM dbo.sysobjects WHERE 
				type = 'U' AND name = 'MSreplication_queue')
		BEGIN
			--
			-- table exists - check if we need to add columns
			--
			if not exists (select * from dbo.syscolumns where 
					id = object_id('MSreplication_queue') and
					name = 'cmdstate')
			BEGIN
				ALTER TABLE dbo.MSreplication_queue ADD cmdstate bit DEFAULT 0 NOT NULL
				IF @@ERROR <> 0
					GOTO UNDO
			END	

			--
			-- change data column from text to varbinary(8000)
			-- SPECIAL CASE : since a simple ALTER does not work here
			-- we create a temp table to save the existing data and then
			-- recreate the table
			--
			if exists (select * from dbo.syscolumns 
				where id = object_id('MSreplication_queue') and
				name = 'data' and xtype = 34)
			begin
				--
				-- save existing column data
				--
				if exists (select * from dbo.MSreplication_queue)
				begin
					select @folddata = 1
					create table #olddata (
						publisher					sysname collate database_default not null ,
						publisher_db				sysname collate database_default not null ,
						publication					sysname collate database_default not null ,
						tranid						sysname collate database_default not null ,
						data						varbinary(8000) NULL ,
						datalen 					int,
						commandtype					int,
						insertdate					datetime ,
						orderkey					bigint,
						cmdstate					bit)
						
					insert into #olddata 
						select publisher, publisher_db, publication, tranid, CAST(data as varbinary(8000)), 
								datalen, commandtype, insertdate, orderkey, cmdstate 
						from dbo.MSreplication_queue
					if @@error != 0
						goto UNDO
				end

				--
				-- drop table
				--
				DROP TABLE dbo.MSreplication_queue
				IF @@ERROR <> 0
					GOTO UNDO				
			end		
		END

		--
		-- Create table if it does not exist
		--
		if NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE 
				type = 'U' AND name = 'MSreplication_queue')		
		BEGIN		
			CREATE TABLE dbo.MSreplication_queue (
				publisher 					sysname NOT NULL ,
				publisher_db 				sysname NOT NULL ,
				publication 				sysname NOT NULL ,
				tranid 						sysname NOT NULL ,
				data 						varbinary(8000) NULL ,
				datalen 					int DEFAULT 0 ,
				commandtype 				int NULL ,
				insertdate 					datetime DEFAULT GETDATE(),
				orderkey					bigint IDENTITY(1,1) PRIMARY KEY,
				cmdstate					bit DEFAULT 0 NOT NULL
			)
			IF @@ERROR <> 0
				GOTO UNDO

			/****
			CREATE NONCLUSTERED INDEX nc1MSreplication_queue ON
					MSreplication_queue(tranid)
			IF @@ERROR <> 0
				GOTO UNDO
			****/

			EXEC @retcode = dbo.sp_MS_marksystemobject 'MSreplication_queue'
			if @retcode <> 0 or @@error <> 0
				GOTO UNDO

			--
			-- Do we need to restore old data
			--
			if (@folddata = 1)
			begin
				insert dbo.MSreplication_queue (publisher, publisher_db, publication, tranid, data,
							datalen, commandtype, insertdate, cmdstate)
					select publisher, publisher_db, publication, tranid, data, 
								datalen, commandtype, insertdate, cmdstate 
						from #olddata
						order by orderkey
				if @@error != 0
					goto UNDO
				
				drop table #olddata
				if @@error != 0
					goto UNDO
			end
		END
		COMMIT TRAN
	END

	return(0)
	
UNDO:
    IF @@TRANCOUNT = 1
        ROLLBACK TRAN
    ELSE
        COMMIT TRAN  
	return(1) 
END
go

exec dbo.sp_MS_marksystemobject sp_MScreate_sub_tables
go

grant exec on dbo.sp_MScreate_sub_tables to public
go


--------------------------------------------------------------------------------
--. sp_MSupdate_mqserver_subdb 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSupdate_mqserver_subdb')
    drop procedure sp_MSupdate_mqserver_subdb
go
--
-- sp_MSupdate_mqserver_subdb
--
-- This procedure is called to upgrade the MSMQ related entries in 
-- MSsubscription_agents in subscription database - this processing 
-- cannot be done directly inside sp_MScreate_sub_tables since we need the 
-- queue_server column for the processing and we can get a syntax error 
-- if the table exists without the column
--
-- Assumption : MSsubscription_agents has been created 
--				and column queue_server exists
--
raiserror('Creating procedure sp_MSupdate_mqserver_subdb', 0,1)
GO
create procedure sp_MSupdate_mqserver_subdb
as
begin
	if exists (select * from dbo.MSsubscription_agents
		where queue_id IS NOT NULL and queue_id != N'mssqlqueue' and queue_server IS NULL)
	begin
		--
		-- we have entries for active Queued subscriptions using MSMQ that need upgrade
		--
		declare @queue_server sysname
				,@publisher sysname
				,@publisher_db sysname
				,@publication sysname

		DECLARE hC CURSOR LOCAL FAST_FORWARD FOR 
			select publisher, publisher_db, publication
			from dbo.MSsubscription_agents
			where queue_id IS NOT NULL 
				and queue_id != N'mssqlqueue' 
				and queue_server IS NULL

		OPEN hC
		FETCH hC INTO @publisher, @publisher_db, @publication
		WHILE (@@fetch_status != -1)
		BEGIN
			--
			-- the table MSsubscription_properties has to exist;
			-- prepare the queue server name from distributor name
			-- strip the instance name if necessary
			--
			select @queue_server = ISNULL(distributor, @@servername)
			from dbo.MSsubscription_properties
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			if (charindex(N'\', @queue_server) > 0)
				select @queue_server = substring(@queue_server, 1, charindex(N'\', @queue_server) - 1)

			--
			-- set the queue_server for this entry
			--
			update dbo.MSsubscription_agents
			set queue_server = @queue_server
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			--
			-- get next entry
			--
			FETCH hC INTO @publisher, @publisher_db, @publication
		END
		CLOSE hC
		DEALLOCATE hC
	end
end
go
exec dbo.sp_MS_marksystemobject sp_MSupdate_mqserver_subdb
go

grant exec on dbo.sp_MSupdate_mqserver_subdb to public
go


--------------------------------------------------------------------------------
--. sp_MSenum_replsqlqueues 
--------------------------------------------------------------------------------
IF EXISTS (select * from sysobjects where
   name = 'sp_MSenum_replsqlqueues' and type = 'P')
      DROP PROCEDURE sp_MSenum_replsqlqueues
go

--
-- sp_MSenum_replsqlqueues
--
-- proc that enumerates all the subscriber + subscriber_db for the currently 
-- active queued subscriptions in all the distribution databases in this system
--
raiserror('Creating procedure sp_MSenum_replsqlqueues', 0,1)
go
create procedure sp_MSenum_replsqlqueues
(
	@curdistdb	sysname = NULL
)
as
begin
    declare @distbit int
    declare @db_name sysname
    declare @cmd nvarchar(1024)

    select @distbit = 16

	--
	-- create the temp table to store the relevant information
	--
	create table #replqueue (
		publisher sysname collate database_default not null,
		publisher_db sysname collate database_default not null,
		subscriber sysname collate database_default not null,
		subscriber_db sysname collate database_default not null,
		publication sysname collate database_default not null,
		dist_db sysname collate database_default not null
	)
	create unique index ucreplqueue ON #replqueue (subscriber, subscriber_db, publication)

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

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

	--
	-- cleanup
	--
	drop table #replqueue
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSenum_replsqlqueues
go

grant execute on dbo.sp_MSenum_replsqlqueues to public
go


--------------------------------------------------------------------------------
--. sp_MSenum_replqueues 
--------------------------------------------------------------------------------
IF EXISTS (select * from sysobjects where
   name = 'sp_MSenum_replqueues' and type = 'P')
      DROP PROCEDURE sp_MSenum_replqueues
go


--
-- sp_MSenum_replqueues
--
-- proc that enumerates all the MSMQ based queues that are currently active 
-- in the specified distribution database
--
-- Parameter :
-- @curdistdb	sysname : specified distribution database. If NULL, then
-- 			enumerate the queues for all the distribution databases
--
raiserror('Creating procedure sp_MSenum_replqueues', 0,1)
go
create procedure sp_MSenum_replqueues
(
	@curdistdb	sysname = NULL
)
as
begin
    declare @distbit int
    declare @db_name sysname
    declare @cmd nvarchar(1024)

    select @distbit = 16

	--
	-- create the temp table to store the relevant information
	--
	create table #replqueue (
		queue_server sysname collate database_default not null,
		queue_id sysname collate database_default not null,
		dist_db sysname collate database_default not null
	)
	create unique clustered index ucreplqueue ON #replqueue (queue_id)

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

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

	--
	-- select the contents of the temp table to present
	-- the formatted queue name
	--
	select 	N'DIRECT=OS:' + queue_server + N'\PRIVATE$\' + queue_id AS 'queue_format'
			,dist_db
	from #replqueue
	
	--
	-- cleanup
	--
	drop table #replqueue
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSenum_replqueues
go

grant execute on dbo.sp_MSenum_replqueues to public
go

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

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

CREATE PROCEDURE sp_repldropcolumn(
    @source_object  	nvarchar(270),
	@column				sysname,
	@from_agent			int = 0, 
	@schema_change_script nvarchar(4000) = NULL,
	@force_invalidate_snapshot bit = 1,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */

	)
as

set nocount on
declare @objid			int
declare @at_publisher	bit
declare @pubname		sysname
declare @artname		sysname
declare @tran_pubname	sysname
declare @tran_artname	sysname
declare @tran_artid		int
declare @tran_pubid		int
declare @colid			int
declare @missing_index	int
declare @tablename		sysname
declare @pubid			uniqueidentifier
declare @artid			uniqueidentifier
declare @partitioned	int
declare @missing_count	int
declare @missing_bm		varbinary(32)
declare @old_missing_bm	varbinary(32)
declare @schematext		nvarchar(4000)
declare @schemaversion	int
declare @not_for_merge	bit
declare @qual_source_object nvarchar(262)
declare @qual_dest_object nvarchar(262)
declare @schematype		int
declare @schemaguid		uniqueidentifier
declare @conflict_table	sysname
declare @ins_conflict_proc sysname
declare @publisher		sysname
declare @publisher_db	sysname
declare @command		nvarchar(3000)
declare @sync_objid		int
declare @retcode 		int
declare @snapshot_ready int
declare @con_id			int
declare @dest_owner		sysname
declare @dest_object	nvarchar(386)
declare @owner			sysname
declare @columnbm		varbinary(128)
declare @in_partition	int
declare @merge_pub_object_bit	int
declare @is_for_merge	bit
declare @is_for_tran    bit
declare @no_schema_replication bit
declare @servername		sysname
declare @dbname			sysname
declare @con_name		sysname
declare @v_unique_index	int
declare @qual_column		nvarchar(140)
declare @indid				int
declare @index_cnt 			int
declare @pkkey				sysname
declare @v_unique_constraint	int
declare @merge_pub_unmarkcolumn_bit	int
declare @merge_pub_markcolumn_bit	int
declare @schema_start_lsn binary(10)
declare @schema_end_lsn binary(10)

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

-- check to see if this stored procedure is called via replication agent.
if sessionproperty('replication_agent')<>1
	select @from_agent = 0
else
	select @from_agent = 1
select @merge_pub_markcolumn_bit = 0x4000
select @merge_pub_unmarkcolumn_bit = ~@merge_pub_markcolumn_bit
select @v_unique_constraint = 4096
select @v_unique_index 	 = 2 		-- status in sysindexes

select @qual_column=QUOTENAME(@column)

select @no_schema_replication = 0
select @not_for_merge	= 0
select @merge_pub_object_bit 	= 128
select @objid = object_id(@source_object)
select @servername=@@SERVERNAME
select @dbname=db_name()

if @objid is NULL
begin
	--if table does not exists and the SP is called from replication agent, ignore the error and exit with success.
	if @from_agent=1
		return (0)
	else
		begin
			raiserror(14027, 16, -1, @source_object)
			return (1)
		end
end

if not exists (select * from syscolumns where name=@column and id=@objid)
begin
	if @from_agent=0
	begin
		raiserror(21166, 16, -1, @column)
		return (1)
	end
	else
		return (0)
end

select @indid = indid from sysindexes where id = @objid and (status & 2048) <> 0    /* PK index */
select @index_cnt = 1
while (@index_cnt <= 16)
begin
	select @pkkey = INDEX_COL(@source_object, @indid, @index_cnt)
	if @pkkey is NULL
		break
	if @pkkey=@column
	begin
		raiserror(21264, 16, -1, @column, @source_object)
		return (1)
	end
	select @index_cnt = @index_cnt + 1
end
	
/*
** Check for unique index defined on this column - to disallow such a column from being dropped
*/	
if exists (select * from sysindexes where id=@objid 
	and (status & @v_unique_index = @v_unique_index 
			or status & @v_unique_constraint = @v_unique_constraint))
begin
	declare @keys varbinary(816)
	declare @i 		int
	declare #check_unique CURSOR LOCAL FAST_FORWARD for 
		select indid from sysindexes where id=@objid 
				and (status & @v_unique_index = @v_unique_index 
					or status & @v_unique_constraint = @v_unique_constraint)
	open #check_unique
	fetch #check_unique into @indid
	while (@@fetch_status<>-1)
	begin
		SELECT @i = 1
		WHILE (@i <= 16)
		BEGIN
			SELECT @pkkey = INDEX_COL(@source_object, @indid, @i)
			if @pkkey is NULL
				break
			if @pkkey=@column
			BEGIN
				raiserror(21265, 16, -1, @column, @source_object)
				close #check_unique
				deallocate #check_unique
				return (1)
			END
			select @i = @i + 1
		END	
		fetch #check_unique into @indid
	end
	close #check_unique
	deallocate #check_unique
end

if exists (select * from sysobjects where name='sysmergearticles')
begin
	if @from_agent=0 and exists (select * from sysmergearticles where objid=@objid and pubid not in 
		(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
	begin
		raiserror(21260, 16, -1, @dbname, @servername, @source_object)
		return (1)
	end
end

-- if not for TRAN, it has to be a merge publication
if not exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysmergearticles where objid=@objid)
		select @no_schema_replication = 1
end

-- if not for merge, it has to be a tran publication
if not exists (select * from sysobjects where name='sysmergepublications')
begin
	if not exists (select * from sysarticles where objid=@objid)
		select @no_schema_replication =1
end

if exists (select * from sysobjects where name='sysmergepublications')
	and exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysarticles where objid=@objid)
			and not exists (select * from sysmergearticles where objid=@objid)
		select @no_schema_replication=1
end

if @no_schema_replication=1
	begin
		raiserror(21246, 16, -1, @source_object)
		return (1)
	end

if exists (select * from sysobjects where name = 'sysmergearticles')
begin
	if exists  (select * from sysmergearticles where objid=@objid)
		select @is_for_merge=1
	else
		select @is_for_merge=0
end
else
	select @is_for_merge=0

-- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
-- END PARSENAME VARS

    select @UnqualName = PARSENAME(@source_object, 1)
    select @QualName1 = PARSENAME(@source_object, 2)
    if @UnqualName IS NULL
         return 1
	if @QualName1 is not NULL
		select @owner = @QualName1
			else select @owner=user_name(uid) from dbo.sysobjects where id = @objid

select @tablename = @UnqualName
select @qual_source_object = QUOTENAME(@owner) + N'.' + QUOTENAME(@tablename)
select @at_publisher = 0
select @colid=colid from dbo.syscolumns where id=@objid and name=@column
if @colid is NULL
	begin
		raiserror(21166, 16, -1, @column)
		return (1)
	end

/*
** Considering holes, colid is not necessarily the one in bitmap. Get this value from count(*)
*/
select @missing_index = count(*) from dbo.syscolumns where id=@objid and colid<=@colid
begin TRAN
save tran sp_repldropcolumn
	if @is_for_merge=1
	begin
		exec sp_replupdateschema @qual_source_object
		if @@ERROR<>0
			goto FAILURE
		exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
		--unmark this column so that it can be dropped
		update dbo.syscolumns set colstat=colstat & @merge_pub_unmarkcolumn_bit where id=@objid and colid = @colid
		if @@ERROR<>0 
			goto FAILURE
	end


	select @is_for_tran = 0	
	if exists (select * from dbo.sysobjects where name='sysarticles')
	begin
		if exists (select * from dbo.sysarticles where objid=@objid)
		begin
			if exists (SELECT P.pubid FROM dbo.syspublications P, dbo.sysarticles A, dbo.syssubscriptions S 
					WHERE A.objid = @objid	and A.pubid = P.pubid and A.artid = S.artid
						and (P.allow_sync_tran = 1 or P.allow_queued_tran = 1) 
						and S.status = 2  -- active
						and S.sync_type != 2 -- not 'none'
						and S.update_mode != 0 ) -- not 'read only'
			 and @force_reinit_subscription = 0
			begin 
				raiserror(21381, 16, -1, @tablename)
				goto FAILURE
			end

			select @is_for_tran =1
			select pubid, artid, columns 
			    into #oldcols 
				from sysarticles
				where objid = @objid
		end
	end

	/*
	** First call TRAN Level stored procedure to 
	*/
	if @is_for_tran = 1
	begin
		exec @retcode = sp_MSprep_exclusive @qual_source_object
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		exec @retcode = sp_replincrementlsn @schema_start_lsn OUTPUT
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		exec @retcode = sp_replpostschema @objid
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name from sysarticles a, syspublications p where a.objid=@objid
					and p.pubid = a.pubid
		open #trancolumn
		fetch #trancolumn into @tran_artid, @tran_pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @tran_artname=name from sysarticles where artid=@tran_artid
			exec @retcode = sp_articlecolumn @publication = @tran_pubname, @article = @tran_artname, @column = @column, 
						 @operation = 'drop', @change_active = 2
						,@force_invalidate_snapshot = 1
						,@force_reinit_subscription = 1
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @tran_pubname			
		END
		close #trancolumn
		deallocate #trancolumn
	end

	if not exists (select * from sysobjects where name='sysmergearticles')
		select @not_for_merge = 1
	else
		if not exists (select * from sysmergearticles where objid=@objid)
			select @not_for_merge =1
	
			
	if @not_for_merge = 1 
	begin
		if exists (select * from syscolumns where name=@column and id =@objid)
		begin
			exec ('alter table '+ @qual_source_object + ' drop column ' + @qual_column )
					if @@ERROR<>0
						goto FAILURE
			
			exec @retcode = sp_MSverifytranfilter @objid
			if @@ERROR <> 0 or @retcode <> 0
			begin
				goto FAILURE
			end					
		end
	end
	else
	begin
		if exists (select * from sysmergepublications where pubid in 
			(select pubid from sysmergearticles where objid=@objid) and snapshot_ready=0)
			and exists (select * from syscolumns where name=@column and id =@objid)
			begin
				declare #nosnapshot CURSOR LOCAL FAST_FORWARD for
					select p.name, a.name from sysmergepublications p, sysmergearticles a 
						where p.pubid=a.pubid and a.objid=@objid and p.snapshot_ready=0
				open #nosnapshot
				fetch #nosnapshot into @pubname, @artname
				while (@@fetch_status<>-1)
				begin
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'drop', 'true'
					if @retcode <>0 or @@ERROR<>0
						goto ERROR_EXIT
					fetch #nosnapshot into @pubname, @artname
				end
				close #nosnapshot
				deallocate #nosnapshot
			end

		declare #dropcolumn_schema CURSOR LOCAL FAST_FORWARD fast_forward for 
				select name, pubid, artid, destination_owner, columns from sysmergearticles where objid=@objid and pubid
							in (select pubid from sysmergepublications where snapshot_ready>0) order by pubid ASC
		open #dropcolumn_schema
		fetch #dropcolumn_schema into @artname, @pubid, @artid, @dest_owner, @columnbm
		while (@@fetch_status <> -1)
		BEGIN
				if @dest_owner is not NULL
					select @dest_object = QUOTENAME(@dest_owner) + N'.' + QUOTENAME(@tablename)
				else
					select @dest_object = QUOTENAME(@tablename)

				exec @in_partition = sp_MStestbit @bm=@columnbm, @coltotest=@colid

				select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
					from sysmergepublications where pubid=@pubid
				select @at_publisher=0
				if @publisher=@@SERVERNAME and @publisher_db=db_name() and @in_partition<>0
				begin
					select @at_publisher=1
					select @schematext = 'exec sp_repldropcolumn ''' + @dest_object + ''', ''' + @column + ''', 1'
					select @schemaversion = schemaversion from sysmergeschemachange
					if (@schemaversion is NULL)
						set @schemaversion = 1
					else
						select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
					set @schemaguid = newid()
					set @schematype = 11 /* alter table */
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'drop', 'true'
					if @retcode<>0 or @@ERROR<>0
						goto INNER_FAIL2 -- need to deallocate cursor for this loop.
					exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
					if @@ERROR<>0 or @retcode<>0 
						goto INNER_FAIL2
						
					select @schematext = 'alter table ' +  @dest_object + ' drop column ' + @column 
					select @schemaversion = @schemaversion + 1
					set @schematype = 13 -- for Jet use only
					set @schemaguid = newid()
					exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext						
					if @@ERROR<>0 or @retcode<>0 
						goto INNER_FAIL2
				end
			fetch #dropcolumn_schema into @artname, @pubid, @artid, @dest_owner, @columnbm
		END
		close #dropcolumn_schema
		deallocate #dropcolumn_schema

		/* drop the column only once */
		if exists (select  *  from syscolumns where id=@objid and name=@column)
		begin
			select @command = 'alter table ' + @qual_source_object + ' drop column ' + @qual_column
			exec (@command)
			if @@ERROR<>0
				GOTO INNER_FAIL

			-- if transactionally replicated, verify that filter columns weren't dropped

			if( @is_for_tran = 1 )
			begin
				exec @retcode = sp_MSverifytranfilter @objid
				if @@ERROR <> 0 or @retcode <> 0
				begin
					goto FAILURE
				end					
			end
		end
		declare #dropcolumn CURSOR LOCAL FAST_FORWARD fast_forward for 
				select pubid, name, sync_objid, artid, missing_col_count, missing_cols, 
					conflict_table, ins_conflict_proc from sysmergearticles where objid=@objid and pubid
							in (select pubid from sysmergepublications where snapshot_ready>0) order by pubid ASC
		open #dropcolumn
		fetch #dropcolumn into @pubid, @artname, @sync_objid, @artid, 
				@missing_count, @missing_bm, @conflict_table, @ins_conflict_proc
		while (@@fetch_status <> -1)
		BEGIN				
			select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
				from sysmergepublications where pubid=@pubid
			select @at_publisher=0
			if @publisher=@@SERVERNAME and @publisher_db=db_name()
				select @at_publisher=1

			if @conflict_table is not NULL 
			begin
				select @con_id = object_id(@conflict_table)
				if @con_id is NULL
				begin
					raiserror(21286, 16, -1, @conflict_table)
					GOTO INNER_FAIL
				end

			select @colid=colid from syscolumns where id = @con_id and name=@column			
			
	
				if exists (select name from syscolumns where name=@column and id=@con_id)
				begin
					select @command = 'alter table ' + QUOTENAME(@conflict_table) + ' drop column ' + @qual_column
					exec (@command)
					if @@ERROR<>0
						goto INNER_FAIL
				end
			end

			/*
			** Force the re-generation of conflict insert table cause the schema is changed for sure
			*/
			if @ins_conflict_proc is not NULL and object_id(@ins_conflict_proc) is not NULL
			begin
				exec ('drop procedure ' + @ins_conflict_proc)
				if @@ERROR<>0
					goto INNER_FAIL
				update sysmergearticles set ins_conflict_proc=NULL where pubid=@pubid and artid=@artid
				if @@ERROR<>0
					goto INNER_FAIL
			end
	
			if @at_publisher=1
			begin
				exec @retcode = sp_MSpublicationview @pubname, 1
				if @retcode<>0 or @@ERROR<>0
				begin
					raiserror(21201, 16, -1) 
					goto INNER_FAIL
				end
			end
			select @missing_count=@missing_count + 1
			select @old_missing_bm=@missing_bm
			exec @retcode=sp_MSsetbit @missing_bm OUTPUT, @missing_index
			if @retcode<>0 or @@ERROR<>0
				goto INNER_FAIL
			--if no change, that is, the column is already marked as missing, do not increase 
			--its count
			if @missing_bm<>@old_missing_bm
			begin
				update sysmergearticles set missing_col_count=@missing_count, missing_cols=@missing_bm
					where pubid=@pubid and artid=@artid
				if @@ERROR<>0
				goto INNER_FAIL
			end
			
				
			exec @retcode = sp_MSdroparticletriggers @qual_source_object
			if @retcode<>0 or @@ERROR<>0
				goto INNER_FAIL
			exec @retcode = sp_MSaddmergetriggers @qual_source_object
			if @retcode<>0 or @@ERROR<>0
				goto INNER_FAIL
			exec @retcode = sp_MSsetartprocs @publication=@pubname, @article=@artname, @force_flag=1
			if @retcode<>0 or @@ERROR<>0
				goto INNER_FAIL
			/*
			** passing in one more parameter to sp_MSgetconflictinsertproc such that there is 
			** no select statement at the end of that SP as needed else where. The default is 1.
			*/
			exec @retcode = sp_MSgetconflictinsertproc @artid, @pubid, 0
			if @retcode<>0 or @@ERROR<>0
				goto INNER_FAIL

			fetch #dropcolumn into @pubid, @artname, @sync_objid, @artid, 
				@missing_count, @missing_bm, @conflict_table, @ins_conflict_proc
		END
		CLOSE #dropcolumn
		DEALLOCATE #dropcolumn
	
		if @is_for_merge=1
		begin
			exec @retcode = sp_MSmarkreplinfo @tablename, @owner
			if @retcode<>0 or @@ERROR<>0
				goto FAILURE
		end
	end

-- finally, if it's transactional, trigger a reinit
if @is_for_tran = 1
begin

	if exists (select * from sysarticles where objid = @objid)
	begin
		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name 
			from sysarticles a, syspublications p, #oldcols oc
			where a.objid=@objid
			and p.pubid = a.pubid
			and oc.artid = a.artid
			and oc.columns <> a.columns

		open #trancolumn
		fetch #trancolumn into @tran_artid, @tran_pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @tran_artname=name, @tran_pubid = pubid, @owner = dest_owner, @tablename = dest_table from sysarticles where artid=@tran_artid
			if(@force_reinit_subscription = 0)
			begin 
				if(@owner is not NULL) and (len(@owner) > 0)
					select @qual_dest_object = QUOTENAME(@owner) + N'.' 
				else 
					select @qual_dest_object = N'' 
				if(@tablename is not null) and (len(@tablename) > 0)
					select @qual_dest_object = @qual_dest_object + QUOTENAME(@tablename)
				else 
					select @qual_dest_object = @qual_source_object
				exec @retcode = sp_MSrepl_schema @pubname = @tran_pubname 
							,@artid = @tran_artid
							,@qual_source_object = @qual_dest_object
							,@column = @column
							,@operation = 1 -- 0 is add, 1 is delete
							,@schema_change_script = @schema_change_script
				if @retcode <>0 or @@ERROR<>0
					goto DROPTRAN
			end
			exec @retcode = dbo.sp_MSreinit_article 
							@publication = @tran_pubname
							,@article = @tran_artname
							,@need_new_snapshot = @force_invalidate_snapshot
							,@need_reinit_subscription = @force_reinit_subscription
							,@force_invalidate_snapshot = @force_invalidate_snapshot
							,@force_reinit_subscription = @force_reinit_subscription
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @tran_pubname			
		END
		close #trancolumn
		deallocate #trancolumn
	 	exec @retcode = sp_replincrementlsn @schema_end_lsn OUTPUT
 		if @@ERROR<>0 or @retcode <> 0
	 		goto FAILURE
 		if (@schema_start_lsn is not null) and (@schema_end_lsn is not null)
	 	begin
 			insert systranschemas (tabid, startlsn, endlsn) values (@objid, @schema_start_lsn, @schema_end_lsn)
 			if @@ERROR<>0
	 			goto FAILURE
 			exec @retcode = sp_replflush @objid, @schema_start_lsn, @schema_end_lsn
 			if @@ERROR<>0 or @retcode <> 0
 				goto FAILURE
	 	end
 		else
 			goto FAILURE
	end
end


COMMIT TRAN
return (0)

DROPTRAN:
CLOSE #trancolumn
DEALLOCATE #trancolumn
GOTO FAILURE

INNER_FAIL:
CLOSE #dropcolumn
DEALLOCATE #dropcolumn
GOTO FAILURE

INNER_FAIL2:
CLOSE #dropcolumn_schema
DEALLOCATE #dropcolumn_schema
GOTO FAILURE


ERROR_EXIT:
CLOSE #nosnapshot
DEALLOCATE #nosnapshot

FAILURE:
	rollback tran sp_repldropcolumn
	commit tran
	raiserror(21284, 16, -1, @column, @source_object)
	return (1)	
go

exec dbo.sp_MS_marksystemobject sp_repldropcolumn 
go

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

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

CREATE PROCEDURE sp_repladdcolumn(
    @source_object  		nvarchar (358),
	@column					sysname,
	@typetext 				nvarchar(3000),
	@publication_to_add		nvarchar(4000) = 'all',
	@from_agent				int = 0, 
	@schema_change_script	nvarchar(4000) = NULL,
	@force_invalidate_snapshot bit = 1,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
	)
as
set nocount on
declare @objid			int
declare @pubid			uniqueidentifier
declare @retcode		int
declare @partitioned	int
declare @at_publisher	bit
declare @pubname		sysname
declare @artname		sysname
declare @colid			int
declare @tablename		sysname
declare @artid			uniqueidentifier
declare @tran_artid		int
declare @tran_pubid		int
declare @schematext		nvarchar(4000)
declare @schemaversion	int
declare @schematype		int
declare @schemaguid		uniqueidentifier
declare @conflict_table	sysname
declare @ins_conflict_proc sysname
declare @publisher		sysname
declare @qual_column	nvarchar(140)
declare @not_for_merge	int
declare @publisher_db	sysname
declare @command		nvarchar(3000)
declare @sync_objid		int
declare @con_id			int
declare @owner			sysname
declare @dest_owner		sysname
declare @dest_object	nvarchar(386)
declare @merge_pub_object_bit	int
declare @is_for_merge	bit
declare @is_for_tran	bit
declare @dbname			sysname
declare @servername		sysname
declare @no_publication bit
declare @no_schema_replication bit
declare @qual_source_object nvarchar(362)
declare @len 			int
declare @prec 			int
declare @scale int
declare @typename nvarchar(270)
declare @qual_dest_object nvarchar(362)
declare @invalid_datatype	bit
declare @is_identity_or_timestamp bit
declare @xtype 		int
declare @iscomputed bit
declare @pass_to_heterogenious bit
declare @merge_pub_markcolumn_bit	int
declare @schema_start_lsn binary(10)
declare @schema_end_lsn binary(10)
declare @nickname 		int
declare @columns_in_partition	int
/*
** Security Check
*/
EXEC @retcode = dbo.sp_MSreplcheck_publish
IF @@ERROR <> 0 or @retcode <> 0
	return (1)


select @qual_column=QUOTENAME(@column)
select @merge_pub_markcolumn_bit = 0x4000

select @objid = object_id(@source_object)

-- check to see if this stored procedure is called via replication agent.
if sessionproperty('replication_agent')<>1
	select @from_agent = 0
else
	begin --if table does not exists and the SP is called from replication agent, ignore the error and exit with success.
		select @from_agent = 1
		if @objid is NULL
			return (0)
	end

if @objid is NULL
begin
	raiserror(14027, 16, -1, @source_object)
	return (1)
end

if exists (select * from syscolumns where id=@objid and name=@column)
begin
	if @from_agent=0
	begin
		raiserror(21255, 16, -1, @column, @source_object)
		return (1)
	end
	else
		return (0)
end


-- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
-- END PARSENAME VARS

    select @UnqualName = PARSENAME(@source_object, 1)
    select @QualName1 = PARSENAME(@source_object, 2)
    if @UnqualName IS NULL
         return 1
	if @QualName1 is not NULL
		select @owner = @QualName1
			else select @owner=user_name(uid) from sysobjects where id = @objid
	select @tablename = @UnqualName

	select @qual_source_object = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename)
select @no_schema_replication = 0
select @no_publication=0
select @servername=@@SERVERNAME
select @dbname=db_name()
select @merge_pub_object_bit 	= 128
select @not_for_merge = 0

if exists (select * from sysobjects where name='sysmergearticles')
begin
	if @from_agent=0 and exists (select * from sysmergearticles where objid=@objid and pubid not in 
		(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@servername) and publisher_db=@dbname))
	begin
		raiserror(21260, 16, -1, @dbname, @servername, @source_object)
		return (1)
	end
end

select @invalid_datatype=0

/* the transaction below is just an experiment to validate type text */
BEGIN TRAN
SAVE TRANSACTION fake_move
	exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
	if @retcode<>0 or @@ERROR<>0
	begin
		goto CHECKING_DONE
	end
	declare @temp_id 		int
	declare @temp_colid 	int
	select @is_identity_or_timestamp = 0
	exec ('alter table ' + @qual_source_object + ' add ' + @qual_column + ' ' + @typetext)
	select @temp_id = object_id(@qual_source_object)
	if @temp_id is NULL
	begin
		raiserror(21285, 16, -1, @column, @source_object)
		select @invalid_datatype = 1
		GOTO CHECKING_DONE
	end
	select @pass_to_heterogenious=0, @temp_colid = colid, @xtype=xtype, @iscomputed=iscomputed 
		from syscolumns where id = @temp_id and name=@column
	if @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'
		select @pass_to_heterogenious=1
	if COLUMNPROPERTY(@temp_id, @column, 'IsIdentity') = 1 or type_name(@xtype) = 'timestamp'
		select @is_identity_or_timestamp = 1
	if COLUMNPROPERTY(@temp_id, @column, 'IsIdentity') = 0
		and not exists (select * from syscolumns where id = @temp_id and name=@column and isnullable=1)
		and not exists (select * from sysconstraints where id=@temp_id and colid=@temp_colid and status & 5 = 5)
		and @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'  --not computed column nor timestamp column
	begin
		select @invalid_datatype = 1
	end
CHECKING_DONE:
ROLLBACK TRANSACTION fake_move
COMMIT TRAN
if @invalid_datatype = 1
	begin
		raiserror(21285, 16, -1, @column, @source_object)
		return (1)
	end
	
if exists (select * from sysobjects where id=@objid and replinfo & @merge_pub_object_bit <>0)
	select @is_for_merge = 1
else
	select @is_for_merge = 0
select @is_for_tran = 0
if not exists (select * from sysobjects where name='sysmergepublications') and
	not exists (select * from sysobjects where name='syspublications')
begin
	raiserror(21230, 16, -1)
	return (1)
end

create table #tmp_table (name sysname collate database_default)

if LOWER(@publication_to_add)='all' or LOWER(@publication_to_add)='[all]'
begin	
	select @publication_to_add = '%'
end
else 
begin
if charindex(',', @publication_to_add)<>0 --publication list
	begin
		declare @tmp_publist	nvarchar(4000)
		declare @total 			int
		declare @invalid_pub	sysname
		select @invalid_pub = NULL
			select @tmp_publist = @publication_to_add
		while @tmp_publist <> ''
		begin
			select @tmp_publist = LTRIM(@tmp_publist)
			select @total=len(@tmp_publist)
			select @len=charindex(',', @tmp_publist)
			if @len=0
				begin
					insert #tmp_table values(@tmp_publist)
					select @tmp_publist=''
				end
			else
				begin
					insert #tmp_table values(substring(@tmp_publist, 1, @len-1))
					select @tmp_publist = right(@tmp_publist, @total-@len)
				end
		end
		if exists (select * from sysobjects where name='sysmergepublications') and 
			exists (select * from sysobjects where name='syspublications')
			select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from sysmergepublications) and 
															name not in (select ('[' + name + ']') from syspublications)
		else 
			if exists (select * from sysobjects where name='sysmergepublications') 
				select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from sysmergepublications)			
			else
				if exists (select * from sysobjects where name='syspublications') 		
					select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from syspublications)						
		if @invalid_pub is not NULL and @from_agent=0
		begin
			raiserror(21274, 16, -1, @invalid_pub)
			return (1)		
		end
	end
else 
	begin --single publication
		insert #tmp_table values(@publication_to_add)
		insert #tmp_table values('[' + @publication_to_add + ']')
	end
	
end



-- if not for TRAN, it has to be a merge publication
if not exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysmergepublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
		select @no_publication = 1

	if not exists (select * from sysmergearticles where objid=@objid and pubid in 
			(select pubid from sysmergepublications where name like @publication_to_add 
					or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication = 1
end

-- if not for merge, it has to be a tran publication
if not exists (select * from sysobjects where name='sysmergepublications')
begin
	if not exists (select * from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))) 
		select @no_publication = 1
		
	if not exists (select * from sysarticles where objid=@objid and pubid in 
			(select pubid from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication =1
end

if exists (select * from sysobjects where name='sysmergepublications')
	and exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
			and not exists (select * from sysmergepublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
		select @no_publication = 1

	if not exists (select * from sysarticles where objid=@objid and pubid in 
			(select pubid from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))))
		and not exists (select * from sysmergearticles where objid=@objid and pubid in 
			(select pubid from sysmergepublications where name like @publication_to_add 
					or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication=1
end

if @no_publication=1 and @publication_to_add <> '%' and LOWER(@publication_to_add)<>'none' and LOWER(@publication_to_add)<>'[none]'
	begin
		raiserror(21200, 16, -1, @publication_to_add)
		return (1)
	end

if @no_schema_replication=1 and LOWER(@publication_to_add)<>'none' and LOWER(@publication_to_add)<>'[none]'
	begin
		if @publication_to_add = '%'
			begin
				raiserror(21246, 16, -1, @source_object)
				return (1)
			end
		else
			begin
				raiserror(21245, 16, -1, @source_object, @publication_to_add)
				return (1)
			end
	end

select @at_publisher = 0

if exists (select * from sysobjects where name = 'sysarticles')
begin
	if exists (select a.objid from sysarticles a, syspublications p where a.objid=@objid
				and p.pubid = a.pubid
				and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0))
	begin
		select @is_for_tran = 1
	end
end

if (@is_for_tran =1 and @force_reinit_subscription = 0)
begin
	if (@is_identity_or_timestamp  = 1 )
	begin
		raiserror(21380, 16, -1)
		return (1)
	end
	if exists (SELECT P.pubid FROM dbo.syspublications P, dbo.sysarticles A, dbo.syssubscriptions S 
					WHERE A.objid = @objid	and A.pubid = P.pubid and A.artid = S.artid
						and (P.allow_sync_tran = 1 or P.allow_queued_tran = 1) 
						and S.status = 2  -- active
						and S.sync_type != 2 -- not 'none'
						and S.update_mode != 0 ) -- not 'read only'

	begin 
		raiserror(21381, 16, -1, @tablename)
		return (1)
	end
end

begin TRAN
save tran sp_repladdcolumn
	if @is_for_merge=1
	begin
		exec sp_replupdateschema @qual_source_object
 		if @@ERROR<>0
			goto FAILURE
		
		exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
	end
	if not exists (select * from sysobjects where name='sysmergearticles')
		select @not_for_merge = 1
	else
		if not exists (select * from sysmergearticles where objid=@objid)
			select @not_for_merge =1

	if @is_for_tran = 1
	begin
		if not exists (select * from syscolumns where name=@column and id =@objid)
		begin
			exec @retcode = sp_MSprep_exclusive @qual_source_object
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec @retcode = sp_replincrementlsn @schema_start_lsn OUTPUT
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec @retcode = sp_replpostschema @objid
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec ('alter table '+ @qual_source_object + ' add ' + @qual_column + ' ' + @typetext )
				if @@ERROR<>0
					goto FAILURE
		end
	end
	if @not_for_merge = 0
	begin		
		if  not exists (select * from syscolumns where name=@column and id =@objid)
			begin
				exec ('alter table '+ @qual_source_object + ' add ' + @qual_column + ' ' + @typetext )
				if @@ERROR<>0
					goto FAILURE
			end

		/*
		** whether the column is added to this publication, the articles whose underlying table contains
		** a new column will be regareded as vertically partitioned.
		*/ 
		update sysmergearticles set vertical_partition=1 where objid=@objid
		if @@ERROR<>0
			goto FAILURE

		/*
		** Heterogenious subscriber are not to receive computed column or timestamp columns
		*/
		declare #nosnapshot CURSOR LOCAL FAST_FORWARD for
			select p.name, a.name, a.pubid from sysmergepublications p, sysmergearticles a 
					where p.pubid=a.pubid and a.objid=@objid and p.snapshot_ready=0 and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0)
							and (p.sync_mode=0 or @pass_to_heterogenious=1)					
			open #nosnapshot
			fetch #nosnapshot into @pubname, @artname, @pubid
				while (@@fetch_status<>-1)
				begin
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'add', 'true'
					if @retcode <>0 or @@ERROR<>0
						goto ERROR_EXIT
					fetch #nosnapshot into @pubname, @artname, @pubid					
				end
		CLOSE #nosnapshot
		DEALLOCATE #nosnapshot
				
		
		/*
		** Handle those cases where snapshot is already ran and new schema change needs to be added
		** ; Heterogenious subscriber are not to receive computed column or timestamp columns
		*/
		declare #addcolumn CURSOR LOCAL FAST_FORWARD fast_forward for 
				select pubid, name, sync_objid, artid, conflict_table, ins_conflict_proc, destination_owner
					from sysmergearticles where objid=@objid and pubid
						in (select pubid from sysmergepublications where snapshot_ready>0 
							and (sync_mode=0 or @pass_to_heterogenious=1))
		open #addcolumn
		fetch #addcolumn into @pubid, @artname, @sync_objid, @artid, @conflict_table, @ins_conflict_proc, @dest_owner
		while (@@fetch_status <> -1)
		BEGIN
				if @dest_owner is not NULL
					select @dest_object = QUOTENAME(@dest_owner) + '.' + QUOTENAME(@tablename)
				else
					select @dest_object = QUOTENAME(@tablename)

				select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
					from sysmergepublications where pubid=@pubid

				if @conflict_table is not NULL 
				begin
					select @con_id = object_id(@conflict_table)
					if @con_id is NULL
						begin
							raiserror(21286, 16, -1, @conflict_table)
							GOTO INNER_FAIL
						end
					if not exists (select name from syscolumns where name=@column and id=@con_id) and (@pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0)
					begin
						select @typename = type_name(xtype), @len = length, @prec = COLUMNPROPERTY(id, name, 'precision'),
								@scale = scale, @iscomputed=iscomputed, @xtype=xtype	
							from syscolumns where name=@column and id=@objid
						--we want to column property of 'computed' or 'timestamp' of the newly added column
						if @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'
						begin
							if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes 
								select @len = @len/2
							exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
							if @@error<>0 OR @retcode <>0 
								GOTO INNER_FAIL
							--doing so instead of using @typetext as we once did is that we do not want any constraint or identity properties 
							--defined on conflict tables. Also it is safe to make the column NULLable in conflict tables.
							select @command = 'alter table ' + QUOTENAME(@conflict_table) + ' add ' + @qual_column + ' ' + @typename + ' NULL '
						end
						else
						--continue to use typetext when adding computed/timestamp column to the conflict tables.
						begin
							select @command = 'alter table ' + QUOTENAME(@conflict_table) + ' add ' + @qual_column + ' ' + @typetext						
						end
						exec (@command)
						if @@ERROR<>0
						goto INNER_FAIL

					end
				end
			
			/*
			** Force the re-generation of conflict insert table cause the schema is changed for sure
			*/
				if @ins_conflict_proc is not NULL and object_id(@ins_conflict_proc) is not NULL and (@pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0)
				begin
					exec ('drop procedure ' + @ins_conflict_proc)
					if @@ERROR<>0
						goto INNER_FAIL
					update sysmergearticles set ins_conflict_proc=NULL where pubid=@pubid and artid=@artid
					if @@ERROR<>0
						goto INNER_FAIL
				end

			/*
			** Force the regeneration of publication view for all publications that publish the current table.
			*/
				update sysmergearticles set vertical_partition=1 where artid=@artid and pubid=@pubid
				if @@ERROR<>0
					goto INNER_FAIL
			
				select @at_publisher=0
				if @publisher=@@SERVERNAME and @publisher_db=db_name()
				begin
					select @at_publisher=1
					if @pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0
					begin
						select @schematext = 'exec sp_repladdcolumn ''' + @dest_object + ''',''' + @column + ''','+  QUOTENAME(@typetext) + ', ''' + @publication_to_add + ''', 1'  
						select @schemaversion = schemaversion from sysmergeschemachange
						if (@schemaversion is NULL)
							set @schemaversion = 1
						else
							select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
						set @schemaguid = newid()
						set @schematype = 11 /* alter table */
						exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'add','true'
						if @retcode<>0 or @@ERROR<>0
							goto INNER_FAIL -- need to deallocate cursor for this loop.
						exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
						if @@ERROR<>0 or @retcode<>0 
							goto INNER_FAIL
							
						--insert a schema change for Jet specifically subscribers	
						select @schematext = 'alter table ' +  @dest_object + ' add ' + @column + ' ' + @typetext
						select @schemaversion = @schemaversion + 1
						set @schematype = 13 -- for Jet use only
						set @schemaguid = newid()
						exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext						
						if @@ERROR<>0 or @retcode<>0 
							goto INNER_FAIL
					end
				end
	
				if @at_publisher=1
				begin
					exec @retcode = sp_MSpublicationview @pubname, 1
					if @retcode<>0 or @@ERROR<>0
						goto INNER_FAIL
				end

				select @columns_in_partition=count(*) from syscolumns where id = @sync_objid
				if @columns_in_partition>246
				begin
					raiserror('Failed to add column ''%s'' to table ''%s'' because there are too many columns in the partition', 16, -1,@column, @source_object)
					goto INNER_FAIL
				end
			
				exec @retcode = sp_MSdroparticletriggers @qual_source_object
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL
				exec @retcode = sp_MSaddmergetriggers @qual_source_object
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL

				/*
				** Force the regeneration of merge procs for all publications that publish the current table
				*/
					
				exec @retcode = sp_MSsetartprocs @publication=@pubname, @article=@artname, @force_flag=1
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL
		/*
		** passing in one more parameter to sp_MSgetconflictinsertproc such that there is 
		** no select statement at the end of that SP as needed else where. The default is 1.
		*/
				exec @retcode = sp_MSgetconflictinsertproc @artid, @pubid, 0
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL

				fetch #addcolumn into @pubid, @artname, @sync_objid, @artid, @conflict_table, @ins_conflict_proc, @dest_owner
		END
		close #addcolumn
		deallocate #addcolumn
	
		declare @column_tracking int
		select @column_tracking=column_tracking, @nickname=nickname from sysmergearticles where objid=@objid
		if @column_tracking = 1
		begin
			--make sure there is no colv overflow, which was not caught by 246 column restriction because
			--users keep adding/dropping column, which causes no increase in number of coumns but consume
			--colv slot cause we never release the slot when a column is dropped
			if exists (select * from MSmerge_contents where tablenick=@nickname and len(colv1)>2040)
			begin				
				raiserror(21418, 16, -1,@column, @source_object)
				goto INNER_FAIL
			end
			--apend an lineage slot for the new column. 
			update MSmerge_contents set 
				colv1=substring(colv1, 1, (datalength(colv1)-1)) + substring(colv1, 1, 4) + 0x01000000FF
					where tablenick=@nickname
			if @@ERROR<>0
				goto FAILURE
		end
	end

	if @is_for_tran = 1
	begin 
		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name from sysarticles a, syspublications p where a.objid=@objid
				and p.pubid = a.pubid
				and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0)
		open #trancolumn
		fetch #trancolumn into @tran_artid, @pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @artname = name, @tran_pubid = pubid, @owner = dest_owner, @tablename = dest_table from sysarticles where artid=@tran_artid
			exec @retcode = sp_articlecolumn @publication = @pubname, @article = @artname, @column = @column, 
							 @operation = 'add', @change_active = 2
							,@force_invalidate_snapshot = 1
							,@force_reinit_subscription = 1
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			if(@force_reinit_subscription = 0)	
			begin
				if(@owner is not NULL) and (len(@owner) > 0)
					select @qual_dest_object = QUOTENAME(@owner) + N'.' 
				else 
					select @qual_dest_object = N'' 
				if(@tablename is not null) and (len(@tablename) > 0)
					select @qual_dest_object = @qual_dest_object + QUOTENAME(@tablename)
				else 
					select @qual_dest_object = @qual_source_object
				exec @retcode = sp_MSrepl_schema @pubname = @pubname 
							,@artid = @tran_artid
							,@qual_source_object = @qual_dest_object
							,@column = @column
							,@operation = 0 -- 0 is add, 1 is delete
							,@typetext = @typetext
							,@schema_change_script = @schema_change_script
				if @retcode <>0 or @@ERROR<>0
					goto DROPTRAN
			end
			exec @retcode = dbo.sp_MSreinit_article 
							@publication = @pubname
							,@article = @artname
							,@need_new_snapshot = @force_invalidate_snapshot
							,@need_reinit_subscription = @force_reinit_subscription 
							,@force_invalidate_snapshot = @force_invalidate_snapshot
							,@force_reinit_subscription = @force_reinit_subscription
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @pubname			
		END
		close #trancolumn
		deallocate #trancolumn
 		exec @retcode = sp_replincrementlsn @schema_end_lsn OUTPUT
 		if @@ERROR<>0 or @retcode <> 0
 			goto FAILURE
 		if (@schema_start_lsn is not null) and (@schema_end_lsn is not null)
 		begin
 			insert systranschemas (tabid, startlsn, endlsn) values (@objid, @schema_start_lsn, @schema_end_lsn)
 			if @@ERROR<>0
 				goto FAILURE
 			exec @retcode = sp_replflush @objid, @schema_start_lsn, @schema_end_lsn
 			if @@ERROR<>0 or @retcode <> 0
 				goto FAILURE
 		end
 		else
 			goto FAILURE
	end
	
	/* Get back to its original replication state */
	if @is_for_merge=1
	begin
		exec @retcode = sp_MSmarkreplinfo @tablename, @owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
		update syscolumns set colstat = colstat | @merge_pub_markcolumn_bit where id=@objid and name= @column
		if @@ERROR<>0
			goto FAILURE
	end

COMMIT TRAN
return (0)

INNER_FAIL:
CLOSE #addcolumn
DEALLOCATE #addcolumn
GOTO FAILURE

ERROR_EXIT:
CLOSE #nosnapshot
DEALLOCATE #nosnapshot
GOTO FAILURE

DROPTRAN:
CLOSE #trancolumn
DEALLOCATE #trancolumn

FAILURE:
	rollback tran sp_repladdcolumn
	commit tran
	raiserror(21285, 16, -1, @column, @source_object)
	return (1)	
go

exec dbo.sp_MS_marksystemobject sp_repladdcolumn 
go
--------------------------------------------------------------------------------
--. sp_MSagent_access_check 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
     where type = 'P '
            and name = 'sp_MSagent_access_check')
     drop procedure sp_MSagent_access_check
go

raiserror('Creating procedure sp_MSagent_access_check',0,1)
go
CREATE PROCEDURE sp_MSagent_access_check (
    @job_id         VARBINARY(16),
    @agent_type     sysname = NULL -- 'distribution' or 'merge', case insensitive
) AS

    DECLARE @retcode int
    DECLARE @count   int

    IF @agent_type IS NOT NULL
    BEGIN
        IF LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN (N'distribution', N'merge')
        BEGIN
            RAISERROR(21170, 16, -1)
            RETURN (1)
        END
    END

    SELECT @retcode = 0
    -- Create a list of owners of the subscriptions depending on the given 
    -- agent 
    CREATE TABLE #sub_owner_list (owner_name sysname collate database_default)

    -- Try querying the Transactional subscriptions for the owner 
    IF @agent_type IS NULL OR LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) = N'distribution'
    BEGIN

        IF EXISTS (SELECT * 
                     FROM sysobjects 
                    WHERE type = N'S' AND name = N'syssubscriptions')
        BEGIN
            INSERT INTO #sub_owner_list 
            SELECT DISTINCT login_name 
              FROM dbo.syssubscriptions 
             WHERE distribution_jobid = @job_id 
        END

        IF NOT EXISTS (SELECT * FROM #sub_owner_list) AND 
           @agent_type IS NOT NULL
        BEGIN
            RAISERROR(21167, 16, -1, 'Distribution')
            SELECT @retcode = 1
            GOTO FAILURE
        END 
    END

    IF (@agent_type IS NULL AND NOT EXISTS (SELECT * FROM #sub_owner_list)) OR
       LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) = N'merge' 
    BEGIN
        
        SELECT @count = COUNT(*)
          FROM sysobjects
         WHERE name IN (N'sysmergesubscriptions', N'MSmerge_replinfo')
        
        IF @count = 2        
        BEGIN
            INSERT INTO #sub_owner_list 
            SELECT DISTINCT sms.login_name 
              FROM dbo.MSmerge_replinfo mr
        INNER JOIN dbo.sysmergesubscriptions sms
                ON mr.repid = sms.subid
             WHERE mr.merge_jobid = @job_id
        END

        IF NOT EXISTS (SELECT * FROM #sub_owner_list) AND 
           @agent_type IS NOT NULL
        BEGIN
            RAISERROR(21167, 16, -1, 'Merge')
            SELECT @retcode = 1
            GOTO FAILURE
        END 
    END

    IF NOT EXISTS (SELECT * FROM #sub_owner_list) 
    BEGIN
        RAISERROR(21134, 16, -1)
        SELECT @retcode = 1
        GOTO FAILURE
    END

    IF suser_sname(suser_sid()) NOT IN (SELECT owner_name FROM #sub_owner_list) AND
       is_srvrolemember('sysadmin') <> 1 AND
       is_member('db_owner') <> 1
    BEGIN

        RAISERROR(21168, 16, -1)
        SELECT @retcode = 1
        GOTO FAILURE
    END

FAILURE:

    DROP TABLE #sub_owner_list
    RETURN @retcode

GO

EXEC dbo.sp_MS_marksystemobject sp_MSagent_access_check
GO


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

raiserror('Creating procedure sp_MSinstance_qv',0,1)
go
create procedure sp_MSinstance_qv @qv varchar(10)
as
begin
	declare @qv_value varchar(10)
	set nocount on
	-- -------------------------------------------------------------
	--
	-- BUGBUG 236535 : IA64 workaround
	--
	-- since xp_qv has not been ported yet - detect the
	-- the platform and preset the config for IA64 servers
	--
	-- NOTE : this code should be later cleaned up
	-- once SETUP is completely functional on IA64
	--
	-- -------------------------------------------------------------
	declare @fia64 bit
	
	create table #tosversion ( propid int, propname sysname collate database_default, value int null, charvalue nvarchar(255) collate database_default)
	insert into #tosversion (propid, propname, value, charvalue)
		exec master.dbo.xp_msver N'Platform'
	
	select @fia64 = case when patindex(N'%IA64%', charvalue) != 0 then 1 else 0 end
	from #tosversion

	if (@fia64 = 1)
	begin
		select @qv_value = 0
	end
	else
	begin
		if serverproperty('instancename') is null
			exec @qv_value = master.dbo.xp_qv @qv	
	    else
		begin
			declare @instance_name varchar(257)
			select @instance_name = cast(serverproperty('instancename') as varchar(257))
			exec @qv_value = master.dbo.xp_qv @qv, @instance_name
		end
	end
	-- -------------------------------------------------------------
	return @qv_value
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSinstance_qv
GO

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

-- No parameter checking is performed in sp_MSremoveoffloadparameter
raiserror(15339,-1,-1,'sp_MSremoveoffloadparameter')
GO
CREATE PROCEDURE sp_MSremoveoffloadparameter (
    @job_id    VARBINARY(16),
    @agenttype NVARCHAR(20) 
    ) AS
    SET NOCOUNT ON
    
    /*
    ** Declarations
    */
    
    DECLARE @paramstart    INT
    DECLARE @paramend      INT
    DECLARE @paramlen      INT
    DECLARE @paramend2     INT
    DECLARE @command       NVARCHAR(3200) 
    DECLARE @commandtail   NVARCHAR(3200)
    DECLARE @pattern       NVARCHAR(100)

    SELECT @pattern = N'%-[Oo][Ff][Ff][Ll][Oo][Aa][Dd]%'
    SELECT @paramlen = LEN(N'-offload')
    SELECT @command = NULL

    -- use the job_id and the agent type to retrieve the agent command
    -- line, only one agent command step is allowed in a job

    SELECT @command = command FROM msdb.dbo.sysjobsteps 
     WHERE job_id = @job_id AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)

    -- purge all instances of '-offload servername' from the agent command line
    SELECT @paramstart = PATINDEX(@pattern, @command)
    WHILE ((@command IS NOT NULL) AND (@paramstart <> 0))
    BEGIN       
        -- extract the part of the command line after the -Offload parameter
        SELECT @commandtail = SUBSTRING(@command, @paramstart + @paramlen, 
                                        LEN(@command) - 
                                        (@paramstart + @paramlen) + 1)

        -- search for the beginning of the server name that follows -offload
        -- in the command tail; note that the empty spaces in the square
        -- bracket of the pattern are actually a space and a tab

        SELECT @paramend = PATINDEX(N'%[^ 	]%', @commandtail)

        -- search for the end of the server name that follows -offload
        IF (@paramend <> 0) 
        BEGIN
            SELECT @commandtail = SUBSTRING(@commandtail, @paramend, 
                                            LEN(@commandtail) - @paramend + 1)
            SELECT @paramend2 = PATINDEX(N'%[ 	]%', @commandtail) 
            IF (@paramend2 <> 0)
            BEGIN
                SELECT @paramend = @paramend + @paramend2 - 1
            END
            ELSE
            BEGIN
                -- reaching the end of the command line
                SELECT @paramend = @paramend + LEN(@commandtail) - 1
                IF @paramstart > 1 
                BEGIN
                    SELECT @paramstart = @paramstart - 1
                    SELECT @paramend = @paramend + 1
                END
            END
        
        END                
        -- Remove the -Offload parameter from the command line
        SELECT @command = STUFF(@command, @paramstart, @paramlen + @paramend, N'')

        SELECT @paramstart = PATINDEX(@pattern, @command)
    END
    
    -- update the agent command line with all the -offload's removed
    UPDATE msdb.dbo.sysjobsteps 
       SET command = @command
     WHERE job_id = @job_id AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)   
    
    RETURN 0
GO
EXEC dbo.sp_MS_marksystemobject sp_MSremoveoffloadparameter
GO

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

-- No parameter checking is performed in sp_MSaddoffloadparameter 
raiserror(15339,-1,-1,'sp_MSaddoffloadparameter')
GO
CREATE PROCEDURE sp_MSaddoffloadparameter (
    @offloadserver sysname, /* Name of the target server to offload the agent to */
    @job_id        VARBINARY(16), 
    @agenttype     NVARCHAR(20) /* Agent type can either be 'merge' or 'distribution' */
    ) AS
    
    SET NOCOUNT ON

    /*
    **  Declarations
    */

    DECLARE @command               NVARCHAR(3200)
    
    -- initialize variables
    SELECT @command = NULL    

    -- call sp_MSremoveoffloadparameter to remove all exisiting instances of the 
    -- -offload parameters from the agent command line; the return status
    -- of sp_MSremoveoffloadparameter is ignored
    EXEC sp_MSremoveoffloadparameter @job_id=@job_id, @agenttype=@agenttype
    
    -- update the agent command line by appending '-Offload ' + 
    -- @offloadserver    
    
    UPDATE msdb.dbo.sysjobsteps
       SET command = command + N' -Offload ' + @offloadserver 
     WHERE job_id = @job_id 
       AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)
         
    RETURN 0
GO
EXEC dbo.sp_MS_marksystemobject sp_MSaddoffloadparameter
GO


--------------------------------------------------------------------------------
--.	Transactional Replication objects (repltran.sql)
--------------------------------------------------------------------------------

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

/*
** 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_MSaddschemaarticle')
        drop procedure sp_MSaddschemaarticle

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

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

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

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

    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_MSarticlecol')
        drop procedure sp_MSarticlecol
    

    dump tran master with no_log
    

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

    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.
        -- 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_compensating_send')
        drop procedure sp_MSscript_compensating_send 

   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_insert_subwins')
        drop procedure sp_MSscript_insert_subwins 

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

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

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

   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_update_subwins')
        drop procedure sp_MSscript_update_subwins 

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

   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_delete_subwins')
        drop procedure sp_MSscript_delete_subwins 

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

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

   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_ExecutionMode_stmt')
        drop procedure sp_MSscript_ExecutionMode_stmt

	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_MSscript_pub_upd_trig')
        drop procedure sp_MSscript_pub_upd_trig

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

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

   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_MSis_identity_insert')
        drop procedure sp_MSis_identity_insert 

    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_MSareallcolumnscomputed')
    begin
        drop procedure sp_MSareallcolumnscomputed
    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_MSgettypestringudt' )
    begin
        drop procedure sp_MSgettypestringudt
    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_MSscript_missing_row_check' )
    begin
        drop procedure sp_MSscript_missing_row_check
    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_scriptreconwhereclause' )
    begin
        drop procedure sp_scriptreconwhereclause
    end

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

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

    if exists( select * from sysobjects 
        where type = 'P ' and name = N'sp_script_reconciliation_xdelproc' )
    begin
        drop procedure sp_script_reconciliation_xdelproc
    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_scriptxdelproc' )
    begin
        drop procedure sp_scriptxdelproc
    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 = N'sp_scriptxupdproc' )
    begin
        drop procedure sp_scriptxupdproc
    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_scriptdynamicupdproc' )
    begin
        drop procedure sp_scriptdynamicupdproc
    end

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

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

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

    if exists ( select * from sysobjects 
        where type = 'P ' and name = 'sp_MSscriptmvastable' )
    begin
        drop procedure sp_MSscriptmvastable
    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_marksubscriptionvalidation' )
    begin
        drop procedure sp_marksubscriptionvalidation
    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_MSget_article_column_list' )
    begin
        drop procedure sp_MSget_article_column_list
    end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if exists (select * from sysobjects
			where type = 'FN' and name = 'fn_sqlvarbasetostr')
	     drop function fn_sqlvarbasetostr

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

raiserror(15339,-1,-1,'sp_MSarticlecolstatus')
GO

CREATE PROCEDURE sp_MSarticlecolstatus (
    @artid int,
    @tabid int,
    @colid int,
    @type nvarchar (10),      /* 'publish', 'nonsqlsub' */
    @status bit OUTPUT)
    AS

    SELECT @status = 0

    IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'nonsqlsub'
    BEGIN

		----------------------------------------------------------
		-- Check all active or subscribed articles for the column.
        ----------------------------------------------------------

		IF EXISTS( SELECT sub.artid FROM sysarticles art, syssubscriptions sub, syspublications sp, master.dbo.sysservers ss
				   WHERE art.objid = @tabid
				   AND art.artid <> @artid
				   AND sub.artid = art.artid
				   AND ss.srvid = sub.srvid
				   AND sp.pubid = art.pubid
				   AND ( ( sub.status in(1,2) AND (ss.srvproduct = N'MSREPL-NONSQL' OR sp.allow_anonymous = 1) ) 
				         OR sub.status = 3 )
				   AND CONVERT(bit, CONVERT( varbinary, SUBSTRING( CONVERT( nvarchar, art.columns ), 16 - FLOOR((@colid-1)/16),1 )) & POWER(2, ((@colid-1)%16))) = 1 )
		BEGIN
			SELECT @status = 1
		END
    END
    ELSE
    BEGIN
    
		-----------------------------------------------------------
		-- Check all articles for the column.
        -----------------------------------------------------------

		IF EXISTS( SELECT artid FROM sysarticles 
                   WHERE objid = @tabid
                   AND artid <> @artid
				   AND CONVERT(bit, CONVERT( varbinary, SUBSTRING( CONVERT( nvarchar, columns ), 16 - FLOOR((@colid-1)/16),1 )) & POWER(2, ((@colid-1)%16))) = 1 )
		BEGIN
			SELECT @status = 1
		END
    END

    RETURN (0)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSarticlecolstatus
GO

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

raiserror(15339,-1,-1,'sp_MSarticlecol')
GO

CREATE PROCEDURE sp_MSarticlecol (
    @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 @publish smallint        /* Constant: 0x1000 */
    DECLARE @nonsqlsub smallint        /* Constant: 0x2000 */
	DECLARE @initiated smallint			/* Constant: 0x4000 */
	DECLARE @repldts smallint			/* Constant: 0x8000 */
    DECLARE @tinycolid tinyint, @allow_dts bit, @pubid int  /* hydra compatible colid */

    if @colid >= 256
    begin
	raiserror(21395, 16, -1)
        RETURN (1)
    end

    SELECT @tinycolid = @colid

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

	select @allow_dts = allow_dts from syspublications where pubid = @pubid


    SELECT @publish = 0x1000
    SELECT @nonsqlsub = 0x2000
	SELECT @initiated = 0x4000
	if @allow_dts = 1
		select @repldts = 0x8000
	else
		select @repldts = 0x0000

	-- loop through all columns in the article

    IF @colid IS NULL
    BEGIN
       DECLARE hCartcol CURSOR LOCAL FAST_FORWARD FOR
            SELECT colid FROM syscolumns, sysarticles
                WHERE artid = @artid
                AND id = @tabid
                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 hCartcol CURSOR LOCAL FAST_FORWARD FOR 
            SELECT colid FROM syscolumns WHERE id = @tabid
                AND colid = @colid
    END


    OPEN hCartcol

    FETCH hCartcol INTO @colid

    WHILE (@@fetch_status <> -1)
    BEGIN

       IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = N'add'
       BEGIN
          IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'publish'
          BEGIN
             UPDATE syscolumns
             SET colstat = colstat | @publish
             WHERE id = @tabid
             AND colid = @colid
          END
          ELSE
          BEGIN
             UPDATE syscolumns
             SET colstat = colstat | @nonsqlsub | @repldts
             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_MSarticlecolstatus @artid, @tabid, @colid,
          @type, @status OUTPUT

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

          IF (@status = 0)
          BEGIN
             IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'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 & ~@repldts
                WHERE id = @tabid
                AND colid = @colid
             END
          END
       END

       FETCH hCartcol INTO @colid

    END


    CLOSE hCartcol
    DEALLOCATE hCartcol

GO

EXEC dbo.sp_MS_marksystemobject sp_MSarticlecol
GO

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

raiserror(15339,-1,-1,'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 = 336,                        /* 14  days */
    @allow_queued_tran      nvarchar(5) = 'false',
    -- Portable Snapshot
    @snapshot_in_defaultfolder      nvarchar(5) = 'true',
    @alt_snapshot_folder    nvarchar(255) = NULL,
    -- Snapshot pre/post- commands
    @pre_snapshot_script    nvarchar(255) = NULL,
    @post_snapshot_script   nvarchar(255) = NULL,
    -- Snapshot compression
    @compress_snapshot      nvarchar(5) = 'false',
    -- Post 7.0 FTP
    @ftp_address            sysname = NULL,
    @ftp_port                   int = 21,
    @ftp_subdirectory       nvarchar(255) = NULL,
    @ftp_login              sysname = N'anonymous',
    @ftp_password           sysname = NULL,
    @allow_dts				nvarchar(5)	= 'false',
	@allow_subscription_copy nvarchar(5) = 'false',
	@conflict_policy		nvarchar(100) = NULL, 	-- NULL, 'pub wins', 'sub reinit', 'sub wins'
	@centralized_conflicts	nvarchar(5) = NULL, 	-- NULL, 'true', 'false'
	@conflict_retention		int = 14,
	@queue_type				nvarchar(10) = NULL,	-- NULL, 'msmq', 'sql'
	@add_to_active_directory	nvarchar(10) = 'false',
	@logreader_job_name sysname = NULL,
	@qreader_job_name sysname = NULL
	) 
AS
BEGIN

    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
    DECLARE @enc_ftp_password nvarchar(524)
	DECLARE @ad_guidname	sysname
	
    -- SyncTran
    DECLARE @allow_sync_tran_id bit
    DECLARE @allow_queued_tran_id bit
    DECLARE @autogen_sync_procs_id bit
	DECLARE @conflict_policy_id int
	DECLARE @centralized_conflicts_bit bit
			, @queue_type_val int
	
    -- Portable snapshot
    DECLARE @snapshot_in_defaultfolder_bit int 

    -- Snapshot compression
    DECLARE @compress_snapshot_bit bit

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

	declare @backward_comp_level int
	select @backward_comp_level = 10 -- default to sphinx
	select @allow_sync_tran_id = 0
			,@autogen_sync_procs_id = 0
			,@allow_queued_tran_id = 0
			,@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
	
    /*
    **  A @retention value of zero means an infinite retention period
    */
	if @retention < 0
	BEGIN
		RAISERROR (20050, 16, -1, 1)
        RETURN(1)
	END

    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() collate database_default) = 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() collate database_default) <> 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
	**		2  dump database
	**		3  concurrent
	**		4  concurrent character
    */

    SELECT @sync_method = LOWER(@sync_method collate SQL_Latin1_General_CP1_CS_AS)										

    IF @sync_method IS NULL OR @sync_method NOT IN ('native', 'character', 'bcp native', 'bcp character', 'dump database', 'concurrent', 'concurrent_c')
        BEGIN
            RAISERROR (14014, 16, -1)
            RETURN (1)
        END

	IF @sync_method = 'concurrent_c'
		SELECT @smid = 4
	ELSE IF @sync_method = 'concurrent'
		SELECT @smid = 3
	ELSE IF @sync_method = 'dump database'
	begin
		SELECT @smid = 2				   
		select @backward_comp_level = 40 -- not sure if we are using this, but has to be shiloh feature
	end
    ELSE 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 collate SQL_Latin1_General_CP1_CS_AS)
    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.sp_MSinstance_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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false'))
        BEGIN
            RAISERROR (14017, 16, -1)
            RETURN (1)
        END

    /*
    ** Restricted publications are no longer supported
    */
    IF LOWER(@restricted collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('inactive', 'active')
        BEGIN
            RAISERROR (14012, 16, -1)
            RETURN (1)
        END

    IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) = 'active' 
	begin
		SELECT @statid = 1
	end
    ELSE 
	begin
		SELECT @statid = 0
	end

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

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

    IF LOWER(@independent_agent collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@immediate_sync')
            RETURN (1)
        END

    IF LOWER(@immediate_sync collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@enabled_for_internet')
            RETURN (1)
        END

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

    IF @enabled_for_internet_id = 1 AND (@alt_snapshot_folder IS NULL OR
        @alt_snapshot_folder = N'')
        BEGIN
            RAISERROR (21159, 16, -1)
            RETURN (1) 
        END

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

    IF @allow_push IS NULL OR LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_push')
            RETURN (1)
        END
    IF LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_pull')
            RETURN (1)
        END
    IF LOWER(@allow_pull collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_anonymous')
            RETURN (1)
        END
    IF LOWER(@allow_anonymous collate SQL_Latin1_General_CP1_CS_AS) = '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

    /*
    ** Parameter Check:  @add_to_active_directory.
    */

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

   /* Is AD supported? */
   DECLARE @retval  INT
   EXECUTE @retval = master.dbo.xp_MSADEnabled
   if (@retval <> 0) and LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
   begin
		RAISERROR(21253, 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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@allow_sync_tran')
        RETURN (1)
    END

    /*
    ** Parameter Check:  @allow_queued_tran
    */

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

    IF LOWER(@allow_sync_tran collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
    BEGIN
		-- If we are doing sync tran, we need independent agents
		-- override the user input
        SELECT @allow_sync_tran_id = 1
			,@independent_agent = 'true'
			,@independent_agent_id = 1
			,@backward_comp_level = 40 -- immediate update needs to have the new sp_addsynctriggers stored proc
    END
    ELSE 
    BEGIN
        SELECT @allow_sync_tran_id = 0
    END

    IF LOWER(@allow_queued_tran collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
    BEGIN
		-- If we are doing queued tran, we need independent agents
		-- override the user input
        SELECT @allow_queued_tran_id = 1
			,@independent_agent = 'true'
			,@independent_agent_id = 1
			,@backward_comp_level = 40 -- queued compenents not avaliable prior to shiloh
    END
    ELSE 
    BEGIN
        SELECT @allow_queued_tran_id = 0
    END

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

	--
	-- For publications that allow updating subscribers (immediate/queued)
	-- this option has to be true at all times, for others
	-- it should be false. This flag is not of any value currently
	-- as we do not have any provision for accepting custom generated
	-- synctan proc names for an article. For now, we will override
	-- the user supplied value
	--
	select @autogen_sync_procs_id = case 
		when (@allow_sync_tran_id = 0 and @allow_queued_tran_id = 0) then 0
		else 1
	end
	
    -- Portable snapshot
    IF @snapshot_in_defaultfolder IS NULL OR LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@snapshot_in_defaultfolder')
        RETURN (1)
    END
    
    IF LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @snapshot_in_defaultfolder_bit = 1
    END
    ELSE
    BEGIN
        SELECT @snapshot_in_defaultfolder_bit = 0
    END

    -- Pre/Post snapshot commands
    -- If @sync_method is character mode bcp, this would indicate that
    -- this publication may support non-SQL Server subscribers. In this 
    -- case, pre- and post- snapshot commands are not allowed.
    IF @smid = 1 AND 
        ((@pre_snapshot_script IS NOT NULL AND @pre_snapshot_script <> '') OR
         (@post_snapshot_script IS NOT NULL AND @post_snapshot_script <> ''))
    BEGIN
        RAISERROR (21151, 16, -1)
        RETURN (1)
    END
    
    -- Parameter check - @compress_snapshot
    -- @compress_snapshot can be 1 if @alt_snapshot_folder is non-null
    IF LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@compress_snapshot')
        RETURN (1)
    END
    
    IF LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @compress_snapshot_bit = 1
    END
    ELSE
    BEGIN
        SELECT @compress_snapshot_bit = 0
    END

    -- Snapshot compression can only be enabled if an alternate 
    -- snapshot generation folder exists or the publication
    -- is enabled for internet.
    IF (@compress_snapshot_bit = 1 AND 
        (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N'') AND
        (LOWER(@enabled_for_internet collate SQL_Latin1_General_CP1_CS_AS) = N'false'))
    BEGIN
        RAISERROR (21157, 16, -1)
        RETURN (1)
    END    

    -- Parameter check: ftp_address
    -- If the publication is enabled for internet, ftp_address cannot be null
    IF @enabled_for_internet_id = 1 AND (@ftp_address IS NULL OR @ftp_address = N'')
    BEGIN
        RAISERROR (21158, 16, -1)
        RETURN (1)
    END     

    -- Parameter check: ftp_port
    IF @ftp_port IS NULL
    BEGIN
        RAISERROR (21160, 16, -1)
    END

	-- Parameter check : DTS
	declare @allow_dts_id bit
    IF @allow_dts IS NULL OR LOWER(@allow_dts collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@allow_dts')
        RETURN (1)
    END

    -- Encrypt ftp password before putting it into the syspublications
    -- table if one is provided
    SELECT @enc_ftp_password = NULL
    IF @ftp_password IS NOT NULL
    BEGIN
        SELECT @enc_ftp_password = @ftp_password 
        EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
        IF @retcode <> 0
        BEGIN
            RETURN (1)
        END
    END    

    IF LOWER(@allow_dts collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @allow_dts_id = 1
    ELSE SELECT @allow_dts_id = 0

	-- To allow DTS, the publication has to be
	-- 1. independent agent
	-- 2. char bcp

	if @allow_dts_id = 1
	begin
		if @smid NOT IN ( 1, 4 )
		begin
			-- 'The publication has to be in char bcp mode.'
			raiserror(21172, 16, -1)
			return(1)
		end
		if @independent_agent_id = 0
		begin
			-- 'The publication has to be independent agent.'
			raiserror(21173, 16, -1)
			return(1)		
		end
		if @allow_sync_tran_id = 1 or @allow_queued_tran_id = 1
		begin
			raiserror(21180, 16, -1)
			return(1)
		end
	end

	declare @allow_subscription_copy_id bit
    IF LOWER(@allow_subscription_copy collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @allow_subscription_copy_id = 1
    ELSE SELECT @allow_subscription_copy_id = 0

	-- To allow subscription copy, the publication has to be
	-- 1. immediate_sync
	if @allow_subscription_copy_id = 1
	begin
		if @immediate_sync_id <> 1
		begin
			raiserror(21210, 16, -1)
			return(1)
		end
	end

	--
	-- Check parameters for @conflict_policy, @centralized_conflicts, @conflict_retention
	-- for queued publications
	--
	if (@allow_queued_tran_id = 1)
	begin
		--
		-- set default conflict_policy if required
		--
		if (@conflict_policy IS NULL)
		begin
			--
			-- if it is snapshot based, then the default policy is 'sub reinit'
			-- else the default policy is 'pub wins'
			--
			select @conflict_policy = case when (@rfid = 1) then 'sub reinit' 
										else 'pub wins' end
		end
		
		if (LOWER(@conflict_policy collate SQL_Latin1_General_CP1_CS_AS) = 'sub reinit')
			select @conflict_policy_id = 3
		else if (LOWER(@conflict_policy collate SQL_Latin1_General_CP1_CS_AS) = 'pub wins')
			select @conflict_policy_id = 1
		else if (LOWER(@conflict_policy collate SQL_Latin1_General_CP1_CS_AS) = 'sub wins')
			select @conflict_policy_id = 2
		else
		begin
			raiserror (21184, 16, 2, '@conflict_policy', 'sub reinit', 'pub wins', 'sub wins')
			return (1)
		end

		--
		-- Check snapshot permissible values
		--
		if ((@rfid = 1) and (@conflict_policy_id = 1))
		begin
			raiserror (21270, 16, 1, '@conflict_policy', @conflict_policy)
			return (1)
		end
		
		--
		-- set default centralized_conflicts if required
		--
		if (@centralized_conflicts IS NULL)
			select @centralized_conflicts = 'true'
		
		if (LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) = 'true')
			select @centralized_conflicts_bit = 1
		else if (LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) = 'false')
			select @centralized_conflicts_bit = 0
		else
		begin
			raiserror (14148, 16, -1, '@centralized_conflicts')
			return (1)
		end

		--
		-- Check snapshot permissible values
		--
		if ((@rfid = 1) and (@centralized_conflicts_bit = 0))
		begin
			raiserror (21270, 16, 1, '@centralized_conflicts', @centralized_conflicts)
			return (1)
		end
		
		if (@conflict_retention IS NULL)
			select @conflict_retention = 14
		else if (@conflict_retention < 0)
		begin
			raiserror(20050, 16, -1, 0)
			return (1)
		end

		if ((@queue_type IS NULL) or (LOWER(@queue_type collate SQL_Latin1_General_CP1_CS_AS) = 'sql'))
			select @queue_type_val = 2
		else if (LOWER(@queue_type collate SQL_Latin1_General_CP1_CS_AS) = 'msmq')
			select @queue_type_val = 1
		else
		begin
			raiserror (21184, 16, 3, '@queue_type', 'msmq', 'sql', 'NULL')
			return (1)
		end
	end

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

	declare @job_existing bit

    -- Create logreader task for the first log based or allow queued publication.
    -- We need logreader for queued publication to do idenity range management.
    IF  (@rfid = 0 or @allow_queued_tran_id = 1)  and NOT EXISTS 
        (SELECT * FROM syspublications where repl_freq = 0 or allow_queued_tran = 1) 
    BEGIN
		-- Clear repl dbtable fields. This will avoid unnecessary log scan in the 
		-- logreader at the first time it runs.
		--
		-- sp_droppublication will clear the fields when dropping the last publication, 
		-- however, it is after the transaction deleting syspublication table being
		-- committed, thus not guaranteed.
		-- 
		-- We also need this logic for upgraded 7.0 databases where we don't clear
		-- distbackuplsn and distlastlsn fields in unpublishing.
		--
		/* ensure we can get in as logreader */
	    exec @retcode = dbo.sp_replflush
        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO

		/* unmark all xacts marked for replication */
		exec @retcode = dbo.sp_repldone NULL, NULL, 0, 0, 1
        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO
    
	    /* release our hold on the db as logreader */
	    EXEC @retcode = dbo.sp_replflush
        IF @@ERROR <> 0 or @retcode <> 0
            GOTO UNDO

		-- Run checkpoint to make sp_repldone result durable (write repl dbtable fields
		-- into the checkpoint record).
		checkpoint
        IF @@ERROR <> 0
            GOTO UNDO


		if @logreader_job_name is null
			select @job_existing = 0
		else
			select @job_existing = 1

        /*
        ** Schedule Log Reader agent for the database
		** If @logreader_job_name is not null
        */
        SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSadd_logreader_agent'

        EXECUTE @retcode = @distproc
			@name = @logreader_job_name,
            @publisher = @@SERVERNAME,
            @publisher_db = @dbname,
            @publication = 'ALL',  
            @local_job = 1,
			@job_existing = @job_existing 

        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, allow_queued_tran,
                           snapshot_in_defaultfolder, alt_snapshot_folder, pre_snapshot_script, 
                           post_snapshot_script, compress_snapshot, ftp_address, ftp_port, 
                           ftp_subdirectory, ftp_login, ftp_password, allow_dts, 
						   allow_subscription_copy, centralized_conflicts, conflict_retention, 
						   conflict_policy, queue_type, backward_comp_level)

    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, @allow_queued_tran_id,
            @snapshot_in_defaultfolder_bit, @alt_snapshot_folder, @pre_snapshot_script,
            @post_snapshot_script, @compress_snapshot_bit, @ftp_address, @ftp_port, 
            @ftp_subdirectory, @ftp_login, @enc_ftp_password, 
			@allow_dts_id, @allow_subscription_copy_id, @centralized_conflicts_bit, @conflict_retention, 
			@conflict_policy_id, @queue_type_val, @backward_comp_level)

    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,
	@sync_method = @smid,
	@allow_subscription_copy = @allow_subscription_copy_id,
	@allow_queued_tran = @allow_queued_tran_id,
	@queue_type = @queue_type_val

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

	if @qreader_job_name is not null
	begin
		--
		-- Schedule Queue Reader agent for the database
		--
		SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSadd_qreader_agent'
		EXECUTE @retcode = @distproc @name = @qreader_job_name
		IF @@ERROR <> 0 or @retcode <> 0
		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

	declare @returnstring nvarchar(512) 
	set @returnstring = N''
	if LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
    begin
    	--no error checking needed here.    
		create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
		if @@ERROR<>0
		begin
    		goto FAILURE 					
		end
		insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @dbname
		if @retcode <> 0 or @@ERROR<>0
    	begin
			set @returnstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory)
    		goto FAILURE 					
	   	end
    	select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory
    	if @ad_guidname is not NULL
    	begin
    		update syspublications set ad_guidname=@ad_guidname where pubid=@pubid
    		if @@ERROR<>0
    			goto FAILURE
    	end
		drop table #guid_name_for_active_directory
    end
	RETURN(0)
FAILURE:
	drop table #guid_name_for_active_directory
	if @returnstring is NULL
		select @returnstring = N''
	raiserror(21363, 16, -1, @publication, @returnstring)
    return (1)   
UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_addpublication
        COMMIT TRAN   
    end
    return 1
END
go
 
EXEC dbo.sp_MS_marksystemobject sp_addpublication
GO

grant execute on dbo.sp_addpublication to public
go


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

raiserror(15339,-1,-1,'sp_changepublication')
GO

CREATE PROCEDURE sp_changepublication (
    @publication sysname = NULL,        /* Publication name */
    @property nvarchar(50) = NULL,           /* The property to change */
    @value nvarchar(255) = NULL,              /* The new property value */
	@force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
) 
AS
BEGIN
    SET NOCOUNT ON

    /*
    ** Declarations.
    */

	DECLARE @cmd nvarchar(255)
			,@cmd2 nvarchar(255)
			,@pubid int
			,@replfreqid tinyint
			,@retcode int
			,@statusid tinyint
			,@syncmethodid tinyint
			,@db_name	sysname
			,@distributor sysname
			,@distproc nvarchar (255)
			,@subscribed int    
			,@virtual_id smallint
			,@prev_value_bit bit
			,@value_bit bit
			,@allow_anonymous bit
			,@push int
			,@pull int
			,@independent_agent bit
			,@immediate_sync bit
			,@distribdb sysname
			,@dbname sysname
			,@taskid int
			,@add_virtual_back bit
			,@alt_snapshot_folder nvarchar(255)
			,@enabled_for_internet bit
			,@ftp_address sysname
			,@snapshot_in_defaultfolder bit
			,@allow_dts bit
			,@in_ActiveD	bit
			,@ad_guidname	sysname
			,@enc_ftp_password nvarchar(524)
			,@conflict_policy_id int
			,@centralized_conflicts_bit bit
			,@conflict_retention int
			,@queue_type int
			,@allow_sync_tran bit
			,@allow_queued_tran bit
			
	SELECT @add_virtual_back = 0
			,@push = 0
			,@pull = 1
			,@alt_snapshot_folder = NULL
			,@subscribed = 1
			,@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() collate database_default) = 0

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

    select @db_name=db_name()
    
    /*
    ** Parameter Check:  @property.
    ** If the @property parameter is NULL, print the options.
    */

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname collate database_default not null)
            INSERT INTO #tab1 VALUES ('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')
            INSERT INTO #tab1 VALUES ('snapshot_in_defaultfolder')
            INSERT INTO #tab1 VALUES ('alt_snapshot_folder')
            INSERT INTO #tab1 VALUES ('pre_snapshot_script')
            INSERT INTO #tab1 VALUES ('post_snapshot_script')
            INSERT INTO #tab1 VALUES ('compress_snapshot')
            INSERT INTO #tab1 VALUES ('ftp_address')
            INSERT INTO #tab1 VALUES ('ftp_port')
            INSERT INTO #tab1 VALUES ('ftp_subdirectory')
            INSERT INTO #tab1 VALUES ('ftp_login')
            INSERT INTO #tab1 VALUES ('ftp_password')
            INSERT INTO #tab1 VALUES ('allow_subscription_copy')
            INSERT INTO #tab1 VALUES ('conflict_policy')
            INSERT INTO #tab1 VALUES ('centralized_conflicts')
            INSERT INTO #tab1 VALUES ('conflict_retention')
            INSERT INTO #tab1 VALUES ('queue_type')
            INSERT INTO #tab1 VALUES ('publish_to_ActiveDirectory')
            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, 
    	@ad_guidname=ad_guidname, --with NULL value if this publication is not in AD
    	@replfreqid = repl_freq,
        @immediate_sync = immediate_sync,
        @independent_agent = independent_agent,
        @syncmethodid = sync_method,
        @alt_snapshot_folder = alt_snapshot_folder,
        @enabled_for_internet = enabled_for_internet,
        @ftp_address = ftp_address,
		@allow_dts = allow_dts
		,@queue_type = queue_type
        ,@snapshot_in_defaultfolder = snapshot_in_defaultfolder
		,@in_ActiveD = case when ad_guidname is NULL then 0 else 1 end 
		,@allow_sync_tran = allow_sync_tran
		,@allow_queued_tran = allow_queued_tran
        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.
    */

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( 'taskid','description', 'sync_method',
     'status', 'repl_freq','immediate_sync', 'independent_agent', 
     'enabled_for_internet', 'allow_push', 'allow_pull', 'allow_anonymous', 'retention',
     'snapshot_in_defaultfolder', 'alt_snapshot_folder', 'pre_snapshot_script', 'post_snapshot_script', 
     'compress_snapshot', 'ftp_address', 'ftp_port', 'ftp_subdirectory',
     'ftp_login', 'ftp_password','allow_subscription_copy','conflict_policy',
     'centralized_conflicts','conflict_retention','queue_type','publish_to_activedirectory')
        BEGIN
            RAISERROR (21183, 16, -1, @property)
            RETURN (1)
        END

    /*
    ** Parameter Check:
    ** If sync_method of the publication is character mode (an indication that it supports
    ** third party Subscribers), pre/post-snapshot setting must be null   
    **
    */
    IF @syncmethodid = 1 
    BEGIN
        IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pre_snapshot_script' OR
            LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'post_snapshot_script') AND
            @value IS NOT NULL AND @value <> ''
        BEGIN
            RAISERROR (21151, 16, -1)
            RETURN (1)
        END   
    END

    /*
    ** Parameter Check:
    ** If the Publication's alt_snapshot_folder setting is null, 
    ** snapshot compression cannot be enabled
    */
    IF (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = '') 
        AND LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
        AND LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'   
    BEGIN
        RAISERROR (21157, 16, -1)        
        RETURN(1)
    END

    /* 
    ** Parameter Check:
    ** If enabled_for_internet is set to true, the publication must have a non-null
    ** ftp_address.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
       LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND 
       (@ftp_address IS NULL OR @ftp_address = N'')
    BEGIN
        RAISERROR(21158, 16, -1)
        RETURN (1)
    END

    /*
    ** .. and ftp_address cannot be null if the publication is enabled for 
    ** internet.
    */
/*
    IF @enabled_for_internet = 1 AND
      (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        AND (@value IS NULL OR @value = N''))
    BEGIN
        RAISERROR(21158, 16, -1)
        RETURN (1)
    END
*/
    /*
    ** .. and 'alternate snapshot folder' is not null
    **
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
        LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND
       (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N'')
    BEGIN
        RAISERROR(21159, 16, -1)
        RETURN (1)
    END 

    /* 
    ** Parameter Check:
    ** If the publication is enabled for internet, the publication must
    ** have a non-null alternate snapshot folder and the 
    ** snapshot_in_defaultfolder property must be 0.
    */
/*
    IF @enabled_for_internet = 1 AND 
       ((LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
        AND (@value IS NULL OR @value = N'')))
    BEGIN
        RAISERROR(21159, 16, -1)
        RETURN (1)
    END  
*/

    /*
    ** Parameter Check:
    ** 'ftp_port' cannot be null
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port' AND @value IS NULL
    BEGIN
        RAISERROR (14043, 16, -1, @property)
        RETURN (1)
    END

	-- Check to see if there are snapshot and subscription needs to be reinited.
	declare @need_new_snapshot bit
		,@need_reinit_subscription bit
		,@active tinyint

	select @active = 2
	select @need_new_snapshot = 0
	select @need_reinit_subscription = 0

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('snapshot_in_defaultfolder', 'alt_snapshot_folder',
		'pre_snapshot_script', 'post_snapshot_script', 'compress_snapshot', 
		'ftp_address','ftp_port','ftp_subdirectory','ftp_login','ftp_password',
		'enabled_for_internet')
	begin
		select @need_new_snapshot = 1
	end
	else if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_method'
	begin
		-- If changing to or from concurrent, must reinit subscription.
		if EXISTS( select * from syspublications sp
			where sp.pubid = @pubid and 
			(sp.sync_method in (3,4) or LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) in ('concurrent', 'concurrent_c'))) 
		BEGIN
			select @need_new_snapshot = 1
			select @need_reinit_subscription = 1			
		END
		else
			select @need_new_snapshot = 1
	end
	else if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'repl_freq'
	BEGIN
		select @need_new_snapshot = 1
		select @need_reinit_subscription = 1			
	END
	
	-- Have to call this stored procedure to invalidate existing snapshot or reint
	-- subscriptions if needed
	EXECUTE @retcode  = dbo.sp_MSreinit_article
		@publication = @publication, 
		@need_new_snapshot = @need_new_snapshot,
		@need_reinit_subscription = @need_reinit_subscription
		,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
		,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
		,@check_only = 1
	IF @@ERROR <> 0 OR @retcode <> 0
		return (1)

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

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='description'
        BEGIN
            UPDATE syspublications SET description = @value
                WHERE pubid = @pubid
            IF @@ERROR <> 0 GOTO UNDO
        END
        
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='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 collate SQL_Latin1_General_CP1_CS_AS) = 'publish_to_activedirectory'
   		BEGIN
        if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        	BEGIN
            	RAISERROR (14137, 16, -1)
            	GOTO UNDO
        	END

	    /* Is AD supported? */
	    DECLARE @retval  INT
	    EXECUTE @retval = master.dbo.xp_MSADEnabled
	    if (@retval <> 0)
	    begin
			RAISERROR(21254, 16, -1, @publication)
			RETURN (1)
	    end

   		if @in_ActiveD=0 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='true'
	   		BEGIN
				create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
				if @@ERROR<>0
				begin
		    		raiserror(21363, 16, -1, @publication, N'')
    				GOTO UNDO									
				end
				insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @db_name
				if @retcode <> 0 or @@ERROR<>0
		    	begin
					declare @errorstring nvarchar(512)
					select @errorstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory) 
					drop table #guid_name_for_active_directory
					if @errorstring is NULL
						select @errorstring=N''
		    		raiserror(21363, 16, -1, @publication, @errorstring)
    				GOTO UNDO					
	   			end
	    		select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory

    			if @ad_guidname is not NULL
	    		begin
    				update syspublications set ad_guidname=@ad_guidname where pubid=@pubid
    				if @@ERROR<>0
    				begin
						drop table #guid_name_for_active_directory
			    		raiserror(21363, 16, -1, @publication, N'')
    					GOTO UNDO					
    				end
	    		end
	    		drop table #guid_name_for_active_directory
   			END
   		else if @in_ActiveD=1 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='false'
   			BEGIN
				exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @db_name, @ad_guidname
				if @@ERROR<>0 or @retcode<>0
				begin
					raiserror(21369, 16, -1, @publication)	
					goto UNDO
				end
				update syspublications set ad_guidname=NULL where pubid=@pubid
				if @@ERROR<>0
				begin
					raiserror(21369, 16, -1, @publication)	
					goto UNDO
				end
   			END
	   END

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

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_method'
        BEGIN

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

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

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('native', 'bcp native')
                SELECT @syncmethodid = 0
            ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('character', 'bcp character')
                SELECT @syncmethodid = 1
			ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ( 'concurrent' )
				SELECT @syncmethodid = 3
			ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ( 'concurrent_c' )
				SELECT @syncmethodid = 4

			if @syncmethodid NOT IN (1,4) and @allow_dts = 1
			begin
				raiserror(21172, 16, -1)
				GOTO UNDO
			end

			-- Non sql subscribers can only use char bcp (not concurrent)
			if @syncmethodid <> 1
			begin
				IF EXISTS( select * from syspublications sp, syssubscriptions ss, 
							sysarticles sa, master..sysservers srv
						   where sp.pubid = @pubid 
						   and sp.pubid = sa.pubid
						   and sa.artid = ss.artid
						   and srv.srvid = ss.srvid
						   and srv.srvproduct = N'MSREPL-NONSQL' collate database_default)
				BEGIN
					RAISERROR(20593, 16, -1, @publication )
					GOTO UNDO
				END			 
			end

			if exists (select * from syspublications where
				pubid = @pubid and
				sync_method <> @syncmethodid)
			begin
				/*
				** Update the publication with the new synchronization method.
				*/

				/*
				** If we switch to character mode bcp (an indication that this 
				** publication may support non-SQL Server subscribers) for this 
				** publication, the pre/post snapshot commands settings should be
				** nullified  
				*/    
				IF @syncmethodid = 1
				BEGIN

					UPDATE syspublications 
					SET sync_method = @syncmethodid, pre_snapshot_script = NULL,
						post_snapshot_script = NULL
					WHERE pubid = @pubid

				END    
				ELSE
				BEGIN
					UPDATE syspublications
					   SET sync_method = @syncmethodid
					 WHERE pubid = @pubid
				END

	            IF @@ERROR <> 0 GOTO UNDO
			end            
        END

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

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

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = 'repl_freq'
        BEGIN

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

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


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

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

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



/*

            IF EXISTS (SELECT * FROM syssubscriptions
            WHERE 
                status <> @subscribed AND
                srvid >= 0 AND
                artid IN (SELECT artid FROM sysextendedarticlesview 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 collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
        BEGIN
            -- If the alt_snapshot_folder is set to '' or NULL,
            -- set the compress_snapshot bit to 0 and disable
            -- internet support  
            IF @value IS NULL OR @value = N''
            BEGIN
                UPDATE syspublications
                   SET alt_snapshot_folder = @value,
                       compress_snapshot = 0,
                       enabled_for_internet = 0
                 WHERE pubid = @pubid
            END
            ELSE
            BEGIN
                UPDATE syspublications
                   SET alt_snapshot_folder = @value
                 WHERE pubid = @pubid

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

        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'pre_snapshot_script'
        BEGIN
            UPDATE syspublications
               SET pre_snapshot_script = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'post_snapshot_script'
        BEGIN
            UPDATE syspublications
               SET post_snapshot_script = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        BEGIN
    
            IF @value IS NULL OR @value = N''
            BEGIN
                UPDATE syspublications
                   SET ftp_address = @value,
                       enabled_for_internet = 0
                 WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END
            END
            ELSE
            BEGIN
                UPDATE syspublications
                   SET ftp_address = @value
                 WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END
            END
        END
            
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port'
        BEGIN
            UPDATE syspublications
               SET ftp_port = CONVERT(int, @value)
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_subdirectory'
        BEGIN
            UPDATE syspublications
               SET ftp_subdirectory = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_login'
        BEGIN
            UPDATE syspublications
               SET ftp_login = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_password'
        BEGIN
            SELECT @enc_ftp_password = NULL
            IF @value IS NOT NULL
            BEGIN
                SELECT @enc_ftp_password = @value
                EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
                IF @retcode <> 0
                BEGIN
                    GOTO UNDO
                END
            END
            UPDATE syspublications
               SET ftp_password = @enc_ftp_password
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('independent_agent', 'immediate_sync','enabled_for_internet',
            'allow_push', 'allow_pull', 'allow_anonymous', 'snapshot_in_defaultfolder', 
			'compress_snapshot', 'allow_subscription_copy')
    BEGIN

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

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

        /*
        ** set value bit
        */
        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            SELECT @value_bit = 1
        ELSE 
            SELECT @value_bit = 0


		IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = '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, sysextendedarticlesview sa
					WHERE ss.artid = sa.artid
						AND   sa.pubid = @pubid
						AND   ss.srvid <> @virtual_id )
			BEGIN
				RAISERROR (20013, 16, -1, @property)
				GOTO UNDO
			END

			--
			-- No share agents for DTS/Updating publications
			--
			if (@value_bit = 0 and 
				(@allow_dts = 1 or @allow_sync_tran = 1 or @allow_queued_tran = 1))			
			begin
				raiserror(21173, 16, -1)
				return(1)
			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 collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = 'enabled_for_internet'
        BEGIN

            UPDATE syspublications 
               SET enabled_for_internet = @value_bit
             WHERE pubid = @pubid

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

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = '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, sysextendedarticlesview 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 collate SQL_Latin1_General_CP1_CS_AS) = '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, sysextendedarticlesview 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

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot_in_defaultfolder'
        BEGIN
            -- snapshot_in_defaultfolder = 1 is only meaningful when
            -- alt_snapshot_folder is non-null, otherwise 
            -- a copy of the snapshot files is always kept
            -- at the publisher's working directory 
    
            UPDATE syspublications 
               SET snapshot_in_defaultfolder = @value_bit
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
                GOTO UNDO
            END
        END

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
        BEGIN

            UPDATE syspublications
               SET compress_snapshot = @value_bit
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
                GOTO UNDO
            END
        END

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_subscription_copy'
        BEGIN
			if @value_bit = 1 and @immediate_sync = 0
			begin
				raiserror(21210, 16, -1)
				goto UNDO
			end

            UPDATE syspublications
               SET allow_subscription_copy = @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 collate SQL_Latin1_General_CP1_CS_AS) IN ('description', 'repl_freq', 'independent_agent',
        'immediate_sync', 'allow_push',
        'allow_pull', 'allow_anonymous','retention', 'allow_subscription_copy')
    BEGIN
        /* Translate the property names and values  */
        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'repl_freq'
        BEGIN
            SELECT @property = 'publication_type'
            SELECT @value = STR(@replfreqid)
        END

        /* Translate values */
        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            SELECT @value = '1'
        ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = '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

	--
	-- Queued properties
	--
	IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('conflict_policy', 'centralized_conflicts', 'conflict_retention', 'queue_type'))
	BEGIN
		--
		-- we will consider changes only if the publication supports queued operations
		--
		if exists (select * from syspublications 
				where pubid = @pubid and allow_queued_tran = 1)
		BEGIN
			IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'conflict_policy')
			BEGIN
				if (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'sub reinit')
					select @conflict_policy_id = 3
				else if (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'pub wins')
					select @conflict_policy_id = 1
				else if (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'sub wins')
					select @conflict_policy_id = 2
				else
				BEGIN
					raiserror (21184, 16, 3, 'conflict_policy', 'sub reinit', 'pub wins', 'sub wins')
					GOTO UNDO                    
				END

				--
				-- cannot change this parameter once we have subscriptions
				--
				IF EXISTS (SELECT * FROM syssubscriptions ss, sysextendedarticlesview sa
								WHERE ss.artid = sa.artid
								AND   sa.pubid = @pubid)
				BEGIN
					RAISERROR (21268, 16, 1)
					GOTO UNDO
				END

				--
				-- Check snapshot permissible values
				--
				if ((@replfreqid = 1) and (@conflict_policy_id = 1))
				begin
					raiserror (21270, 16, 1, '@conflict_policy', @value)
					GOTO UNDO                    
				end
				
				UPDATE syspublications
				SET conflict_policy = @conflict_policy_id
				WHERE pubid = @pubid
				IF @@error <> 0
				BEGIN
					GOTO UNDO
				END
			END

			IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'centralized_conflicts')
			BEGIN
				if (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true')
					select @centralized_conflicts_bit = 1
				else if (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false')
					select @centralized_conflicts_bit = 0
				else
				begin
					raiserror (14148, 16, 3, 'centralized_conflicts')
					GOTO UNDO                    
				end

				--
				-- Check snapshot permissible values
				--
				if ((@replfreqid = 1) and (@centralized_conflicts_bit = 0))
				begin
					raiserror (21270, 16, 1, '@centralized_conflicts', @value)
					GOTO UNDO                    
				end

				--
				-- cannot change this parameter once we have subscriptions
				--
				IF EXISTS (SELECT * FROM syssubscriptions ss, sysextendedarticlesview sa
								WHERE ss.artid = sa.artid
								AND   sa.pubid = @pubid)
				BEGIN
					RAISERROR (21268, 16, 2)
					GOTO UNDO
				END

				UPDATE syspublications
				SET centralized_conflicts = @centralized_conflicts_bit
				WHERE pubid = @pubid
				IF @@error <> 0
				BEGIN
					GOTO UNDO
				END
			END

			IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'conflict_retention')
			BEGIN
				select @conflict_retention = CAST(@value as integer)
				if (@@error != 0) or (@conflict_retention < 0)
				BEGIN
					raiserror(20050, 16, -1, 0)
					GOTO UNDO                    
				END
				if (@conflict_retention IS NULL)
					select @conflict_retention = 60

				UPDATE syspublications
				SET conflict_retention = @conflict_retention
				WHERE pubid = @pubid
				IF @@error <> 0
				BEGIN
					GOTO UNDO
				END
			END
			
			IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'queue_type')
			BEGIN				
				IF (CAST(@value as integer) NOT IN (1,2))
				BEGIN
					RAISERROR(21267, 16, 1, '1,2')
					GOTO UNDO
				end

				IF (CAST(@value as integer) != @queue_type)
				BEGIN
					select @queue_type = CAST(@value as integer)
					IF EXISTS (SELECT * FROM syssubscriptions ss, sysextendedarticlesview sa
									WHERE ss.artid = sa.artid
									AND   sa.pubid = @pubid)
					BEGIN
						RAISERROR (21268, 16, 3)
						GOTO UNDO
					END

					UPDATE syspublications
					SET queue_type = @queue_type
					WHERE pubid = @pubid
					IF @@error <> 0
					BEGIN
						GOTO UNDO
					END

					--
					-- For MSMQ queue_type - Check if the distributor supports it
					--
					if (@queue_type = 1)
					begin
						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()
								,@distproc = RTRIM(@distributor) + '.' + @distribdb + 
											N'.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
				END
			END			
		END
	END

	
	-- Have to call this stored procedure to invalidate existing snapshot or reint
	-- subscriptions if needed
	EXECUTE @retcode  = dbo.sp_MSreinit_article
		@publication = @publication, 
		@need_new_snapshot = @need_new_snapshot,
		@need_reinit_subscription = @need_reinit_subscription
		,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
		,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
	IF @@ERROR <> 0 OR @retcode <> 0
		GOTO UNDO

	COMMIT TRAN sp_changepublication

	--update its registration in active directory
	if @in_ActiveD=1 and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description','allow_pull', 'allow_anonymous')
	begin
		create table #guid_name_for_ADupdate(ad_guidname sysname collate database_default null)
		if @@ERROR<>0
		begin
            goto FAILURE
		end
		insert into #guid_name_for_ADupdate exec @retcode = master.dbo.sp_ActiveDirectory_Obj N'UPDATE', N'PUBLICATION', @publication, @db_name, @ad_guidname
		if @@ERROR<>0 or @retcode<>0
    	begin
    		goto FAILURE 					
	   	end
    	select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_ADupdate
    	if @ad_guidname is not NULL
    	begin
    		update syspublications set ad_guidname=@ad_guidname where pubid=@pubid
    		if @@ERROR<>0
    			goto FAILURE
    	end
	    drop table #guid_name_for_ADupdate
    end

    /*
    ** Return succeed.
    */

    RAISERROR (14077, 10, -1)
    RETURN (0)
FAILURE:
	drop table #guid_name_for_ADupdate
    raiserror(21371, 10, -1, @publication)
    return (1)   

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

grant execute on dbo.sp_changepublication to public
go

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

raiserror(15339,-1,-1,'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) = N'add'      /* Add or delete a column */
        -- synctran
        , @refresh_synctran_procs bit = 1      -- refresh synctran procs or not
		, @ignore_distributor bit = 0
		-- DDL
		, @change_active int = 0
		, @force_invalidate_snapshot bit = 0	/* Force invalidate existing snapshot */
		, @force_reinit_subscription bit = 0	/* Force reinit subscription */

        ) 
AS
BEGIN

    /*
    ** Declarations.
    */

	DECLARE @bit tinyint                /* Bit offset */
			,@word tinyint               /* word offset */
			,@cnt tinyint, @idx tinyint  /* Loop counter, index */
			,@columns binary(32)         /* Temporary storage for the converted column */
			,@mask binary(2)              /* Bit mask to set the bit on */
			,@mval int
			,@newword binary(2)
			,@oldword binary(2)
			,@pubid int                  /* Publication identification number */
			,@retcode int                /* Return code for stored procedures */
			,@artid int
			,@active tinyint
			,@objid int            /* Article base table id */    
			,@tablename  sysname
			,@fSynctranColChanged bit
			,@pkkey sysname
			,@indid int
			,@index_cnt int

	select @active = 2
			,@fSynctranColChanged = 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() collate database_default) = 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, N'@publication')
            RETURN (1)
        END

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
            RETURN (1)

	declare @allow_queued_tran bit
	declare @allow_sync_tran bit

    SELECT @pubid = pubid, 
		@allow_sync_tran = allow_sync_tran,
		@allow_queued_tran = allow_queued_tran
		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, N'@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


    /*
    ** 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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN (N'add', N'drop')
        BEGIN
            RAISERROR (14019, 16, -1)
            RETURN (1)
        END
        
    SELECT @objid = (SELECT objid FROM sysarticles WHERE artid = @artid)
    SELECT @tablename = OBJECT_NAME(@objid)
   
	if @column is not null
	begin
		declare @colid	smallint
		select @colid=colid from syscolumns where id=@objid and name=@column
		if @colid is null
		begin
            RAISERROR (14020, 16, -1)
            RETURN (1)
		end

	if LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
	begin		
		-- Vertical partition is only allowed on table-based article, not IV->table
	    	IF OBJECTPROPERTY(@objid, 'IsTable') <> 1
	        BEGIN
        	    RAISERROR (14112, 11, -1 )
           	    RETURN (1)
	        END
		-- PK column has to be included in vertical partition
		select @indid = indid from sysindexes where id = @objid and (status & 2048) <> 0    /* PK index */
		select @index_cnt = 1
		while (@index_cnt <= 16)
			begin
				select @pkkey = INDEX_COL(@tablename, @indid, @index_cnt)
				if @pkkey is NULL
					break
				if @pkkey=@column
					begin
						raiserror(21250, 16, -1, @column)
						return (1)
					end
				select @index_cnt = @index_cnt + 1
			end
	end

		-- If the publication is allow_sync_tran, we cannot drop the timestamp
		-- column from the partition.
		if (@allow_sync_tran = 1 or @allow_queued_tran = 1) and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = N'drop'
		begin
			if N'msrepl_tran_version' = @column
            BEGIN
                RAISERROR (21080, 16, -1)
                RETURN (1)
            END
		end

		-- Only columns that have default values can be outside the partition
		-- Note: do check error if it is schema change.
		if @change_active = 0 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS)=N'drop' and 
			(@allow_queued_tran = 1 or @allow_sync_tran = 1) and
			ColumnProperty(@objid, @column, N'IsIdentity') <> 1 and
			-- 189 is timestamp.
			not exists (select * from syscolumns where id = @objid and 
				name=@column and (isnullable=1 or xtype = 189)) and
			not exists (select * from sysconstraints where id=@objid and 
				colid=@colid and status & 5 = 5)
		BEGIN
			RAISERROR(21165, 16, -1, @column)
			return (1)
		END
	end

	-- @ignore_distributor is set to 1 when removing replication forcefully. In that
	-- case, no need to check or reinit
	if @ignore_distributor = 0
	begin
		-- Check if there are snapshot or subscriptions and raiserror if needed.
		EXECUTE @retcode  = dbo.sp_MSreinit_article
			@publication = @publication, 
			@article = @article,
			@need_new_snapshot = 1,
			@need_reinit_subscription = 1
			,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
			,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
			,@check_only = 1
		IF @@ERROR <> 0 OR @retcode <> 0
			return (1)
	end

	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
       DECLARE hCartcolumn CURSOR LOCAL FAST_FORWARD FOR
            SELECT name FROM syscolumns where
				id = @objid
    END
	ELSE
    BEGIN
       DECLARE hCartcolumn CURSOR LOCAL FAST_FORWARD FOR 
            SELECT @column
	END


    OPEN hCartcolumn

    FETCH hCartcolumn INTO @column

	WHILE (@@fetch_status <> -1)
	BEGIN

		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 @allow_queued_tran = 1 and 
		exists (select * from syscolumns WHERE id = @objid and xtype = 189 and name = @column)
		begin
			--
			-- For queued publication, don't mark the timestamp column in the column bitmap
			-- Refer to sp_helparticlecolumns
			--
			IF lower(@operation collate SQL_Latin1_General_CP1_CS_AS) = N'add'
				-- Set bit to indicate the timestamp column should be scripted out
				-- Also need to set to use explicit column name list at the same time.
				update sysarticles set status = (status | 32) | 8  where artid = @artid
			else
				-- Clear the bit
				update sysarticles set status = status & ~32 where artid = @artid

			if @@error <> 0
			BEGIN
				if @@trancount > 0
				begin
					ROLLBACK TRANSACTION articlecolumn
					commit tran
				end
				RETURN (1)
			END

			-- mark for synctran proc refresh
			select @fSynctranColChanged = 1			
		end
		else
		begin

			/*
			** 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 collate SQL_Latin1_General_CP1_CS_AS) = N'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
			if(@change_active = 2) -- Only post if it came from sp_repladd(drop)column
			begin
				exec sp_replpostcmd 0, @pubid, @artid, 51, @columns
			end

			/*
			** 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 collate SQL_Latin1_General_CP1_CS_AS) = N'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

			/*
			** Update the sysarticles table.  Set the bit appropriately 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 the status has changed, call sp_MSarticlecol to update the publication
			** status as appropriate.
			*/

			IF @oldword != @newword
			BEGIN
				/* Update column published status */
				EXECUTE @retcode = dbo.sp_MSarticlecol @artid, @columnid,
										N'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
				select @fSynctranColChanged = 1
			END

		end -- end of if else block

		-- fetch the next column
		FETCH hCartcolumn INTO @column

	END -- end of while block

    -- Synctran
    /*
    ** If publication is enabled for Synctran and sprocs are auto-generated - regenerate them
    */
	declare @autogen_sync_procs_id bit
		,@ins_proc_id int, @upd_proc_id int, @del_proc_id int, @upd_trig_id int
		,@ins_proc sysname, @upd_proc sysname, @del_proc sysname, @owner sysname, @objname sysname
		,@upd_trig sysname
		,@sync_pubid int
		,@conflict_table_id int, @ins_conflict_proc int
		,@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 and @fSynctranColChanged = 1
    begin
        -- Drop existing synctran procs
        select @owner = user_name(OBJECTPROPERTY(objid, N'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, 
				@upd_trig_id = sync_upd_trig,
				@conflict_table_id = conflict_tableid,
				@ins_conflict_proc = ins_conflict_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
                goto UNDO
        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
                goto UNDO
        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
                goto UNDO
        end

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

		if (@conflict_table_id is not null)
		begin
			select @objname = object_name(@conflict_table_id)     
			exec @retcode = dbo.sp_MSdrop_object
				@object_name = @objname,
				@object_owner = @owner
			if (@@error != 0 or @retcode != 0)
                goto UNDO
		end

		if (@ins_conflict_proc is not null)
		begin
			select @objname = object_name(@ins_conflict_proc)     
			exec @retcode = dbo.sp_MSdrop_object
				@object_name = @objname,
				@object_owner = @owner
			if (@@error != 0 or @retcode != 0)
                goto UNDO
		end
		
        -- Now generate new ones        
        select @ins_proc = N'sp_MSsync_ins_' + SUBSTRING(RTRIM(@article), 1, 100) + N'_' + rtrim(convert(varchar, @sync_pubid))
        select @upd_proc = N'sp_MSsync_upd_' + SUBSTRING(RTRIM(@article), 1, 100) + N'_' + rtrim(convert(varchar, @sync_pubid))
        select @del_proc = N'sp_MSsync_del_' + SUBSTRING(RTRIM(@article), 1, 100) + N'_' + rtrim(convert(varchar, @sync_pubid))
        select @upd_trig = N'sp_MSsync_upd_trig_' + SUBSTRING(RTRIM(@article), 1, 100) + N'_' + 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,N'-',N'_')
            select @ins_proc = N'sp_MSsync_ins_' + @guid_name
            select @upd_proc = N'sp_MSsync_upd_' + @guid_name
            select @del_proc = N'sp_MSsync_del_' + @guid_name
            select @upd_trig = N'sp_MSsync_upd_trig' + @guid_name
        end

        if @ins_proc IS NULL
        begin
            RAISERROR (14043, 11, -1, N'@ins_proc')
            goto UNDO
        end

        if @upd_proc IS NULL
        begin
            RAISERROR (14043, 11, -1, N'@upd_proc')
            goto UNDO
        end

        if @del_proc IS NULL
        begin
            RAISERROR (14043, 11, -1, N'@del_proc')
            goto UNDO
        end

        if @upd_trig IS NULL
        begin
            RAISERROR (14043, 11, -1, N'@del_proc')
            goto UNDO
        end

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

        IF @@ERROR <> 0 OR @retcode <> 0
            goto UNDO

        --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
        SELECT @upd_trig_id = id FROM sysobjects WHERE name = @upd_trig

        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 @upd_trig_id IS NULL RAISERROR (20500, 16, 1, @upd_trig)
            goto UNDO
        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,
            sync_upd_trig = @upd_trig_id
        where pubid = @pubid and artid = @artid
		if @@error <> 0
			goto UNDO


		--
		-- create the conflict tran table and table if necessary
		--
		if (@allow_queued_tran = 1)
		begin
			exec @retcode = dbo.sp_MSmakeconflicttable @article, @publication, 0
			IF (@@ERROR != 0 OR @retcode != 0)
	            goto UNDO
			exec @retcode = dbo.sp_MSmaketrancftproc @article, @publication
			IF (@@ERROR != 0 OR @retcode != 0)
	            goto UNDO
		end 
		
        IF @@ERROR <> 0
        BEGIN
            RAISERROR (20501, 16, -1)
            goto UNDO
         END
    end
    -- end synctran

	-------------------------------------------------------------------
	-- active article fixups
	-------------------------------------------------------------------

	if @change_active<> 0 and @fSynctranColChanged = 1 or
		-- Besides schema change, we automatically refresh article view if there are 
		-- subscriptions. We don't refresh the article view otherwise to avoid the view
		-- being dropped and recreated when adding columns into the partition during
		-- the creation of the article.
		exists (select * from syssubscriptions where artid = @artid and
			srvid >= 0)
	BEGIN
		-----------------------------------
		-- regenerate the article view  
		-----------------------------------

		declare @view_name nvarchar(386)
		declare @filter_clause nvarchar(4000)
		declare @sync_objid int
		declare @art_type tinyint

		select @sync_objid = sa.sync_objid, @filter_clause = sa.filter_clause, @art_type = sa.type
							 FROM sysarticles sa JOIN syspublications sp ON sa.pubid = sp.pubid
							 WHERE sa.name = @article 
							 AND sp.name = @publication
		-- Only invoke sp_articleview if not manual view and not manual filter
		if ( @art_type & 0x4 <> 4 and @art_type & 0x2 <> 2 )
		begin 
			select @view_name = object_name( @sync_objid )

			exec @retcode = dbo.sp_articleview @publication = @publication, 
											@article = @article,
											@view_name = @view_name,
											@filter_clause = @filter_clause,
											@change_active = @change_active,
											@force_invalidate_snapshot = @force_invalidate_snapshot,
											@force_reinit_subscription = @force_reinit_subscription

			IF @@ERROR <> 0 OR @retcode <> 0
        		    goto UNDO
		end
	END

	-- sp_repldropcolumn used @change_active = 2 to prepare, don't invalidate or reinitialize
	if @change_active <> 2 	and
		-- @ignore_distributor is set to 1 when removing replication forcefully. In that
		-- case, no need to check or reinit
		@ignore_distributor = 0
	begin
		-- Have to call this stored procedure to invalidate existing snapshot or reint
		-- subscriptions if needed
        EXECUTE @retcode  = dbo.sp_MSreinit_article
            @publication = @publication, 
            @article = @article,
			@need_new_snapshot = 1,
			@need_reinit_subscription = 1
			,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
			,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
        IF @@ERROR <> 0 OR @retcode <> 0
			GOTO UNDO
	end

    /*
    ** 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
END
return (0)
UNDO:
	if @@trancount > 0
    begin
        ROLLBACK TRANSACTION articleview
        commit tran
    end
    RETURN (1)
go
 
EXEC dbo.sp_MS_marksystemobject sp_articlecolumn
GO

grant execute on dbo.sp_articlecolumn to public
go


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

raiserror(15339,-1,-1,'sp_MSaddexecarticle')
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

    /*
    ** Parameter Check:  @destination_proc.
    ** If the destination proc is not specified, assume it's the same
    ** as the source. 
    */
    
    IF @destination_proc IS NULL
    BEGIN
        -- Perform parsing only if the destination_proc parameter is not provided
        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 
    END

    /*
    ** 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 sysextendedarticlesview
                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 collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'none'
       SELECT @precmdid = 0
    ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('proc exec', 'serializable proc exec')
    BEGIN
            RAISERROR (14118, 16, -1)
            RETURN (1)
    END

    IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'proc exec'
    BEGIN
       SELECT @typeid = 8
       SELECT @incompatible_typeid = 24
    END
    ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = '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 NULL
    BEGIN
        SELECT @schema_option = 1
    /* 
        RAISERROR (14043, 16, -1, '@schema_option')
        RETURN (1)
        */
    END

    IF @schema_option <> 0x0000000000000000 AND 
       @schema_option <> 0x0000000000000001 AND
       @schema_option <> 0x0000000000002000 AND
       @schema_option <> 0x0000000000002001  
    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

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

raiserror(15339,-1,-1,'sp_MSaddschemaarticle')
GO

CREATE PROCEDURE sp_MSaddschemaarticle
    @publication        sysname,        /* Name of the publciation */
    @article            sysname,        /* Name of the article */
    @source_object      sysname,        /* Name of object to be replicated */
    @destination_object sysname,        /* Name of the object created on the subscriber */
    @type               tinyint,        /* Must be one of 0x20, 0x40, or 0x80 */
    @creation_script    nvarchar(255),  /* custom creation script for the article */
    @description        nvarchar(255),  /* article description */
    @pre_creation_cmd   nvarchar(10),   /* must be 'none' or 'drop' */
    @schema_option      binary(8),
    @destination_owner  sysname,        /* owner of the article object on the subscriber */
    @status             tinyint, 
    @artid              int OUTPUT
AS
    SET NOCOUNT ON
    DECLARE @retcode int
        
    DECLARE @source_owner           sysname
    DECLARE @object                 sysname
    DECLARE @bInTran                bit
    DECLARE @pubid                  int
    DECLARE @source_objid           int
    DECLARE @pre_creation_cmdid     tinyint
    
    /* Variables for setting up RPC call to the Distributor */
    DECLARE @distproc               nvarchar(2000)
    DECLARE @distributor            sysname
    DECLARE @distributiondb         sysname
    DECLARE @dbname                 sysname
    DECLARE @valid_schema_options   int
    
    SELECT @bInTran = 0

    SELECT @source_owner = PARSENAME(@source_object, 2)
    SELECT @object = PARSENAME(@source_object, 1)

    /* Note that @article & @publication has been by sp_addarticle 
       as non-null */
        
    /*
    ** Get the pubid of the publication
    */
    SELECT @pubid = NULL
    SELECT @pubid = pubid
      FROM syspublications
     WHERE name = @publication

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

    /*
    ** Get the source object id
    */
    SELECT @source_objid = NULL
    SELECT @source_objid = OBJECT_ID(@source_object)    

    /*
    **  Destination object name
    */
    IF @destination_object IS NULL
        SELECT @destination_object = @source_object

    /*
    ** Parameter check: @type
    ** @type must correspond to the object type of the source object
    **
    ** @type = 0x20 => source object type = 'P'
    ** @type = 0x40 => source object type = 'V'
    ** @type = 0x80 => source object type = 'FN' OR 'TF' OR 'IF'
    */
    IF @type = 0x20
    BEGIN
        IF NOT EXISTS (SELECT *
                         FROM sysobjects
                        WHERE id = @source_objid
                          AND xtype = 'P ')
        BEGIN
            RAISERROR(21219, 16, -1)
            RETURN (1)
        END
    END
    ELSE IF @type = 0x40
    BEGIN
        IF NOT EXISTS (SELECT *
                         FROM sysobjects 
                        WHERE id = @source_objid
                          AND xtype = 'V ')
        BEGIN
            RAISERROR(21221, 16, -1)
            RETURN (1)
        END
    END   
    ELSE IF @type = 0x80
    BEGIN
        IF NOT EXISTS (SELECT *
                         FROM sysobjects 
                        WHERE id = @source_objid
                          AND (xtype in ('FN','TF','IF')))
        BEGIN
            RAISERROR(21228, 16, -1)            
            RETURN (1)
        END
    END


    /*
    ** Parameter check: @schema_option
    ** @schema_option can only contain the bits 0x0000000000000001 and
    ** 0x0000000000002000
    ** for schema only articles except view. View articles can contain 
    ** the options 0x0000000000000010, 0x0000000000000020, and 
    ** 0x0000000000000100 in addition to the aforementioned options.
    */
    IF @type = 0x40
    BEGIN

        -- Since only the lower 32 bits of @schema_option are
        -- currently used, the following check is sufficient.
        -- Note that @schema_option should have been padded out by now
        DECLARE @schema_option_lodword int
        SELECT @valid_schema_options = 0x2151
        SELECT @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
        IF (@schema_option_lodword & ~@valid_schema_options) <> 0
        BEGIN
            RAISERROR (21229, 16, -1)
            RETURN (1)
        END
    END
    ELSE IF @schema_option NOT IN (0x0000000000000000,
                                   0x0000000000000001,
                                   0x0000000000002000,
                                   0x0000000000002001)
    BEGIN
        RAISERROR (21222, 16, -1)
        RETURN (1)
    END 
    
    /*
    ** Parameter check: @pre_creation_command must be
    ** 'drop' (id = 1) or 'none' (id = 0)
    */
    SELECT @pre_creation_cmd = LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS)
    IF @pre_creation_cmd NOT IN (N'none', N'drop')
    BEGIN
        RAISERROR(21223, 16, -1)
        RETURN (1)
    END
    
    IF @pre_creation_cmd = N'none'
        SELECT @pre_creation_cmdid = 0
    ELSE IF @pre_creation_cmd = N'drop'
        SELECT @pre_creation_cmdid = 1
    
    /*
    ** Parameter Check:  @article, @publication.
    ** Check if the article already exists in this publication.
    */

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

    BEGIN TRANSACTION sp_MSaddschemaarticle
    SAVE TRANSACTION sp_MSaddschemaarticle
    SELECT @bInTran = 1    

    -- Add a dummy record to sysarticles to reserve an artid
    INSERT sysarticles (dest_table, filter, name, objid, pubid, 
                        pre_creation_cmd, status, sync_objid, type)  
    VALUES (@destination_object, N'', @article, @source_objid, @pubid,
            @pre_creation_cmdid, @status, @source_objid, @type)

    IF @@ERROR <> 0
        GOTO Failure

    SELECT @artid = @@IDENTITY   

    -- Now that we have reserved an artid in sysarticles,
    -- we can remove the dummy record
    
    DELETE sysarticles WHERE artid = @artid AND pubid = @pubid

    IF @@ERROR <> 0
        GOTO Failure

    -- Insert a record into sysschemaarticles to represent this
    -- schema only article
    INSERT sysschemaarticles 
    VALUES (@artid, @creation_script, @description, @destination_object,
            @article, @source_objid, @pubid, @pre_creation_cmdid, @status,
            @type, @schema_option, @destination_owner)

    IF @@ERROR <> 0
        GOTO Failure

    -- Make a bit in replinfo to prevent the source object from
    -- being dropped
    UPDATE sysobjects SET replinfo = replinfo | 0x00000200 WHERE id = @source_objid
    
    IF @@ERROR <> 0
        GOTO Failure       

    COMMIT TRANSACTION  

    RETURN (0)
Failure:

    IF @bInTran = 1
    BEGIN
        ROLLBACK TRANSACTION sp_MSaddschemaarticle
        COMMIT TRANSACTION
    END
    RETURN (1)
go

EXEC dbo.sp_MS_marksystemobject sp_MSaddschemaarticle
GO


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

raiserror(15339,-1,-1,'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      varbinary(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 */
    @artid              int = NULL OUTPUT,       /* article id of the new article  */
    @auto_identity_range	nvarchar(5)	= 'FALSE',	/* set it to false for now - change is possible */
    @pub_identity_range		bigint	= NULL,
    @identity_range			bigint = NULL,
    @threshold				int	= NULL,
	@force_invalidate_snapshot bit = 0	/* Force invalidate existing snapshot */
    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 @sync_method tinyint
    -- SyncTran
    DECLARE @autogen_sync_procs_id int
	DECLARE @custom_proc_name nvarchar(255)
	DECLARE @guid varbinary(16)
	declare @allow_sync_tran bit
    DECLARE @repl_freq int
	declare @allow_queued_tran bit
	declare @allow_dts bit
	declare @merge_pub_object_bit  int
	declare @valid_ins_cmd nvarchar(255)
			,@valid_upd_cmd nvarchar(255)
			,@valid_del_cmd nvarchar(255)
			,@MSrepl_tran_version_datatype sysname
			,@colid int
	declare @backward_comp_level int
	declare @schema_option_int int
	select @backward_comp_level = 10 -- default to sphinx
	
	select @merge_pub_object_bit 	= 128
    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)

    /*
    ** Padding out the specified schema option to the left
    */
    select @schema_option = fn_replprepadbinary8(@schema_option)

    /*
    ** 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
		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 
	begin
		-- Make @source_table qualifed.
		select @tabid = object_id(@source_table)
		if @tabid is not null
		begin
			exec @retcode = dbo.sp_MSget_qualified_name @tabid, @source_table output
			if @retcode <> 0 or @@error <> 0
				return 1	
			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)	
		end
	end
        
	select @num_columns=count(*) from syscolumns where id = object_id(@source_table)
	if @num_columns > 255
		begin
			RAISERROR (20068, 16, -1, @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

    /*
    ** Parameter Check: @type
    ** If the article is added as a 'schema-bound view schema only' article,
    ** make sure that the source object is a schema-bound view.
    ** Conversely, a schema-bound view cannot be published as a 
    ** 'view schema only' article.
    */
    IF @type IS NULL
		SELECT @type = 'logbased'

    select @type = lower(@type collate SQL_Latin1_General_CP1_CS_AS)

    if @type = N'indexed view schema only' and objectproperty(@tabid, 'IsSchemaBound') <> 1
    begin
        raiserror (21277, 11, -1, @source_table)        
        return (1)    
    end

    /*
    ** If the article is published as an IV logbased article, we'd better make
    ** sure that the view is schema bound and it has a clustered index.
    ** Conversely, a schema-bound view should never be published as a regular
    ** table logbased article.
    */
    if @type in (N'indexed view logbased', 
                 N'indexed view logbased manualfilter', 
                 N'indexed view logbased manualview', 
                 N'indexed view logbased manualboth') and 
            objectproperty(@tabid, 'IsSchemaBound') <> 1 and
        not exists (select * from sysindexes where id = @tabid)
    begin
        raiserror (21278, 11, -1, @source_table)
        return (1)
    end    
    
    if @type in (N'view schema only', 
                 N'logbased', 
                 N'logbased manualfilter', 
                 N'logbased manualview', 
                 N'logbased manualboth') and 
        objectproperty(@tabid, 'IsSchemaBound') = 1
    begin
        raiserror (21275, 11, -1, @source_table)
        return (1)
    end

	-- Check if there are snapshot or subscriptions and raiserror if needed.
    EXECUTE @retcode  = dbo.sp_MSreinit_article
        @publication = @publication, 
		-- Virtual subscriptions of all the articles will be deactivated.
        -- @article = @article,
		@need_new_snapshot = 1,
		@force_invalidate_snapshot = @force_invalidate_snapshot,
		@check_only = 1
    IF @@ERROR <> 0 OR @retcode <> 0
		return 1


    -- Encrypted objects are not publishable for replication
    IF @type IN (N'proc exec',
                 N'serializable proc exec',
                 N'proc schema only',
                 N'indexed view schema only',
                 N'indexed view logbased',
                 N'indexed view logbased manualfilter',
                 N'indexed view logbased manualview',
                 N'indexed view logbased manualboth',
                 N'view schema only',
                 N'func schema only')
    BEGIN
        IF EXISTS (SELECT * FROM syscomments
                    WHERE id = @tabid
                      AND encrypted = 1)
        BEGIN
            RAISERROR(21004, 16, -1, @source_table)        
            RETURN (1)
        END
    END   

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

    IF (@object_type = 'P' AND @type <> N'proc schema only') or 
		@type IN (N'proc schema only', N'view schema only', N'func schema only', 'indexed view schema only')
    BEGIN
		begin tran
        save TRAN sp_addarticle

		IF (@object_type = 'P' AND @type <> N'proc schema only')
		begin

            IF @schema_option IS NULL
            BEGIN
                SELECT @schema_option = 0x0000000000000001
            END

			EXECUTE @retcode = dbo.sp_MSaddexecarticle @publication,
				@article,
				@source_table,
				@destination_table,
				@type,
				@creation_script,
				@description,
				@pre_creation_cmd,
				@schema_option,
				@destination_owner,
				@artid OUTPUT
		end
		else 
		begin
		    -- Note: a transaction is started inside sp_MSaddschemaarticle        
            IF @schema_option IS NULL
            BEGIN
                SELECT @schema_option = 0x0000000000000001
            END

			IF @type = N'proc schema only'
			BEGIN
				SELECT @typeid = 0x20
			END
			ELSE IF @type = N'view schema only'
			BEGIN
				SELECT @typeid = 0x40
			END    
			ELSE IF @type = N'func schema only'
			BEGIN
				SELECT @typeid = 0x80
			select @backward_comp_level = 40 -- UDF not available in sphinx
			END
			ELSE IF @type = N'indexed view schema only'
			BEGIN
				SELECT @typeid = 0x40
			select @backward_comp_level = 40 -- SchemaBinding not available in sphinx
			END    

			EXECUTE @retcode = dbo.sp_MSaddschemaarticle 
				@publication = @publication,
				@article = @article,
				@source_object = @source_table,
				@destination_object = @destination_table,
				@type = @typeid,
				@creation_script = @creation_script,
				@description = @description,
				@pre_creation_cmd = @pre_creation_cmd,
				@schema_option = @schema_option,
				@destination_owner = @destination_owner,
				@status = @status,
				@artid = @artid OUTPUT

		end
		IF @retcode <> 0 or @@error <> 0
			goto UNDO
	end
    ELSE
	begin

		/*
		** 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')
			AND NOT EXISTS ( SELECT * FROM sysobjects so, sysindexes si
			WHERE so.id = OBJECT_ID(@source_table)
			AND so.type = 'V'
			AND si.id = so.id )
		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.
		*/

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

		SELECT @vertical_partition = LOWER(@vertical_partition collate SQL_Latin1_General_CP1_CS_AS)
		IF @vertical_partition NOT IN ('true', 'false')
		BEGIN
			RAISERROR (14029, 16, -1)
			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 and its properties
		*/
		SELECT @pubid = pubid, @autogen_sync_procs_id = autogen_sync_procs, @sync_method = sync_method,
			@allow_sync_tran = allow_sync_tran,
			@allow_queued_tran = allow_queued_tran,
			@allow_dts	= allow_dts,
			@repl_freq = repl_freq 
		FROM syspublications where name = @publication

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

		-- Only allow table and index view for dts publications
		if @allow_dts <> 0 and @type not in ( 
			N'logbased', 
			N'logbased manualfilter', 
			N'logbased manualview', 
			N'logbased manualboth',
			N'indexed view logbased', 
			N'indexed view logbased manualfilter', 
			N'indexed view logbased manualview', 
			N'indexed view logbased manualboth')
		begin
			raiserror(20611, 16, -1)
			return(1)
		end

		-- can't do fancy type stuff with MVs!

		ELSE IF (@allow_sync_tran <> 0 
				OR @allow_queued_tran <> 0)
				AND EXISTS ( select * from sysobjects 
					where id = OBJECT_ID(@source_table)
					and xtype = 'V' )
		BEGIN
			RAISERROR(14059, 16, -1)
			RETURN 1
		END
		
		--
		-- parameter check: @status
		-- bits 8, 16, 64 can be set directly
		-- Other bits from 1 ~ 64 are used but cannot be set here.
		-- Bit 64 can only be set for publication that allows DTS.
		-- Bit 32 is set internally according to whether or not timestamp is in
		-- the partition for queued publications.

		IF (@status & ~ 88 ) <> 0 
		BEGIN
			RAISERROR( 21061, 16, -1, @status, @article )
			RETURN (1)
		END
		else if (@status & 64 <> 0 and @allow_dts = 0)
		begin
			raiserror(20590, 16, -1)
			return (1)
		end


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

		IF EXISTS (SELECT *
					 FROM sysextendedarticlesview
					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)
		**          32    proc schema only       (valid in dbo.sp_MSaddschemaarticle)
		**          64    view schema only       (valid in dbo.sp_MSaddschemaarticle)
		**         128    func schema only       (valid in dbo.sp_MSaddschemaarticle)
		**       Note that for the following article types, the 256 bit is not really persisted
		**         257    indexed view logbased
		**         259    indexed view logbased manualfilter
		**         261    indexed view logbased manualview
		**         263    indexed view logbased manualboth
		**         320    indexed view schema only (valid in dbo.sp_MSaddschemaarticle)
		*/


		IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
                                    ('logbased', 
									 'logbased manualfilter', 
									 'logbased manualview', 
									 'logbased manualboth',
									 'indexed view logbased', 
									 'indexed view logbased manualfilter', 
									 'indexed view logbased manualview', 
									 'indexed view logbased manualboth',
									 'proc schema only', 
									 'view schema only')
		BEGIN
			RAISERROR (14023, 16, -1)
			RETURN (1)
		END

		IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'logbased' OR LOWER(@type) = 'indexed view logbased'
			SELECT @typeid = 1
		ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'logbased manualfilter' OR LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'indexed view logbased manualfilter'
		   SELECT @typeid = 3
		ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'logbased manualview' OR LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'indexed view logbased manualview'
		   SELECT @typeid = 5
		ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'logbased manualboth' OR LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = 'indexed view 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 collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'none'
			SELECT @precmdid = 0
		ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
			SELECT @precmdid = 1
		ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
			SELECT @precmdid = 2
		ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = '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, or allows updating subscribers
		** make sure there is a primary key on the source table.
		** or a UCI on the view.
		** NOTE!  sprok in SPSUP.SQL
		*/
		IF EXISTS (SELECT * FROM syspublications 
			WHERE pubid = @pubid AND
				(repl_freq = 0 OR allow_sync_tran = 1 OR @allow_queued_tran = 1))
		BEGIN
			EXEC @fHasPk = dbo.sp_MSreplsup_table_has_pk @tabid

			IF @fHasPk = 0
			BEGIN
				IF EXISTS ( select * from sysobjects 
					where id = OBJECT_ID(@source_table)
					and xtype = 'U' )
				BEGIN
					RAISERROR (14088, 16, -1, @source_table)
				END
				ELSE
				BEGIN
					RAISERROR( 14089, 16, -1, @source_table)
				END
				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
			-- Snapshot publication, no custom proc. generation
			-- We need insert proc for snapshot publications for DTS.
			-- Do not generate user triggers by default (0x00100 - user trigger flag)
			IF @repl_freq = 1 and @allow_dts = 0
			BEGIN
				SELECT @schema_option  = 0x0000000000000071
			END
			ELSE
			BEGIN
				SELECT @schema_option  = 0x00000000000000F3
			END

			if (@allow_queued_tran = 1)
				select @schema_option = fn_replprepadbinary8(fn_replgetbinary8lodword(@schema_option) | 0x8000)
		END

		/*
		** Parameter Check: @schema_option
		** If bit 0x2 is set, this cannot be an article for a snapshot publication
		** For queued updating, DRI_Primary Key option has to be set
		*/
		IF ((CONVERT(INT, @schema_option) & 0x2) <> 0) AND (@repl_freq = 1)
		BEGIN
			RAISERROR (21143, 16, -1)
			RETURN (1)
		END
		else if ((@allow_queued_tran = 1) and 
			((fn_replgetbinary8lodword(@schema_option) & 0x8000) = 0))
		BEGIN
			RAISERROR (21394, 16, 1)
			RETURN (1)
		END
		
		/* 
		** Since custom proc name is based on destination table name
		*/
		
		if @allow_dts = 0
			set @custom_proc_name = @destination_table
		else
			set @custom_proc_name = @article

		-- Publication allow dts/queued must use parameterized commands and 
		-- ins/upd/del commands are generated 
		-- internally and are fixed (they will used as keys to find the correct transformations)
		if (@allow_dts = 1 or @allow_queued_tran = 1)
		begin
			select @valid_ins_cmd = N'CALL sp_MSins_' + @custom_proc_name
			IF @repl_freq = 0
			begin
				--
				-- Note :
				-- Now that we are autogenrating the custom procs for queued
				-- we will follow the current behavior :
				-- for queued INS/UPD/DEL will use CALL/XCALL/XCALL respectively
				-- for DTS INS/UPD/DEL will use CALL/XCALL/XCALL
				-- In case it allows both queued and DTS, DTS will take precedence
				-- YWU: Check this
				--
				select @valid_del_cmd = N'XCALL sp_MSdel_' + @custom_proc_name
				if (@allow_queued_tran = 1)
				begin
					select @valid_upd_cmd = N'XCALL sp_MSupd_' + @custom_proc_name
				end
				if (@allow_dts = 1)
				begin
					if @status = 16
						select @valid_upd_cmd = N'CALL sp_MSupd_' + @custom_proc_name
					else 
						select @valid_upd_cmd = N'XCALL sp_MSXpd_' + @custom_proc_name
				end
			end
			else
			begin
				select @valid_upd_cmd = N'SQL'
				select @valid_del_cmd = N'SQL'
			end

			if (@allow_dts = 1)
			begin
				-- For publication allows DTS, @status can only be 16 or 48
				-- 
				if  (@status <> 16 and @status <> 80) or
					(@ins_cmd is not null and @ins_cmd <> @valid_ins_cmd) or 
					(@upd_cmd is not null and @upd_cmd <> @valid_upd_cmd) or 
					(@del_cmd is not null and @del_cmd <> @valid_del_cmd)
				begin
					raiserror(21174, 16, -1)
					return (1)
				end
			end 
			else if (@allow_queued_tran = 1)
			begin
				if  (@ins_cmd is not null and @ins_cmd != @valid_ins_cmd) or 
					(@upd_cmd is not null and @upd_cmd != @valid_upd_cmd) or 
					(@del_cmd is not null and @del_cmd != @valid_del_cmd)
				begin
					raiserror(21191, 16, -1, @valid_ins_cmd, @valid_upd_cmd, @valid_del_cmd)
					return (1)
				end
			end
				
			select @ins_cmd = @valid_ins_cmd
			select @upd_cmd = @valid_upd_cmd
			select @del_cmd = @valid_del_cmd
		end
		-- If pub sync_type is character mode bcp(1) 
		else if @sync_method = 1
		begin
			-- Parameterized command is not supported. Mask it off.
			select @status = @status & ~16
			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.
		-- Use destination table name as the base name by default. 
	/*	
		-- Use article name by default. If the name is too long or there's confliction,
		-- use guid (to prevent proc for diff art in diff pub has same name which cause problems
		-- when being subscribed by the same subscriber db.
		if ((@source_object is not NULL and len(@article) > 119) or
			(@source_object is NULL and len(@article) > 21)) or
			exists (select * from sysarticles where name = @article)
		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

		--
		-- Sync/QueuedTran
		-- Add guid column if not exists
		--
		if (@allow_sync_tran = 1 or @allow_queued_tran = 1)
		begin
			SELECT @MSrepl_tran_version_datatype = TYPE_NAME(xtype),
				@colid = colid
			FROM dbo.syscolumns  
			WHERE id = @tabid AND name = 'msrepl_tran_version'

			if (@MSrepl_tran_version_datatype IS NULL)
			begin
				--
				-- column does not exist, add it
				--
				if exists (select * from sysobjects where id = @tabid and replinfo & @merge_pub_object_bit <>0)
				begin
					--if being merged, call stored procedure to add this column.
					exec @retcode = sp_repladdcolumn @source_object=@source_table,
													 @column = 'msrepl_tran_version',
													 @typetext= 'uniqueidentifier not null default newid()'
					if @@ERROR<>0 or @retcode<>0
						return (1)
				end
				else
				begin
					exec ('alter table ' + @source_table + ' add msrepl_tran_version uniqueidentifier not null default newid()' )
	        		IF @@ERROR <> 0 
	            		RETURN (1)
				end
			end
			else
			begin
				--
				-- column exists, it should be of type uniqueidentifier
				--
				if (@MSrepl_tran_version_datatype != 'uniqueidentifier')
				begin
					raiserror(21192, 16, -1) 
					RETURN (1)
				end

				-- Create the default constraint if it is not there
				if not exists (select * from sysconstraints where
					id = @tabid and 
					colid = @colid and
					status & 5 = 5) -- default
				begin 
					declare @constraint_name sysname
					select @constraint_name = 'MSrepl_tran_version_default_' + convert(nvarchar(10), @tabid)
					if not exists (select * from sysobjects where name = @constraint_name)
					begin
						exec ('alter table ' + @source_table + 
							' add constraint ' + @constraint_name + 
							' default newid() for msrepl_tran_version')
						if @@ERROR<>0 return 1
					end
				end

			end
		end

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

		-- if concurrent, must use stored procedures at subcriber when replicating commands

		if @sync_method IN (3,4) and 
		   (lower(@del_cmd) not like N'%call%' or 
			lower(@ins_cmd) not like N'%call%' or
			lower(@upd_cmd) not like N'%call%' )
		begin
			raiserror( 21153, 16, -1, @article )
			return 1
		end

		-- Identity range support
			/*
		** Parameter Check:  @allow_push.
		*/

		IF @auto_identity_range IS NULL OR LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
			BEGIN
				RAISERROR (14148, 16, -1, '@auto_identity_range')
				RETURN (1)
			END
		IF LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
		begin
			if @allow_queued_tran = 0
			begin
				raiserror(21231, 16 ,-1)
				return 1
			end
			/*
			** If you want to have identity support, @range and threshold can not be NULL
			*/
			if (@pub_identity_range is NULL or @identity_range is NULL or @threshold is NULL)
				begin
					raiserror(21193, 16, -1)
					return (1)
				end

			if OBJECTPROPERTY(@tabid, 'tablehasidentity') <> 1
			begin
				raiserror(21194, 16, -1)
				return (1)
			end

			if @pub_identity_range <= 1 or @identity_range <= 1
			begin
				raiserror(21232, 16 ,-1)
				return 1
			end

			if @threshold < 1 or @threshold > 100
			begin
				raiserror(21233, 16 ,-1)
				return 1
			end

			declare @xtype int, @xprec int, @max_range bigint
			select @xtype=xtype, @xprec=xprec from syscolumns where id=@tabid and 
				columnproperty(id, name, 'IsIdentity')=1
			select @max_range =
					case @xtype when 52 then power((convert(bigint,2)), 8*2-1) - 1 --smallint 
						when 48 then power((convert(bigint,2)), 8-1) - 1 		 --tinyint
						when 56 then power((convert(bigint,2)), 8*4-1) - 1 		 --int
						when 127 then power((convert(bigint,2)), 62) - 1 + power((convert(bigint,2)), 62)  	--bigint
       					when 108 then power((convert(bigint,10)), @xprec) 	 --numeric
       					when 106 then power((convert(bigint,10)), @xprec) 	 --decimal
 					else
						power((convert(bigint,2)), 62) + power((convert(bigint,2)), 62) - 1  -- defaulted to bigint
					end
		
			if @pub_identity_range * 2 + @identity_range > (@max_range - IDENT_CURRENT(@source_table))
				begin
					raiserror(21290, 16, -1)
					return (1)
				end

			-- Set the range to negtive if incr of the identity is negtive
			if IDENT_INCR(@source_table) < 0
			begin
				select @pub_identity_range = -1 * @pub_identity_range;
				select @identity_range = -1 * @identity_range;
			end

			-- If the table is already published in queued but is not auto identity
			-- raiserror error
			if exists (select * from  sysarticles sa, sysarticleupdates au, syspublications pub where 
				sa.objid = @tabid and
				au.artid = sa.artid and
				au.pubid = pub.pubid and
				pub.allow_queued_tran = 1 and 
				au.identity_support = 0)
			begin
				raiserror (21240, 16, -1, @source_table)
				return (1)
			end

			-- If the table is already published in queued and have different auto identity 
			-- range values, raise error.
			if exists (select * from MSpub_identity_range where objid=@tabid and 
			((pub_range<>@pub_identity_range) or (range <> @identity_range) or (threshold <> @threshold)))
			begin
				raiserror(21291, 16, -1)
				return (1)
			end
		end
		else
		begin
			-- @auto_identity_range is false
			-- If the publication is queued and the table has published with auto identity
			-- already, raise error.
			if exists (select * from  sysarticles sa, sysarticleupdates au where 
				sa.objid = @tabid and
				au.artid = sa.artid and
				au.identity_support = 1)
			begin
				raiserror (21240, 16, -1, @source_table)
				return (1)
			end
		end

		-- SQL insert doesn't work because we need to do 'set identity_insert on/off' 
		-- before and after the insert.
		-- The exception is snapshot publication.
		/* Queue now uses fixed commands. Message 21234 should be removed.
		if @allow_queued_tran = 1 and OBJECTPROPERTY(@tabid, 'tablehasidentity') = 1 and
			@ins_cmd = 'SQL' and @repl_freq <> 1
		begin
			raiserror(21234, 16, -1)
			return (1)
		end
		*/

		-- Do not allow the table to be published by both merge and queued tran
		if @allow_queued_tran = 1
		begin
			if exists (select * from sysobjects where name = 'sysmergearticles')
			begin
				if exists (select * from sysmergearticles where objid = @tabid)
				begin
					declare @obj_name sysname
					select @obj_name = object_name(@tabid)
					raiserror(21266, 16, -1, @obj_name)
					return (1)
				end
			end
		end

		/*
		**  Add article to sysarticles and update sysobjects category bit.
		*/
		-- begin tran
		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
			goto UNDO

		SELECT @artid = @@IDENTITY

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

		IF @@ERROR <> 0
			goto UNDO

		IF @filter IS NOT NULL
		BEGIN
			EXEC dbo.sp_MSsetfilterparent @filter, @tabid
			IF @@ERROR <> 0
				goto UNDO
		END

		EXEC dbo.sp_MSsetfilteredstatus @tabid
		IF @@ERROR <> 0
			goto UNDO

		/*
		** 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
 			, @force_invalidate_snapshot = @force_invalidate_snapshot
      
			IF @@ERROR <> 0 OR @retcode <> 0
				goto UNDO
		END
    
		/*
		** 1. Set all bits to '1' for all columns in the primary key.
		** 2. Set version column bit to 1 if the publication is synctran
		** 3. For queued replication, set all column bits to 1 that do not allow
		**		NULL or DEFAULT value
		*/
		ELSE
		BEGIN
			--
			-- for updating subscribers build a temp table
			-- to keep track of columns that are mandatory
			--
			if (@allow_sync_tran = 1 or @allow_queued_tran = 1)
			begin
				create table #pktable(name sysname collate database_default)
			end
        	
			--
			-- if it's a table, get the indid of the PK
			--
			if exists( select * from sysobjects where id = @tabid and xtype = 'U' )
			begin
				SELECT @indid = indid FROM sysindexes
				WHERE id = @tabid
				AND (status & 2048) <> 0    /* PK index */
			end
			else  -- else it's a mview, use the CI (which, for a MV, must be unique)        
			begin
				SELECT @indid = 1
			end

			/*
			**  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
					, @force_invalidate_snapshot = @force_invalidate_snapshot
				IF @@ERROR <> 0 OR @retcode <> 0
					goto UNDO

				if (@allow_sync_tran = 1 or @allow_queued_tran = 1)
					insert into #pktable(name) values(@pkkey)
					
				select @i = @i + 1
			END

			if (@allow_sync_tran = 1 or @allow_queued_tran = 1)
			BEGIN
				--
				-- The version column needs to go in
				--
				declare @version_col sysname
				-- Get synctran column
				select @version_col = 'msrepl_tran_version'
				EXECUTE @retcode  = dbo.sp_articlecolumn @publication,
					@article, @version_col, 'add'
					-- synctran
					, @refresh_synctran_procs = 0
					, @force_invalidate_snapshot = @force_invalidate_snapshot

				IF @@ERROR <> 0 OR @retcode <> 0
					goto UNDO

				insert into #pktable(name) values('msrepl_tran_version')

				--
				-- select the columns that are not IDENTITY columns
				-- and do not allow NULL 
				-- and do not have any DEFAULT constraints defined for them
				-- and have not been processed already
				-- (IDENTITY columns do not need to be referenced explicitly - 
				-- which is like having a DEFAULT value so they can be excluded)
				--
				declare #htemp cursor local fast_forward for
					select name from dbo.syscolumns 
					where id = @tabid and isnullable = 0 
						and cdefault = 0 
						and ColumnProperty(id, name, N'IsIdentity') != 1
						and name not in (select name from #pktable)	

				open #htemp
				fetch #htemp into @version_col
				while (@@fetch_status = 0)
				begin
					EXECUTE @retcode  = dbo.sp_articlecolumn @publication,
					@article, @version_col, 'add', @refresh_synctran_procs = 0
					, @force_invalidate_snapshot = @force_invalidate_snapshot

					IF (@@ERROR != 0 OR @retcode != 0)
					BEGIN
						close #htemp
						deallocate #htemp
						drop table #pktable
						goto UNDO
					END
					fetch #htemp into @version_col
				end
				close #htemp
				deallocate #htemp
				drop table #pktable
			END
		end -- IF @vertical_partition = 'false' ELSE
 
		------------------------------------------------------------------------------
		-- 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
				goto UNDO
			
			set @viewname = 'syncobj_' + @viewname

			-- create view for object synchronization
			if ((@allow_sync_tran = 1 or @allow_queued_tran = 1) 
				and @vertical_partition = 'true')
			begin
				--
				-- vertical partition is true - this means we may not have the 
				-- complete view yet - column could be added or dropped.
				-- we do not want to validate the provided filter clause now
				-- sp_articlefilter will be called explicitly later to add article 
				-- filter and sp_articleview will be called finally to regenerate the 
				-- view - and the filter validation will be done then for updating subscribers
				--
				exec @retcode = dbo.sp_articleview @publication, @article, @viewname, NULL
					,@force_invalidate_snapshot = @force_invalidate_snapshot
			end
			else
			begin
				exec @retcode = dbo.sp_articleview @publication, @article, @viewname, @filter_clause
					,@force_invalidate_snapshot = @force_invalidate_snapshot
			end
			if @@ERROR <> 0 OR @retcode <> 0
				goto UNDO
		end

		-- Need to change syscolumns status before generating sync procs because the
		-- status will be used to decide whether or not call set identity insert.
		IF LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
		begin
			-- Make the identity column as not for replication
			select @colid = null
			select @colid = colid from syscolumns  where
				 id = @tabid and
				 colstat & 0x0001 <> 0 and -- is identity
				 colstat & 0x0008 = 0 -- No 'not for repl' property
			if @colid is not null
			begin
				exec @retcode  = dbo.sp_replupdateschema @source_table
				-- Mark 'not for repl'
				update syscolumns set colstat = colstat | 0x0008 where
					id = @tabid and colid = @colid
				-- Single to refresh the object cache.
				exec @retcode  = dbo.sp_replupdateschema @source_table
				IF @@ERROR <> 0 OR @retcode <> 0
					goto UNDO
			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, @updtrig 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))
			select @updtrig   = 'sp_MSsync_upd_trig_'+ 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, @updtrig))
			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
				select @updtrig = 'sp_MSsync_upd_trig_' + @guid_name
			end

			if @insproc IS NULL
			begin
				RAISERROR (14043, 11, -1, '@insproc')
				goto UNDO
			end

			if @updproc IS NULL
			begin
				RAISERROR (14043, 11, -1, '@updproc')
				goto UNDO
			end

			if @delproc IS NULL
			begin
				RAISERROR (14043, 11, -1, '@delproc')
				goto UNDO
			end


			if @updtrig IS NULL
			begin
				RAISERROR (14043, 11, -1, '@updtrig')
				goto UNDO
			end


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

			IF @@ERROR <> 0 OR @retcode <> 0
				goto UNDO
		end
		-- end SyncTran

		-- Generate the conflict table and conflict proc for Queued Tran case
		if (@allow_queued_tran = 1)
		begin
			exec @retcode = dbo.sp_MSmakeconflicttable @article, @publication, 0
			IF @@ERROR <> 0 OR @retcode <> 0
				goto UNDO
			exec @retcode = dbo.sp_MSmaketrancftproc @article, @publication
			IF @@ERROR <> 0 OR @retcode <> 0
				goto UNDO
		end 

		IF LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
		begin
			-- Have to do the update below after sync proc generation since
			-- it will insert row to sysarticleupdates
			update sysarticleupdates set identity_support = 1 where artid = @artid
			IF @@ERROR <> 0
				goto UNDO
			
			-- It is possible that the table is already being published. If so
			-- keep the old identity range values.
			if not exists (select * from MSpub_identity_range where objid = @tabid)
			begin
				insert into MSpub_identity_range (objid, range, pub_range, current_pub_range, last_seed, threshold) 
					values (@tabid, @identity_range, @pub_identity_range, @pub_identity_range, null, @threshold) 
				IF @@ERROR <> 0
					goto UNDO
			
				-- Call stored procedure to reconcile identity range
				exec @retcode = dbo.sp_MSpub_adjust_identity @artid = @artid
				IF @@ERROR <> 0 OR @retcode <> 0
					goto UNDO
			end					
		end -- IF LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
	END -- End of the else block handle table articles.

	-- 0x00001000 collation
	-- 0x00002000 extended property
    -- @schema_option is already padded out at the beginning of this procedure

	SELECT @schema_option_int = fn_replgetbinary8lodword(@schema_option)
	IF ((@schema_option_int & 0x00001000 <>0 ) or 
        (@schema_option_int & 0x00002000 <> 0 ))
		select @backward_comp_level = 40
	if @backward_comp_level > 10
		update syspublications set backward_comp_level = @backward_comp_level where pubid = @pubid

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

    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 = @artid,
		@destination_object = @destination_table,
		@source_owner = @source_owner,
		@source_object = @bak_source,
		@description = @description

    IF @@ERROR <> 0 OR @retcode <> 0
		goto UNDO
    
    /* 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
        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
			GOTO UNDO

		-- 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
			GOTO UNDO
		
		-- Have to call this stored procedure to invalidate existing snapshot
		-- if there are any. 
        EXECUTE @retcode  = dbo.sp_MSreinit_article
            @publication = @publication, 
			-- Virtual subscriptions of all the articles will be deactivated.
			-- @article = @article,
			@need_new_snapshot = 1,
			@force_invalidate_snapshot = @force_invalidate_snapshot	
        IF @@ERROR <> 0 OR @retcode <> 0
			GOTO UNDO
    END

    COMMIT TRANSACTION
	return 0
UNDO:
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION sp_addarticle
		commit tran
	end
	RETURN (1)
go
 
EXEC dbo.sp_MS_marksystemobject sp_addarticle
GO

grant execute on dbo.sp_addarticle to public
go

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

raiserror(15339,-1,-1,'sp_MSmaketrancftproc')
GO

create procedure sp_MSmaketrancftproc (
	@article sysname, 
	@publication sysname,
	@is_debug bit=0)
as
BEGIN
declare @source_table nvarchar(540)
		,@owner sysname
		,@procname sysname
		,@source_objid int
		,@artid int
		,@pubid int
		,@conflict_tableid int
		,@conflict_table	sysname
		,@conflict_proc_id int
		,@indid int
		,@indkey int
		,@ind_col_name sysname
		,@qualname   nvarchar(266)
		,@dbname sysname
		,@retcode smallint
		,@retain_varname int

declare @colid		int
		,@colname	sysname
		,@coltype	sysname
		,@ccoltype	sysname
		,@rowcnt	int

declare @argtabempty	bit
		,@seltabempty	bit
		,@sel2tabempty	bit
		,@valtabempty 	bit
		,@paramtabempty	bit
		,@where_clausetabempty bit
		,@decltabempty bit
		,@assigntabempty bit
		,@compinsertabempty bit

declare @argterm	nvarchar(4000)
		,@selterm	nvarchar(4000)
		,@sel2term	nvarchar(4000)
		,@updterm	nvarchar(4000)
		,@valterm 	nvarchar(4000)
		,@paramterm	nvarchar(4000)
		,@where_term nvarchar(4000)
		,@declterm	nvarchar(4000)
		,@assignterm nvarchar(4000)
		,@compinsterm nvarchar(4000)

declare @cmd		nvarchar(4000)

set nocount on

--
-- prepare the proc name and get the other parameters
--
select @artid = a.artid, @pubid = a.pubid, @source_table = object_name(a.objid), 
		@source_objid = a.objid 
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

--
-- Prepare the proc name 
-- The source table should be owner qualified
--
select @source_table = QUOTENAME(@owner) + N'.' + QUOTENAME(@source_table)
exec @retcode = sp_MSgettranconflictname @publication=@publication, 
					@source_object= @source_table, 
					@str_prefix='sp_MScft_', 
					@conflict_table=@procname OUTPUT

--
-- The conflict table should exist before we do any conflict procs
--
select @conflict_tableid = conflict_tableid, 
		@conflict_table = OBJECT_NAME(conflict_tableid) 
from sysarticleupdates
where artid = @artid and pubid = @pubid
if ( @conflict_tableid is NULL)
	return (1)
--
-- To check if specified object exists in current database
--
if (@owner is null or @owner = ' ')
	set @qualname = QUOTENAME(@conflict_table)
else
	set @qualname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)

if (object_id(@qualname) is NULL)
	return (1)

--
-- The source table should have an unique index
--
exec @indid = dbo.sp_MStable_has_unique_index @source_objid
if (@indid = 0)
	return (1)

--
-- Get all the columns participating in the index of the source table
--
create table #indcoltab ( colname sysname collate database_default )
select @indkey = 1;
while (@indkey <= 16)
begin
	select @ind_col_name = index_col(@source_table, @indid, @indkey)
	if (@ind_col_name is not NULL) 
		insert into #indcoltab(colname) values(@ind_col_name)
	else
		select @indkey = 16

	select @indkey = @indkey + 1
end

-- build the lists
select @argtabempty = 1
	,@valtabempty = 1
	,@paramtabempty = 1
	,@seltabempty = 1
	,@sel2tabempty = 1
	,@decltabempty = 1
	,@assigntabempty = 1
	,@where_clausetabempty = 1
	,@compinsertabempty = 1

create table #argtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #valtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #paramtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #seltab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #sel2tab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #decltab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #assigntab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #where_clausetab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
create table #compinstab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

-- some predefined declares and assignments
select @cmd = N'
	declare @reinit_code int, @subwins_code int, @pubwins_code int, @qcfttabrowid uniqueidentifier
			,@retcode smallint, @compcmd nvarchar(4000), @centralized_conflicts bit'
insert into #decltab(procedure_text) values(@cmd)
select @decltabempty = 0
	
select @cmd = N'
	select @reinit_code = 3
			,@subwins_code = 2
			,@pubwins_code = 1
			,@qcfttabrowid = NEWID()'
insert into #assigntab(procedure_text) values(@cmd)
select @cmd = N'
	select @centralized_conflicts = centralized_conflicts
	from dbo.syspublications where pubid = ' + cast(@pubid as nvarchar)
insert into #assigntab(procedure_text) values(@cmd)
select @assigntabempty = 0
	
declare #argcursor cursor local FAST_FORWARD FOR 
		select colid
		from syscolumns
		where iscomputed = 0 and id=@conflict_tableid 
		order by colid
FOR READ ONLY

select @retain_varname = 0
open #argcursor
fetch #argcursor into @colid
while (@@FETCH_STATUS = 0)
begin
	--
	-- Get the column name and column type
	--
	exec dbo.sp_MSget_type @conflict_tableid, @colid, @colname output, @coltype OUTPUT
	if (@@ERROR<>0 or @retcode<>0)
		return (1)

	--
	-- skip this specific column or if type is not returned
	--
	if ((@coltype IS NULL) or (LOWER(@colname) = 'qcfttabrowid'))
	begin
		-- do the next fetch and continue
		fetch #argcursor into @colid
		continue	
	end
		
	exec dbo.sp_MSget_colinfo @conflict_tableid, @colid, NULL, 0, NULL, @ccoltype output
	if (@@ERROR<>0 or @retcode<>0)
		return (1)

	--
	-- parameterize the vars that are the column values of the source
	-- table. For the columns that are specific to the conflict table
	-- retain specific names for the vars
	--
	if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'origin_datasource')
		select @retain_varname = @colid

	if (@retain_varname = 0)
		select @argterm = N'@param' + cast(@colid as nvarchar) 
	else
		select @argterm = N'@' + @colname
		
	select @valterm = quotename(@colname)
	select @paramterm = @argterm
	select @updterm = @valterm + N' = ' + @argterm

	if (@retain_varname = 0)
	begin
		select @selterm = @paramterm + N' = ' + @valterm
		select @sel2term = @paramterm + N' = case when ' + @paramterm + 
					N' is NULL then ' + @valterm + N' else ' + @paramterm + N' end'
	end
	else
	begin
		select @selterm = NULL
		select @sel2term = NULL
	end
	 
	select @argterm = @argterm + N' ' + @coltype

	-- Check if this is part of primary key	/ unique index
	if (@colname in ( select colname from #indcoltab ) )
	begin
		-- this key assignment becomes part of where clause
		select @where_term = @updterm
		select @updterm = NULL
		select @selterm = NULL
		select @sel2term = NULL
	end
	else
		select @where_term = NULL

	-- special columns - process them as local var
	if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'insertdate' )
	begin
		select @declterm = N'
	declare ' + @argterm
		select @assignterm = N'
	select ' + @paramterm + N' = GETDATE()'
		select @argterm = NULL
	end
	else if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'pubid' )
	begin
		select @declterm = N'
	declare ' + @argterm
		select @assignterm = N'
	select ' + @paramterm + N' = ' + cast(@pubid as nvarchar)
		select @argterm = NULL
	end
	else
	begin
		select @declterm = NULL
		select @assignterm = NULL
	end

	-- build the term for compensating insert
	if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
		select @compinsterm = N' '''''' + master.dbo.fn_MSgensqescstr(' + @valterm + N') collate database_default + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
		select @compinsterm = N' N'''''' + master.dbo.fn_MSgensqescstr(' + @valterm + N') collate database_default + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
		select @compinsterm = N' '''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @valterm + N') as nvarchar(4000))) collate database_default + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
		select @compinsterm = N' N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @valterm + N') as nvarchar(4000))) collate database_default + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
		select @compinsterm = N' '' + master.dbo.fn_varbintohexstr(' + @valterm + N') collate database_default ' 
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
		select @compinsterm = N' '' + CAST(' + @valterm + N' as nvarchar) '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
		select @compinsterm = N' '' + CONVERT(nvarchar(40),' + @valterm + N', 2) '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
		select @compinsterm = N' '''''' + CAST(' + @valterm + N' as nvarchar(40)) + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
		select @compinsterm = N' '''''' + CONVERT(nvarchar(40), ' + @valterm + N', 121) + '''''''' '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
		select @compinsterm = N' '' + master.dbo.fn_sqlvarbasetostr(' + @valterm + N' ) collate database_default '
	else
		select @compinsterm = N' '' + CAST(' + @valterm + N' as nvarchar) '
	
	-- Now append to the various lists
	if (@argterm is NOT NULL)
	begin		
		if (@argtabempty = 1)
		begin
			select @argtabempty = 0
			select @cmd = N'
	' + @argterm
		end
		else
			select @cmd = N',
	' + @argterm
		insert into #argtab(procedure_text) values(@cmd)
	end
	if (@valterm is NOT NULL)
	begin
		if (@valtabempty = 1)
		begin
			select @valtabempty = 0
			select @cmd = @valterm
		end
		else
			select @cmd = N', ' + @valterm
		insert into #valtab(procedure_text) values(@cmd)
	end
	if (@paramterm is NOT NULL)
	begin
		if (@paramtabempty = 1)
		begin
			select @paramtabempty = 0
			select @cmd = @paramterm
		end
		else
			select @cmd = N', ' + @paramterm
		insert into #paramtab(procedure_text) values(@cmd)
	end
	if (@selterm is NOT NULL)
	begin
		if (@seltabempty = 1)
		begin
			select @seltabempty = 0
			select @cmd = N'
		' + @selterm
		end
		else
			select @cmd = N'
		,' + @selterm		
		insert into #seltab(procedure_text) values(@cmd)
	end
	if (@sel2term is NOT NULL)
	begin
		if (@sel2tabempty = 1)
		begin
			select @sel2tabempty = 0
			select @cmd = N'
		' + @sel2term
		end
		else
			select @cmd = N'
		,' + @sel2term		
		insert into #sel2tab(procedure_text) values(@cmd)
	end	
	if (@where_term is NOT NULL)
	begin
		if (@where_clausetabempty = 1)
		begin
			select @where_clausetabempty = 0
			select @cmd = @where_term
		end
		else
			select @cmd = N' AND 
			' + @where_term
		insert into #where_clausetab(procedure_text) values(@cmd)
	end
	if (@declterm is NOT NULL)
	begin
		select @cmd = @declterm + N'
	'
		insert into #decltab(procedure_text) values(@cmd)
	end		

	if (@assignterm is NOT NULL)
	begin
		select @cmd = @assignterm + N'
	'
		insert into #assigntab(procedure_text) values(@cmd)
	end		

	if (@compinsterm is NOT NULL)
	begin
		if (@compinsertabempty = 1)
		begin
			select @compinsertabempty = 0
			select @cmd = N' + ISNULL(''' + @compinsterm + N', ''null'')'
		end
		else
			select @cmd = N' + ISNULL('',' + @compinsterm + N', ''null'')'
		insert into #compinstab(procedure_text) values(@cmd)
	end
	
	-- do the next fetch
	fetch #argcursor into @colid

end
close #argcursor
deallocate #argcursor
drop table #indcoltab

--
-- generation phase
--
BEGIN TRAN sp_MSmaketrancftproc

-- create temp table to select the command text out of
if exists (select * from sysobjects where name = 'tempcmd' and uid = user_id('dbo'))
		drop table dbo.tempcmd
create table dbo.tempcmd ( c1 int identity NOT NULL, cmdtext nvarchar(4000) NULL)

-- create header
insert into  dbo.tempcmd(cmdtext) 
values(N'create procedure '+QUOTENAME(@owner)+ N'.'+ QUOTENAME(@procname) + N'( 
')

-- insert the arglist
insert into dbo.tempcmd(cmdtext) select procedure_text from #argtab order by c1 
insert into dbo.tempcmd(cmdtext) values(N' ,@subcriber sysname = NULL, @subdb sysname = NULL )
as
begin
')

-- insert the declare list
insert into dbo.tempcmd(cmdtext) select procedure_text from #decltab order by c1 
insert into dbo.tempcmd(cmdtext) values(N'
')

-- insert the assignment list (for declared vars)
insert into dbo.tempcmd(cmdtext) select procedure_text from #assigntab order by c1

-- do the select for the case where we need to retain values of publisher
insert into dbo.tempcmd(cmdtext) values(N'
	if (@reason_code = @subwins_code)
	begin
		select ')
insert into dbo.tempcmd(cmdtext) select procedure_text from #seltab order by c1
insert into dbo.tempcmd(cmdtext) values(N'
		from ' + @source_table + N' where ')
insert into dbo.tempcmd(cmdtext) select procedure_text from #where_clausetab order by c1
insert into dbo.tempcmd(cmdtext) values(N'
	end')

insert into dbo.tempcmd(cmdtext) values(N'
	else
	begin
		select ')
	
insert into dbo.tempcmd(cmdtext) select procedure_text from #sel2tab order by c1
insert into dbo.tempcmd(cmdtext) values(N'
		from ' + @source_table + N' where ')
insert into dbo.tempcmd(cmdtext) select procedure_text from #where_clausetab order by c1
insert into dbo.tempcmd(cmdtext) values(N'
	end
')

--
-- insert the conflict row in the publisher cft table
--
insert into dbo.tempcmd(cmdtext) values(N'
	insert into ' + @qualname + N'(')
insert into dbo.tempcmd(cmdtext) select procedure_text from #valtab order by c1
insert into dbo.tempcmd(cmdtext) values(N',[qcfttabrowid]) 
	values (')
insert into dbo.tempcmd(cmdtext) select procedure_text from #paramtab order by c1
insert into dbo.tempcmd(cmdtext) values(N',@qcfttabrowid)
')

--
-- generate compensating command decentralized logging
-- depending on the number of columns, we will split the compensating
-- command into several compensating commands
--
select @rowcnt = 0, @compinsertabempty = 1
select @cmd = N'
	if (@centralized_conflicts = 0)
	begin
		select @compcmd = N''insert into ' + master.dbo.fn_MSgensqescstr(@qualname) collate database_default + N' ( '
insert into dbo.tempcmd(cmdtext) values(@cmd)

declare #htempcur cursor local for
	select master.dbo.fn_MSgensqescstr(procedure_text) from #valtab order by c1
for read only

open #htempcur
fetch #htempcur into @compinsterm
while (@@fetch_status = 0)
begin
	insert into dbo.tempcmd(cmdtext) select @compinsterm
	select @rowcnt = @rowcnt + 1

	--
	-- if we have processed 10 terms then split the command
	--
	if (@rowcnt > 9)
	begin
		select @cmd = N'''
		from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
		insert into dbo.tempcmd(cmdtext) values(@cmd)		
	
		select @cmd = N'
		exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
			+ CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',1,0,'
			+ CAST(@compinsertabempty as nvarchar(4)) + N'
		if (@@error != 0 or @retcode != 0)
			return 1 
		
		select @compcmd = N''' 
		insert into dbo.tempcmd(cmdtext) values(@cmd)
		select @rowcnt = 0, @compinsertabempty = 0
	end
	fetch #htempcur into @compinsterm
end

close #htempcur
deallocate #htempcur

insert into dbo.tempcmd(cmdtext) values(N', [qcfttabrowid] ) values ('' ')
select @rowcnt = @rowcnt + 1

declare #htempcur cursor local for
	select procedure_text from #compinstab order by c1
for read only

open #htempcur
fetch #htempcur into @compinsterm
while (@@fetch_status = 0)
begin
	insert into dbo.tempcmd(cmdtext) select @compinsterm
	select @rowcnt = @rowcnt + 1

	--
	-- if we have processed 10 terms then split the command
	--
	if (@rowcnt > 9)
	begin
		select @cmd = N'
		from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
		insert into dbo.tempcmd(cmdtext) values(@cmd)		
	
		select @cmd = N'
		exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
			+ CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',1,0,'
			+ CAST(@compinsertabempty as nvarchar(4)) + N'
		if (@@error != 0 or @retcode != 0)
			return 1 
		
		select @compcmd = N'' ''' 
		insert into dbo.tempcmd(cmdtext) values(@cmd)
		select @rowcnt = 0, @compinsertabempty = 0
	end
	fetch #htempcur into @compinsterm
end

close #htempcur
deallocate #htempcur

--
-- script the remaining compensating command
--
select @cmd = N' + '', '''''' + CAST([qcfttabrowid] as nvarchar(40)) + '''''''' + N'' ) ''
		from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
insert into dbo.tempcmd(cmdtext) values(@cmd)
select @rowcnt = @rowcnt + 1

select @cmd = N'
		exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
			+ CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',0,0,'
			+ CAST(@compinsertabempty as nvarchar(4)) + N'
		if (@@error != 0 or @retcode != 0)
			return 1 ' 
insert into dbo.tempcmd(cmdtext) values(@cmd)		
insert into dbo.tempcmd(cmdtext) values(N'
	end
end')

if (@is_debug = 0)
begin
	-- Now we select out the command text pieces in proper order so that our caller,
	-- xp_execresultset will execute the command that creates the stored procedure.
	select @dbname = db_name()
	select @cmd = N'select cmdtext from dbo.tempcmd order by c1'
	exec @retcode = master..xp_execresultset @cmd, @dbname
	if (@@error != 0 or @retcode != 0)
	begin
		-- roll back the tran
		rollback tran sp_MSmaketrancftproc
		return (1)
	end
	
	--
	-- Check if we create the proc and update sysarticleupdates
	--
	select @conflict_proc_id = id from sysobjects where name = @procname and type = 'P '
	if (@conflict_proc_id is NULL or @conflict_proc_id = 0)
	begin
		-- roll back the tran
		rollback tran sp_MSmaketrancftproc
		return (1)
	end
	else
	begin
		update dbo.sysarticleupdates set ins_conflict_proc = @conflict_proc_id
			where artid = @artid and pubid = @pubid
		if @@error <> 0
		begin
			-- roll back the tran
			rollback tran sp_MSmaketrancftproc
			return (1)
		end

		-- mark the proc as system object
		if (@owner in ('dbo','INFORMATION_SCHEMA'))
		begin
			exec @retcode = dbo.sp_MS_marksystemobject @procname
			if (@@error != 0 or @retcode != 0)
			begin
				-- roll back the tran
				rollback tran sp_MSmaketrancftproc
				return (1)
			end
		end
	end
end
else
	select cmdtext from dbo.tempcmd order by c1

COMMIT TRAN 

-- drop the temp tables
drop table dbo.tempcmd
drop table #argtab 
drop table #valtab 
drop table #paramtab 
drop table #seltab 
drop table #sel2tab 
drop table #decltab 
drop table #assigntab 
drop table #where_clausetab 
drop table #compinstab
END
go

exec dbo.sp_MS_marksystemobject sp_MSmaketrancftproc 
go

grant execute on dbo.sp_MSmaketrancftproc to public
go

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

raiserror(15339,-1,-1,'sp_changesubstatus')
GO

CREATE PROCEDURE sp_changesubstatus (
    @publication sysname = '%',    /* publication name */
    @article sysname = '%',        /* article name */
    @subscriber sysname = '%',      /* subscriber name */
    @status sysname,                /* subscription status */
    @previous_status sysname=NULL,  /* previous subscription status */
    @destination_db sysname = '%',   /* destination database name */

    @frequency_type int = NULL,
    @frequency_interval int = NULL,
    @frequency_relative_interval int = NULL,
    @frequency_recurrence_factor int = NULL,
    @frequency_subday int = NULL,
    @frequency_subday_interval int = NULL,
    @active_start_time_of_day int = NULL,
    @active_end_time_of_day int = NULL,
    @active_start_date int = NULL,
    @active_end_date int = NULL,
    @optional_command_line nvarchar(4000) = NULL,
    @distribution_jobid binary(16) = NULL OUTPUT,
    @from_auto_sync bit = 0,
    @ignore_distributor bit = 0,
    -- Agent offload
    @offloadagent bit = 0,
    @offloadserver sysname = NULL,
	@dts_package_name sysname = NULL,
	@dts_package_password nvarchar(524) = NULL,
	@dts_package_location int = 0,
    @schemastabilityonly int = 0,
	@distribution_job_name sysname = NULL

) AS

    SET NOCOUNT ON
    DECLARE @inactive tinyint
    DECLARE @subscribed tinyint
    DECLARE @active tinyint
	DECLARE @initiated tinyint
    DECLARE @public tinyint
    DECLARE @replicate_bit smallint
    DECLARE @msg nvarchar(255)
    DECLARE @prevstatid tinyint
    DECLARE @artid int
    DECLARE @tabid int
    DECLARE @srvid smallint
    DECLARE @statusid tinyint
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @pub_db sysname
    DECLARE @dest_db sysname
    DECLARE @sub_name sysname
    DECLARE @sub_status tinyint
    DECLARE @sub_ts varbinary (16)
    DECLARE @non_sql_flag bit
    DECLARE @qcmd nvarchar (4000)
    DECLARE @cmd1 nvarchar (255)
    DECLARE @cmd2 nvarchar (255)
    DECLARE @cmd3 nvarchar (255)
    DECLARE @retcode int
    DECLARE @repl_freq tinyint
    DECLARE @art_type tinyint
    DECLARE @proccmd  nvarchar(255)
    DECLARE @procnum  smallint
    DECLARE @finished_real bit
    DECLARE @finished_virtual bit
    DECLARE @virtual_id smallint
    DECLARE @immediate_sync bit
    DECLARE @enabled_for_internet bit
    DECLARE @allow_anonymous bit
    DECLARE @subscription_type int
    DECLARE @xact_seqno binary(10)
    DECLARE @sync_type tinyint
    DECLARE @automatic tinyint
    DECLARE @bcp_char tinyint	
    DECLARE @concurrent_char tinyint	

    DECLARE @art_change bit
    declare @login_name sysname

	DECLARE @pubid int
	DECLARE @syncinit_lsn binary(10)

	DECLARE @f_syncstat_posted bit

    -- synctran
    DECLARE @update_mode tinyint
    DECLARE @art_name sysname
    declare @synctran tinyint
    declare @no_distproc bit
    declare @loopback_detection bit
	
    /*
    ** Initializations.
    */
    select @synctran = 1
			
    SELECT @automatic = 1
    SELECT @inactive = 0        /* Const: subscription status 'inactive' */
    SELECT @subscribed = 1      /* Const: subscription status 'subscribed' */
    SELECT @active = 2          /* Const: subscription status 'active' */
	SELECT @initiated = 3        /* Const: subscription status 'initiated' */
    SELECT @public = 0          /* Const: publication status 'public' */
    SELECT @pub_db = DB_NAME()
    SELECT @virtual_id = -1
    SELECT @art_change = 0
    select @bcp_char = 1
    select @concurrent_char = 4	

	SELECT @f_syncstat_posted = 0

    SELECT @replicate_bit = 2

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

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

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

    IF @publication <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @publication
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END

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

    /*
    ** Parameter Check:  @article
    ** Check to make sure that the article exists, that it's not null,
    ** and that it conforms to the rules for identifiers.
    */

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

    /*
    IF @article <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @article
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END
    */

    IF NOT EXISTS (SELECT *
                     FROM sysextendedarticlesview a,
                          syspublications b
                WHERE a.name LIKE @article
                      AND a.pubid = b.pubid
                      AND b.name LIKE @publication)

        BEGIN
        IF @article = '%'
                RAISERROR (14009, 11, -1, @publication)
        ELSE
                RAISERROR (20027, 11, -1, @article)
        RETURN (1)
        END

    /*
    ** Parameter Check:  @subscriber
    ** Check to make sure that the subscriber exists, that it is not NULL,
    ** and that it conforms to the rules for identifiers.
    ** Null subscriber represents virtual subscriptions
    */

    IF @subscriber IS NOT NULL AND @subscriber <> '%'
    BEGIN    
        EXECUTE @retcode = dbo.sp_validname @subscriber
        IF @@ERROR <> 0 OR @retcode <> 0
        RETURN (1)

        IF NOT EXISTS (SELECT *
                         FROM master..sysservers
                        WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
                          AND (srvstatus & 4) <> 0)

            BEGIN
                RAISERROR (14063, 11, -1)
                RETURN (1)
            END
    END

    /*
    ** Parameter Check: @status.
    ** Set the @statusid according to the @status value.  Values can be
    ** any of the following:
    **
    **      status      statusid
    **      =========   ========
    **      inactive           0
    **      subscribed         1
    **      active             2
	**		initiated          3
    */

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

	IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
		SELECT @statusid = @initiated
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
        SELECT @statusid = @active
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
        SELECT @statusid = @subscribed
    ELSE
        SELECT @statusid = @inactive

    /*
    ** Parameter Check: @previous_status.
    ** Set the @prevstatid according to the @previous_status value.
    ** Values can be any of the following:
    **
    **      previous_status      prevstatid
    **      ===============      ==========
    **      inactive                      0
    **      subscribed                    1
    **      active                        2
	**		initiated					  3
    */

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

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

		IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
			SELECT @prevstatid = @initiated
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
            SELECT @prevstatid = @active
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
            SELECT @prevstatid = @subscribed
        ELSE
           SELECT @prevstatid = @inactive
    END

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

    IF @destination_db <> '%' 
    BEGIN
		EXECUTE @retcode = dbo.sp_validname @destination_db
		IF @retcode <> 0
		RETURN (1)
    END

    /*
    ** Get distribution server information for remote RPC
    ** subscription calls.
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 1 
        select @no_distproc = 1
    else
        select @no_distproc = 0

    IF @no_distproc = 0 --and @from_auto_sync = 0 
    BEGIN
        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distribdb OUTPUT

        IF @@ERROR <> 0
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END

        IF @retcode <> 0 OR @distribdb IS NULL OR @distributor IS NULL
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END
    END


    create table #sysextendedarticlesview
    (
    artid               int                 NULL,
    columns             varbinary(32)       NULL,
    creation_script     nvarchar(255)       collate database_default null,
    del_cmd             nvarchar(255)       collate database_default null,
    description         nvarchar(255)       collate database_default null,
    dest_table          sysname             collate database_default null,
    filter              int                 NULL,
    filter_clause       ntext               NULL,
    ins_cmd             nvarchar(255)       collate database_default null,
    name                sysname             collate database_default null,
    objid               int                 NULL,
    pubid               int                 NULL,
    pre_creation_cmd    tinyint             NULL,
    status              tinyint             NULL,
    sync_objid          int                 NULL,
    type                tinyint             NULL,
    upd_cmd             nvarchar(255)       collate database_default null,
    schema_option       binary(8)           NULL,
    dest_owner          sysname             collate database_default null
    )

    insert into #sysextendedarticlesview select * from sysextendedarticlesview

    begin tran
    save TRANSACTION changesubstatus

        SELECT @finished_virtual = 0
        SELECT @finished_real = 0

        /* 
        ** If @subscriber is null, don't process real subscriptions
        ** If @subscriber is not null and '%', don't process virtual subscriptions
        */
        IF @subscriber IS NULL SELECT @finished_real = 1
        ELSE IF @subscriber <> '%'  SELECT @finished_virtual = 1

        WHILE (@finished_real = 0 OR @finished_virtual = 0)
        BEGIN
            /*
            ** Declare cursor containing subscriptions to be updated.
            */
            IF @finished_real = 0
            BEGIN
                IF @previous_status IS NOT NULL
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND sub.status = @prevstatid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db collate database_default))
                END
                ELSE
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db))
                END		   
                SELECT @finished_real = 1
            END

            ELSE IF @finished_virtual = 0  
            BEGIN
                DECLARE @sub_bit smallint
                DECLARE @null_name sysname

                SELECT @sub_bit = 4
                SELECT @null_name = NULL

                /*
                ** Treat anonymous virtual subscription as DSN subscriber.
                ** This will cause sp_MSarticlecol being called in sp_changesubstatus
                */
                DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                    SELECT sub.artid,
                           art.objid,
                           sub.srvid,
                           @null_name,              /* subscriber name. NULL for virtual */
                           sub.dest_db,
                           sub.status,
                      case when (pub.allow_anonymous = 1 and (pub.sync_method = @bcp_char or pub.sync_method = @concurrent_char)) or
							pub.allow_dts = 1 then 1
                       else 0 end, /*indicate dsn or not */ 
                       pub.repl_freq,
                       art.type,
                       pub.immediate_sync,
                       pub.enabled_for_internet,
                       pub.allow_anonymous,
                       sub.subscription_type,
                       sub.sync_type,
                       sub.update_mode,
                       art.name,
                       login_name,
                       sub.loopback_detection,
					   pub.pubid

                      FROM syssubscriptions sub,
                           #sysextendedarticlesview art,
                           syspublications pub
                     WHERE pub.name LIKE @publication
                       AND art.name LIKE @article
                       AND sub.srvid = -1
                       AND sub.artid = art.artid
                       AND art.pubid = pub.pubid
                SELECT @finished_virtual = 1
            END

            OPEN hCsubstatus
            FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
                @sub_status, @non_sql_flag, @repl_freq, @art_type,
                @immediate_sync, @enabled_for_internet,
                @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection,@pubid


            WHILE (@@fetch_status <> -1)
            BEGIN

                IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
                    AND is_member ('db_owner') <> 1
                BEGIN
                        RAISERROR (14126, 11, -1)
                        RETURN (1)
                END
                /*
				** condition 1:
                ** If current status is same as new status, and status is not 'initiated' do nothing.
				** If both old and new status = 'initiated', this indicates that the 
				** snapshot agent previously bombed out between the initiation and activation stages and
				** is now again trying to sync the publication.
				**
				** condition 2:
                ** @auto_sync_only is used by snapshot for immediate_sync
                ** publications.
				**
				** condition 3:
				** Because sp_MSactivate_auto_sub (and thus the snapshot agent)
				** calls this procedure for all subscriptions, we need to ignore
				** the real subscriptions that are already active so that they won't be
				** transitioned to the initiated state.  If we don't do this, those
				** subscriptions will be resynced using the new snapshot.
				** 
				** however, we DO want a new snapshot to be generated for virtual
				** subscriptions to active publications.
				**
                */
                IF  (@sub_status = @statusid AND @sub_status <> @initiated ) OR
                    (@from_auto_sync = 1 AND @sync_type <> @automatic) OR
					(@sub_status = @active AND @statusid = @initiated AND @srvid <> -1 AND @from_auto_sync = 1)
                BEGIN
                    FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name,
                       @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type, 
                       @immediate_sync, @enabled_for_internet,
                       @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                       @art_name, @login_name, @loopback_detection, @pubid

                    CONTINUE
                END

				-- If changing a virtual subscription to 'subscribed' status
				-- change the immediate_sync_ready bit
				if @statusid = @subscribed and @sub_name is NULL
				begin
					UPDATE syspublications SET immediate_sync_ready = 0 WHERE 
						pubid = @pubid and
						immediate_sync_ready <> 0
                    IF @@ERROR <> 0
                    BEGIN
                      CLOSE hCsubstatus
                      DEALLOCATE hCsubstatus
                      if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION changesubstatus
                            commit tran
                        end
                      RETURN (1)
                    END
				end


				-- acquire schema lock, mark rollback point in order to allow
				-- for 'unflush' of proc cache

                declare @qualified_name nvarchar(512)

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

                /*
                ** Update syssubscription status
                */
                UPDATE syssubscriptions
                       SET status = @statusid
                       FROM syssubscriptions sub,
                           sysextendedarticlesview art,
                           syspublications pub
                       WHERE pub.name LIKE @publication
                            AND art.artid = @artid
                            AND sub.srvid = @srvid
                            AND sub.artid = @artid
                            AND art.pubid = pub.pubid
                            AND sub.dest_db = @dest_db
                if @@ERROR <> 0
                               BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                                   RETURN (1)
                               END

				--
				-- Subscription reinitialization processing for Immediate 
				-- and Queued publications
				--
				if (@update_mode in (1,2,3,4,5))
				begin
					select @retcode = 0
					IF ((@statusid != @active) AND (@sub_status = @active))
					begin
						--
						-- If we are going from active state to subscribed
						-- set the reinit column so that no more updates from
						-- subscriber are applied until (re)activation
						--
						update dbo.syssubscriptions
						set queued_reinit = 1
						where 
							artid = @artid 
							and srvid = @srvid
							and dest_db = @dest_db
					end
					ELSE IF ((@statusid = @active) AND (@sub_status != @active ))
					begin
						--
						-- If we are going from subscribed state to active state
						--
						if (@update_mode = 1)
						begin
							--
							-- Sync tran case : reset the reinit column
							--
							update dbo.syssubscriptions
							set queued_reinit = 0
							where 
								artid = @artid 
								and srvid = @srvid
								and dest_db = @dest_db
						end

						--
						-- For queued case : we do not need to send compensating
						-- command anymore, sp_addqueued_artinfo will do the 
						-- queue reinitialization for all types of queued
						-- subscriptions
						--

						/**********
						else
						begin
							-- 
							-- Queued case : send a compensating action command to 
							-- subscriber to reinitialize its queue
							--
							select @qcmd = N'exec sp_MSreset_queue ''' + @@servername + '''' + 
								', ''' + db_name() + '''' +
								', ''' + name + '''' +
								', ' + cast(@artid as nvarchar(8))
							from syspublications
							where pubid = @pubid
								  					
							exec @retcode = dbo.sp_MSadd_compensating_cmd
								@orig_srv = @sub_name
								,@orig_db = @dest_db
								,@command = @qcmd
								,@article_id = @artid 
								,@publication_id = @pubid
						end
						**********/
					end					

					--
					-- Check for error
					--
					if (@@error != 0 or @retcode != 0)
					begin
						CLOSE hCsubstatus
						DEALLOCATE hCsubstatus
						if @@trancount > 0
						begin
							ROLLBACK TRANSACTION changesubstatus
							commit tran
						end
						RAISERROR (14053, 16, -1)
						RETURN (1)
					end
				end

                /*
                ** Get timestamp of subscription.
                */
                EXEC @retcode = dbo.sp_replincrementlsn @xact_seqno OUTPUT
                IF @@ERROR <> 0 or @retcode <> 0
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                               RETURN (1)
                            END
                select @sub_ts = @xact_seqno


                IF @sub_ts IS NULL
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                               RETURN (1)
                            END
				
				-------------------------------------------------------------------
				-- If initiating the subscription, toss a SYNCINIT token into the 
				-- log for the article and return LSN as a results set
				--
				-- Note:  This should come after the subscription LSN is obtained.
				-- in order to assure proper application of SYNSTAT tokens in the
				-- distribution database
				-------------------------------------------------------------------

				IF @statusid = @initiated --and @sub_status <> @initiated
				BEGIN
					-- set filtered status.  Must log old text information during initiated state
					-- in order to support update splitting

					exec sp_MSsetfilteredstatus @tabid

					-- set nonsqlsub status.  must prevent UPDATETEXT operations during
					-- initiated state

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'add'
					exec sp_replpostsyncstatus @pubid, @artid, 1, @syncinit_lsn output
					if @f_syncstat_posted = 0
					begin
						select @pubid, @artid, @syncinit_lsn
						select @f_syncstat_posted = 1
					end
				END

				-------------------------------------------------------------------
				-- If changing the state FROM initiated, post a SYNCDONE token to the 
				-- log for the article. 
				-------------------------------------------------------------------
				IF @sub_status = @initiated and @statusid <> @initiated
				BEGIN
					-- reset filtered status to normal value

					exec sp_MSsetfilteredstatus @tabid

					-- clear nonsqlsub status for this article.

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'drop'

					--if @f_syncstat_posted = 0
					--begin
						exec sp_replpostsyncstatus @pubid, @artid, 0, @syncinit_lsn output
					--	select @f_syncstat_posted = 1
					--end
				END

                /*
                ** If activating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */
                IF @statusid in ( @active, @initiated )
                BEGIN
                    
                    /*
                    ** Update status of article to show it has been activated.
                    */
                    IF @repl_freq = 0 and EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                        AND status & 1 <> 1)
                    BEGIN
                        -- At most one row will be updated in the following two updates as the artid is unique
                        -- among both sysarticles and sysschemaarticles
                        UPDATE sysarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        UPDATE sysschemaarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        SELECT @art_change = 1
                    END

                        /*
                        ** Turn the replication flag on for this object in the
                        ** sysobjects table (make it logbased).
                        */

                    if @repl_freq = 0
                      BEGIN
                        UPDATE sysobjects SET replinfo = replinfo | @replicate_bit
                        WHERE id = ( SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )
                      END

                      IF @@ERROR <> 0
                      BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                      END

                END

                /*
                ** Update status of all columns if subscriber is non-SQL Server.
                */
                IF @non_sql_flag <> 0 AND ( @art_type & 1 ) = 1
                BEGIN
                    IF @statusid = @subscribed OR @statusid = @active
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'add'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RAISERROR (14068, 16, -1)
                            RETURN (1)
                        END


                    END
                    ELSE IF @statusid = @inactive
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'drop'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                        END
                    END
                END

				
                /*
                ** If deactivating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */

                IF @statusid NOT IN( @active, @initiated ) AND @sub_status IN ( @active, @initiated )
                BEGIN
                    /*
                    ** Set the article status to 'inactive' if there are
                    ** no other active subscriptions on it.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                       artid = @artid AND status = @active)
                    BEGIN
                        IF EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                            AND status & 1 = 1)
                        BEGIN
                            -- At most one row will be updated in the following two updates as the artid is unique
                            -- among both sysarticles and sysschemaarticles
                            UPDATE sysarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                            UPDATE sysschemaarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END

                            SELECT @art_change = 1
                        END
                    END

                    /*
                    ** Set the object replication bits  to 'inactive' if
                    ** there are no other active subscriptions on the
                    ** table.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                        artid IN (SELECT sa.artid FROM sysextendedarticlesview sa, syspublications sp WHERE
                        sa.objid = @tabid and sa.pubid = sp.pubid and sp.repl_freq = 0) AND status = @active)
                    BEGIN
                        UPDATE sysobjects SET replinfo =  replinfo & ~@replicate_bit
                        WHERE id = (SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )

                        IF @@ERROR <> 0
                        BEGIN
                           CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14068, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                END

				-- Note:  Not only do we need to have the replupdateschema already executed
				-- so we can handle rollbacks, we also need to
                -- acquire the schema lock before RPC to the distributor to avoid livelock
                -- with snapshot agents. Snapshot agents acquire lock on user table before
                -- updating the distribution db.

                if @no_distproc = 0
                begin
                    /*
                    ** Add the active subscription to the distributor's
                    ** subscriptions table if changing status from @inactive
                    */
                    IF @sub_status = @inactive 
                    -- From inactive to subscribed or active
                    BEGIN

                        DECLARE @null_char sysname
                        SELECT @null_char = NULL

                        DECLARE @zero_bit bit
                        SELECT @zero_bit = 0

                        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadd_subscription'
                        EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, 
                            @artid, @dest_db, @statusid, @sub_ts,
                            @publication, 
                            @null_char, /* Pass null to @article, we already gave @artid */
                            @subscription_type,
                            --@immediate_sync, 
                            @sync_type, 
                            @zero_bit,
                            @frequency_type,
                            @frequency_interval,
                            @frequency_relative_interval,
                            @frequency_recurrence_factor,
                            @frequency_subday,
                            @frequency_subday_interval,
                            @active_start_time_of_day,
                            @active_end_time_of_day,
                            @active_start_date,
                            @active_end_date,
                            @optional_command_line = @optional_command_line,
                            -- synctran
                            @update_mode = @update_mode,
                            @loopback_detection = @loopback_detection,
                            @distribution_jobid = @distribution_jobid OUTPUT,
                            @offloadagent = @offloadagent,
                            @offloadserver = @offloadserver,
							@dts_package_name = @dts_package_name,
							@dts_package_password = @dts_package_password,
							@dts_package_location = @dts_package_location,
							@distribution_job_name = @distribution_job_name

                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14070, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                    ELSE
                    -- From subscribed or active to others
                    BEGIN
                        /*
                        ** Drop the deactivated subscription from the distributor's
                        ** subscriptions table.
                        */
                        IF @statusid = @inactive
                        -- From subscribed to inactive or from active to inactive
                        BEGIN
                            SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_subscription'
                            EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name,  @artid, @dest_db, @publication
                            IF @@ERROR <> 0 OR @retcode <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                RAISERROR (14070, 16, -1)
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RETURN (1)
                            END
                        END
                        ELSE 
                        -- From subscribed to initiated to active or from active to subscribed.
                        BEGIN
                            -- Don't do it if activating the subscription for snapshot agent.
                            --IF NOT (@from_auto_sync = 1 AND @statusid in(@active, @initiated) )
                            IF NOT (@from_auto_sync = 1 AND @statusid in(@active) )
                            BEGIN
                                SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSupdate_subscription'
                                EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @statusid, @sub_ts, @dest_db
                                IF @@ERROR <> 0 OR @retcode <> 0
                                BEGIN
                                    CLOSE hCsubstatus
                                    DEALLOCATE hCsubstatus
                                    RAISERROR (14070, 16, -1)
                                    if @@trancount > 0
                                    begin
                                        ROLLBACK TRANSACTION changesubstatus
                                        commit tran
                                    end
                                    RETURN (1)
                                END
                            END
                        END
                    END
                end

                /*
                ** Set internal object replication bit  to 'inactive' if
                ** there are no other active subscriptions on the
                ** table.
                */

                IF @statusid = @inactive AND @sub_status IN (@active,@initiated) AND
                    NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                    artid IN (SELECT artid FROM sysextendedarticlesview WHERE
                    objid = @tabid) AND status IN (@active,@initiated) )
                BEGIN
                       /*
                       ** If it's a procedure execution article, clear proc status bits
                       */
                       IF (@art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo & ~24 WHERE id = @tabid
                       END
                END


                /* Turn on object replication */

                ELSE IF @statusid = @active
                BEGIN
                       IF (@art_type & 24 ) = 24
                       BEGIN

                           UPDATE sysobjects SET replinfo = replinfo | 24 WHERE id = @tabid
                       END
                       ELSE IF( @art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo | 8 WHERE id = @tabid
                       END
                END


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

               /*
               ** Get next row.
               */
               FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
               @sub_status, @non_sql_flag, @repl_freq, @art_type ,  
               @immediate_sync, @enabled_for_internet,
               @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection, @pubid

          
                                    
           END  -- end while for cursor

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

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

    COMMIT TRANSACTION
    drop table #sysextendedarticlesview
    RETURN(0)
go
 
 
EXEC dbo.sp_MS_marksystemobject sp_changesubstatus
GO

grant execute on dbo.sp_changesubstatus to public
go


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

raiserror(15339,-1,-1,'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(30)    = 'read only',    -- Can be 'read only', 'sync tran', 'queued tran', 'failover'
    @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 */
    -- Agent offload
    @offloadagent bit = 0,
    @offloadserver sysname = NULL,
    -- End of agent offload
	-- DTS package name
	@dts_package_name sysname  = NULL,	/* value will be sent and validated at distributor */                                  
 	@dts_package_password  sysname = NULL,
	@dts_package_location nvarchar(12) = N'distributor',
	@distribution_job_name sysname = NULL
   ) 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 @concurrent tinyint
	DECLARE @concurrent_char 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
    		,@artsrctabid int

    DECLARE @dsn_dbname sysname
    DECLARE @dts_package_enc_password nvarchar(524)

    -- SyncTran
    DECLARE @allow_sync_tran_id bit
    DECLARE @allow_queued_tran_id bit
    DECLARE @update_mode_id     tinyint -- 0 = read only, 1 = sync tran, 2 = queued tran, 3 = failover
										-- 4 = sqlqueued tran, 5 = sqlqueued failover
	DECLARE	@publication_queue_type int 
    -- 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 @concurrent = 3  /* Const: concurrent sync method */
    SELECT @concurrent_char = 4  /* Const: concurrent char mode sync method */
	SELECT @virtual_id = -1 /* Const: virtual subscriber id */
    SELECT @internal = 'internal' /* Const: Flag of calling internally from system */
                                  /* stored procedures     */
	
	-- Change it  in 7.5 to avoid confusion, expecially in ole db case
    -- SELECT @dsn_dbname = 'DSN'
    SELECT @dsn_dbname = formatmessage(20586)
    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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull')
        BEGIN
            RAISERROR (14128, 16, -1)    
            RETURN (1)
        END

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

    /*
    ** Parameter Check: @offloadagent
    ** Valid values: 0 or 1 
    ** If @offloadagent = 1 then @subscription_type must be 'push'
    */
    IF (@offloadagent = 1 AND LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) <> 'push')
    BEGIN
        RAISERROR(21138, 16, -1)
        RETURN (1)
    END 


    /*
    ** Parameter Check: @offloadserver
    ** Make sure that @offlaod server doesn't contain any invalid characters
    */
    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode<>0 OR @@error<>0
        RETURN (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

   declare @allow_dts bit

   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,
        @allow_queued_tran_id = allow_queued_tran,
        @independent_agent_id = independent_agent,
		@allow_dts = allow_dts
		,@publication_queue_type = queue_type
    FROM syspublications WHERE name = @publication

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

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


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

	/* 
	** If publication is of concurrent sync, then all articles must
	** be subscribed to
	*/
	IF @sync_method IN( @concurrent, @concurrent_char) AND
	   LOWER(@article) != 'all' AND
	   @reserved != @internal
	BEGIN
		RAISERROR( 14100, 16, -1 )
		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) collate database_default
               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 not NULL
	begin
		EXECUTE @retcode = dbo.sp_validname @destination_db
		IF @retcode <> 0
		RETURN (1)
	end

    /*
    ** Parameter Check:  @article
    */

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

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

    IF (LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = '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','sync tran')
            RETURN (1)
        END
    END
    ELSE IF (LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'queued tran')
    BEGIN    	
		SELECT @update_mode_id = case 
			when (@publication_queue_type = 2) then 4
			else 2 end
       
        -- Check if publication allows this option
        -- If the publication allow synctran, it allows queued tran.
        IF @allow_queued_tran_id <> 1
        BEGIN
            RAISERROR (20503, 16, -1, '@update_mode', 'sp_addsubscription', 'queued tran')
            RETURN (1)
        END
    END
    ELSE IF (LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'failover')
    BEGIN
		SELECT @update_mode_id = case
			when (@publication_queue_type = 2) then 5
			else 3 end
       
        -- Check if publication allows this option
        IF @allow_sync_tran_id <> 1
        BEGIN
            RAISERROR (20503, 16, -1, '@update_mode', 'sp_addsubscription', 'sync tran')
            RETURN (1)
        END

        -- Check if publication allows this option
        IF @allow_queued_tran_id <> 1
        BEGIN
            RAISERROR (20503, 16, -1, '@update_mode', 'sp_addsubscription','queued tran')
            RETURN (1)
        END
    END
    ELSE 
    BEGIN
        SELECT @update_mode_id = 0
    END
    -- end SyncTran
    -- end Queued Tran

    /*
    ** Parameter Check: @dts_package_location
    ** Valid values:
    ** distributor
    ** subscriber
    **
    */
    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('distributor', 'subscriber')
    BEGIN
		RAISERROR(21179, 16, -1)    
        RETURN (1)
    END

	declare @dts_package_location_id int

    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = 'distributor'
        SELECT @dts_package_location_id = 0
    ELSE 
        SELECT @dts_package_location_id = 1

	-- Have to be a push, non updatable  subscription to set DTS package name
    if @dts_package_name is not null
	begin
		if	@subscription_type_id != 0
		begin
			RAISERROR(21181, 16, -1)    
			RETURN (1)
		end
		if	@allow_dts = 0
		begin
			RAISERROR(21178, 16, -1)    
			RETURN (1)
		end
	end
	
	/** 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 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 sysextendedarticlesview art
            WHERE art.pubid = @pubid 

		if @count_arts = 0
		BEGIN
            RAISERROR (14124, 16, -1)
            RETURN(1)
        END

        SELECT @count_subs = count(*) FROM syssubscriptions sub, 
                  sysextendedarticlesview art
            WHERE sub.srvid = @srvid
              AND sub.srvid >= 0
              AND sub.dest_db = @destination_db --or @non_sql_flag <> 0)
              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


	-- If the publication is 'allow_dts', push subscription has to specify a DTS package.
	-- Error check that disallow ODBC subscriber to subscriber with DTS package
	-- is at the distributor.
	-- Show dts error first, otherwise user will get 21060 below which is confusing
	IF @allow_dts <> 0 and @dts_package_name is null and @subscriber IS not NULL and
		@reserved is null and @subscription_type_id = 0
	begin
		raiserror(21213, 16, -1)
		return(1)
	end

    /* 
    ** Do special things for DSN subscribers.
    */
    IF @subscriber IS NOT NULL AND @non_sql_flag <> 0
    BEGIN
		-- DSN or oledb subscriber not using DTS 
		-- cannot subscribe to native mode or concurrent snapshot publication
        IF @sync_method <> @char_bcp and @dts_package_name is null
        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 sysextendedarticlesview 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
			
			declare @art_status tinyint

			select @art_status = sa.status, @artsrctabid = sa.objid 
			from sysarticles sa, syspublications sp
				where sa.pubid = sp.pubid 
				and sp.name = @publication
				and sa.name = @article

			-- OLEDB or ODBC subscriber can not subscribe to article with parameterized command 
			-- unless using DTS 
            IF @dts_package_name is null and @art_status & 16 = 16 
            BEGIN
                RAISERROR(21060, 16, -1, @subscriber)
                RETURN (1)
            END

			-- OLEDB or ODBC subscribers can not subscriber to article with subscriber managed
			-- timestamp column
			if @art_status & 32 = 32
			begin
				raiserror(21249, 16, -1, @article, @publication)
				return (1)
			end

        END
    END

    -- DNS may define db.  If no db given, specify that DSN default should be used.
    -- use internal values
	if @subscriber IS NOT NULL and @destination_db is NULL
	begin
		IF @non_sql_flag <> 0 
			SELECT @destination_db = @dsn_dbname
		else
			SELECT @destination_db = DB_NAME()
	end

	-- if we're subscribing to a dump type publication, error
	-- out if this subscriber has any other subscriptions to publications
	-- other than this one

	IF @sync_method = 2
	BEGIN
		IF EXISTS( SELECT * FROM syssubscriptions sub, sysextendedarticlesview art
				WHERE sub.srvid = @srvid
				  AND sub.srvid >= 0
				  AND sub.dest_db = @destination_db
				  AND sub.artid = art.artid
				  AND art.pubid != @pubid )
		BEGIN
			RAISERROR(21144, 16, -1)
			RETURN 1
		END
	END

	-- else if we're subscribing to a char or native mode publication, 
	-- error out if the subscriber is subscribed to any dump type publications
	ELSE
	BEGIN
		IF EXISTS( SELECT * FROM syssubscriptions sub, sysextendedarticlesview art, syspublications pub
				WHERE sub.srvid = @srvid
				  AND sub.srvid >= 0
				  AND sub.dest_db = @destination_db
				  AND sub.artid = art.artid
				  AND art.pubid != @pubid
				  AND pub.pubid = art.pubid
				  AND pub.sync_method = 2 )

		BEGIN
			RAISERROR(21145, 16, -1, @publication )
			RETURN 1
		END
	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 sysextendedarticlesview 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,
                                @offloadserver = @offloadserver,
                                @offloadagent = @offloadagent,
								@dts_package_name = @dts_package_name,
								@dts_package_password = @dts_package_password,
								@dts_package_location = @dts_package_location,
								@distribution_job_name = @distribution_job_name
    

                    IF @@error <> 0 OR @retcode <> 0
                    BEGIN
                       CLOSE 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)
    */

	declare @dest_owner sysname

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

    IF NOT EXISTS (SELECT *
                             FROM sysextendedarticlesview
                            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

    IF @non_sql_flag <> 0 AND @dest_owner is not null and @dest_owner <> N''
        BEGIN
			--RAISERROR (21039, 16, -1, @article, @subscriber)
			-- YWU: UNDONE fix the message after Beta2
			RAISERROR (21039, 16, -1)
            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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'manual', 'none')
       BEGIN
           RAISERROR (14052, 16, -1)
           RETURN (1)
       END

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


   IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
   BEGIN
        SELECT @sync_typeid = @automatic
   END
   ELSE
   BEGIN
        SELECT @sync_typeid = @none
   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 collate SQL_Latin1_General_CP1_CS_AS) 
        NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@loopback_detection')
        RETURN (1)
    END

    IF  LOWER(@loopback_detection collate SQL_Latin1_General_CP1_CS_AS) = 'true'  
        SELECT @loopback_detection_id = 1
    ELSE IF LOWER(@loopback_detection collate SQL_Latin1_General_CP1_CS_AS) = 'false' 
        SELECT @loopback_detection_id = 0
    ELSE 
    -- if @loopback_detection is null, we will chose the value
    begin
	    -- turn on loopback detection for sync and queued
		if @update_mode_id in (1,2,3,4,5) 
            select @loopback_detection_id = 1
        else
            select @loopback_detection_id = 0
    end

	select @dts_package_enc_password = @dts_package_password
	if @dts_package_password is not null
	begin
		EXEC @retcode = master.dbo.xp_repl_encrypt @dts_package_enc_password OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end

	--
	-- For updating subscriptions (immediate)
	-- Check if there exists an subscription to the same
	-- dest_db which contain at least one article which has 
	-- the same source_table as the current article - 
	-- If yes then raise a warning
	-- NOTE : this restriction is due to the fact that loopback
	-- detection happens at database level and hence for updating
	-- subscriptions, we can lose the updates made in one subscription
	-- w.r.t. the other subscription
	--
	if (@update_mode_id = 1)
	begin
		if exists (select * from dbo.syssubscriptions 
			where srvid = @srvid and dest_db = @destination_db and artid in 
				(select artid from dbo.sysarticles 
					where objid = (select objid from sysarticles where artid = @artid)))
		begin
			raiserror(21293, 10, 1, @article, @destination_db)
		end
	end

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

    /*
    ** If no subscription exists, add it to syssubscriptions.
    */
    IF NOT EXISTS (SELECT *
                     FROM syssubscriptions
                    WHERE srvid = @srvid
                      AND artid = @artid
                      AND dest_db = @destination_db )--or @non_sql_flag <> 0))
        BEGIN
       INSERT syssubscriptions (artid,
                                    srvid,
                                    dest_db,
                                    login_name,
                                    status,
                                    sync_type,
                                    subscription_type,
                                    distribution_jobid,
                                    -- SyncTran
                                    update_mode,
                                    loopback_detection,
                                    queued_reinit)
                                 /*  timestamp) */
       VALUES (@artid,
                   @srvid,
                   @destination_db,    
                   suser_sname(suser_sid()),
                   @inactive,
                   @sync_typeid,
                   @subscription_type_id,
                   0,
                   -- SyncTran
                   @update_mode_id,
                   @loopback_detection_id,
                   1)
           /*  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,
    @offloadagent = @offloadagent,
    @offloadserver = @offloadserver,
	@dts_package_name = @dts_package_name,
	@dts_package_password = @dts_package_enc_password,
	@dts_package_location = @dts_package_location_id,
	@distribution_job_name = @distribution_job_name  
    
	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 sysextendedarticlesview 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,
        @offloadagent = @offloadagent,
        @offloadserver = @offloadserver

        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 collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = '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 = password
                    from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername) collate database_default
                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 = @distributor_password,
                                    @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

grant execute on dbo.sp_addsubscription to public
go

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

raiserror(15339,-1,-1,'sp_MSchangeschemaarticle')
GO

CREATE PROCEDURE sp_MSchangeschemaarticle (
    @pubid int,
    @artid int,
    @property sysname,
    @value nvarchar(255)
    ) AS
    SET NOCOUNT ON
    DECLARE @retcode int
    DECLARE @pre_creation_cmdid tinyint
    DECLARE @statusid int
    DECLARE @schema_option_table_created bit
    DECLARE @creation_script nvarchar(255)
    DECLARE @type tinyint
    DECLARE @schema_option binary(8)
    DECLARE @valid_schema_options int

    SELECT @type = type 
      FROM sysextendedarticlesview
     WHERE artid = @artid
       AND pubid = @pubid 

    SELECT @schema_option_table_created = 0

    /* 
    ** The pubid and artid passed into this procedure from sp_changearticle
    ** have to be valid by now.
    */
    
    /*
    ** Parameter check: @property
    */
    SELECT @property = LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)
    IF @property NOT IN ('description',
                         'dest_object',
                         'creation_script',
                         'pre_creation_cmd',
                         'schema_option',
                         'destination_owner')
    BEGIN
        RAISERROR(21224, 16, -1, @property)
        RETURN (1)
    END
                         
    -- Since all property changes will take the form of 
    -- simple update stataments, no transaction will be 
    -- started. 

    IF @property = N'description'
    BEGIN
        UPDATE sysschemaarticles 
           SET description = @value
         WHERE artid = @artid
           AND pubid = @pubid

        IF @@ERROR <> 0
            RETURN (1)
    END
    ELSE IF @property = N'dest_object'
    BEGIN
        UPDATE sysschemaarticles
           SET dest_object = @value
         WHERE artid = @artid
           AND pubid = @pubid 

        IF @@ERROR <> 0
            RETURN (1)
    END
    ELSE IF @property = N'creation_script'
    BEGIN
        UPDATE sysschemaarticles 
           SET creation_script = @value
         WHERE artid = @artid
           AND pubid = @pubid

        IF @@ERROR <> 0
            RETURN (1)
    END
    ELSE IF @property = N'pre_creation_cmd'
    BEGIN
        /* 
        ** Validate the given value for
        ** the property. It has to be either 
        ** 'none' or 'drop' case-insensitive.
        */
        SELECT @value = LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)
        IF @value NOT IN ('none', 'drop')
        BEGIN
            RAISERROR(21223, 16, -1)
            RETURN (1)
        END

        IF @value = N'none'
            SELECT @pre_creation_cmdid = 0
        ELSE IF @value = N'drop'
            SELECT @pre_creation_cmdid = 1
        
        UPDATE sysschemaarticles
           SET pre_creation_cmd = @pre_creation_cmdid
         WHERE artid = @artid
           AND pubid = @pubid
        
        IF @@ERROR <> 0
            RETURN (1)

    END
    ELSE IF @property = N'schema_option'    
    BEGIN
        
        IF @value IS NULL
        BEGIN
            RAISERROR(14146, 16,1)
            RETURN (1)
        END

        CREATE TABLE #tab_changeschemaarticle (value varbinary(8) NULL)
        IF @@ERROR <> 0
        BEGIN
           RETURN (1)
        END

        EXEC ('insert #tab_changeschemaarticle values (' + 
            @value + ')')

        IF @@ERROR <> 0
        BEGIN
            DROP TABLE #tab_changeschemaarticle 
            RETURN (1)
        END
        
        SELECT @schema_option = fn_replprepadbinary8(value) 
          FROM #tab_changeschemaarticle
        /*
        ** schema_option can only contain the bits 0x0000000000000001 and
        ** 0x0000000000002000
        ** for schema only articles except view. View articles can contain 
        ** the options 0x0000000000000010, 0x0000000000000020, 
        ** and 0x0000000000000100 in addition to the aforementioned options.
        */
        IF @type = 0x40
        BEGIN

            -- Since only the lower 32 bits of @schema_option are
            -- currently used, the following check is sufficient.
            -- Note that @schema_option should have been padded by now.
            DECLARE @schema_option_lodword int
            SELECT @valid_schema_options = 0x2151
            SELECT @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
            IF (@schema_option_lodword & ~@valid_schema_options) <> 0
            BEGIN
                RAISERROR (21229, 16, -1)
                RETURN (1)
            END
        END
        ELSE IF @schema_option NOT IN (0x0000000000000000,
                                       0x0000000000000001,
                                       0x0000000000002000,
                                       0x0000000000002001)
        BEGIN
            DROP TABLE #tab_changeschemaarticle
            RAISERROR (21222, 16, -1)
            RETURN (1)
        END 

        IF EXISTS (SELECT * FROM #tab_changeschemaarticle
                    WHERE value = 0x0000000000000000)
        BEGIN
        
            SELECT @creation_script = NULL
            SELECT @creation_script = creation_script
              FROM sysschemaarticles
             WHERE artid = @artid
               AND pubid = @pubid
/*            
            IF @creation_script IS NULL OR
               @creation_script = N''
            BEGIN
                RAISERROR(21218, 16, -1)
                DROP TABLE #tab_changeschemaarticle
                RETURN (1)
            END
*/
        END
            
        UPDATE sysschemaarticles
           SET schema_option = tab.value
          FROM #tab_changeschemaarticle tab
         WHERE artid = @artid 
           AND pubid = @pubid         
            
        IF @@ERROR <> 0
        BEGIN
            DROP TABLE #tab_changeschemaarticle
            RETURN (1)
        END    

        DROP TABLE #tab_changeschemaarticle

        IF @@ERROR <> 0
            RETURN (1)
    END
    ELSE IF @property = N'destination_owner'
    BEGIN
        
        UPDATE sysschemaarticles
           SET dest_owner = @value
         WHERE artid = @artid
           AND pubid = @pubid

        IF @@ERROR <> 0
            RETURN (1)
    END    

    RAISERROR (14025, 10, -1)
    RETURN (0)
GO

EXEC dbo.sp_MS_marksystemobject sp_MSchangeschemaarticle
GO

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

raiserror(15339,-1,-1,'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 */
	@force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
) AS
BEGIN

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

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

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

			,@distributor sysname
			,@distribdb sysname
			,@dbname sysname
			,@distproc nvarchar (255)
			,@dts_part nvarchar(50)
			,@no_dts_part nvarchar(50)
			,@backward_comp_level int
			,@allow_dts bit
			,@allow_queued_tran bit

	select @backward_comp_level = 10 -- default to sphinx
			,@dts_part = N'dts horizontal partitions'
			,@no_dts_part = N'no dts horizontal partitions'
			,@active = 2
			,@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() collate database_default) = 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
		,@allow_dts = allow_dts
		,@allow_queued_tran = allow_queued_tran
	FROM syspublications 
	WHERE name = @publication

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

    /*
    ** Check to see that the article exists in sysextendedarticlesview.
    ** 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, @article_type = type, @objid = objid 
      FROM sysextendedarticlesview
     WHERE name = @article
       AND pubid = @pubid
    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END


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

    SELECT @objtype = type
       FROM sysobjects
       WHERE id = @objid

    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 collate database_default not null)
            INSERT INTO #tab1 VALUES ('description')
            INSERT INTO #tab1 VALUES ('sync_object (log based article only)')
            INSERT INTO #tab1 VALUES ('type')
            INSERT INTO #tab1 VALUES ('ins_cmd (log based article only)')
            INSERT INTO #tab1 VALUES ('del_cmd (log based article only)')
            INSERT INTO #tab1 VALUES ('upd_cmd (log based article only)')
            INSERT INTO #tab1 VALUES ('filter (log based article only)')
            INSERT INTO #tab1 VALUES ('dest_table (log based article only)')
            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')
   			INSERT INTO #tab1 VALUES ('pub_identity_range (log based article only)')
			INSERT INTO #tab1 VALUES ('identity_range (log based article only)')
			INSERT INTO #tab1 VALUES ('threshold (log based article only)')
            PRINT ''
            SELECT * FROM #tab1
            RETURN (0)
        END

    /*
    ** At this point, we have completed all the validations and 
    ** preprocessings common to both regular and schema only articles 
    ** so we call a different proceudre here to handle the schema only
    ** articles differently.
    */
    
    IF @article_type in (0x20, 0x40, 0x80)
    BEGIN
        EXEC @retcode = sp_MSchangeschemaarticle 
                @pubid = @pubid,
                @artid = @artid,
                @property = @property,
                @value = @value    
        RETURN @retcode
    END  

    IF @objtype = 'U' AND LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) 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',
                                                    'pub_identity_range',
                                                    'identity_range',
                                                    'threshold')
        BEGIN
            RAISERROR (21183, 16, -1, @property)
            RETURN (1)
        END

    IF @objtype = 'P' AND LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'dest_object'
        SELECT @property = 'dest_table' 

	
	IF (@allow_dts = 1 or @allow_queued_tran = 1) and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('ins_cmd', 'del_cmd', 'upd_cmd' )
	begin
		raiserror(21175, 16, -1)
		return (1)
	end
	
	/*
	** Check to make sure that we have a valid type for status
	*/
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status'
    BEGIN
		IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('not owner qualified', 'owner qualified')
		BEGIN
			RAISERROR (21023, 16, -1,@value)
			RETURN (1)
		END

		IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('no column names', 'include column names', 'string literals', 'parameters',
			@dts_part, @no_dts_part )
		BEGIN
			RAISERROR (14097, 16, -1)
			RETURN (1)
		END

		IF	LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) in (@dts_part,@no_dts_part)
		begin
			if @allow_dts = 0
			begin
				-- Invalid status for non dts pub
				raiserror(20592, 16, -1)
				RETURN (1)
			end
		end
		else
		begin
			if @allow_dts = 1
			begin
				-- Invalid status for dts pub
				raiserror(20591, 16, -1)
				RETURN (1)
			end
		end
	end
	
	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ( 'ins_cmd', 'del_cmd', 'upd_cmd' )
	BEGIN
		if exists (select * from syspublications 
		where
		pubid = @pubid and sync_method = 3) and lower(@value) not like '%call%'
		BEGIN
			RAISERROR( 21154, 16, -1, @article )
			return 1
		END
	END

	declare @need_new_snapshot bit
		,@need_reinit_subscription bit

	select @need_new_snapshot = 0
	select @need_reinit_subscription = 0

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ( N'ins_cmd', N'del_cmd', N'upd_cmd', 
        N'dest_table', N'destination_owner' ,N'type',N'filter',  
		N'pre_creation_cmd', N'schema_option') or 
		(LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status' and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) in (@dts_part,
		@no_dts_part))
	begin
		select @need_new_snapshot = 1
		select @need_reinit_subscription = 1
	end
	else if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('sync_object',
		'creation_script')
	begin
		select @need_new_snapshot = 1
	end

	-- Have to call this stored procedure to invalidate existing snapshot or reint
	-- subscriptions if needed
	EXECUTE @retcode  = dbo.sp_MSreinit_article
		@publication = @publication, 
		@article = @article,
		@need_new_snapshot = @need_new_snapshot,
		@need_reinit_subscription = @need_reinit_subscription
		,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
		,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
		,@check_only = 1
	IF @@ERROR <> 0 OR @retcode <> 0
		return(1)

    /*
    ** Change the property.
    */

    begin tran
    save TRAN sp_changearticle

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'dest_table' OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) + ' = 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 collate SQL_Latin1_General_CP1_CS_AS) + ' = ''' + @value + ''''
                SELECT @cmd2 = ' WHERE artid = ' + STR(@artid)
                SELECT @cmd2 = @cmd2 + '   AND pubid = ' + STR(@pubid)
                EXECUTE (@cmd1 + @cmd2)
            END

            IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'upd_cmd'
            BEGIN
                IF ( 0 <> ( SELECT PATINDEX( '%[789].[0-9]%', @@version ) ) ) OR
                   ( 0 <> ( SELECT PATINDEX( '%[1-9][0-9].[0-9]%', @@version ) ) )
                BEGIN
                    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 collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = 'type'
            BEGIN

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) IN ('logbased', 'indexed view logbased')
            SELECT @typeid = 1
            ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('logbased manualfilter', 'indexed view logbased manualfilter')
            SELECT @typeid = 3
            ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('logbased manualview', 'indexed view logbased manualview')
            SELECT @typeid = 5
            ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('logbased manualboth', 'indexed view 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 collate SQL_Latin1_General_CP1_CS_AS) = '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

                    ------------------------------------------------------
                    -- 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 collate SQL_Latin1_General_CP1_CS_AS) = 'pre_creation_cmd'
            BEGIN

                /*
                ** Check to make sure that we have a valid pre_creation_cmd.
                */
            IF @objtype = 'P' and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'none'
                    SELECT @precmdid = 0
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
                    SELECT @precmdid = 1
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
                    SELECT @precmdid = 2
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) = 'status'
            BEGIN
                /*
                ** Determine the integer value for the type.
                */
                IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'not owner qualified'
                    UPDATE sysarticles 
                    SET status = status & ~4
                    WHERE artid = @artid
                                  AND pubid = @pubid

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

                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'string literals'
                    UPDATE sysarticles 
                    SET status = status & ~16
                    WHERE artid = @artid
                                  AND pubid = @pubid
                     
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'parameters'
                    UPDATE sysarticles 
                    SET status = status | 16
                    WHERE artid = @artid
                                  AND pubid = @pubid
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = @dts_part
				begin
					if exists (select * from sysarticles where
						artid = @artid and
						status & 64 = 0)
					begin
						UPDATE sysarticles 
							SET status = status | 64,
								upd_cmd = N'XCALL sp_MSXpd_' + @article
							WHERE artid = @artid
					end
				end
                ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = @no_dts_part
				begin
					if exists (select * from sysarticles where
						artid = @artid and
						status & 64 <> 0)
					begin
						UPDATE sysarticles 
							SET status = status & ~64,
								upd_cmd = N'CALL sp_MSupd_' + @article
							WHERE artid = @artid
					end
                end
                IF @@ERROR <> 0 
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
            END

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = '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 varbinary(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

				--
				-- For queued updating publications
				-- DRI option has to be included
				--
				if ((@allow_queued_tran = 1) and 
					exists (select * from #tab_changearticle where 
						fn_replgetbinary8lodword(fn_replprepadbinary8(value)) & 0x8000 = 0))
				BEGIN
					RAISERROR (21394, 16, 2)
					if @@trancount > 0
					begin
						ROLLBACK TRAN sp_changearticle
						commit tran
					end
					RETURN (1)
				END

                -- Seems to be a good place to check and see if using 
                -- collation 0x00001000 or extended property 0x00002000
	            declare @schema_option_int int
	            select @schema_option_int  = 
                    fn_replgetbinary8lodword(fn_replprepadbinary8(value)) 
                from #tab_changearticle
	            if ((@schema_option_int & 0x000001000 <> 0) or 
                    (@schema_option_int & 0x000002000 <> 0))
		        select @backward_comp_level = 40
                -- End 
               
                UPDATE sysarticles 
                   SET schema_option = fn_replprepadbinary8(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 collate SQL_Latin1_General_CP1_CS_AS) = 'destination_owner'
            BEGIN
                IF @value IS NOT NULL
                BEGIN
                    EXECUTE @retcode = dbo.sp_validname @value

                    IF @retcode <> 0
                    BEGIN
                        if @@trancount > 0
                        begin
                            ROLLBACK TRAN sp_changearticle
                            commit tran
                        end
                        RETURN (1)
                    END
                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

	       
	    if  LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pub_identity_range'
        begin
            if not exists (select * from sysarticleupdates where artid = @artid and
                identity_support = 1)
            begin
                raiserror(21235, 16, -1, @property)
                goto UNDO
            end

            declare @pub_range bigint
            select @pub_range = convert(bigint, @value) 
            if @pub_range < 0
            begin
                raiserror(21232, 16, -1)
                goto UNDO
            end

            if exists (select * from MSpub_identity_range where objid = @objid and
                pub_range < 0)
                select @pub_range = @pub_range * -1
			
            update MSpub_identity_range set
                pub_range = @pub_range 
                where objid=@objid
            if @@error < 0
                goto UNDO
        end
                
	    if  LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'identity_range'
        begin
            if not exists (select * from sysarticleupdates where artid = @artid and
                identity_support = 1)
            begin
                raiserror(21235, 16, -1, @property)
                goto UNDO
            end

            declare @range bigint
            select @range = convert(bigint, @value) 
            if @range < 0
            begin
                raiserror(21232, 16, -1)
                goto UNDO
            end

            if exists (select * from MSpub_identity_range where objid = @objid and
                range < 0)
                select @range = @range * -1
			
            update MSpub_identity_range set
                range = @range 
                where objid=@objid
            if @@error < 0
                goto UNDO

            -- Distributor side data will be changed later by sp_MSchange_article.
        end

		-- Check to see if the range is too big.
		-- Must be down after the change. If the check fails, the transaction
		-- will be rolled back.
		if  LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('pub_identity_range', 'identity_range')
		begin
			declare @pub_identity_range bigint, @identity_range int
			select @pub_identity_range = pub_range, 
				@identity_range = range from MSpub_identity_range where
				objid = @objid 

			declare @xtype int, @xprec int, @max_range bigint
			select @xtype=xtype, @xprec=xprec from syscolumns where id=@objid and 
				columnproperty(id, name, 'IsIdentity')=1
			select @max_range =
					case @xtype when 52 then power((convert(bigint,2)), 8*2-1) - 1 --smallint 
						when 48 then power((convert(bigint,2)), 8-1) - 1 		 --tinyint
						when 56 then power((convert(bigint,2)), 8*4-1) - 1 		 --int
						when 127 then power((convert(bigint,2)), 62) - 1 + power((convert(bigint,2)), 62)  	--bigint
       					when 108 then power((convert(bigint,10)), @xprec) 	 --numeric
       					when 106 then power((convert(bigint,10)), @xprec) 	 --decimal
 					else
						power((convert(bigint,2)), 62) + power((convert(bigint,2)), 62) - 1  -- defaulted to bigint
					end
		
			declare @source_table nvarchar (386)
			exec @retcode = dbo.sp_MSget_qualified_name @objid, @source_table output
			if @retcode <> 0 or @@error <> 0
				goto UNDO
			if @pub_identity_range * 2 + @identity_range > (@max_range - IDENT_CURRENT(@source_table))
				begin
					raiserror(21290, 16, -1)
					goto UNDO
				end
		end

        if  LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'threshold'
        begin
            if not exists (select * from sysarticleupdates where artid = @artid and
                identity_support = 1)
            begin
                raiserror(21235, 16, -1, @property)
                goto UNDO
            end

            declare @threshold bigint
            select @threshold = convert(int, @value) 
            if @threshold < 1 or @threshold > 100
            begin
                raiserror(21233, 16, -1)
                goto UNDO
            end

            update MSpub_identity_range set
                threshold = @threshold
                where objid=@objid
            if @@error < 0
                goto UNDO
            -- Distributor side data will be changed later by sp_MSchange_article.
        end

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

		if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ( N'description', N'dest_table', N'dest_object', 
            'identity_range', 'threshold' )
		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 @distproc = RTRIM(@distributor) + '.' + @distribdb + 
				'.dbo.sp_MSchange_article'
			EXECUTE @retcode = @distproc
				@publisher = @@SERVERNAME,
				@publisher_db = @dbname,
				@publication = @publication,
				@article = @article,
				@article_id = @artid,
				@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

		-- Have to call this stored procedure to invalidate existing snapshot or reint
		-- subscriptions if needed
		EXECUTE @retcode  = dbo.sp_MSreinit_article
			@publication = @publication, 
			@article = @article,
			@need_new_snapshot = @need_new_snapshot,
			@need_reinit_subscription = @need_reinit_subscription
			,@force_invalidate_snapshot = @force_invalidate_snapshot	/* Force invalidate existing snapshot */
			,@force_reinit_subscription = @force_reinit_subscription	/* Force reinit subscription */
		IF @@ERROR <> 0 OR @retcode <> 0
			GOTO UNDO


if @backward_comp_level > 10
	update syspublications set backward_comp_level = @backward_comp_level where pubid = @pubid
    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)

UNDO:
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_changearticle
        COMMIT TRAN
    end
    return(1)
END
go
 
dump tran master with no_log
go

EXEC dbo.sp_MS_marksystemobject sp_changearticle
GO

grant execute on dbo.sp_changearticle to public
go


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

raiserror(15339,-1,-1,'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
	DECLARE @ad_guidname sysname
    DECLARE @alt_snapshot_folder nvarchar(255)
    DECLARE @pub_alt_snapshot_folder nvarchar(255)
	
    SELECT @virtual_id = -1
    select @dbname = db_name()
	select @ad_guidname = NULL
    /*
    ** 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 sysextendedarticlesview 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, sysextendedarticlesview 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.
    */

    EXECUTE dbo.sp_droparticle @publication = @publication, 
        @article = N'all',
        @ignore_distributor = @ignore_distributor
		, @force_invalidate_snapshot = 1
    IF @@ERROR <> 0 OR  @retcode <> 0
		RETURN (1)

	select @ad_guidname = ad_guidname,
           @alt_snapshot_folder = alt_snapshot_folder 
      from syspublications 
     where name=@publication

    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
        
        /*
        ** If alternate snapshot folder is specified for this publication,
        ** try to remove the publication's snapshot folder underneath the
        ** the alternate snapshot location in Distributor's context
        */
        if @alt_snapshot_folder is not null and
           @alt_snapshot_folder <> N''
        begin

            /* Append publication specific folder name */
            if substring(@alt_snapshot_folder,len(@alt_snapshot_folder),1)<>
                N'\'
            begin
                select @alt_snapshot_folder = @alt_snapshot_folder + N'\'
            end 

            -- UNC version
            select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'unc\' + fn_replcomposepublicationsnapshotfolder(@@servername,db_name(),@publication) collate database_default
            select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + N'.'  + fn_replquotename(@distribdb) collate database_default + 
                N'.dbo.sp_MSreplremoveuncdir'
            -- Ignore errors as the snapshot folder may not exist at all
            EXECUTE @distproc
                @dir = @pub_alt_snapshot_folder

            -- FTP-enabled version
            select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'ftp\' + fn_replcomposepublicationsnapshotfolder(@@servername,db_name(),@publication) collate database_default
            select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + N'.'  + fn_replquotename(@distribdb) collate database_default + 
                N'.dbo.sp_MSreplremoveuncdir'
            -- Ignore errors as the snapshot folder may not exist at all
            EXECUTE @distproc
                @dir = @pub_alt_snapshot_folder
        end
    end

	DECLARE @retval  INT
	EXECUTE @retval = master.dbo.xp_MSADEnabled
    if @ad_guidname is not NULL 
    begin
    	if @retval = 0
		begin
    		exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @dbname, @ad_guidname
			if @@ERROR<>0 or @retcode<>0
			begin
				raiserror(21369, 16, -1, @publication)
				goto UNDO
			end
    	end
    	else
    	begin
			RAISERROR(21254, 16, -1, @publication)
    		GOTO UNDO
    	end
    end

    COMMIT TRAN

	-- Since we drop publisher_database_id in sp_MSdrop_publication at the distribution db when
	-- dropping the last tran (snapshot) publication, we should call repldone here to clear
	-- repl counters and lsns. This will ensure the correctness of repl counters and avoid
	-- unnecessary log scan in the logreader if it is created again after this.
	-- Ignore all errors.
	if not exists (select * from syspublications)
	begin
		DECLARE @replicate_bit	smallint
		SELECT @replicate_bit = 2

		-- Used for attach and restored db.
		-- sysservers table in master db might be changed so that
		-- sp_dropsubscription won't work, which left repl bits marked in
		-- sysobjects.
		-- We have to unmark them before calling sp_repldone, otherwise
		-- A new transaction updating those objects will be considered
		-- as repl tran. It will set the truncation point to not null, which will
		-- prevent log truncation.
		UPDATE sysobjects SET replinfo =  replinfo & ~@replicate_bit

		/* ensure we can get in as logreader */
	    exec dbo.sp_replflush

		/* clear repl dbtable fields unmark all xacts marked for replication */
		exec dbo.sp_repldone NULL, NULL, 0, 0, 1
    
	    /* release our hold on the db as logreader */
	    EXEC dbo.sp_replflush

		-- Run checkpoint to make sp_repldone result durable (write repl dbtable fields
		-- into the checkpoint record).
		checkpoint
	end	    

    return (0)  
    
UNDO:
    if @@TRANCOUNT = 1
        ROLLBACK TRAN
    else
        COMMIT TRAN
    return(1)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_droppublication
GO

grant execute on dbo.sp_droppublication to public
go


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

raiserror(15339,-1,-1,'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)
    /*
    ** Initialization
    */

    SELECT @dbname = DB_NAME()

    /*
    ** Parameter check
    ** @value
    */
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'true'
                RAISERROR (20028, 16, -1)
            ELSE
                RAISERROR (20029, 16, -1)
            RETURN (1)
        END
    end

    /*
    ** Enable the database for publishing.
    */
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = '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.

		delete syssubscriptions where srvid >= 0
        IF @@ERROR <> 0 
        BEGIN
            return (1)
        END

        /*
        ** Remove all publications and articles in the database.
		** sp_droppublication will also forcefully unmark repl bits in sysobjects
		** and call sp_repldone when dropping the last
		** publication.
        */
        EXEC @retcode = dbo.sp_droppublication @publication = 'all', 
            @ignore_distributor = @ignore_distributor
        IF @@ERROR <> 0 or @retcode <> 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
    return (0)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSpublishdb
GO



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

raiserror(15339,-1,-1,'sp_MSactivate_auto_sub')
GO

CREATE PROCEDURE sp_MSactivate_auto_sub (
    @publication sysname,        /* Publication name */
    @article sysname,
	@status sysname = 'active',
    @schemastabilityonly int = 0
    ) 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() collate database_default) = 0

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

	-- parameter check: @status:  

	IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) not in (N'active', N'initiated')
	BEGIN
		RAISERROR(21156, 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

	IF @status = N'active'
	BEGIN
		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
	END

    EXECUTE @retcode = dbo.sp_changesubstatus 
        @publication = @publication,
        @article = @article,
        @status = @status,
        @from_auto_sync = 1,
        @schemastabilityonly = @schemastabilityonly

    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

grant exec on dbo.sp_MSactivate_auto_sub to public
go

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

raiserror(15339,-1,-1,'sp_MSis_identity_insert')
GO

create procedure sp_MSis_identity_insert
@publication sysname,
@article sysname,
@identity_insert bit output,
@artid int = NULL	-- If pass in @artid, you don't need to pass in 
					-- @publication and @article
as
	declare @pubid int, @source_objid int
		,@columns      binary(32)
	
	select @identity_insert = 0

	-- Get @artid if not there
	-- If the publication is not queued
	if @artid is null
	begin
		select @pubid = pubid from syspublications where name = @publication
		select @artid = artid from sysarticles where
			pubid = @pubid and
			name = @article
	end		

	-- Get @pubid from @artid
	if @pubid is null
		select @pubid = pubid	from sysarticles where 
			artid = @artid

	if exists (select * from syspublications where
		pubid = @pubid and
		allow_queued_tran = 1)
	begin
		select @source_objid = objid, @columns = columns from sysarticles where
			artid = @artid and
			OBJECTPROPERTY(objid, 'tablehasidentity') = 1
		if @source_objid is not null
		begin
			declare @colid smallint, @in_partition int
			select @colid = colid from syscolumns where id = @source_objid and
				COLUMNPROPERTY(@source_objid, name, 'IsIdentity') = 1
			exec @in_partition = sp_isarticlecolbitset @colid, @columns
			if @in_partition = 1
				select @identity_insert = 1
		end
	end
	return @identity_insert
go

EXEC dbo.sp_MS_marksystemobject sp_MSis_identity_insert
GO



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

raiserror('Creating procedure sp_MSscript_insert_pubwins', 0,1)
go
create procedure sp_MSscript_insert_pubwins (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32) )
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner sysname
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(512)
			,@cast_str nvarchar(1000)
			,@decl_str nvarchar(2000)
			,@assign_str nvarchar(4000)
			,@typestring nvarchar(100)
			,@exec_str nvarchar(1000)

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
				
	--
	-- start script generation
	--
	select @cmd = N'
	else if (@error in (0, 547, 2627) and @execution_mode = @QPubWins)
	begin
		' + N'--
		' + N'-- Publisher Wins resolution
		' + N'-- Find where we have to generate compensating action
		' + N'--
		if (@rowcount = 1 and @error = 0)
		begin'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			' + N'--
			' + N'-- No conflict for this command
			' + N'-- Row does not exist
			' + N'-- Generate delete compensating action
			' + N'--
			select @cftcase = 23'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- Continue with scripting
	--
	select @cmd = N'
		end
		else if (@rowcount = 0 and @error in (547, 2627))
		begin
			' + N'--
			' + N'-- conflict for this command
			' + N'-- Row already exists
			' + N'-- generate update compensating action
			' + N'-- DELETE compensating command + INSERT compensating command
			' + N'--			
			select @cftcase = 21'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- continue with scripting
	--			
	select @cmd = N'		
		end
		else
			return -1

		' + N'--
		' + N'-- generate compensating command according to the cases
		' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
		if (@cftcase in (21,23))
		begin
			' + N'--
			' + N'-- delete compensating command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	
	--
	-- Generate the delete compensating code
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + @dest_owner + quotename(@dest_table) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1

	select @cmd = N'
		end

		if (@cftcase = 21)
		begin
			' + N'--
			' + N'-- insert compensating command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- generate the compensating insert command
	--
	exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 0

	--
	-- continue with scripting
	--			
	select @cmd = N'		
		end
	end'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	return 0	
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_insert_pubwins
GO

grant execute on dbo.sp_MSscript_insert_pubwins to public
go

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

raiserror(15339,-1,-1,'sp_MSscript_compensating_insert')
GO

create procedure sp_MSscript_compensating_insert (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@proctype	int = 1)		-- 0 = use new_pk, 1 = use old_pk
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner sysname
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(512)
			,@cast_str nvarchar(4000)
			,@column_string nvarchar(4000)
			,@ins_cmd nvarchar(255)
			,@startoffset int
			,@setprefix bit
			,@commandlen int
			,@fragmentlen int
			,@collen int
			,@first_time bit
			,@fullcastlen int
			,@splitlen int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, 
		@dest_owner = dest_owner, @ins_cmd = ins_cmd from sysarticles 
	where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- The compensating command will be split into one or more
	-- fragment commands if the length exceeds 3450 characters in length 
	-- (to accomodate compensating server/db names)
	-- For correctly estimating the length of the compensating command
	-- we have to take the max column length of the data into consideration along
	-- with the scripting command length
	--

	--
	-- use the insert command if available
	--
	select @commandlen = 0
			,@setprefix = 1

	if (@ins_cmd = N'SQL')
	begin
		select @cmd = N'
			select @cmd = ''INSERT INTO ' + @dest_owner + quotename(@dest_table) + N''' + 
		 				'' SELECT '' + '
	end
	else
	begin
		select @cmd = N'
			select @cmd = ''EXEC ' + substring(@ins_cmd, 5, len(@ins_cmd) - 4) + N' '' + '
	end
	insert into #proctext(procedure_text) values( @cmd )
 	select @commandlen = @commandlen + len(@cmd)
	
	select @num_col = 0
	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid, length from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col, @collen
	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) not like N'timestamp' 
			begin
				select @num_col = @num_col + 1

				--
				-- Compute the command fragment length needed for this column
				-- based on the coltype
				--				
				if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('ntext','text','image'))
				begin
					--
					-- For compensating commands we have to include the text and image data
					-- as the custom procs used by Distribution process expects them - as it
					-- done for regular transactional replication - but we will only send NULLs
					-- as it is not possible to ascertain the size of the data during the generation
					--		
					select @cast_str = N' ''null'' '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
				begin
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
						select @collen = (@collen / 2)
	
					select @cast_str = case 
							when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
								then N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
								else N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
							end
	   
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
				begin
					--
					-- each byte has 2 nibbles - we need a char to represent each nibble
					--
					select @collen = @collen * 2
					select @cast_str = N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' + quotename(@colname) + N',1,0) collate database_default, ''null'') '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen + 2
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CONVERT(nvarchar(40),' + quotename(@colname) + N',2), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CAST(' + quotename(@colname) + N' as nvarchar(40)) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 121) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
				begin
					--
					-- need to revisit this later
					--
					select @cast_str = N' ISNULL(master.dbo.fn_sqlvarbasetostr(' + quotename(@colname) + N' ) collate database_default, ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end					
				else
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
			
				--
				-- for fixed datatypes - we will not split the data at all we will
				-- flush the command script and continue
				-- for varying/large datatypes, we will have to split data if necessary
				--
				if ((lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar','binary','varbinary')) 
						and (@fragmentlen + @commandlen > 3450))
				begin
			 		--
			 		-- the column length is too big, we have to break the data string
			 		-- initialize
			 		--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' 
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' 
					end

					--
					-- use substring to break the string value in the
					-- compensating command
					--
					select @first_time = 1
							,@startoffset = 1
					while (@collen > 0)
					begin
				 		select @splitlen = case when ((@first_time = 1) or (@collen > 3450))
				 								then (3450 - @commandlen - 30 - @fullcastlen)
				 								else @collen end
				 		if (@splitlen < 1)
				 		begin
				 			--
				 			-- we have overcompensated the splitlen
				 			-- set to half of the column length
				 			--
				 			select @splitlen = @collen / 2
				 		end

						--
						-- Do we need to put quotes (many datatypes need it)
						--
					 	if (@first_time = 1)
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
								select @column_string = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
										then @column_string + N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr( '
										else @column_string + N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr( '
									end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' 
						end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
						 		select @column_string = N' + ISNULL(master.dbo.fn_MSgensqescstr( '
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' + ISNULL(master.dbo.fn_varbintohexsubstring(0,' 
					 	end

						--
						-- prepare the substring script
						--
						if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							select @cast_str = N'SUBSTRING(' + quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast(@splitlen as nvarchar) + N')'
						else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
							select @cast_str = quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast((@splitlen/2) as nvarchar)

						if (@first_time = 1)
					 	begin
							select @cast_str = @cast_str + N') collate database_default, ''null'') '
									,@first_time = 0
					 	end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							begin
								--
								-- for strings the last fragment needs the single
								-- quote to be added for the string
								--
								select @cast_str = @cast_str + N') collate database_default '
								select @cast_str = case 
									when (@collen - @splitlen < 1)
										then @cast_str + N'+ '''''''', '''') '											
										else @cast_str + N', '''') ' 
									end
							end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @cast_str = @cast_str + N') collate database_default, '''') '
						end
						 		
						select @column_string = @column_string + @cast_str
						insert into #proctext(procedure_text) values( @column_string )

						if (@fragmentlen + @commandlen > 3450)
						begin
							select @cmd = N'
			from ' + @qualname 
							insert into #proctext(procedure_text) values( @cmd )
							if (@proctype = 1)
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
							else
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
							exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
							if (@setprefix = 1)
								select @setprefix = 0

							select @cmd = N'
			select @cmd = N''''' 
							insert into #proctext(procedure_text) values( @cmd )
							select @commandlen = 0
						end
						else
							select @commandlen = @commandlen + len(@column_string)

						--
						-- update vars for next round
						--
						select @collen = @collen - @splitlen
								,@column_string = N''
								,@startoffset = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) 
										then (@splitlen/2) + @startoffset 
										else @splitlen + @startoffset 
									end
						select @fragmentlen = @fullcastlen + 4 + @collen
					end							

					--
					-- we done with this column now
					-- skip processing further and continue
					--						
					select @commandlen = @commandlen + len(@column_string)
			 	end
			 	else
			 	begin
					--
					-- Handling general fixed type column cases
					--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' + @cast_str
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' + @cast_str
					end

					--
					-- check if we need to flush the command first
					--
					if (@fragmentlen + len(@column_string) + @commandlen > 3450)
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )

						if (@proctype = 1)
							exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
						else
							exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
		
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end

					--
					-- script out the column string
					--
					insert into #proctext(procedure_text) values( @column_string )

					--
					-- if we are processing sql_variants, flush the command again
					--
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )

						if (@proctype = 1)
							exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
						else
							exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
		
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end
					else
						select @commandlen = @commandlen + @fragmentlen + len(@column_string)
				end
			end
		end

		--
		-- process the next column
		--
		FETCH hCColid INTO @this_col, @collen
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	--
	-- Check if we need to flush the command one more time (final)
	--
	if (@commandlen > 0)
	begin
		--
		-- send the last fragment of the command
		--
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )

		if (@proctype = 1)
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
		else
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
		exec sp_MSscript_compensating_send @pubid, @artid, 0, @setprefix
	end

	--
	-- all done
	--
	return 0
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_compensating_insert
GO

grant execute on dbo.sp_MSscript_compensating_insert to public
go

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

raiserror(15339,-1,-1,'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
    @upd_trig sysname
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
    DECLARE @upd_trig_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, @upd_trig
    -- 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)

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

    EXECUTE @retcode = dbo.sp_validname @upd_trig
    IF @retcode <> 0
        RETURN (1)

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

    IF LOWER(@autogen collate SQL_Latin1_General_CP1_CS_AS) = '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, @upd_trig
            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
        select @upd_trig_id = id FROM sysobjects WHERE name = @upd_trig

        IF (@ins_proc_id IS NULL) OR (@upd_proc_id IS NULL) OR (@del_proc_id IS NULL) OR
            (@upd_trig_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 @upd_trig_id IS NULL RAISERROR (20500, 16, 1, @upd_trig)
            IF @@TRANCOUNT <> 0
                ROLLBACK tran sp_articlesynctranprocs
            RETURN (1)
        END

        -- perform insert into sysarticleupdates
        -- 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, sync_upd_trig)
            VALUES (@pubid, @artid, @ins_proc_id, @upd_proc_id, @del_proc_id, @autogen_id, @upd_trig_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

grant exec on dbo.sp_articlesynctranprocs to public
go

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

raiserror(15339,-1,-1,'sp_script_reconciliation_insproc')
GO

create procedure sp_script_reconciliation_insproc (
	@artid int)
as
BEGIN
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @artcolumns   binary(32)
declare @pkcolumns    binary(32)
declare @ins_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(1)
	, @identity_insert bit
	

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @ins_cmd = ins_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid


-- save off cmd fragment

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

insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

---- if already exists, apply as update

insert into #proctext(procedure_text) 
    values( N'if exists ( select * from ' + @dest_owner + QUOTENAME(@dest_tabname) )
exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output
exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
insert into #proctext(procedure_text) values( N')' )
insert into #proctext(procedure_text) values (N'begin')


if( @artcolumns != @pkcolumns )
begin
	-- construct update 

	select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

	-- create SET clause

	select @art_col = 1
	select @spacer = N' '

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
		if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset = 0
			begin
				if not (@identity_insert = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
					select @spacer = N','

					if len( @cmd ) > 3000
					begin
						insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
			end
			select @art_col = @art_col + 1
		end
		FETCH hCColid INTO @this_col
   	end
	CLOSE hCColid
	DEALLOCATE hCColid

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

	exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
end

-- all article columns are included in the PK, & PK already exists, do nothing
else 
begin
	insert into #proctext(procedure_text ) values( N'return' )
end


insert into #proctext(procedure_text) values (N'end')
insert into #proctext(procedure_text) values (N'else')
insert into #proctext(procedure_text) values (N'begin')

---- normal insert

-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end

-- prepare the column list

select @cmd = N'insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ('
select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col))  
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- now the data parameter list

select @cmd = @cmd + N' ) values ('
select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) 
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- finish up proc body

select @cmd = @cmd + N' )'

-- save off cmd fragement

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

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

insert into #proctext(procedure_text) values (N'end')

-- send fragments to client

select procedure_text from #proctext order by c1 asc
END
go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_insproc
GO

grant exec on dbo.sp_script_reconciliation_insproc to public
go

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

raiserror(15339,-1,-1,'sp_script_reconciliation_delproc')
GO


create procedure sp_script_reconciliation_delproc @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 @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) collate database_default null)

-- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @del_cmd = del_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'


-------- construct parameter list


select @art_col = 1
select @spacer = N' '

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off 

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

-- flush to client

select procedure_text from #proctext order by c1 asc


go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_delproc
GO

grant exec on dbo.sp_script_reconciliation_delproc to public
go

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

raiserror(15339,-1,-1,'sp_script_reconciliation_xdelproc')
GO

create procedure sp_script_reconciliation_xdelproc @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 @pkcolumns    binary(32)
declare @del_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @del_cmd = del_cmd, @columns = columns
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off 

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns

-- flush to client

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_xdelproc
GO

grant exec on dbo.sp_script_reconciliation_xdelproc to public
go

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

raiserror(15339,-1,-1,'sp_scriptinsproc')
GO


create procedure sp_scriptinsproc (
	@artid int)
as
BEGIN
declare @cmd          nvarchar(4000)
		,@dest_owner   nvarchar(255)
		,@dest_tabname sysname
		,@src_objid    int
		,@columns      binary(32)
		,@ins_cmd      nvarchar(255)
		,@dest_proc    sysname
		,@this_col     int
		,@art_col      int
		,@isset        int
		,@pubid		  int

		,@identity_insert bit
		,@rc int
		,@colname sysname
		,@ccoltype     sysname
		,@typestring   nvarchar(255)
		,@spacer       nvarchar(1)
		,@queued_check bit
		,@column_string nvarchar(4000)
		,@var_string nvarchar(4000)
		,@qwhere_string nvarchar(4000)
		,@indkey      int
		,@indid       int

set nocount on

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments and insert column list

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @columns = columns, @ins_cmd = ins_cmd,
       @pubid = pubid
from sysarticles
where artid = @artid

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check if this is a queued publication
select @queued_check = ISNULL(allow_queued_tran, 0) 
from syspublications
where pubid = @pubid

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off cmd fragment

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

select @cmd = N'
AS
BEGIN
'
insert into #proctext(procedure_text) values( @cmd )

------- construct proc body

-- For Queued case, build a temp table of index columns
-- we also need temp tables for where clause list
if (@queued_check = 1)
begin
	declare @source_object nvarchar(540)

	--
	-- Get the object owner name and build a owner qualified 
	-- source object name
	--
	select @source_object = QUOTENAME(u.name) 
	from sysusers u, sysobjects o 
	where o.id = @src_objid and o.uid = u.uid

	select @source_object = @source_object + N'.' + QUOTENAME(OBJECT_NAME(@src_objid))

	create table #wherecltab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)	
	create table #indcoltab ( colname sysname collate database_default )
	
	exec @indid = dbo.sp_MStable_has_unique_index @src_objid
	select @indkey = 1;	
	while (@indkey <= 16)
	begin
		select @colname = index_col(@source_object, @indid, @indkey)
		if (@colname is NULL) 
			select @indkey = 16
		else
			insert into #indcoltab(colname) values(@colname)

		select @indkey = @indkey + 1
	end
end

-- Generate strings for col names and variables
select @art_col = 0
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
	exec @rc = dbo.sp_MSget_colinfo @src_objid, @this_col, @columns, 1, @colname output, @ccoltype output
	if @rc = 0  and EXISTS (select name from syscolumns where id=@src_objid and colid=@this_col and iscomputed<>1)
	begin
		select @art_col = @art_col + 1
		if (@art_col = 1)
		begin
			select @column_string = QUOTENAME(@colname)
			select @var_string = N'@c' + cast(@art_col as nvarchar(4))
		end
		else
		begin
			select @column_string = @column_string + N', ' + QUOTENAME(@colname)
			select @var_string = @var_string + N', @c' + cast(@art_col as nvarchar(4))
		end

		-- transfer column list string to table if too large
		if (len(@column_string) > 3000)
		begin
			insert into #collisttab(procedure_text) values( @column_string )
			select @column_string = ' '
		end

		-- queued processing : add to where clause if column part of PK
		if (@queued_check = 1)
		begin
			if (@colname in (select colname from #indcoltab))
			begin
				select @qwhere_string = case 
					when (@qwhere_string IS NULL) then 
						QUOTENAME(@colname) + N'=@c' + cast(@art_col as nvarchar(4))
					else
						@qwhere_string + N' and ' + QUOTENAME(@colname) + N'=@c' + cast(@art_col as nvarchar(4))
					end

				-- transfer where clause string to table if too large
				if (len(@qwhere_string) > 3000)
				begin
					insert into #wherecltab(procedure_text) values( @qwhere_string )
					select @qwhere_string = ' '
				end
			end
		end
	end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- insert the remaining strings for column list and where clause
insert into #collisttab(procedure_text) values( @column_string )
if (@queued_check = 1)
	insert into #wherecltab(procedure_text) values( @qwhere_string )

--
-- If we are a part of queued publication then 
-- insert only if PK does not exist
--
if (@queued_check = 1)
begin
	select @cmd = N'
	if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' 
		where '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) 
		select procedure_text from #wherecltab order by c1 asc
	select @cmd = N')
	BEGIN'
	insert into #proctext(procedure_text) values( @cmd )
	drop table #wherecltab
	drop table #indcoltab
end


-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end


--
-- prepare the insert statement now
--
select @cmd = N'
insert into ' +  @dest_owner + QUOTENAME(@dest_tabname)  + N'( '
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) 
	select procedure_text from #collisttab order by c1 asc
select @cmd = N' )'
insert into #proctext(procedure_text) values( @cmd )
if @art_col > 0
begin
	select @cmd = N'
values ( '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) values( @var_string )
	select @cmd = N' )
'
	insert into #proctext(procedure_text) values( @cmd )
end

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

--
-- If we are a part of queued publication then 
-- add the block delimiter
--
drop table #collisttab
if (@queued_check = 1)
begin
	select @cmd = N'
	END
END'
end
else
	select @cmd = N'
END'
insert into #proctext(procedure_text) values( @cmd )

-- send fragements to client

select procedure_text from #proctext order by c1 asc
END
go

EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc
GO

grant exec on dbo.sp_scriptinsproc to public
go


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

raiserror(15339,-1,-1,'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 @this_col     int
declare @art_col      int
declare @isset        int, @pubid 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) collate database_default null)

-- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @del_cmd = del_cmd, @pubid = pubid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off 

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

if exists (select * from syspublications where pubid = @pubid and allow_queued_tran = 0)
	exec dbo.sp_MSscript_missing_row_check
-- flush to client

select procedure_text from #proctext order by c1 asc


go

EXEC dbo.sp_MS_marksystemobject sp_scriptdelproc
GO

grant exec on dbo.sp_scriptdelproc to public
go

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

raiserror(15339,-1,-1,'sp_scriptxdelproc')
GO

create procedure sp_scriptxdelproc @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 @pkcolumns    binary(32)
declare @del_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @this_col     int
declare @art_col      int
declare @isset        int
declare @pubid		  int
declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)
declare @queued_check bit
		,@qwhere_string nvarchar(4000)

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-- get sysarticles information

select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @del_cmd = del_cmd, @columns = columns
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check if this is a queued publication
select @queued_check = ISNULL(allow_queued_tran, 0) 
from syspublications
where pubid = @pubid

-------- get dest proc name

if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 

		--
		-- Queued processing:if this is the row version column : need to add to where clause
		--
		if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
			select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )

        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off 

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns
if (@queued_check = 1)
	insert into #proctext(procedure_text) values( @qwhere_string )
else
	exec dbo.sp_MSscript_missing_row_check

-- flush to client

select procedure_text from #proctext order by c1 asc


go

EXEC dbo.sp_MS_marksystemobject sp_scriptxdelproc
GO

grant exec on dbo.sp_scriptxdelproc to public
go

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


raiserror(15339,-1,-1,'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 @this_col     int
declare @art_col      int
declare @pkart_col    int
declare @isset        int
declare @pkcomputed   int
declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)
declare @pubid        int, @allow_queued_tran bit, @need_end bit

select @need_end = 0

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-------- get sysarticles information

select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

declare @keep_identity bit
if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
    select @keep_identity = 1
else
    select @keep_identity = 0

select @dest_proc = substring( @upd_cmd, 6, len( @upd_cmd ) - 4 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

-------- construct parameter list

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

insert into #proctext(procedure_text) values ( N'as' )

-------- now create the update statement

-- construct test to see if pk has changed 
-- only do this if the article has columns not included in the pk

exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

declare @pk_is_identity bit
select @pk_is_identity = 0

if @artcolumns != @pkcolumns and @pkcomputed = 0
begin
    select @cmd = N'if'

    select @art_col = 1
    select @pkart_col = 1
    select @spacer = ' '

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	select @pk_is_identity = 1
	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
            if @isset != 0
            begin
				if not (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @pk_is_identity = 0
					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col ) + N' = @pkc' + convert( nvarchar, @pkart_col ) 
					select @spacer = N' and '
					select @pkart_col = @pkart_col + 1
					if len( @cmd ) > 3000
					begin
					insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
            end
            select @art_col = @art_col + 1
        end
		FETCH hCColid INTO @this_col
    end

	CLOSE hCColid
	DEALLOCATE hCColid

	if @pk_is_identity = 0
	begin
		insert into #proctext(procedure_text) values( @cmd )

		insert into #proctext(procedure_text) values( N'begin' )

		-- construct update if pk hasn't changed

		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

		-- create SET clause

		select @art_col = 1
		select @spacer = N' '

		DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid from syscolumns where id = @src_objid order by colid asc

		OPEN hCColid

		FETCH hCColid INTO @this_col
		WHILE (@@fetch_status <> -1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
			begin
				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
				if @isset = 0
				begin
					if not (@keep_identity = 1 and 
						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
					begin
						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
						select @spacer = N','

						if len( @cmd ) > 3000
						begin
							insert into #proctext(procedure_text) values( @cmd )
							select @cmd = N''
						end
					end
				end
				select @art_col = @art_col + 1
			end
			FETCH hCColid INTO @this_col
		end
		CLOSE hCColid
		DEALLOCATE hCColid

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

		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

		if @allow_queued_tran <> 1
			exec dbo.sp_MSscript_missing_row_check

		insert into #proctext(procedure_text) values( N'end' )
		insert into #proctext(procedure_text) values( N'else' )
		insert into #proctext(procedure_text) values( N'begin' )

		select @need_end = 1

	end
end -- end if artcols != pkcols


-- construct update if pk has changed

select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

-- create SET clause

select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col
WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    begin
		if not (@keep_identity = 1 and 
			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
		begin
			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
			select @spacer = N','

			if len( @cmd ) > 3000
			begin
			insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		select @art_col = @art_col + 1
    end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

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

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

if @allow_queued_tran <> 1
	exec dbo.sp_MSscript_missing_row_check

if @need_end = 1
	insert into #proctext(procedure_text) values( N'end' )
-- flush to client

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptupdproc
GO

grant exec on dbo.sp_scriptupdproc to public
go

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

raiserror(15339,-1,-1,'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 @art_cols     int
declare @this_col     int
declare @art_col      int
declare @pkart_col    int
declare @isset        int
declare @bytestr      nvarchar(10)
declare @bitstr       nvarchar(10)
declare @typestring   nvarchar(255)
declare @spacer       nvarchar(10)
declare @update_created  bit
declare @pkcomputed   int
declare @pubid        int, @allow_queued_tran bit

select @update_created	 = 0

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
	   @pubid = pubid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'MCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

declare @keep_identity bit
if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
    select @keep_identity = 1
else
    select @keep_identity = 0

select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
  

-------- construct parameter list

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

----- add changed data bitmap

select @art_col = 1


DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
   begin
        select @art_col = @art_col + 1
   end
   FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- Note that bitmap size is based on number of article columns
-- (computed by loop above) not source table columns

select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )


-- construct IF statement to examine colbitmap and determine if a 
-- primary key column has been updated.  

-- do this only if the article contains columns not included in the pk
-- and at least one of the columns in the PK is real ( i.e. not computed )

-- note that if all the article columns are PK columns, we will
-- construct the 'update all columns including PK columns' statement
-- w/o a preceeding IF, and we will NOT construct the 'only update non-pk columns' 
-- part of the procedure

-- also note that this is pretty much worthless since 7.0 and above are
-- guaranteed to NEVER generate an UPDATE if a PK columns is updated... oh well.
declare @pk_is_identity bit
select @pk_is_identity = 0

exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

if @artcolumns != @pkcolumns and @pkcomputed = 0
begin
    select @art_col = 1
    select @spacer = N' '

    select @cmd = N'if'

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	select @pk_is_identity = 1

	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin 
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
            if @isset != 0
            begin
				if not (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @pk_is_identity = 0
					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

					select @cmd = @cmd + @spacer + N'substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
							 N' = ' + @bitstr 
                
					select @spacer = N' or '

					if len( @cmd ) > 3000
					begin
						insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
            end
            select @art_col = @art_col + 1
        end
		FETCH hCColid INTO @this_col
    end
	CLOSE hCColid
	DEALLOCATE hCColid

	if @pk_is_identity = 0
		insert into #proctext(procedure_text) values( @cmd )

end  -- if artcolumns != pkcolumns

-- construct update statement including PK columns

insert into #proctext(procedure_text) values( N'begin' )

insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )

-- create SET clause consisting of CASE statements

select @art_col = 1
select @spacer = N''

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
		if not (@keep_identity = 1 and 
			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
		begin
			select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
			select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

			insert into #proctext(procedure_text) values (
				 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
				 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
				 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

			select @spacer = ',' 
		end

        select @art_col = @art_col + 1
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- create where clause

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

if @allow_queued_tran <> 1
	exec dbo.sp_MSscript_missing_row_check

-- construct UPDATE that does not set PK cols
-- only do this if the article contains columns that are not included
-- in the pk

if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
begin

    -- create SET clause consisting of CASE statements

    select @art_col = 1
    select @spacer = N''

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns 
            if @isset = 0 
            begin
				if not (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
            		if (@update_created = 0)
            		begin
            			insert into #proctext(procedure_text) values( N'end' )
            			insert into #proctext(procedure_text) values( N'else' )
            			insert into #proctext(procedure_text) values( N'begin' )
			    		insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )
			    		select @update_created = 1
					end
					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

					insert into #proctext(procedure_text) values (
						 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
						 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
						 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

					select @spacer = ',' 
				end
            end
            select @art_col = @art_col + 1
        end
       	FETCH hCColid INTO @this_col
    end
	CLOSE hCColid
	DEALLOCATE hCColid

    if @update_created = 1
	begin
		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns
		if @allow_queued_tran <> 1
			exec dbo.sp_MSscript_missing_row_check
	end

end

insert into #proctext(procedure_text) values( N'end' )
select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptmappedupdproc
GO

grant exec on dbo.sp_scriptmappedupdproc to public
go

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

raiserror(15339,-1,-1,'sp_scriptxupdproc')
GO


create procedure sp_scriptxupdproc @artid int
as
declare @cmd          nvarchar(4000),
		@dest_owner   nvarchar(255),
		@dest_tabname sysname,
		@src_objid    int,
		@artcolumns   binary(32),
		@pkcolumns    binary(32),
		@upd_cmd      nvarchar(255),
		@dest_proc    sysname,
		@this_col     int,
		@art_col      int,
		--@pkart_col    int,
		@isset        int,
		@pkcomputed   int,
		@typestring   nvarchar(255),
		@spacer       nvarchar(10),
		@pubid		  int, 
		@param_count  int
		,@queued_check bit, @exists_else bit
		,@qwhere_string nvarchar(4000)

set nocount on
if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

select @exists_else = 0

-------- create temp table for command fragments

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

-------- get sysarticles information

select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check if this is a queued publication
select @queued_check = ISNULL(allow_queued_tran, 0) 
from syspublications
where pubid = @pubid

-------- get dest proc name

if( 1 != charindex( N'XCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

declare @keep_identity bit
if exists (select * from syspublications where pubid = @pubid and
	allow_queued_tran = 1) and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
    select @keep_identity = 1
else
    select @keep_identity = 0

select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

-------- construct parameter list

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

-- Send null as @pkcolumns. We don't need pk parameters.
exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, NULL, @param_count output

insert into #proctext(procedure_text) values ( N'as' )

-------- now create the update statement

-- construct test to see if pk has changed 
-- only do this if the article has columns not included in the pk

exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

declare @pk_is_identity bit
select @pk_is_identity = 0

if @artcolumns != @pkcolumns and @pkcomputed = 0
begin
    select @cmd = N'if'

    select @art_col = 1
    --select @pkart_col = 1
    select @spacer = ' '

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	select @pk_is_identity = 1
	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
            if @isset != 0
            begin
				if not (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @pk_is_identity = 0
					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col + @param_count/2) + 
						N' = @c' + convert( nvarchar, @art_col ) 
					select @spacer = N' and '
					--select @pkart_col = @pkart_col + 1
					if len( @cmd ) > 3000
					begin
					insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
            end
            select @art_col = @art_col + 1
        end
		FETCH hCColid INTO @this_col
    end

	CLOSE hCColid
	DEALLOCATE hCColid

	if @pk_is_identity = 0
	begin
		insert into #proctext(procedure_text) values( @cmd )

		insert into #proctext(procedure_text) values( N'begin' )

		-- construct update if pk hasn't changed
		-- We know that there would be a least one column for the update below, even if
		-- the columns outside the pk are identity or timestamp. Since identity and timestamp
		-- will be mapped off unless it is queued tran. In that case, we have 'msrepl_tran_version'
		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

		-- create SET clause

		select @art_col = 1
		select @spacer = N' '

		DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid from syscolumns where id = @src_objid order by colid asc

		OPEN hCColid

		FETCH hCColid INTO @this_col
		WHILE (@@fetch_status <> -1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
			begin
				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
				if @isset = 0
				begin
					if not (@keep_identity = 1 and 
						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
					begin
						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
							N' = @c' + convert( nvarchar, @art_col + @param_count/2) 
						select @spacer = N','

						if len( @cmd ) > 3000
						begin
							insert into #proctext(procedure_text) values( @cmd )
							select @cmd = N''
						end

						--
						-- Queued processing:if this is the row version column : need to add to where clause
						--
						if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
							select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
					end
				end
				select @art_col = @art_col + 1
			end
			FETCH hCColid INTO @this_col
		end
		CLOSE hCColid
		DEALLOCATE hCColid

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

		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
		if (@queued_check = 1)
			insert into #proctext(procedure_text) values( @qwhere_string )
		else
			exec dbo.sp_MSscript_missing_row_check

		insert into #proctext(procedure_text) values( N'end' )
		insert into #proctext(procedure_text) values( N'else' )
		insert into #proctext(procedure_text) values( N'begin' )

		select @exists_else = 1

	end
end -- end if artcols != pkcols


-- construct update if pk has changed
select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

-- create SET clause

select @art_col = 1
select @spacer = N' '

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col
WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    begin
		if not (@keep_identity = 1 and 
			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
		begin
			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
				N' = @c' + convert( nvarchar, @art_col + @param_count/2 ) 
			select @spacer = N','

			if len( @cmd ) > 3000
			begin
			insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end

			--
			-- Queued processing:if this is the row version column : need to add to where clause
			--
			if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
				select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
		end
		select @art_col = @art_col + 1
    end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

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

exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
if (@queued_check = 1)
	insert into #proctext(procedure_text) values( @qwhere_string ) 
else
	exec dbo.sp_MSscript_missing_row_check

if @exists_else = 1
	insert into #proctext(procedure_text) values( N'end' )

-- flush to client

select procedure_text from #proctext order by c1 asc

go

EXEC dbo.sp_MS_marksystemobject sp_scriptxupdproc
GO

grant exec on dbo.sp_scriptxupdproc to public
go


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

raiserror(15339,-1,-1,'sp_changesubscriptiondtsinfo')
GO

CREATE PROCEDURE sp_changesubscriptiondtsinfo (
    @job_id varbinary(16),
    @dts_package_name sysname = NULL,
	@dts_package_password sysname = NULL,
	@dts_package_location nvarchar(12) = NULL

    ) AS

    /*
    ** Declarations.
    */

    DECLARE @srvid smallint
    DECLARE @artid int
    DECLARE @retcode int
	declare @login_name sysname
	declare @update_mode int
	declare @subscription_type int
	declare @dts_package_location_id int

    /*
    ** Initializations.
    */
    SET NOCOUNT ON
    
	
    /* 
    ** Get subscription properties and do Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

	select @update_mode = update_mode, @login_name = login_name,
		@subscription_type = subscription_type,
		@artid = artid              
		FROM syssubscriptions s WHERE 
			s.distribution_jobid = @job_id

    /*
    ** Check if the subscription exists.
    */
    IF @update_mode is null
	BEGIN
        RAISERROR (14055, 11, -1)
        RETURN (1)
    END

	if	@update_mode != 0
	begin
		RAISERROR(21180, 16, -1)    
		RETURN (1)
	end

	-- Only push store DTS info at distributor.
	if @subscription_type <> 0
	begin
		RAISERROR(21181, 16, -1)    
		RETURN (1)
	end

	--Security check

    IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
        AND is_member ('db_owner') <> 1
    BEGIN
		-- Only members of the sysadmin fixed server role, db_owner fixed database role or the creator of the subscription can change this subscription property.'
        RAISERROR(21175, 11, -1)
        RETURN (1)
    END

    -- Get pubid
	declare @pubid int
	select @pubid = pubid from sysarticles where artid = @artid

    /* Get subscription type of the publication */
	if not exists (select * from syspublications where
		pubid = @pubid and
		allow_dts = 1)
	begin
		RAISERROR(21178, 16, -1)    
		RETURN (1)
	end

	if @dts_package_location is null
		select @dts_package_location_id = null
	else IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = N'distributor' 
		select @dts_package_location_id = 0
	ELSE IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = N'subscriber' 
		select @dts_package_location_id = 1
	ELSE 
	begin
		raiserror(20587, 16, -1, '@dts_package_location', 'sp_changesubscriptiondtsinfo')
		return(1)
	end

	-- Encrypt DTS package password
	declare @change_password bit

	if @dts_package_password is null
		select @change_password = 0
	else
		select @change_password = 1

	-- When user sends in empty string, reset it to null.
	-- Have to do this before scramble because the result may contains invalid
	-- unicode code points which are equael to some collation.
	if @dts_package_password = N''
		select @dts_package_password = NULL

	declare @enc_dts_package_password nvarchar(524)
        select @enc_dts_package_password = @dts_package_password

	if @enc_dts_package_password is not null
	begin
		EXEC @retcode = master.dbo.xp_repl_encrypt @enc_dts_package_password OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end

    /*
    ** Get distribution server information for remote RPC
    ** agent verification.
    */
    declare @distributor sysname
	declare @distribdb sysname
	declare @distproc nvarchar(1000)

	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

    /*
    ** Call proc to change the distributor
    */
    SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
        '.dbo.sp_MSchange_subscription_dts_info'

	exec @retcode = @distproc 
		@job_id = @job_id,
		@dts_package_name = @dts_package_name,
		@dts_package_password = @enc_dts_package_password,
		@dts_package_location = @dts_package_location_id,
		@change_password = @change_password

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

    RETURN (0)
go

EXEC dbo.sp_MS_marksystemobject sp_changesubscriptiondtsinfo
GO

grant execute on dbo.sp_changesubscriptiondtsinfo to public
go


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

raiserror(15339,-1,-1,'sp_MScomputearticlescreationorder')
GO
CREATE PROCEDURE sp_MScomputearticlescreationorder
    @publication sysname
AS
    SET NOCOUNT ON
    DECLARE @pubid int 
    DECLARE @max_level int
    DECLARE @current_level int
    DECLARE @update_level int
    DECLARE @limit int
    DECLARE @result int

    SELECT @pubid = NULL
    -- Get the pubid from syspublications 
    SELECT @pubid = pubid 
      FROM syspublications
     WHERE name = @publication

    IF @@ERROR <> 0
        RETURN (1)

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

    EXEC @result = sp_getapplock @Resource = @publication, 
				@LockMode = N'Shared', 
				@LockOwner = N'Session', 
				@LockTimeout = 0

    IF @result < 0
    BEGIN
        RAISERROR(21385, 16, -1, @publication)
        RETURN (1)
    END

    -- Find out the total number of articles in this publication and
    -- compute the maximum tree height based on the number of articles in 
    -- the publication. Here, the tree height is counted from the
    -- leaf-nodes towards the root(s)
    SELECT @max_level = COUNT(*) + 10,
           @limit =2 *  COUNT(*) + 11 
      FROM sysextendedarticlesview 
     WHERE pubid = @pubid
 
    IF @@ERROR <> 0
    BEGIN
        RETURN (1)
    END
   
    -- The following temp table contains the minimal amount of 
    -- article information that we want to keep around and the current
    -- computed tree level of the article
    CREATE TABLE #article_level_info
    (
        article         sysname collate database_default not null,
        source_objid    INT     NOT NULL,
        tree_level      INT     NOT NULL,
        ref_level       INT     NOT NULL,
        major_type      TINYINT NOT NULL  -- 1-view&func, 0-other 
    )  
   
    CREATE CLUSTERED INDEX ucarticle_level_info 
        ON #article_level_info(source_objid)

    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END

    -- Populate the article level info table. All articles will be
    -- assigned 0 as their initial tree level. Having 
    -- a tree level of 0 means that the algorithm hasn't discovered 
    -- any objects that the article depends on within the publication.

    INSERT INTO #article_level_info 
    SELECT name, objid, 0, 0, 
        CASE type    
            WHEN 0x40 THEN 1
            WHEN 0x80 THEN 1
            ELSE 0 
        END
      FROM sysextendedarticlesview
     WHERE pubid = @pubid
      
    -- To jump-start the algorithm, update the tree_level of 
    -- all articles with no dependency to @max_level.

    UPDATE #article_level_info 
       SET tree_level = @max_level
     WHERE NOT EXISTS (SELECT * 
                         FROM sysdepends 
                        WHERE source_objid = id)
    IF @@ERROR <> 0
        GOTO Failure

    -- For each increasing tree level starting from @max_level, update the 
    -- the tree_level of articles depending on objects at the current
    -- level to current level + 1
    SELECT @current_level = @max_level
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1

        UPDATE #article_level_info
           SET tree_level = @update_level
          FROM #article_level_info 
        INNER JOIN sysdepends d
            ON #article_level_info.source_objid = d.id 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid       
               AND ali1.tree_level = @current_level)
    
        -- Terminate the algorithm if we cannot find any articles 
        -- depending on articles at the current level     
        IF @@ROWCOUNT = 0
            GOTO PHASE1

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1

        -- Although there should not be any circular 
        -- dependencies among the articles, the following
        -- check is performed to guarantee that 
        -- the algorithm will terminate even if there 
        -- is circular dependency among the articles
        
        -- Note that with at least one node per level,
        -- the current level can never exceed the total 
        -- number of articles (nodes) unless there is
        -- circular dependency among the articles.
        
        -- @limit is defined to be # of articles + 1
        -- although @limit = # of articles - 1 will be
        -- sufficient. This is to make absolutely sure that 
        -- the algorithm will never terminate too early

        IF @current_level > @limit
            GOTO PHASE1
    END

PHASE1:

    -- There may be interdependencies among articles 
    -- that haven't been included in the previous calculations so
    -- we compute the proper order among these articles here.
    SELECT @limit = @max_level - 9
    SELECT @current_level = 0
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info 
           SET tree_level = @update_level
          FROM #article_level_info
        INNER JOIN sysdepends d
            ON (#article_level_info.source_objid = d.id
                AND #article_level_info.tree_level < @max_level) 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid
                AND ali1.tree_level = @current_level)
        IF @@ROWCOUNT = 0
            GOTO PHASE2
        
        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE2
    END         

PHASE2:

    -- Since transactional doesn't keep the nickname around in 
    -- sysmergearticles as merge does, we need to compute FK/PK ordering on 
    -- the fly. 
    SELECT @current_level = 0
    SELECT @limit = @max_level - 9
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info
           SET ref_level = @update_level
          FROM #article_level_info
        INNER JOIN sysreferences r
            ON (#article_level_info.source_objid = r.fkeyid
                and r.rkeyid <> r.fkeyid)
        INNER JOIN #article_level_info ali1
            ON (r.rkeyid = ali1.source_objid 
                AND ali1.ref_level = @current_level)
        IF @@ROWCOUNT = 0
            GOTO PHASE3

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE3
    END

PHASE3:

    -- Select the articles out of #article_level_info 
    -- in ascending order of tree_level. This will give
    -- the proper order in which articles can be created
    -- without violating the internal dependencies among
    -- themselves. Note that this algorithm still allows 
    -- unresolved external references outside the publication.
    -- All this algorithm can guarantee is that all articles will
    -- be created successfully using the resulting order if 
    -- there is no dependent object outside the publication. 
    -- We need to order the articles in reverse ref_level
    -- to account for FK/PK constraints when dropping/deleting rows/truncating
    -- tables on the Subscriber.

    SELECT article
      FROM #article_level_info
    ORDER BY major_type ASC, tree_level ASC, ref_level DESC

    DROP TABLE #article_level_info
    RETURN (0)

Failure:

    DROP TABLE #article_level_info
    RETURN (1)
GO

exec dbo.sp_MS_marksystemobject sp_MScomputearticlescreationorder
go

grant exec on dbo.sp_MScomputearticlescreationorder to public
go

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

raiserror(15339,-1,-1,'sp_scriptpublicationcustomprocs')
GO

raiserror('Creating procedure sp_scriptpublicationcustomprocs',0,-1)
go
--
-- Name: sp_scriptpublicationcustomprocs
--
-- Description: This is a utility procedure for scripting out the 
--              article "custom" ins/upd/del procedures for all 
--              table articles in a publication with the auto-generate custom
--              procedure schema option enabled. This is particularly useful 
--              and in fact specifically designed for setting up no-sync 
--              subscriptions. 
-- 
-- Notes: 1) Reconciliation procedures for concurrent snapshot will
--           not be scripted by this procedure. It does not really make 
--           sense to have concurrent snapshots for no-sync subscriptions.
--        2) Custom procedures will not be scripted out for articles 
--           without the auto-generate custom procedure (0x2) schema_option.
--
-- Parameter: @publication sysname
--
-- Security: Execute permission is granted to public; procedural security 
--           check is performed inside the procedure to restrict access
--           to sysadmins and db_owners of current database. 
--
-- Example: exec Northwind.dbo.sp_scriptpublicationcustomprocs @publication = N'Northwind'
--
create procedure dbo.sp_scriptpublicationcustomprocs
    @publication sysname
as
begin
    set nocount on

    declare @retcode          int,
            @artid            int,
            @pubid            int,
            @cursor_allocated bit,
            @cursor_opened    bit,
            @table_created    bit,
            @ins_cmd          nvarchar(255),
            @upd_cmd          nvarchar(255),
            @del_cmd          nvarchar(255),
            @article          sysname,
            @schema_option    int,
            @repl_freq        int,
            @formattedmessage nvarchar(4000)
    
    -- Initializations 
    select @retcode = 0,
           @pubid = null,
           @cursor_allocated = 0,
           @cursor_opened = 0,
           @table_created = 0

    -- Security check: Sysadmins and db_owners only
    exec @retcode = sp_MSreplcheck_publish
    if @retcode <> 0 or @@error <> 0
    begin
        return 1
    end

    -- Make sure the current database is enabled for transaction replication
    if not exists (select * 
                     from master..sysdatabases 
                    where name = db_name() collate database_default
                      and (category & 0x1) <> 0)
    begin
        raiserror(14013, 16, -1)
        return 1
    end
 
    -- Parameter check: The specified @publication is a valid Transactional publication

    select @pubid = pubid, 
           @repl_freq = repl_freq
      from dbo.syspublications
     where name = @publication
    if @pubid is null
    begin
        raiserror(20026, 16, -1, @publication)
        return 1            
    end
    
    -- Don't script out custom procs for a snapshot publication
    if @repl_freq = 1
    begin
        raiserror(21515, 16, -1, @publication) 
        return 1
    end
    -- Create temp table for procedure text
    create table #proctext_scriptpublicationcustomprocs
    (
        line_no int identity(1,1) primary key,
        line nvarchar(4000)
    ) 
    if @@error<>0
    begin
        return 1
    end    
    
    -- Script header
    select @formattedmessage = formatmessage(21516, @publication, db_name())
    if @@error <> 0 begin select @retcode = 1 goto Failure end
    insert into #proctext_scriptpublicationcustomprocs values(N'--')
    insert into #proctext_scriptpublicationcustomprocs values(N'-- ' + @formattedmessage)
    insert into #proctext_scriptpublicationcustomprocs values(N'--')
    insert into #proctext_scriptpublicationcustomprocs values(N'')
    insert into #proctext_scriptpublicationcustomprocs values(N'')

    -- Open cursor through all table articles in the specified publication and script out
    -- custom procs as necessary
    
    declare harticle cursor local fast_forward for
        select artid, ins_cmd, upd_cmd, del_cmd, name, fn_replgetbinary8lodword(schema_option)
          from sysarticles
         where pubid = @pubid
           and (type & 1) <> 0
    if @@error <> 0
    begin
        select @retcode = 1
        goto Failure
    end
    select @cursor_allocated = 1

    open harticle
    if @@error <> 0
    begin
        select @retcode = 1
        goto Failure
    end
    
    fetch harticle into @artid, @ins_cmd, @upd_cmd, @del_cmd, @article, @schema_option

    while (@@fetch_status<>-1)
    begin        
        
        if (@schema_option & 2) = 0
        begin
            
            select @formattedmessage = formatmessage(21517,@article)
            if @@error <> 0 begin select @retcode = 1 goto Failure end
            insert into #proctext_scriptpublicationcustomprocs values(N'----')
            insert into #proctext_scriptpublicationcustomprocs values(N'---- ' + @formattedmessage)
            insert into #proctext_scriptpublicationcustomprocs values(N'----')
            insert into #proctext_scriptpublicationcustomprocs values(N'')
            goto SkipArticle
        end 

        select @formattedmessage = formatmessage(21518,@article)
        if @@error <> 0 begin select @retcode = 1 goto Failure end
        insert into #proctext_scriptpublicationcustomprocs values(N'----')
        insert into #proctext_scriptpublicationcustomprocs values(N'---- ' + @formattedmessage)
        insert into #proctext_scriptpublicationcustomprocs values(N'----')
        insert into #proctext_scriptpublicationcustomprocs values(N'')

        if lower(substring(@ins_cmd,1,len(N'call'))) = N'call'
        begin
            
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptinsproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@ins_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@ins_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end

        if lower(substring(@upd_cmd,1,len(N'call'))) = N'call'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')

        end
        else if lower(substring(@upd_cmd,1,len(N'mcall'))) = N'mcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptmappedupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@upd_cmd,1,len(N'xcall'))) = N'xcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptxupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@upd_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@upd_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end

        if lower(substring(@del_cmd,1,len(N'call'))) = N'call'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptdelproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@del_cmd,1,len(N'xcall'))) = N'xcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptxdelproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@del_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@del_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
SkipArticle:
        fetch harticle into @artid, @ins_cmd, @upd_cmd, @del_cmd, @article, @schema_option
    end
    
    select '--' = line from #proctext_scriptpublicationcustomprocs order by line_no asc
   
Failure:
    if @table_created <> 0
    begin
        drop table #proctext_scriptpublicationcustomprocs
    end
    
    if @cursor_opened <> 0
    begin
        close harticle
    end

    if @cursor_allocated <> 0
    begin
        deallocate harticle
    end 
    return @retcode    
end
go

exec sp_MS_marksystemobject sp_scriptpublicationcustomprocs
grant execute on dbo.sp_scriptpublicationcustomprocs to public

--------------------------------------------------------------------------------
--. fn_sqlvarbasetostr 
--------------------------------------------------------------------------------

if exists (select * from sysobjects
		where type = 'FN' and name = 'fn_sqlvarbasetostr')
     drop function fn_sqlvarbasetostr
go

raiserror('Creating function fn_sqlvarbasetostr',0,1)
go
--
-- fn_sqlvarbasetostr
--
-- UDF to generate string from a given sqlvariant using its base type.
-- This function is used by compensating commands and use special rules
-- for generating strings :
-- For datatypes - varchar, nvarchar, char, nchar, uniqueidenfier, 
-- datetime, smalldatetime, invalid date : The value is quoted with single
-- quotes and any embedded quotes are prefixed with single quote
-- For other datatypes - The value is not quoted
-- 
-- Parameters:
--	@ssvar sql_variant 		input sqlvariant parameter (could be NULL)
--
-- Returns:
-- 	nvarchar(4000) NULL		generated string. Is NULL if input is NULL
--
create function dbo.fn_sqlvarbasetostr (
	@ssvar sql_variant
)
returns nvarchar(4000)
as
begin
	declare @pstrout nvarchar(4000)
			,@basetype sysname

	select @basetype = CAST(SQL_VARIANT_PROPERTY ( @ssvar, 'BaseType' ) as nvarchar(255))
	if (@ssvar IS NOT NULL and @basetype IS NOT NULL)
	begin
		if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
			select @pstrout = N'''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
			select @pstrout = N'N''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
			select @pstrout = N'''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
			select @pstrout = N'N''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
			select @pstrout = master.dbo.fn_varbintohexsubstring(1, CAST(@ssvar as varbinary(8000)), 1, 0)
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','float','real','decimal','numeric'))
			select @pstrout = CAST(@ssvar as nvarchar(40))
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
			select @pstrout = CONVERT(nvarchar(40), @ssvar, 2)
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
			select @pstrout = N'''' + CAST(@ssvar as nvarchar(40)) + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
			select @pstrout = N'''' + CONVERT(nvarchar(40), @ssvar, 121) + N''''
		else
			select @pstrout = N'''Invalid Datatype' + lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) + N'(' + CAST(@ssvar as nvarchar) + N')'''
	end

	-- All done
	return @pstrout
end
go
exec dbo.sp_MS_marksystemobject fn_sqlvarbasetostr
go

grant execute on dbo.fn_sqlvarbasetostr to public
go


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

raiserror(15339,-1,-1,'sp_replqueuemonitor')
GO

--
-- sp_replqueuemonitor
--
-- Description: this stored procedure displays the messages stored in the 
--  	queue for a given subscription to a queued publication
--
-- Parameters:  
--    1. publisher (sysname, NULL for all publishers)
--    2. publisherdb (sysname, NULL for all publisherdbs)
--    3. publication (sysname , NULL for all publications)
--    4. tranid ( nvarchar(70) NULL for all transactions)
--	  5. queuetype (tinyint 0 for all types of queues, 1 for MSMQ, 2 for SQL)
--
-- Results:
--  Rows of Messages stored in the queue (all types) in the following format:
--	publisher 		sysname,
--	publisher_db 	sysname,
--	publication 	sysname,
--	tranid 			sysname,
--	commandlen 		int,
--	command 		nvarchar(4000)
-- The command is truncated (less than 4000 characters) if
--	1. The total rowsize exceeds the maximum of 8060 bytes
--	2. The SQL command spans multiple queue messages
-- The queue messages that do not contain SQL command or are part of a spanning
-- SQL command are not displayed
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_replqueuemonitor', 0,1)
go
create proc sp_replqueuemonitor (
	@publisher 		sysname = NULL
	,@publisherdb 	sysname = NULL
	,@publication 	sysname = NULL
	,@tranid		 	sysname = NULL
	,@queuetype		tinyint = 0	-- 0 = All Queues, 1 = MSMQ, 2 = SQL
)
as
begin
	set nocount on
	declare @retcode int
			,@queue_server sysname
			,@queue_id sysname
			,@data varbinary(8000)
			,@datalen int
			,@commandtype int
			,@cmdstate bit
			,@mesglen int
			,@command nvarchar(4000)
			,@partialindex int
			,@rowlen int
			,@comandlen int

	declare	@k_mesg_partial_state bit
			,@k_mesg_complete_state bit
			,@k_mesg_tran_cmd int
			,@k_max_rowlen int
			,@k_queuetype_all tinyint
			,@k_queuetype_msmq tinyint
			,@k_queuetype_sql tinyint

	create table #mesgs (mesgid int identity PRIMARY KEY, queuetype tinyint default 1, publisher sysname collate database_default, publisher_db sysname collate database_default, publication sysname collate database_default, 
							tranid sysname collate database_default, commandlen int, command ntext)

	--
	-- Check if need to look for subscriptions
	--
	if exists (select * from dbo.sysobjects where name = 'MSsubscription_agents')
	begin
		--
		-- Are there any qualifying subscriptions
		--
		if exists (select * from dbo.MSsubscription_agents where
				publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
				publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
				publication = case when @publication is NULL then publication else @publication end )
		begin
			--
			-- initialize
			--
			select 	@k_queuetype_all = 0
					,@k_queuetype_msmq = 1
					,@k_queuetype_sql = 2
					
			--
			-- MSMQ based
			--
			if (@queuetype in (@k_queuetype_all, @k_queuetype_msmq) and
				exists (select * from dbo.MSsubscription_agents where
					publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
					publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
					publication = case when @publication is NULL then publication else @publication end  AND
					update_mode IN (2,3) AND
					queue_id != N'mssqlqueue'))
			begin
				--
				-- enumerate each queue
				--
				create table #queues (publisher sysname collate database_default, publisher_db sysname collate database_default, publication sysname collate database_default, queue_id sysname collate database_default)
				declare #htempcursor cursor local for
					select publisher, publisher_db, publication, queue_server, queue_id 
					from dbo.MSsubscription_agents 
					where
						publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
						publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
						publication = case when @publication is NULL then publication else @publication end  AND
						update_mode IN (2,3) AND
						queue_id != N'mssqlqueue'

				open #htempcursor
				fetch #htempcursor into @publisher, @publisherdb, @publication, @queue_server, @queue_id
				while (@@fetch_status = 0)
				begin
					--
					-- add the queue server prefix
					--
					select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
					
					--
					-- Display all the messages in this queue
					--
					insert into #mesgs (publisher, publisher_db, publication, tranid, commandlen, command)
						exec @retcode = master.dbo.xp_displayqueuemesgs @publisher, @publisherdb, @publication, @queue_id, @tranid
					if (@retcode != 0 or @@error != 0)
						return 1

					--
					-- fetch next row
					--
					fetch #htempcursor into @publisher, @publisherdb, @publication, @queue_server, @queue_id
				end
				close #htempcursor
				deallocate #htempcursor
	
				--
				-- All MSMQ Queues processed
				--
				drop table #queues
			end
			
			--
			-- SQL Queued based
			--
			if (@queuetype in (@k_queuetype_all, @k_queuetype_sql) and
				exists (select * from dbo.MSsubscription_agents where
					publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
					publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
					publication = case when @publication is NULL then publication else @publication end  AND
					update_mode IN (4,5) AND
					queue_id = N'mssqlqueue'))
			begin
				--
				-- check if we have a queue
				--
				if exists (select * from dbo.sysobjects where name = 'MSreplication_queue')
				begin
					--
					-- initialize
					--
					select @mesglen = 0
							,@partialindex = 0
							,@k_mesg_partial_state = 1
							,@k_mesg_complete_state = 0
							,@k_mesg_tran_cmd = 1
							,@k_max_rowlen = 8000
					
					--
					-- select the messages that qualify
					--
											
					declare #htempcursor cursor local for
						select publisher, publisher_db, publication, tranid, datalen, data, commandtype, cmdstate
						from dbo.MSreplication_queue 
						where
							publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
							publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
							publication = case when @publication is NULL then publication else @publication end  AND
							tranid = case when @tranid IS NULL then tranid else @tranid end
					open #htempcursor
					fetch #htempcursor into @publisher, @publisherdb, @publication, @tranid, @datalen, @data, @commandtype, @cmdstate
					while (@@fetch_status = 0)
					begin
						--
						-- check the message state
						--
						if (@cmdstate = @k_mesg_partial_state)
							select @partialindex = @partialindex + 1
						select @mesglen = @mesglen + @datalen

						--
						-- process the body only for command type messages
						-- and if the command spans multiple rows, then
						-- display only the first row
						--
						if ((@commandtype = @k_mesg_tran_cmd) and
							((@cmdstate = @k_mesg_complete_state and @partialindex = 0) or
							(@cmdstate = @k_mesg_partial_state and @partialindex = 1)))
						begin
							--
							-- decode the command
							--
							exec @retcode = master.dbo.xp_decodequeuecmd @data, @command OUTPUT
							if (@retcode != 0 or @@error != 0)
								return 1
						end
						
						--
						-- Are processing the final row for this command
						--
						if (@cmdstate = @k_mesg_complete_state)
						begin
							--
							-- reset partial index
							--
							if (@partialindex > 0)
								select @partialindex = 0

							if (@command IS NOT NULL)
							begin
								--
								-- check if the command needs to truncated to fit the max rowsize
								--
								select @rowlen = 4 + DATALENGTH(@k_queuetype_sql) + 
												 DATALENGTH(@publisher) + DATALENGTH(@publisherdb) +
												 DATALENGTH(@publication) + DATALENGTH(@tranid) + 
												 DATALENGTH(@mesglen)
										,@comandlen = DATALENGTH(@command)
								if (@rowlen + @comandlen > @k_max_rowlen)
								begin
									select @comandlen = @k_max_rowlen - @rowlen
									select @comandlen = @comandlen / 2
									select @command = SUBSTRING(@command, 1, @comandlen)
								end
								
								insert into #mesgs (queuetype, publisher, publisher_db, publication, tranid, commandlen, command)
								values (@k_queuetype_sql, @publisher, @publisherdb, @publication, @tranid, @mesglen, @command)
								if (@retcode != 0 or @@error != 0)
									return 1

								select @command = NULL
							end

							--
							-- reset command len
							--
							if (@mesglen > 0)
								select @mesglen = 0
						end
						
						--
						-- fetch next row
						--
						fetch #htempcursor into @publisher, @publisherdb, @publication, @tranid, @datalen, @data, @commandtype, @cmdstate
					end
					close #htempcursor
					deallocate #htempcursor
				end 
	
				--
				-- All SQL Queues processed
				--
			end
		end
	end
	
	--
	-- return result
	--
	select 	queue = case when queuetype = @k_queuetype_msmq then N'MSMQ'
						when queuetype = @k_queuetype_sql then N'SQLQ' end 
			,publisher
			,publisher_db
			,publication
			,tranid
			,commandlen
			,command 
	from #mesgs
	order by mesgid
	
	--
	-- All done
	--
	drop table #mesgs
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_replqueuemonitor
go


--
-- sp_MSrepl_schema 
--
-- Description: Helper store proc, used by schema replication.
--		constructs schema modification code and post to the log.
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSrepl_schema', 0,1)
go

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

raiserror(15339,-1,-1,'sp_MSrepl_schema')
GO

create proc sp_MSrepl_schema @pubname sysname
				,@artid int 
				,@qual_source_object nvarchar(362) -- quoted table name
				,@column sysname -- column name, not quoted, as we need to search in syscolumns by it.
				,@operation int -- 0 is add, 1 is drop
				,@typetext nvarchar(3000) = NULL	
				,@schema_change_script nvarchar(4000) = NULL
as
begin
	declare @retcode int
	declare @pubid int
	declare @objid int
	declare @schema_option binary(8)
	declare @auto_gen int
	declare @cmd_type int
	declare @ins_cmd nvarchar(510)
	declare @del_cmd nvarchar(510)
	declare @upd_cmd nvarchar(510)
	declare @repub_command nvarchar(4000)
	declare @nopub_command nvarchar(4000)
	declare @prefix nvarchar(32)
	declare @post_cmd nvarchar(4000)
	declare @qual_column sysname
	declare @use_script bit
	declare @allow_dts bit
	
	set nocount on
	select @retcode = 0
	select @auto_gen = 2 -- auto generate custom procs
	select @cmd_type = 35 -- SQL statement
	select @qual_column = QUOTENAME(@column)
	select @objid = object_id(@qual_source_object)

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

	if (@schema_change_script is not NULL) and (len(@schema_change_script) > 0)
		select @use_script = 1
	else
		select @use_script = 0
	
	
	select @pubid = a.pubid, @schema_option = schema_option, @ins_cmd = ins_cmd, @del_cmd = del_cmd, @upd_cmd = upd_cmd, @allow_dts = allow_dts 
		from sysarticles a join syspublications p on a.pubid = p.pubid where artid = @artid
	
	if (@allow_dts = 1)
		goto SCRIPTONLY

	if(@operation = 0)
	begin
		select @repub_command = N'exec sp_repladdcolumn @source_object=N''' + @qual_source_object + N''',@column=N''' + replace(@column  , N'''', N'''''')
						+ N''',@typetext=N''' + replace(@typetext, N'''', N'''''') + N''' '
		select @nopub_command = N'else alter table ' + @qual_source_object + N' add ' + @qual_column + N' ' + @typetext + N' ' 
		select @prefix = N'if not exists '
	end
	else
	begin
		select @repub_command = N'exec sp_repldropcolumn @source_object=N''' + @qual_source_object + N''',@column=N''' + @column  + N''' '
		select @nopub_command = N'else alter table ' + @qual_source_object + N' drop column ' + @qual_column + N' '
		select @prefix = N'if exists '
	end
	if (@use_script = 1)--Need to pass the script file along if sub is republished.
		select @repub_command = @repub_command  + N',@schema_change_script=N''' + @schema_change_script + N''' '
	select @post_cmd = @prefix + N'(select * from syscolumns where name=''' + @column + ''' and id = object_id('''+ PARSENAME(@qual_source_object, 1) + ''')) begin '
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @post_cmd 
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	select @post_cmd = N'if exists (select * from sysobjects where name=''syspublications'') if exists (select * from sysarticles where objid=object_id('''+ PARSENAME(@qual_source_object, 1) + ''')) and @@microsoftversion >= 0x07320000 '
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @post_cmd 
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @repub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @nopub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @nopub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 0, @pubid, @artid, @cmd_type, N' end '
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	
	if ((convert(int, @schema_option) & @auto_gen) > 0)-- No script, but custom procs were auto-generated
	begin
		if(UPPER(LEFT(LTRIM(@ins_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptinsproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		if(UPPER(LEFT(LTRIM(@del_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptdelproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@del_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('XCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptxdelproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		if(UPPER(LEFT(LTRIM(@upd_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@upd_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('MCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptmappedupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@upd_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('XCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptxupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
	end
SCRIPTONLY:

	if (@use_script = 1)
	begin
		exec @retcode = sp_addscriptexec @publication = @pubname, @scriptfile = @schema_change_script
		if @retcode<>0 or @@ERROR<>0
			return 1
	end 
	return 0
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSrepl_schema 
go

grant execute on dbo.sp_MSrepl_schema to public
go

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

raiserror(15339,-1,-1,'sp_getqueuedrows')
GO

--
-- sp_getqueuedrows
--
-- sp_getqueuedrows is invoked by user to find the rows of given table on
-- a subscriber database that have participated in a queued update and 
-- currently have not been resolved by the queue reader agent - i.e. current
-- have an outstanding queued transaction. The table has to be part of 
-- queued subscription.
-- 
-- Parameters
-- 	@tablename	sysname -- name of table
--	@user		sysname -- optional name of user
--	@tranid		nvarchar(70) -- optional tranid to filter results on
--
-- Returns
--	0 if success 
--	1 if failure
--
-- Resultset
-- 	Rows that currently have at least one queued transaction for this
--	subscribed table
--
raiserror('Creating procedure sp_getqueuedrows', 0,1)
go
create proc sp_getqueuedrows (
	@tablename sysname
	,@owner sysname = NULL
	,@tranid nvarchar(70) = NULL
)
as
begin
	set nocount on
	declare @retcode int
		,@dbname sysname
		,@qualified_tabname nvarchar(1000)
		,@tabid int
		,@agent_id int
		,@publisher sysname
		,@publisher_db sysname
		,@publication sysname
		,@queue_id sysname
		,@update_mode int
		,@failover_id int
		,@cmd nvarchar(4000)
		,@queue_server sysname
		,@indid int
		,@indkey int
		,@key sysname
		,@colid int
		,@typestring nvarchar(4000)
		,@artcol int
		,@xpinputstr nvarchar(4000)
		,@selectcl nvarchar(4000)
		,@joincl nvarchar(4000)

	--
	-- prepare the fully qualified table
	--
	select @owner = case when (@owner IS NULL) then N'dbo' else @owner end
			,@dbname = db_name()	
	select @qualified_tabname = quotename(@dbname) + N'.' 
					+ quotename(@owner) + N'.' + quotename(@tablename)
	select @tabid = object_id(@qualified_tabname)
	if (@tabid IS NULL) or (@tabid = 0)
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): could not locate table %s', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- current user should have SELECT permission on the table
	--
	if ( permissions(@tabid) & 0x1 = 0 )
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): current user does not have SELECT permission on table %s', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- make sure the table is participating in a active queued subscription
	--
	select @agent_id = agent_id 
	from dbo.MSsubscription_articles 
	where dest_table = @tablename and owner = @owner

	if (@agent_id IS NULL)
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): table %s is not part of any active initialized queued subscription. Make sure your queued subscriptions are properly initialized', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- get the details for the subscription
	--
	select @publisher = publisher
			,@publisher_db = publisher_db
			,@publication = publication
			,@update_mode = update_mode
			,@queue_server = queue_server
			,@queue_id = queue_id
			,@failover_id = failover_mode
	from dbo.MSsubscription_agents where id = @agent_id
	if (@update_mode not in (2,3,4,5))
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): table %s is not part of any active initialized queued subscription. Make sure your queued subscriptions are properly initialized', 16, 2, @qualified_tabname)
		return 1
	end
	
	--
	-- If we are in Immediate Failover mode - no queued messages
	--
	if (@update_mode in (3,5) and (@failover_id = 0))
	begin
		--
		-- do an empty select on the source table and return
		--
		select @cmd = N'declare @dummy_action nvarchar(10), @dummy_tranid nvarchar(70)
					select action=@dummy_action, tranid=@dummy_tranid, * from ' + 
					@qualified_tabname + N' where 1 = 2 '
		exec (@cmd)
		return 0
	end

	if (@update_mode in (2,3))
	begin
		--
		-- set queue prefix for MSMQ cases
		--
		select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
	end
	else
	begin
		--
		-- Check the queue table for SQLQ
		--
		if not exists (select * from dbo.MSreplication_queue
		where UPPER(publisher) = UPPER(@publisher) and
				publisher_db = @publisher_db and
				publication = @publication and
				tranid = case when @tranid IS NULL then tranid else @tranid end)
		begin
			--
			-- do an empty select on the source table and return
			--
			select @cmd = N'declare @dummy_action nvarchar(10), @dummy_tranid nvarchar(70)
					select action=@dummy_action, tranid=@dummy_tranid, * from ' + 
					@qualified_tabname + N' where 1 = 2 '
			exec (@cmd)
			return 0
		end
	end

	--
	-- Now find the PK columns for this table
	--
	select @indkey = 1
		,@artcol = 0
		,@xpinputstr = N''
		,@selectcl = N''
		,@joincl = N''
		,@retcode = 0

	select @indid = i.indid 
	from dbo.sysindexes i 
	where ((i.status & 2048) != 0) and (i.id = @tabid)
	if (@indid is null)
	begin
		raiserror('sp_getqueuedrows(debug): Cannot find primary key for %s', 
				16, -1, @qualified_tabname)
		return 1
	end
	
	--
	-- create an enumeration of all the columns that are part of PK
	--
	create table #pkcoltab(pkindex int identity, keyname sysname collate database_default not null)
	while (@indkey <= 16)
	begin
		select @key = index_col( @qualified_tabname, @indid, @indkey )
		if (@key is null)
			break
		else
			insert into #pkcoltab(keyname) values(@key)

		select @indkey = @indkey + 1
	end

	--
	-- initialize the commands that we need to build
	--
	if exists (select * from dbo.sysobjects where name = 'tempcrtcmd')
		drop table tempcrtcmd
	create table tempcrtcmd (c1 int identity NOT NULL, procedure_text nvarchar(4000) NULL)
	
	select @cmd = N'create table tempqjointab (action nvarchar(10), tranid nvarchar(70) '
	insert into tempcrtcmd(procedure_text) values(@cmd)

	--
	-- now walk through each article col and if it is
	-- a part of PK, then check find the column position of the key
	-- corresponding to any article column is set
	--
	DECLARE #hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid, [name] from dbo.syscolumns 
		where id = @tabid order by colid asc

	OPEN #hCColid
	FETCH #hCColid INTO @colid, @key
	WHILE (@@fetch_status != -1)
	begin
		exec sp_MSget_type @tabid, @colid, NULL, @typestring output
		if ((@typestring IS NOT NULL) and (@typestring != N'timestamp'))
		begin
			--
			-- this column is part of the article
			--
			select @artcol = @artcol + 1
			if exists (select * from #pkcoltab where keyname = @key)
			begin
				--
				-- this column is part of PK (offset and precision, scale)
				-- prepare the input string for XP
				-- prepare the create join table command
				-- prepare the join and select clause for the result
				--
				select @xpinputstr = @xpinputstr + N';' + cast(@artcol as nvarchar) 
				if (@typestring = N'bigint')
					select @xpinputstr = @xpinputstr + N'(19,0)'
				else if (@typestring like N'decimal%') or (@typestring like N'numeric%')
				begin
					declare @startpos int
							,@endpos  int

					select @startpos = charindex(N'(', @typestring, 1)
					select @endpos = charindex(N')', @typestring, @startpos)
					select @xpinputstr = @xpinputstr + substring(@typestring, @startpos, (@endpos - @startpos + 1))
				end
				select @cmd = N',' + quotename(@key) + N' ' + @typestring
				insert into tempcrtcmd(procedure_text) values(@cmd)
				select @selectcl = @selectcl + N', b.' + quotename(@key)
				
				if (@artcol = 1)
				begin
					select @joincl = @joincl + N'a.' + quotename(@key) + N' = b.' + quotename(@key)
				end
				else
				begin
					select @joincl = @joincl + N'and a.' + quotename(@key) + N' = b.' + quotename(@key)
				end				
			end
			else
			begin
				--
				-- this column is not part of PK
				-- build the select clause for this column
				--
				select @selectcl = @selectcl + N', a.' + quotename(@key)
			end
		end		

		--
		-- get the next column
		--
		FETCH #hCColid INTO @colid, @key
	end
	CLOSE #hCColid
	DEALLOCATE #hCColid
	drop table #pkcoltab

	--
	-- create the join table now
	--
	select @cmd = N') '
	insert into tempcrtcmd(procedure_text) values(@cmd)
	if exists (select * from dbo.sysobjects where name = N'tempqjointab')
		drop table tempqjointab
	select @cmd = 'select procedure_text from dbo.tempcrtcmd order by c1'
	exec master..xp_execresultset @cmd, @dbname

	--
	-- populate the join table now
	--
	if (@update_mode in (2,3))
	begin
		--
		-- MSMQ case : one call to the xp should populate the join table
		--
		insert into tempqjointab
			exec master.dbo.xp_readpkfromqueue @tablename, @queue_id, @xpinputstr, @tranid
	end
	else
	begin
		--
		-- SQLQ case : select the data for this subscription and call the
		-- xp for each row in the cursor to populate the join table
		--
		declare @spancount int
				,@data varbinary(8000)
				,@state bit
		
		declare #hcurQInfo cursor local FAST_FORWARD FOR
		select data, cmdstate, tranid
		from dbo.MSreplication_queue
		where UPPER(publisher) = UPPER(@publisher) and
				publisher_db = @publisher_db and
				publication = @publication and
				tranid = case when @tranid IS NULL then tranid else @tranid end and
				commandtype = 1
		order by orderkey
		FOR READ ONLY

		select @spancount = 0
		open #hcurQInfo
		fetch #hcurQInfo into @data, @state, @tranid
		while (@@FETCH_STATUS = 0)
		begin
			declare @qbdata0 varbinary(8000)
					,@qbdata1 varbinary(8000)

			if (@state = 1)
			begin
				--
				-- command spanning more than a row
				-- we will allow spanning upto 2 rows
				--
				if (@spancount = 0)
					select @qbdata0 = @data
				else
				begin
					raiserror('sp_getqueuedrows(debug): Queued data spans 3 rows, cannot proceed', 16, -1)
					close #hcurQInfo
					deallocate #hcurQInfo
					select @retcode = 1
					goto cleanup
				end
				select @spancount = @spancount + 1
			end
			else
			begin
				--
				-- final row for the command
				--
				if (@spancount = 0)
					select @qbdata0 = @data				
				else if (@spancount = 1)
					select @qbdata1 = @data
				else
				begin
					raiserror('sp_getqueuedrows(debug): Queued data spans 3 rows, cannot proceed', 16, -1)
					close #hcurQInfo
					deallocate #hcurQInfo
					select @retcode = 1
					goto cleanup
				end

				--
				-- call the xp to populate the join table
				--
				insert into tempqjointab
					exec master.dbo.xp_readpkfromvarbin @tablename, @xpinputstr, @tranid, @spancount, @qbdata0, @qbdata1

				--
				-- reset the span count
				--
				select @spancount = 0
			end

			--
			-- fetch the next row
			--
			fetch #hcurQInfo into @data, @state, @tranid
		end
		close #hcurQInfo
		deallocate #hcurQInfo
	end

	--
	-- Now perform the join
	--
	select @cmd = N'select b.action, b.tranid ' + @selectcl 
		+ N'from ' + @qualified_tabname + N' a right join tempqjointab b on (' + @joincl + N') '
	exec (@cmd)
	
	--
	-- all done
	--
cleanup:	
	if exists (select * from dbo.sysobjects where name = N'tempqjointab')
		drop table tempqjointab
	if exists (select * from dbo.sysobjects where name = 'tempcrtcmd')
		drop table tempcrtcmd
	return @retcode
end
go

EXEC dbo.sp_MS_marksystemobject sp_getqueuedrows
GO


grant execute on dbo.sp_getqueuedrows to public
go

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

raiserror(15339,-1,-1,'sp_verify_publication')
GO

--
-- sp_verify_publication
--
-- Description: Invoked by user on a distributor server to perform a simple replication plumbing check.
--		Tests the connectivity of all the push subscriptions for a given publication.
--		(doesn't test pull or anonymous subscriptions)
--
-- Returns:
-- 		0 if success
--		1 if failure
--
create proc sp_verify_publication (
	@publisher sysname,		/*name of the publisher*/
	@publisher_db sysname,		/*the database for the publication*/
	@publication sysname,		/*name of the publication*/
	@reserved int = 0		/*reserved -- should not be used directly by user.
					  For internal use only.*/
)
AS
BEGIN
set nocount on

if( @reserved = 0 )
begin
  declare @proc nvarchar(255),
	  @distribution_db sysname,
	  @recurse_retcode int
  --
  --verify that this server is a distributor.
  --
  if (not exists( select * from msdb..sysobjects where name = 'MSdistpublishers') )
  begin
    RAISERROR(14114, 16, -1, @@SERVERNAME)
    return(1)
  end
  --
  --get the distribution database
  --
  select @distribution_db = distribution_db from msdb.dbo.MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default
  if( @distribution_db is NULL )
  begin
    RAISERROR(21169, 16, -1, @publisher, @@SERVERNAME, @publisher)
    return(1)
  end

  select @proc = @distribution_db + '.dbo.sp_verify_publication'
  exec @recurse_retcode = @proc @publisher, @publisher_db, @publication, 1
  return(@recurse_retcode)
end

declare @publisher_id smallint,
	@subscriber sysname,
	@subscriber_db sysname,
	@type tinyint,
	@job_id binary(16),
	@publication_type int,
	@agent_type varchar(15),
	@command nvarchar(3200),
	@success varchar(300),
	@srvid smallint

select @srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
if @srvid is NULL
begin
  RAISERROR(21169, 16, -1, @publisher, @@SERVERNAME, @publisher)
  return(1)
end

select @publication_type = publication_type from MSpublications
  where publisher_id = @srvid and
  publisher_db = @publisher_db and
  publication = @publication

if @publication_type is NULL
begin
  RAISERROR(21332, 16, -1, @publication)
  return(1)
end

create table #T_VERIFICATION_RESULTS (
  subscriber sysname NOT NULL, subscriber_db sysname NOT NULL, type int NOT NULL,
  job_id binary(16) NULL, results varchar(300) NULL
)

-- Parameter Check: @publication_type
-- Make sure that the publication type is one of the following:
-- 0  transactional
-- 1  snapshot
-- 2  merge
if( @publication_type = 0 or @publication_type = 1 )
  begin
    select @agent_type = 'distribution'

    create table #T_SUBSCRIPTIONS (subscriber sysname NOT NULL,  status int NOT NULL, 
	subscriber_db sysname NOT NULL,
	type tinyint NOT NULL, distribution_agent nvarchar(100) NOT NULL, last_action nvarchar(255) NULL, 
	action_time nvarchar(24) NULL, start_time nvarchar(24) NULL, duration int NULL, 
	delivery_rate float NULL,
	delivery_latency int NULL, delivered_transactions int NULL, 
	delivered_commands int NULL,
	delivery_time int NULL, average_commands int NULL, 
	error_id int NULL, 
	job_id binary(16) NULL, local_job bit NULL, profile_id int NOT NULL,
	agent_id int NOT NULL, last_timestamp binary(8) NOT NULL, offload_enabled bit NOT NULL, 
	offload_server sysname NULL, subscriber_type tinyint NULL)

    insert #T_SUBSCRIPTIONS
      exec sp_MSenum_subscriptions @publisher, @publisher_db, @publication

    insert into #T_VERIFICATION_RESULTS (subscriber, subscriber_db, type, job_id)
	(select subscriber, subscriber_db, type, job_id from #T_SUBSCRIPTIONS)

    drop table #T_SUBSCRIPTIONS
  end
else if( @publication_type = 2 )
  begin
    select @agent_type = 'merge'

    create table #T_MERGE_SUBSCRIPTIONS (subscriber sysname NOT NULL,  status int NOT NULL, 
        subscriber_db sysname NOT NULL, type int NOT NULL, agent_name nvarchar(100) NOT NULL, last_action nvarchar(255) NULL, 
        action_time nvarchar(24) NULL, start_time nvarchar(24) NULL, duration int NULL, 
        delivery_rate float NULL,
        publisher_insertcount int NULL, publisher_updatecount int NULL, publisher_deletecount int NULL,
        publisher_conficts int NULL, 
        subscriber_insertcount int NULL, subscriber_updatecount int NULL, subscriber_deletecount int NULL,
        subscriber_conficts int NULL, error_id int NULL, job_id binary(16) NULL,
        local_job bit NULL, profile_id int NOT NULL, 
        agent_id int NOT NULL, last_timestamp binary(8) NOT NULL, offload_enabled bit NOT NULL, 
	offload_server sysname NULL, subscriber_type tinyint NULL)

    insert #T_MERGE_SUBSCRIPTIONS
      exec sp_MSenum_merge_subscriptions @publisher, @publisher_db, @publication

    insert into #T_VERIFICATION_RESULTS (subscriber, subscriber_db, type, job_id)
	(select subscriber, subscriber_db, type, job_id from #T_MERGE_SUBSCRIPTIONS)

    drop table #T_MERGE_SUBSCRIPTIONS
  end
else
  begin
    drop table #T_VERIFICATION_RESULTS
    RAISERROR(20033, 16, -1)
    return(1)
  end

if( not exists( select * from #T_VERIFICATION_RESULTS ) )
begin
  --
  --if #T_VERIFICATION_RESULTS is empty, then there's no subscriptions
  --
  RAISERROR(14135, 16, -1, @publisher, @publisher_db, @publication)
  drop table #T_VERIFICATION_RESULTS
  return(1)
end

declare subscribers_cursor cursor LOCAL FAST_FORWARD for
select subscriber, subscriber_db, type, job_id
  from #T_VERIFICATION_RESULTS
  order by subscriber, subscriber_db

open subscribers_cursor
fetch next from subscribers_cursor
  into @subscriber, @subscriber_db, @type, @job_id
while @@FETCH_STATUS = 0
begin
  if( @type = 0 )
  begin
    --
    --local push subscription
    --
    select @command = ''
    select @success = 'unknown'
    select @command = command from msdb.dbo.sysjobsteps
      where job_id = @job_id and
	    subsystem = case @publication_type  -- 0 = Transactional 1 = Snapshot 2 = Merge
	      when 0 then N'Distribution'
	      when 1 then N'Distribution'
	      when 2 then N'Merge'
	    end

    exec master.dbo.xp_replproberemsrv 'local', @agent_type, @success OUTPUT, @command, 1 --(islocal)
    if( @@ERROR <> 0) return(1)
    if UPPER(@success collate SQL_Latin1_General_CP1_CS_AS) = 'FALSE'
      select 'subscriber' = @subscriber, 'subscriber database' = @subscriber_db,
	     'subscription type' = case @type
		    when 0 then 'push'
		    when 1 then 'pull'
		    when 2 then 'anonymous'
		    else 'unknown'
		  end
	     , 'results' = 'connection failed'
    else if( ( CHARINDEX('TRUE', UPPER(@success collate SQL_Latin1_General_CP1_CS_AS)) = 1 ) and (LEN(@success) = 4) )
      select @success = 'connection succeeded'
  end
  else
  begin
    --
    --non-push subscription, not supported
    --
    select @success = 'only push subscriptions can be verified with this stored procedure'
  end

  update #T_VERIFICATION_RESULTS set results = @success where
    subscriber = @subscriber and
    subscriber_db = @subscriber_db and
    type = @type and
    job_id = @job_id
  --
  --get next subscription
  --
  fetch next from subscribers_cursor
    into @subscriber, @subscriber_db, @type, @job_id
end
close subscribers_cursor
deallocate subscribers_cursor

select subscriber, subscriber_db as 'subscriber database', 'subscription type' =
  case type
    when 0 then 'push'
    when 1 then 'pull'
    when 2 then 'anonymous'
    else 'unknown'
  end
, results from #T_VERIFICATION_RESULTS where UPPER(results collate SQL_Latin1_General_CP1_CS_AS) != 'FALSE'

drop table #T_VERIFICATION_RESULTS
END
go
EXEC dbo.sp_MS_marksystemobject sp_verify_publication


grant execute on dbo.sp_verify_publication to public
go

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

raiserror(15339,-1,-1,'sp_scriptdynamicupdproc')
GO

create procedure sp_scriptdynamicupdproc @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 @art_cols     int
declare @this_col     int
declare @art_col      int
declare @pk_col       int
declare @pkart_col    int
declare @isset        int
declare @ispk         int
declare @isidentity   bit
declare @iscomputed   bit
declare @bytestr      nvarchar(10)
declare @bitstr       nvarchar(10)
declare @typestring   nvarchar(255)
declare @spacer_param nvarchar(10)
declare @update_created  bit
declare @pkcomputed   int
declare @pubid        int, @allow_queued_tran bit

set nocount on 

select @update_created	 = 0

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
create table #proctext_params ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
create table #proctext_paramdef ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
create table #proctext_pkparams ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )



-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
	   @pubid = pubid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-------- get dest proc name

if( 1 != charindex( N'MCALL', upper(@upd_cmd) ) ) or @upd_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

declare @keep_identity bit
if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
    select @keep_identity = 1
else
    select @keep_identity = 0

select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
  

-------- construct parameter list

exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

----- add changed data bitmap

select @art_col = 1
select @pk_col = 1

DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
select colid from syscolumns where id = @src_objid order by colid asc

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
   begin
        select @art_col = @art_col + 1
   end
   FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- Note that bitmap size is based on number of article columns
-- (computed by loop above) not source table columns

select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'as' )



-- Find out if pk is identity
declare @pk_is_identity bit
select @pk_is_identity = 0

exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

if @artcolumns != @pkcolumns and @pkcomputed = 0
begin
    select @art_col = 1

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	select @pk_is_identity = 1

	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin 
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
            if @isset != 0
            begin
				if not (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @pk_is_identity = 0
				end
            end
            select @art_col = @art_col + 1
        end
		FETCH hCColid INTO @this_col
    end
	CLOSE hCColid
	DEALLOCATE hCColid
end 

-- construct UPDATE that does not set PK cols
-- only do this if the article contains columns that are not included
-- in the pk
-- Note: we assume pk columns never change. pk changes will be replicated
-- as delete insert.

if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
begin

    -- create SET clause consisting of CASE statements

    select @art_col = 1
    select @spacer_param = N''

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @src_objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0  
		begin
            exec @ispk = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			
			if EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
				select @iscomputed = 0
			else
				select @iscomputed = 1
			
			if (@keep_identity = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)  
				select @isidentity = 1
			else
				select @isidentity = 0
				
			-- If not pk, not computed and not identity	
			if @ispk = 0 and @iscomputed = 0 and @isidentity = 0
            begin
            	if (@update_created = 0)
            	begin
			    	insert into #proctext(procedure_text) values( 
						N'declare @stmt nvarchar(4000), @spacer nvarchar(1)')

			    	insert into #proctext(procedure_text) values( 
						N'select @spacer =N''''')

			    	insert into #proctext(procedure_text) values( 
						N'select @stmt = N''update ' + 
						replace(@dest_owner + QUOTENAME(@dest_tabname), N'''', N'''''' ) +
						N' set ''')

			    	select @update_created = 1
				end

				select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
				select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

				insert into #proctext(procedure_text) values (
					 N'if substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
					 N' = ' + @bitstr)

				insert into #proctext(procedure_text) values (N'begin')

				-- Append statement
				insert into #proctext(procedure_text) values (
					 N'select @stmt = @stmt + @spacer + ' + 
					 N'N''' + replace(QUOTENAME(col_name( @src_objid, @this_col)), N'''', N'''''') + N''' + ' +
					 N'N''=@'+ convert( nvarchar, @art_col ) + N'''')

				-- Set @spacer is the proc
				insert into #proctext(procedure_text) values (
					N'select @spacer = N'',''')

				insert into #proctext(procedure_text) values (N'end')
            end
			-- If pk or (not computed and not identity) add the param
			if @ispk <> 0 or (@iscomputed = 0 and @isidentity = 0)
			begin
				-- Add to param list
			    if (@ispk <> 0)
				  begin
				    -- Use primary key value
				    insert into #proctext_params(procedure_text) values( 
						@spacer_param + N'@pkc' + convert( nvarchar, @pk_col ))

				    -- Increment primary key counter
				    select @pk_col = @pk_col + 1;

				  end
				else
				    -- Use column value
					insert into #proctext_params(procedure_text) values( 
						@spacer_param + N'@c' + convert( nvarchar, @art_col ))

				-- Get type str
				exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT

				-- Append typedef
				insert into #proctext_paramdef(procedure_text) values (
					 @spacer_param + N'@' + convert( nvarchar, @art_col ) + 
					 N' ' + @typestring )

				select @spacer_param = ',' 
			end

            select @art_col = @art_col + 1
        end
       	FETCH hCColid INTO @this_col
    end
	CLOSE hCColid
	DEALLOCATE hCColid

    if @update_created = 1
	begin

		-- Append statement of the start of where clause
		insert into #proctext(procedure_text) values (
			 N'	select @stmt = @stmt + N'' ')

		-- Escape ' in the where clause
		declare @low_mark int, @high_mark int
		select @low_mark = max(c1) from #proctext
		-- Pass in @artcolumns so that the where clause will use the ordinal in the
		-- article bit map rather then one in pk bitmap. This is consistent with
		-- the type def string.
		-- UNDONE: change comments in sp_scriptpkwhereclause
		-- Use prefix '@' to be consistent with type def string
		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, '@', @artcolumns
		select @high_mark = max(c1) from #proctext
		update #proctext set procedure_text = replace ( procedure_text, N'''', N'''''') 
			where c1 > @low_mark and c1 <= @high_mark

		-- Close the where clause
		insert into #proctext(procedure_text) values (
			 N'''')

		-- Add call to sql_executesql and the param list
		insert into #proctext(procedure_text) values( 
			N'exec sp_executesql @stmt, N'' ')

		-- Add param def
		insert into #proctext(procedure_text) 
			select procedure_text from #proctext_paramdef order by c1 asc

		-- Close the param def
		insert into #proctext(procedure_text) values (
			 N''',')

		-- Add param list
		insert into #proctext(procedure_text) 
			select procedure_text from #proctext_params order by c1 asc

		if @allow_queued_tran <> 1
			exec dbo.sp_MSscript_missing_row_check
	end

end

select procedure_text from #proctext order by c1 asc

go
  
EXEC dbo.sp_MS_marksystemobject sp_scriptdynamicupdproc
go

grant execute on sp_scriptdynamicupdproc to public
go  

--------------------------------------------------------------------------------
--.	Merge Replication objects (rladmin.sql)
--------------------------------------------------------------------------------

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

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

create procedure sp_addmergearticle
    @publication            sysname,                            /* publication name */
    @article                sysname,                            /* article name */
    @source_object          sysname,                            /* source object name */
    @type                   sysname = 'table',                  /* article type */
    @description            nvarchar(255)= NULL,                /* article description */
    @column_tracking        nvarchar(10) = 'false',             /* column level tracking */
    @status                 nvarchar(10) = 'unsynced',          /* unsynced, active */
    @pre_creation_cmd       nvarchar(10) = 'drop',              /* 'none', 'drop', 'delete', 'truncate' */
    @creation_script        nvarchar(255)= NULL,                /* article schema script */
    @schema_option          varbinary(8)   = NULL,              /* article schema creation options */
    @subset_filterclause    nvarchar(1000) = '',                /* filter clause */
    @article_resolver       nvarchar(255)= NULL,                 /* custom resolver for article */
    @resolver_info          nvarchar(255) = NULL,                /* custom resolver info */
    @source_owner           sysname = NULL,
    @destination_owner		sysname = NULL,
    @vertical_partition		nvarchar(5) = 'FALSE',				/* vertical partitioning or not */
    @auto_identity_range	nvarchar(5)	= 'FALSE',				/* set it to false for now - change is possible */
    @pub_identity_range		bigint	= NULL,
    @identity_range			bigint = NULL,
    @threshold				int	= NULL,
	@verify_resolver_signature 		int = 0,					/* 0=do not verify signature, 1=verify that signature is from trusted source, more values may be added later */
    @destination_object     		sysname = @source_object,
	@allow_interactive_resolver		nvarchar(5) = 'false',		/* whether article allows interactive resolution or not */
	@fast_multicol_updateproc		nvarchar(5) = 'true',		/* whether update proc should update multiple columns in one update statement or not. if 0, then separate update issued for each column changed. */
	@check_permissions		int = 0, /* bitmap where 0x00 for nochecks, 0x01 for insert check, 0x2 for update check, 0x4 for delete check */
	@force_invalidate_snapshot bit = 0	/* Force invalidate existing snapshot */
    AS

    set nocount on

    /*
    ** Declarations.
    */
	declare @max_range				bigint
    declare @publisher				sysname
    declare @publisher_db			sysname
	declare @already_published		bit
    declare @identity_so_far		bigint
    declare @ver_partition			int
    declare @sp_resolver			sysname
    declare @num_columns            smallint
    declare @pubid                  uniqueidentifier                /* Publication id */
    declare @db                     sysname
	declare @identity_support		int
    declare @object                 sysname
    declare @owner                  sysname
    declare @retcode                int
    declare @objid                  int
    declare @sync_objid             int
    declare @typeid                 smallint
    declare @nickname               int
    declare @merge_pub_object_bit int
    declare @column_tracking_id     int
    declare @cmd                    nvarchar(255)
    declare @statusid               tinyint --1: inactive; 2: active; 5:new_inactive 6:new_active
    declare @next_seed				bigint
    declare @precmdid               int
    declare @resolver_clsid         nvarchar(50)
    declare @resolver_clsid_old     nvarchar(50)
    declare @tablenick              int
    declare @artid                  uniqueidentifier
	declare @i						int
	declare @max_identity			bigint
	declare @colname				sysname
	declare @indid					int
	declare @pkkey					sysname
    declare @distributor            sysname
    declare @distribdb              sysname
    declare @distproc               nvarchar(300)
    declare @dbname                 sysname
    declare @replinfo               int
    declare @db_name                sysname
    declare @subset                 int
    declare @is_publisher			int
    declare @row_size               int
    declare @sp_name				sysname
    declare @sp_owner				sysname
    declare @qualified_name         nvarchar(270)
    declare @snapshot_ready         tinyint
	declare @sync_mode				tinyint
	declare @allow_interactive_bit	bit
	declare @fast_multicol_updateproc_bit bit
    declare @additive_resolver		sysname
    declare @average_resolver		sysname
    declare @mindate_resolver		sysname
    declare @needs_pickup			bit
    declare @maxdate_resolver		sysname
    declare @minimum_resolver		sysname
    declare @maximum_resolver		sysname
    declare @mergetxt_resolver		sysname
    declare @pricolumn_resolver		sysname
	declare @xtype					int
	declare @xprec					int
	declare @initial_setting		bit
	declare @bump_to_80				bit
	declare @gen 					int
	declare @replnick 				int
	declare @genguid 				uniqueidentifier
	declare @guidnull 				uniqueidentifier
	declare @dt 					datetime
	
	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    /*
    ** Initializations 
    */
	set @guidnull = '00000000-0000-0000-0000-000000000000'
    select @is_publisher = 0
    select @initial_setting = 0
    select @needs_pickup = 0
    select @bump_to_80 = 0
    select @already_published = 0
    select @publisher = @@SERVERNAME
    select @publisher_db = db_name()
    select @max_identity	= NULL
    select @next_seed		= NULL
    select @statusid        = 0
    select @resolver_clsid  = NULL
    select @subset          = 1     /* Const: publication type 'subset' */
    select @merge_pub_object_bit    = 128
	select @db_name	= db_name()
    select @sp_resolver 		= 'Microsoft SQLServer Stored Procedure Resolver'
    select @additive_resolver 	= 'Microsoft SQL Server Additive Conflict Resolver'
    select @average_resolver 	= 'Microsoft SQL Server Averaging Conflict Resolver'
    select @minimum_resolver 	= 'Microsoft SQL Server Minimum Conflict Resolver'
    select @maximum_resolver 	= 'Microsoft SQL Server Maximum Conflict Resolver'
    select @mindate_resolver 	= 'Microsoft SQL Server DATETIME (Earlier Wins) Conflict Resolver'
    select @maxdate_resolver 	= 'Microsoft SQL Server DATETIME (Later Wins) Conflict Resolver'
    select @mergetxt_resolver 	= 'Microsoft SQL Server Merge Text Columns Conflict Resolver'
    select @pricolumn_resolver 	= 'Microsoft SQL Server Priority Column Resolver'

    if @source_owner is NULL
        begin
            select @source_owner = user_name(uid) from sysobjects where id = object_id(@source_object)
            if @source_owner is NULL  
                begin
                    raiserror (14027, 11, -1, @source_object)
                    return (1)
                end
        end
    select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_object)

	if @subset_filterclause <> '' and @subset_filterclause is not NULL
	begin
	/* check the validity of subset_filterclause */
	exec ('declare @test int select @test=1 from ' + @qualified_name + ' where ' + @subset_filterclause)
	if @@ERROR<>0
		begin
			raiserror(21256, 16, -1, @subset_filterclause, @article)
			return (1)
		end
	end
    if @destination_owner is NULL
    	select @destination_owner = 'dbo'
    
    /*
    ** Security Check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    /*
    ** Pad out the specified schema option to the left
    */
    select @schema_option = fn_replprepadbinary8(@schema_option)

    /*
    ** Parameter Check: @publication.
    ** The @publication id cannot be NULL and must conform to the rules
    ** for identifiers.
    */   
        
    if @publication is NULL
        begin
            raiserror (14043, 16, -1, '@publication')
            return (1)
        end

    select @pubid = pubid, @snapshot_ready = snapshot_ready, @sync_mode=sync_mode from sysmergepublications 
        where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
    if @pubid is NULL
        begin
            raiserror (20026, 16, -1, @publication)
            return (1)
        end

	if lower(@article)='all'
		begin
			raiserror(21401, 16, -1)
			return (1)
		end

    /*
    ** Parameter Check: @type
    ** If the article is added as a 'indexed view schema only' article,
    ** make sure that the source object is a schema-bound view.
    ** Conversely, a schema-bound view cannot be published as a 
    ** 'view schema only' article.
    */
    select @type = lower(@type collate SQL_Latin1_General_CP1_CS_AS)

    if @type = N'indexed view schema only' and objectproperty(object_id(@qualified_name), 'IsSchemaBound') <> 1
    begin
        raiserror (21277, 11, -1, @qualified_name)        
        return (1)    
    end
    else if @type = N'view schema only' and objectproperty(object_id(@qualified_name), 'IsSchemaBound') = 1
    begin
        raiserror (21275, 11, -1, @qualified_name)
        return (1)
    end

    /*
    ** Only publisher can call sp_addmergearticle
    */
    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
    IF @@ERROR <> 0 or @retcode <>  0
        BEGIN
            RAISERROR (20073, 16, -1)
            RETURN (1)
        END
        
    /*
    ** Parameter Check: @article.
    ** Check to see that the @article 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 @article is NULL
        begin
            raiserror (20045, 16, -1)
            return (1)
        end

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

    /*
    ** 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 collate SQL_Latin1_General_CP1_CS_AS) 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 collate SQL_Latin1_General_CP1_CS_AS) = 'none'
       select @precmdid = 0
    ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
       select @precmdid = 1
    ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
       select @precmdid = 2
    ELSE IF LOWER(@pre_creation_cmd collate SQL_Latin1_General_CP1_CS_AS) = 'truncate'
       select @precmdid = 3


    /*
    ** Set the typeid.  The default type is table.  It can 
    ** be one of following.
    **
    **      @typeid     type
    **      =======     ========
    **         0xa      table
    **        0x20      proc schema only
    **        0x40      view schema only
    **        0x80      func schema only
    **        0x40      indexed view schema only (overloaded)
    */        

    IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('table', 'proc schema only', 'view schema only', 'func schema only', 'indexed view schema only')
       BEGIN
            RAISERROR (20074, 16, -1)
            RETURN (1)
       END

    IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'table'
    BEGIN
       SET @typeid = 0x0a
    END
    ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'proc schema only'
    BEGIN
       SET @typeid = 0x20 
    END
    ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'view schema only'
    BEGIN
       SET @typeid = 0x40
    END
    ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'indexed view schema only'
    BEGIN
       SET @typeid = 0x40
    END
    ELSE IF LOWER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'func schema only'
    BEGIN
       SET @typeid = 0x80
    END

    select @sync_objid = OBJECT_ID(@qualified_name)
    if @sync_objid is NULL
        begin
            raiserror (14027, 11, -1, @qualified_name)
            return (1)
        end


    if @typeid in (0x20,0x40,0x80)
    begin
        if exists (select * from syscomments
                    where id = @sync_objid
                      and encrypted = 1)
        begin
            raiserror(21004, 16, -1, @source_object)
            return 1
        end
    end

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

    IF EXISTS (SELECT *
                 FROM sysmergeextendedarticlesview
                WHERE pubid = @pubid
                  AND name = @article)
        BEGIN
			raiserror (21292, 16, -1, @source_object)
            RETURN (1)
        END
        
    /*
    ** At this point, all common parameter validations 
    ** for table and schema only articles have been 
    ** performed, so branch out here to handle schema
    ** only articles as a special case.
    */
    
    IF @typeid in (0x20, 0x40, 0x80)
    BEGIN
    
        IF @destination_object IS NULL OR @destination_object = N''
        BEGIN
            SELECT @destination_object = @source_object
        END
    
        IF @schema_option IS NULL
        BEGIN
            SELECT @schema_option = 0x0000000000000001
        END
        EXEC @retcode = dbo.sp_MSaddmergeschemaarticle 
            @pubid = @pubid,
            @article = @article,
            @source_object = @source_object,
            @type = @typeid,
            @description = @description,
            @status = @status,
            @pre_creation_command = @precmdid,
            @creation_script = @creation_script,
            @source_owner = @source_owner,
            @destination_owner = @destination_owner,
            @schema_option = @schema_option,
            @destination_object = @destination_object,
            @qualified_name = @qualified_name,   
            @publication = @publication,
            @snapshot_ready = @snapshot_ready,
            @force_invalidate_snapshot = @force_invalidate_snapshot
        
       RETURN (@retcode)
    END

    IF @schema_option IS NULL
    BEGIN
        SELECT @schema_option = 0x000000000000CFF1
    END

    /*
    ** If scheme option contains collation or extended properties, 
    ** bump up the compatibility-level
    */    
    -- Since only the lower 32 bits of @schema_option are 
    -- used, the following check is sufficient. Note that @schema_option is
    -- already padded out to the left at the beginning of this procedure.
    declare @schema_option_lodword int
    declare @xprop_schema_option int
    declare @collation_schema_option int
    select @xprop_schema_option = 0x00002000
    select @collation_schema_option = 0x00001000
    select @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
    if (@schema_option_lodword & @collation_schema_option) <> 0
    begin    
        raiserror(21389, 10, -1, @publication)
        select @bump_to_80 = 1
    end
    if (@schema_option_lodword & @xprop_schema_option) <> 0
    begin   
        raiserror(21390, 10, -1, @publication)
        select @bump_to_80 = 1
    end

    /*
    ** Merge table articles does not really support destination object. It has the same value as source
    */
    select @destination_object = @source_object

/*
    select @row_size=sum(length) from syscolumns where id=OBJECT_ID(@qualified_name)
    if @row_size>6000 
        begin
			RAISERROR (21062, 16, -1, @qualified_name)  
            -- RETURN (1)
        end
*/
	IF LOWER(@vertical_partition collate SQL_Latin1_General_CP1_CS_AS) = 'false'
		begin
			select @ver_partition = 0
		end
	else
		begin			
			select @ver_partition = 1
		end
    select @num_columns=count(*) from syscolumns where id = object_id(@qualified_name)

    if @num_columns > 246 and LOWER(@vertical_partition collate SQL_Latin1_General_CP1_CS_AS) = 'false'
        begin
            RAISERROR (20068, 16, -1, @qualified_name, 246)
            RETURN (1)
        end

    /*
    **  Get the id of the @qualified_name
    */
    select @objid = id, @replinfo = replinfo from sysobjects where id = OBJECT_ID(@qualified_name)
    if @objid is NULL
        begin
            raiserror (14027, 11, -1, @qualified_name)
            return (1)
        end

    /*
    ** If current publication contains a non-sync subscription, all articles to be added in it
    ** has to contain a rowguidcol.
    */
    if exists (select * from sysmergesubscriptions where pubid = @pubid and sync_type = 2)
        begin
            if not exists (select * from syscolumns c 
                where c.id=@objid and ColumnProperty(c.id, c.name, 'isrowguidcol') = 1)
                begin
                    raiserror(20086 , 16, -1, @publication)
                    return (1)
                end
        end

	/*
	** If you want to have identity support, @range and threshold can not be NULL
	*/
	if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' and (@identity_range is NULL or @threshold is NULL or @pub_identity_range is NULL)
		begin
			raiserror(21193, 16, -1)
			return (1)
		end

	if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'false' and (@identity_range is not NULL or @threshold is not NULL or @pub_identity_range is not NULL)
		begin
			raiserror(21282, 16, -1)
			return (1)
		end

	if @threshold<0 OR @threshold>100
		begin
			raiserror(21241, 16, -1)
			return (1)
		end

	if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		begin
			select @identity_support = 1
			if OBJECTPROPERTY(@objid, 'tablehasidentity') <> 1
			begin
				raiserror(21194, 16, -1)
				return (1)
			end
		
		    if @pub_identity_range <= 1 or @identity_range <= 1
			begin
				raiserror(21232, 16 ,-1)
				return 1
			end

			select @xtype=xtype, @xprec=xprec from syscolumns where id=@objid and columnproperty(id, name, 'IsIdentity')=1
			select @max_range =
					case @xtype when 52 then power((convert(bigint,2)), 8*2-1) - 1 --smallint 
						when 48 then power((convert(bigint,2)), 8-1) - 1 		 --tinyint
						when 56 then power((convert(bigint,2)), 8*4-1) - 1 		 --int
						when 127 then power((convert(bigint,2)), 62) - 1 + power((convert(bigint,2)), 62)  	--bigint
 						else
							power((convert(bigint,2)), 62) -1 + power((convert(bigint,2)), 62)  -- defaulted to bigint
					end

			if (@xtype=108 or @xtype=106) and @xprec<18
				select @max_range = power((convert(bigint,10)), (@xprec+1)) - 1
		
			if @pub_identity_range * 2 + @identity_range > (@max_range - IDENT_CURRENT(@source_object))
				begin
					raiserror(21290, 16, -1)
					return (1)
				end
		end
	else
		select @identity_support = 0			


    /*
    ** 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(@qualified_name)) AND type = 'U')
        begin
            raiserror (20074, 16, -1)
            return (1)
        end

    /*
    ** If the table contains one more columns of type bigint or sql_variant, 
    ** and the publication is not of type native mode, we bump up the backward 
    ** compatibility level.
    */
    if @sync_mode=0 and EXISTS (SELECT * FROM syscolumns c WHERE c.id = @sync_objid
                AND (type_name(c.xtype) = 'bigint' or type_name(c.xtype) = 'sql_variant'))
	begin
		raiserror(21357, 10, -1, @publication)
		select	@bump_to_80 = 1
	end

	/*
	** 7.0 subscribers do not like data type 'timestamp'
	*/
	if EXISTS (select * from syscolumns where id=@sync_objid and type_name(xtype) ='timestamp')
	begin
		raiserror(21358, 10, -1, @publication)
		select @bump_to_80 = 1
	end
        
    /*
    ** Validate the column tracking
    */
    if @column_tracking IS NULL OR LOWER(@column_tracking collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@column_tracking')
            RETURN (1)
        END
    if LOWER(@column_tracking collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        SET @column_tracking_id = 1
    else 
        SET @column_tracking_id = 0

	if @column_tracking_id=0 and @sync_mode = 1 and @ver_partition = 1
		begin
			RAISERROR (21244, 16, -1)
            RETURN (1)
		end

   	/*
    ** Parameter Check: @allow_interactive_resolver  
    */
    if LOWER(@allow_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_interactive_resolver')
            RETURN (1)
        END
    if LOWER(@allow_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        set @allow_interactive_bit = 1
    else 
        set @allow_interactive_bit = 0

	/*
    ** Parameter Check: @fast_multicol_updateproc  
    */
	if LOWER(@fast_multicol_updateproc collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@fast_multicol_updateproc')
            RETURN (1)
        END
    if LOWER(@fast_multicol_updateproc collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        set @fast_multicol_updateproc_bit = 1
    else 
        set @fast_multicol_updateproc_bit = 0

    /*
    ** Get the pubid.
    */
    SELECT @pubid = pubid FROM sysmergepublications 
        WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
    if @pubid is NULL
        begin
            raiserror (20026, 11, -1, @publication)
            return (1)
        end

    execute @retcode = dbo.sp_MSgetreplnick @pubid = @pubid, @nickname = @nickname output
    if (@@error <> 0) or @retcode <> 0 or @nickname IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

	/*
	** 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 or @distributor is NULL
	BEGIN
		RAISERROR (21337, 16, -1)
		RETURN (1)
	END

    /*
    ** Validate the article resolver
    */
    if @article_resolver IS NOT NULL
        begin
            if @article_resolver = 'default' OR @article_resolver = ''
                begin
                    select @article_resolver = NULL
                    select @resolver_clsid = NULL
                end                 
            else
                begin
                    /*
                    ** Get the distributor info
                    */
                    select @distproc = RTRIM(@distributor) + '.master.dbo.xp_regread'
                    EXECUTE @retcode = @distproc 'HKEY_LOCAL_MACHINE',
                                  'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver',
                                  @article_resolver,
                                  @param = @resolver_clsid  OUTPUT

                    IF @retcode <> 0 or @resolver_clsid IS NULL
                        BEGIN
                          RAISERROR (20020, 16, -1)
                          RETURN (1)
                        END
                end
        end

	/*
	** If article resolver is 'SP resolver', make sure that resolver_info refers to an SP or XP;
	** Also make sure it is stored with owner qualification
	*/
	if  @article_resolver = @sp_resolver
		begin
			if not exists (select * from sysobjects where id = object_id(@resolver_info) and ( type = 'P' or type = 'X'))
				begin
					raiserror(21343, 16, -1, @resolver_info)
					return (1)
				end
				
			select @sp_name = name, @sp_owner=user_name(uid) from sysobjects where id = object_id(@resolver_info)
			select @resolver_info = QUOTENAME(@sp_owner) + '.' + QUOTENAME(@sp_name) 
		end

	/* The following resolvers expect the @resolver_info to be NON NULL */
	if  @article_resolver = @sp_resolver or 
		@article_resolver = @additive_resolver or
		@article_resolver = @average_resolver or
		@article_resolver = @minimum_resolver or
		@article_resolver = @maximum_resolver or
		@article_resolver = @mindate_resolver or
		@article_resolver = @maxdate_resolver or
		@article_resolver = @mergetxt_resolver or
		@article_resolver = @pricolumn_resolver
		begin
		    if @resolver_info IS NULL 
		        begin
        			RAISERROR (21301, 16, -1, @article_resolver)
					return (1)
		        end
		end
	/*
	** If article resolver uses column names, make sure that resolver_info refers to a valid column.
	*/
	if  @article_resolver = @pricolumn_resolver or
		@article_resolver = @additive_resolver or
		@article_resolver = @average_resolver or
		@article_resolver = @minimum_resolver or
		@article_resolver = @maximum_resolver
		begin
			if not exists (select * from syscolumns where id = @objid and name=@resolver_info)
				begin
		            RAISERROR (21501, 16, -1, @article_resolver)
					return (1)
				end
		end
	/*
	** If article resolver is 'mindate/maxdate resolver', make sure that resolver_info refers to a column that is of datatype 'datetime' or smalldatetime
	*/
	if  @article_resolver = @mindate_resolver or
		@article_resolver = @maxdate_resolver
		begin
			if not exists (select * from syscolumns where id = @objid and name=@resolver_info and type_name(xtype)='datetime' or type_name(xtype) = 'smalldatetime' )
				begin
		            RAISERROR (21302, 16, -1, @article_resolver)
					return (1)
				end
		end

	/* The following resolvers expect the article to be column tracked - warn that the default resolver will be used */
	if  @article_resolver = @additive_resolver or
		@article_resolver = @average_resolver or
		@article_resolver = @mergetxt_resolver
		begin
			if @column_tracking_id = 0
				begin
		            RAISERROR (21303, 10, -1, @article, @article_resolver)
				end
				
		end

    if @resolver_info IS NOT NULL and @article_resolver IS NULL
	    begin
    	    RAISERROR (21300, 10, -1, @article)
        	set @resolver_info = NULL
        end

	/* Make sure that coltracking option matches */
	if exists (select * from sysmergearticles where objid = @objid and
			identity_support <> @identity_support)
		begin
			raiserror (21240, 16, -1, @source_object)
			return (1)
		end

	-- Do not allow the table to be published by both merge and queued tran
	if exists (select * from sysobjects where name = 'syspublications')
	begin
		if exists (select * from syspublications p, sysarticles a where 
			p.allow_queued_tran = 1 and
			p.pubid = a.pubid and
			a.objid = @objid)
		begin
			declare @obj_name sysname
			select @obj_name = object_name(@objid)
			raiserror(21266, 16, -1, @obj_name)
			return (1)
		end
	end

	if exists (select * from sysmergearticles where objid=@objid and pubid in(select pubid from sysmergepublications where UPPER(publisher)=UPPER(@publisher) 
        		and publisher_db=@publisher_db))
	select @already_published = 1

	if @already_published = 1 and LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true'
	begin
		raiserror(21359, 10, -1, @publication)
		select @bump_to_80 = 1
		if exists (select * from MSrepl_identity_range where objid=@objid and 
			((pub_range<>@pub_identity_range) or (range <> @identity_range) or (threshold <> @threshold)))
			begin
				raiserror(21291, 16, -1)
				return (1)
			end
	end
	
    /*
    **  Add article to sysmergearticles and update sysobjects category bit.
    */
    begin tran
    save TRAN sp_addmergearticle

	/*
	** We used to prevent an article from being added to a publication whose snapshot
	** has been run already. Now we change this so that it is acceptable by doing reinit.
	*/
		if @snapshot_ready > 0 
		begin
			if @force_invalidate_snapshot = 0
			begin
				raiserror(21364, 16, -1, @article)
				goto FAILURE
			end
			update sysmergepublications set snapshot_ready=2 where pubid=@pubid
			if @@ERROR<>0
				goto FAILURE
		end

	/* 
	** article status 5 or 6 means there is at least one new article after snapshot is ready
	** hence all articles added after that point will be new articles as well, regardless of snapshot_ready value.
	*/
		if @snapshot_ready>0 or exists (select * from sysmergearticles where pubid=@pubid and (status=5 or status=6))
		begin
			select @needs_pickup=1
		end


        /*
        ** the case when @already_publisher=1 has been handled outside of the transaction
        */
        if LOWER(@auto_identity_range collate SQL_Latin1_General_CP1_CS_AS) = 'true' and @already_published = 0
		begin
			-- Set the range to negtive if incr of the identity is negtive
	        if IDENT_INCR(@source_object) < 0
    	    begin
        	    select @pub_identity_range = -1 * @pub_identity_range;
            	select @identity_range = -1 * @identity_range;
	        end
			raiserror(21359, 10, -1, @publication)
			select @bump_to_80 = 1
			select @next_seed = next_seed, @max_identity=max_identity from MSrepl_identity_range where objid=@objid
			select @identity_so_far = 0
			if @next_seed is NULL
			begin
				select @initial_setting = 1 -- adjust for existing rows, only for original publisher
				select @is_publisher= 1 --original publisher
				select @identity_so_far = IDENT_CURRENT(@source_object)
				if @identity_so_far is NULL
					begin
						select @next_seed = IDENT_SEED(@source_object)
						select @identity_so_far = @next_seed
					end
				else
					select @next_seed = @identity_so_far

				-- use boundary values by cutting off odds,	
				-- and always give publisher side one more range to allow for existing rows.				

				/* To avoid div by zero errors, error out if pub_range is 0 */
				if @pub_identity_range = 0
					begin
						goto FAILURE
					end
				select @next_seed = (@next_seed/@pub_identity_range) * @pub_identity_range 

				-- to compensate publisher side an extra range in case it loses some slots by rounding up.
				-- which only happens when the identity incremental is a positive value

				if (((@pub_identity_range > 0) and (@identity_so_far > @next_seed))
					OR
					((@pub_identity_range < 0) and (@identity_so_far < @next_seed))) --to make it symmetric both directions
					
					select @next_seed = @next_seed + @pub_identity_range
					
				select @max_identity = @max_range --max range decided by data type of identity column
				
				insert MSrepl_identity_range(objid, next_seed, pub_range, range, max_identity, threshold, current_max)
					values (@objid,@next_seed + @pub_identity_range, @pub_identity_range, @identity_range, @max_identity, @threshold, @next_seed + @pub_identity_range)
			end	
			else
			begin
				select @is_publisher=2 -- republisher
				update MSrepl_identity_range set current_max = @next_seed + @pub_identity_range,
												 pub_range = @pub_identity_range,
												 threshold= @threshold,
												 range = @identity_range
					where objid=@objid
				if @@ERROR<>0
					goto FAILURE
			end
				
	        select @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSinsert_identity'
			SELECT @dbname =  DB_NAME()
			exec @retcode = @distproc @publisher = @publisher,
									  @publisher_db = @publisher_db,
									  @identity_support=@identity_support,
									  @tablename=@source_object,
									  @pub_identity_range = @pub_identity_range,
									  @identity_range =@identity_range,
									  @threshold =@threshold,
									  @next_seed = @next_seed,
									  @max_identity=@max_identity
			if @retcode<>0 or @@ERROR<>0
				goto FAILURE
				
			/* This is to change identity column to 'not for replication' if not having been so already */
			select @colname=NULL
			select @colname = name from syscolumns  where
				 id = @objid and
				 colstat & 0x0001 <> 0 and -- is identity
				 colstat & 0x0008 = 0 -- No 'not for repl' property
			if @colname is not null
			begin
                exec @retcode  = dbo.sp_replupdateschema @source_object
				-- Mark 'not for repl'
				update syscolumns set colstat = colstat | 0x0008 where
					id = @objid and name = @colname
				-- Single to refresh the object cache.
                exec @retcode  = dbo.sp_replupdateschema @source_object
				IF @@ERROR <> 0 OR @retcode <> 0
					goto FAILURE
			end

		end

        select @artid = artid from sysmergearticles where objid = @objid
        select @statusid = 1  /*default status is inactive */

        if @artid is NULL
            begin
                set @artid = newid()
                if @@ERROR <> 0
                    goto FAILURE
                execute @retcode = dbo.sp_MSgentablenickname @tablenick output, @nickname, @objid
                if @@ERROR <> 0 OR @retcode <> 0
                    goto FAILURE
            end
        /* Clone the article properties if article has already been published (in a different pub) */
        else
            begin
            /*
            ** Parameter Check:  @article, @publication.
            ** Check if the table already exists in this publication.
            */
            if exists (select * from sysmergearticles
                where pubid = @pubid AND artid = @artid)
                begin
                    raiserror (21292, 16, -1, @source_object)
                    goto FAILURE
                end
            
            /* Make sure that coltracking option matches */
            if exists (select * from sysmergearticles where artid = @artid and
                         column_tracking <> @column_tracking_id)
                begin
                    raiserror (20030, 16, -1, @article)
                    goto FAILURE
                end

            /* Reuse the article nickname if article has already been published (in a different pub)*/
            select @tablenick = nickname from sysmergearticles where artid = @artid
            if @tablenick IS NULL
                goto FAILURE
                
            /* Make sure that @resolver_clsid matches the existing resolver_clsid */
            select @resolver_clsid_old = resolver_clsid from sysmergearticles where artid = @artid 
            if ((@resolver_clsid IS NULL AND @resolver_clsid_old IS NOT NULL) OR
                (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NULL) OR
                (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NOT NULL AND @resolver_clsid_old <> @resolver_clsid))
                begin
                    raiserror (20037, 16, -1, @article)
                    goto FAILURE
                end

            /* Insert to articles, copying some stuff from other article row */
            insert into sysmergearticles (name, type, objid, sync_objid, artid, description,
                    pre_creation_command, pubid, nickname, column_tracking, status,
                    creation_script, article_resolver,
                    resolver_clsid, schema_option, 
                    destination_object, destination_owner, subset_filterclause, view_type, resolver_info, gen_cur, 
                    missing_cols, missing_col_count, excluded_cols, excluded_col_count, identity_support,
                    before_image_objid, before_view_objid, verify_resolver_signature, allow_interactive_resolver, 
                    fast_multicol_updateproc, check_permissions)
                -- use top 1, distinct could return more than one matching row if status different on partitioned articles
                select top 1 @article, type, objid, @sync_objid, @artid, @description, @precmdid,
                    @pubid, nickname, column_tracking, @statusid, @creation_script,
                    article_resolver, resolver_clsid, @schema_option, @destination_object, @destination_owner, @subset_filterclause, 
                    0, resolver_info, gen_cur, 0x00, 0, 0x00,0, identity_support,
                    before_image_objid, before_view_objid, verify_resolver_signature, allow_interactive_resolver, 
                    fast_multicol_updateproc, check_permissions
                    from sysmergearticles where artid = @artid

            /* Jump to end of transaction  */
            goto DONE_TRAN
            end

        /* Add the specific GUID based replication columns to sysmergearticles */
        insert sysmergearticles (name, objid, sync_objid, artid, type, description, pubid, nickname, 
                column_tracking, status, schema_option, pre_creation_command, destination_object, destination_owner, 
                article_resolver, resolver_clsid, subset_filterclause, view_type, resolver_info, columns,
                missing_cols, missing_col_count, excluded_cols, excluded_col_count, identity_support,
                before_image_objid, before_view_objid, verify_resolver_signature, creation_script, allow_interactive_resolver, 
                fast_multicol_updateproc, check_permissions)
        values (@article, @objid, @sync_objid, @artid, @typeid, @description, @pubid, @tablenick, 
                @column_tracking_id, @statusid, @schema_option, @precmdid, @destination_object, @destination_owner, 
                @article_resolver, @resolver_clsid, @subset_filterclause, 0, @resolver_info, NULL,
                 0x00, 0, 0x00,0, @identity_support, NULL, NULL, @verify_resolver_signature, @creation_script, @allow_interactive_bit, 
                 @fast_multicol_updateproc_bit, @check_permissions)
        if @@ERROR <> 0
            goto FAILURE

        exec @retcode = dbo.sp_replupdateschema @qualified_name
        if @@ERROR <> 0 or @retcode <> 0
            goto FAILURE
        update sysobjects set replinfo = (replinfo | @merge_pub_object_bit) where id = @objid
        if @@ERROR <> 0
            goto FAILURE

        /* set up the article's gen-cur */
		set @genguid = newid()
		set @dt = getdate()

		exec @retcode=sp_MSgetreplnick @nickname = @replnick out
		if @retcode<>0 or @@error<>0 
			goto FAILURE

		/*
		** If there are no zero generation tombstones or rows, add a dummy row in there. 
		*/
	   	if not exists (select * from MSmerge_genhistory)
			begin
			begin tran
		   	insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
				(@genguid, @genguid, 1, 0, @replnick, @dt)
			if (@@error <> 0)
				begin
				goto FAILURE
				end	
			commit tran
			end

		/* Make a generation and update the article's gen_cur */
		select @gen = max(gen_cur) from sysmergearticles (updlock holdlock) where nickname = @tablenick and gen_cur is not null
		if @gen is null
			begin
			set @genguid = newid()
			set @dt = getdate()
			insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
				select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @tablenick, @replnick, @dt from MSmerge_genhistory (updlock)
			if (@@error <> 0)
				goto FAILURE
			select @gen =  generation from MSmerge_genhistory where guidsrc = @genguid
			update sysmergearticles set gen_cur = @gen where nickname = @tablenick
			if (@@error <> 0)
				goto FAILURE
			end

        /* If the article status is active then prepare the article for merge replication */
        if @status = 'active'
            begin
                /* Get a holdlock on the underlying table */
                select @cmd = 'select * into #tab1 from '
                select @cmd = @cmd + @qualified_name 
                select @cmd = @cmd + '(TABLOCK HOLDLOCK) where 1 = 2 '
                execute(@cmd)

                /* Add the guid column to the user table */
                execute @retcode = dbo.sp_MSaddguidcolumn @source_owner, @source_object
                if @@ERROR <> 0 OR  @retcode <> 0  -- NOTE: new change
                    goto FAILURE

                /* Create an index on the rowguid column in the user table */
                execute @retcode = dbo.sp_MSaddguidindex @publication, @source_owner, @source_object
                if @@ERROR <> 0 OR @retcode <> 0
                    goto FAILURE

                /* Create the merge triggers on the base table */
                execute @retcode = dbo.sp_MSaddmergetriggers @qualified_name, NULL, @column_tracking_id
                if @@ERROR <> 0 OR @retcode <> 0
                    goto FAILURE 

                /* Create the merge insert/update stored procedures for the base table */
                execute @retcode = dbo.sp_MSsetartprocs @publication, @article
                if @@ERROR <> 0 OR @retcode <> 0
                    goto FAILURE

                /* Set the article status to be active so that Snapshot does not do this again */
                select @statusid = 2 /* Active article */
                update sysmergearticles set status = @statusid where artid = @artid
                if @@ERROR <> 0 
                    goto FAILURE
            end
        
DONE_TRAN:				
			/* identity range control is row level. So one the one is needed for each table */
			if @identity_support=1 and @already_published=0
			begin

				exec @retcode = sp_MSreseed @objid=@objid,
										@next_seed=@next_seed,
										@range = @pub_identity_range,
										@is_publisher=@is_publisher,
										@check_only = 1,
										@initial_setting = @initial_setting,
										@bound_value = @identity_so_far
				if @@ERROR<>0 or @retcode<>0
						goto FAILURE
			end

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

        IF @ver_partition = 0 --meanning no vertical partition needed.
        BEGIN
            EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication=@publication, @article=@article, @schema_replication='true'            
			IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
				RAISERROR(21198, 16, -1)
				goto FAILURE
            END
        END

        /*
        **  Set all bits to '1' for all columns in the primary key.
        */
        ELSE
        BEGIN
            SELECT @indid = indid FROM sysindexes WHERE id = @objid 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_object, @indid, @i)
                if @pkkey is NULL
                    break
                EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication, @article, @pkkey, 'add'
                IF @@ERROR <> 0 OR @retcode <> 0
                BEGIN
					RAISERROR(21198, 16, -1)
					goto FAILURE
				END
                select @i = @i + 1
            END
			/*
			** make sure any existing rowguidcol is in the partition. We can not live without it.
			*/
			select @colname=NULL
			select @colname = name from syscolumns where id = @objid 
				and ColumnProperty(@objid, name, 'isrowguidcol') = 1
			if @colname is not NULL
			BEGIN
				EXECUTE @retcode  = dbo.sp_mergearticlecolumn @publication, @article, @colname, 'add'
				if @@error<>0 or @retcode<>0
					goto FAILURE
			END
		END

        exec @retcode = sp_MSfillupmissingcols @publication, @source_object
        if @retcode<>0 or @@ERROR<>0
        	goto FAILURE

        /*
        ** For articles with subset filter clause - set the pub type to subset
        */
        if len(@subset_filterclause) > 0
            begin
                execute @retcode = dbo.sp_MSsubsetpublication @publication
                if @@ERROR <> 0 or @retcode<>0
                    goto FAILURE
            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,
            @destination_object = @destination_object,
            @source_owner = @source_owner,
            @source_object = @source_object,
            @description = @description
            -- @article_id = NULL
        IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                goto FAILURE
            END

		if @bump_to_80=1
			begin
				exec @retcode = sp_MSBumpupCompLevel @pubid, 40
				if @@ERROR<>0 or @retcode<>0
					goto FAILURE
			end
		if @needs_pickup=1
			begin
				declare @needs_pick_value int 
				select @needs_pick_value=5 --new_inactive status
				update sysmergearticles set status=@needs_pick_value where artid = @artid and pubid=@pubid
				if @@ERROR<>0
					goto FAILURE

                /* 
                ** Add the guid column to the user table if needed, cause snapshot_ready>0 would imply
                ** this article has got a rowguid column. No need to add index, triggers, or procedures
                ** as snapshot run will take care of those.
                */
                execute @retcode = dbo.sp_MSaddguidcolumn @source_owner, @source_object
                if @@ERROR <> 0 OR  @retcode <> 0  -- NOTE: new change
                    goto FAILURE

                execute @retcode = dbo.sp_MSaddguidindex @publication, @source_owner, @source_object
                if @@ERROR <> 0 OR @retcode <> 0
                    goto FAILURE
                    
			end

        COMMIT TRAN 

        /* If the article status is active adding the merge triggers to the base table */
         
        return (0)
FAILURE:
        RAISERROR (20009, 16, -1, @article, @publication)
        if @@TRANCOUNT > 0
        begin
            ROLLBACK TRANSACTION sp_addmergearticle
            COMMIT TRANSACTION
        end
        return (1)
go

exec dbo.sp_MS_marksystemobject sp_addmergearticle
go

grant execute on dbo.sp_addmergearticle to public
go


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

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

CREATE PROCEDURE sp_MSchangemergeschemaarticle (
    @pubid uniqueidentifier,
    @artid uniqueidentifier,
    @property sysname,
    @value nvarchar(2000)
    ) AS
    
    set nocount on

    /*
    ** No need to bump the compatibility level
    ** here as the compatibility level for
    ** a publication with a schema-only article 
    ** is already 80
    */
    declare @schema_option   binary(8)
    declare @precmdid        tinyint
    declare @creation_script nvarchar(255)
    declare @statusid        tinyint
    declare @type            tinyint
    declare @source_object   sysname
    declare @valid_schema_options int

    /* 
    ** Parameter Check: @property
    ** Check to make sure that @property is a valid property in 
    ** sysmergeschemaarticles.
    */
    select @property = lower(@property collate SQL_Latin1_General_CP1_CS_AS)
    if @property NOT IN ('description',
                         'pre_creation_command',
                         'creation_script',
                         'status',
                         'schema_option',
                         'destination_owner',
                         'destination_object')
    begin
        raiserror(21224, 16, -1, @property)
        return (1)
    end  

    select @type = type, @source_object = object_name(objid)
      from sysmergeextendedarticlesview
     where pubid = @pubid
       and artid = @artid 

    -- Since all property changes will take the form of 
    -- simple update stataments, no transaction will be 
    -- started. 

    if @property = N'description'
    begin
        update sysmergeschemaarticles 
           set description = @value 
         where pubid = @pubid
           and artid = @artid
            
        if @@error <> 0
            return 1
    end
    else if @property = N'pre_creation_command'
    begin
        /*
        ** The value for the pre_creation_command
        ** property must be either 'none' or 'drop'  
        */
        select @value = lower(@value collate SQL_Latin1_General_CP1_CS_AS)
        if @value not in (N'none', N'drop')
        begin
            raiserror(21223, 16, -1)
            return (1)
        end
 
        if @value = N'none'
            select @precmdid = 0
        else if @value = N'drop'
            select @precmdid = 1 
            
        update sysmergeschemaarticles
           set pre_creation_command = @precmdid
         where pubid = @pubid
           and artid = @artid

        if @@error <> 0
            return (1)

    end   
    else if @property = N'creation_script'
    begin
        if @value is NULL or @value = N''
        begin
            /*
            ** Existing schema option must not be 
            ** 0x0000000000000000 if the creation_script 
            ** path has to be set to null
            */

            select @schema_option = schema_option from sysmergeschemaarticles
            where pubid = @pubid and artid = @artid
/*            
            if @schema_option = 0x0000000000000000
            begin
                raiserror(21218, 16, -1)
                return (1)
            end
*/

        end

        update sysmergeschemaarticles 
           set creation_script = @value
         where pubid = @pubid 
           and artid = @artid     

        if @@error <> 0
            return (1)

    end 
    else if @property = N'status'
    begin
        select @value = lower(@value collate SQL_Latin1_General_CP1_CS_AS)

        if @value not in ('active', 'unsynced')
        begin
            raiserror(20075, 16, -1)
            return (1)
        end

        if @value = N'unsynced'
            select @statusid = 1
        else if @value = N'active'
            select @statusid = 2

        update sysmergeschemaarticles
           set status = @statusid 
         where pubid = @pubid
           and artid = @artid
        
        if @@error <> 0
            return (1)
    end
    else if @property = N'schema_option'
    begin
       
        if @value is null
        begin
            raiserror(14146, 16,1)
            return (1)
        end

        create table #tab_changeschemaarticle (value varbinary(8) NULL)
        if @@error <> 0
        begin
            return(1)
        end
    
        exec ('insert #tab_changeschemaarticle values (' + 
            @value + ')')    
    
        if @@error <> 0
        begin
            drop table #tab_changeschemaarticle    
            return (1)
        end
    
        select @schema_option = fn_replprepadbinary8(value) 
          from #tab_changeschemaarticle
     
        /*
        ** schema_option can only contain the bits 0x0000000000000001 and
        ** 0x0000000000002000
        ** for schema only articles except view. View articles can contain 
        ** the options 0x0000000000000010, 0x0000000000000020, and 0x0000000000000100 
        ** in addition to the aforementioned options.
        */
        if @type = 0x40
        begin

            -- Since only the lower 32 bits of @schema_option are
            -- currently, the following check is sufficient.
            declare @schema_option_lodword int
            select @valid_schema_options = 0x2151
            select @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
            if (@schema_option_lodword & ~@valid_schema_options) <> 0
            begin
                raiserror (21229, 16, -1)
                return (1)
            end
        end
        else if @schema_option not in (0x0000000000000000,
                                       0x0000000000000001,
                                       0x0000000000002000,
                                       0x0000000000002001)
        begin
            drop table #tab_changeschemaarticle 
            raiserror (21222, 16, -1)
            return (1)
        end

        if exists (select * from #tab_changeschemaarticle 
                    where value = 0x0000000000000000)
        begin

            select @creation_script = NULL
            select @creation_script = creation_script 
              from sysmergeschemaarticles
             where pubid = @pubid
               and artid = @artid
/*            
            if @creation_script is NULL or 
               @creation_script = N''
            begin
                raiserror(21218, 16, -1) 
                drop table #tab_changeschemaarticle    
                return (1)
            end
*/
        end 
            
        update sysmergeschemaarticles
           set schema_option = fn_replprepadbinary8(tab.value)
          from #tab_changeschemaarticle tab
         where pubid = @pubid 
           and artid = @artid
        
        if @@error <> 0
        begin
            drop table #tab_changeschemaarticle    
            return (1)
        end

        drop table #tab_changeschemaarticle    
            
        if @@error <> 0
            return (1)
    end
    else if @property = N'destination_owner'
    begin
        select @value = rtrim(@value) 
        update sysmergeschemaarticles 
           set destination_owner = @value
         where pubid = @pubid
           and artid = @artid
        
        if @@error <> 0
            return (1)
    end
    else if @property = N'destination_object'
    begin
        select @value = rtrim(@value) 
        if @value is null or @value = ''
        begin
            select @value = @source_object
        end
        update sysmergeschemaarticles
           set destination_object = @value
         where pubid = @pubid
           and artid = @artid        
    end

    return (0)        

go

exec dbo.sp_MS_marksystemobject sp_MSchangemergeschemaarticle
go

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

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

CREATE PROCEDURE sp_changemergearticle (
    @publication sysname,              /* Publication name */
    @article sysname,              /* Article name */
    @property sysname = NULL,          /* The property to change */
    @value nvarchar(2000) = NULL,             /* The new property value */
	@force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @sp_resolver			sysname
    declare @db_name            sysname
    declare @intvalue			bigint
    declare @artid              uniqueidentifier
    declare @pubid              uniqueidentifier
    declare @artidstr           nvarchar(38)
    declare @object_view		sysname
	declare @vertical			int
    declare @pubidstr           nvarchar(38)
    declare @object             sysname
    declare @owner              sysname
    declare @identity_support 	int
    declare @column_list		nvarchar(4000)
    declare @resolver_clsid     nvarchar(50)
    declare @article_resolver   nvarchar(255)
    declare @resolver_clsid_str nvarchar(55)
    declare @article_resolver_str   nvarchar(270)
	declare @value_str			nvarchar(270)
    declare @retcode            int
    declare @statusid           int
    declare @precmdid           tinyint
    declare @regkey             nvarchar(255)
    declare @distributor        sysname
    declare @distribdb        sysname
    declare @distproc           nvarchar(300)
    declare @snapshot_ready		int
    declare @schemaversion      int 
    declare @objid				int
    declare @schemaguid         uniqueidentifier
    declare @schematype         int
    declare @schematext         nvarchar(2000)
    declare @type               tinyint
    declare @allow_interactive_bit	int
    declare @additive_resolver		sysname
    declare @average_resolver		sysname
    declare @mindate_resolver		sysname
    declare @maxdate_resolver		sysname
    declare @minimum_resolver		sysname
    declare @maximum_resolver		sysname
    declare @mergetxt_resolver		sysname
    declare @pricolumn_resolver		sysname
	declare @pre_command			int
	declare @coltrack				int

	declare @qual_object_view		nvarchar(140)
	declare @qual_object			nvarchar(140)
	declare @quoted_object			nvarchar(140)
    declare @bump_to_80             bit
    declare @schema_option          binary(8)
    declare @old_schema_option      binary(8)

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

	select @db_name = db_name()
    select @bump_to_80 = 0

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

    if (select category & 4
          FROM master..sysdatabases
         WHERE name = @db_name collate database_default) = 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

    select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications 
        where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=@db_name
    if @pubid IS NULL
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END
	
    select @db_name = db_name from sysmergesubscriptions
        where (pubid=@pubid) and (subid=@pubid)
        IF @db_name <> @db_name
        BEGIN
            RAISERROR (20047, 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 collate database_default)
            INSERT INTO #tab1 VALUES ('description')
            INSERT INTO #tab1 VALUES ('pre_creation_command')
            INSERT INTO #tab1 VALUES ('creation_script')
            INSERT INTO #tab1 VALUES ('column_tracking (table article only)')
            INSERT INTO #tab1 VALUES ('article_resolver (table article only)')
            INSERT INTO #tab1 VALUES ('resolver_info (table article only)')
            INSERT INTO #tab1 VALUES ('status')
            INSERT INTO #tab1 VALUES ('subset_filterclause (table article only)')
            INSERT INTO #tab1 VALUES ('schema_option')
            INSERT INTO #tab1 VALUES ('destination_owner')
   			INSERT INTO #tab1 VALUES ('pub_identity_range (table article only)')
			INSERT INTO #tab1 VALUES ('identity_range (table article only)')
			INSERT INTO #tab1 VALUES ('threshold (table article only)')
			INSERT INTO #tab1 VALUES ('verify_resolver_signature')
			INSERT INTO #tab1 VALUES ('allow_interactive_resolver')
			INSERT INTO #tab1 VALUES ('check_permissions')
            select * FROM #tab1
            RETURN (0)
        END

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

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

    select @artid = artid, 
           @type = type,
           @old_schema_option = schema_option,
           @objid = objid
     FROM sysmergeextendedarticlesview
        WHERE name = @article AND pubid = @pubid
    if @artid IS NULL
        BEGIN
            RAISERROR (20027, 16, -1, @article)
            RETURN (1)
        END

	select @pre_command=pre_creation_command, @identity_support = identity_support from sysmergearticles where pubid=@pubid and artid=@artid
    /*
    ** Handle the changing of schema only articles property
    ** in a different procedure
    */
    if @type in (0x20, 0x40, 0x80)
        begin
            exec @retcode = sp_MSchangemergeschemaarticle @pubid = @pubid,
                                                           @artid = @artid,
                                                           @property = @property,
                                                           @value = @value
            return @retcode
        end             

    /*
    ** Parameter Check:  @property.
    ** Check to make sure that @property is a valid property in
    ** sysmergearticles.
    */
    if @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT in 
                                                    ('name',
                                                     'description',
                                                     'pre_creation_command',
                                                     'creation_script',
                                                     'column_tracking',
                                                     'article_resolver',    
                                                     'resolver_info',
                                                     'status',
                                                     'subset_filterclause',
                                                     'schema_option',
                                                     'pub_identity_range',
                                                     'identity_range',
                                                     'threshold',
                                                     'verify_resolver_signature',
                                                     'check_permissions',
                                                     'allow_interactive_resolver',
                                                     'destination_owner')
        BEGIN
            RAISERROR (21259, 16, -1, @property)
            RETURN (1)
        END
        
	-- COMMENT: the following article properties can not be changed at republisher side
	if	LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('article_resolver','resolver_info','column_tracking',
					'allow_interactive_resolver','verify_resolver_signature') and 
			exists (select * from sysmergearticles where objid=@objid and pubid not in 
				(select pubid from sysmergepublications where UPPER(publisher)=UPPER(@@servername) 
					and publisher_db=@db_name))
		
		BEGIN
			RAISERROR(21400, 16, -1, @article)
			return (1)
		END

	if @identity_support=0 and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('pub_identity_range','identity_range','threshold')
		begin
			RAISERROR(21257, 16, -1, @property, @article)
			return (1)
		end

	exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
           			@distribdb   = @distribdb OUTPUT
	IF @@ERROR <> 0 or @retcode <> 0 or @distributor is NULL
	BEGIN
		RAISERROR (20036, 16, -1)
		RETURN (1)
	END

	SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
	select @objid=objid, @object = object_name(objid), @vertical=vertical_partition from sysmergearticles where artid=@artid and pubid=@pubid
    set @artidstr = '''' + convert(nchar(36), @artid) + '''' 
    set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
    select @sp_resolver 		= 'Microsoft SQLServer Stored Procedure Resolver'
    select @additive_resolver 	= 'Microsoft SQL Server Additive Conflict Resolver'
    select @average_resolver 	= 'Microsoft SQL Server Averaging Conflict Resolver'
    select @minimum_resolver 	= 'Microsoft SQL Server Minimum Conflict Resolver'
    select @maximum_resolver 	= 'Microsoft SQL Server Maximum Conflict Resolver'
    select @mindate_resolver 	= 'Microsoft SQL Server DATETIME (Earlier Wins) Conflict Resolver'
    select @maxdate_resolver 	= 'Microsoft SQL Server DATETIME (Later Wins) Conflict Resolver'
    select @mergetxt_resolver 	= 'Microsoft SQL Server Merge Text Columns Conflict Resolver'
    select @pricolumn_resolver 	= 'Microsoft SQL Server Priority Column Resolver'

	BEGIN TRAN
	save TRAN changemergearticle
	/*
	** Changing of the following properties would require a snapshot rerun.and reinit, if snapshot is ready
	*/
	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in 
                                                    ('pre_creation_command',
                                                     'creation_script',
                                                     'column_tracking',
                                                     'subset_filterclause',
                                                     'schema_option',
                                                     'destination_owner',
                                                     'check_permissions')
		and	@snapshot_ready > 0
	begin
		if @pre_command<>1 -- 1 means'drop': which is the only option that support reintialization
		begin
			raiserror(21416, 16, -1, @property, @article)
			goto UNDO			
		end
		if @force_invalidate_snapshot = 0
		begin
			raiserror(20607, 16, -1)
			goto UNDO
		end
		if @force_reinit_subscription = 0
		begin
			raiserror(20608, 16, -1)
			goto UNDO
		end
		
		update sysmergepublications set snapshot_ready=2 where pubid=@pubid and snapshot_ready=1
		if @@ERROR<>0	
			GOTO UNDO
		exec @retcode=sp_MSreinitmergepublication @publication
		if @@ERROR<>0 or @retcode<>0
			GOTO UNDO 
	end

    /*
    ** Change the property.
    */
    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'column_tracking'
        BEGIN
            /*
            ** Check to make sure that we have a valid type.
            */
            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
                BEGIN
                    RAISERROR (14137, 16, -1)
                    goto UNDO
                END

            /*
            ** Update the syssubsetdefintions table with the new column tracking.
            */
            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
                    update sysmergearticles set column_tracking = 1 where artid=@artid      
            else
                    update sysmergearticles set column_tracking = 0 where artid=@artid
            if @@ERROR <> 0 
                goto UNDO

        END

	
	/* pub_identity_range is not stored at distribution database because it is not interested in this value.*/   
	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pub_identity_range'
        BEGIN
			select @intvalue = convert(bigint, @value)
			if @intvalue<0
			begin
				raiserror(21232, 16, -1)
				goto UNDO
			end
			update MSrepl_identity_range set pub_range=@intvalue where objid=@objid
			if @@ERROR<>0
				goto UNDO		
        END
	 
	/* the property of check permissions is a bitmask of which operation do we want to check for*/   
	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'check_permissions'
        BEGIN
			select @intvalue = convert(int, @value)
			if @intvalue<0
			begin
				raiserror(21232, 16, -1)
				goto UNDO
			end
			update sysmergearticles set check_permissions=@intvalue
			if @@ERROR<>0
				goto UNDO		
        END


	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'identity_range'
        BEGIN
			select @intvalue = convert(bigint, @value)
			if @intvalue<0
			begin
				raiserror(21232, 16, -1)
				goto UNDO
			end

			update MSrepl_identity_range set range=@intvalue where objid=@objid
			if @@ERROR<>0
				goto UNDO
			exec  @retcode=@distproc @publisher=@@SERVERNAME,
										@publisher_db=@db_name,
										@tablename=@object,
										@range=@intvalue
				if @retcode<>0 or @@ERROR<>0
					goto UNDO

        END

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'threshold'
        BEGIN
			select @intvalue = convert(int, @value)
			if @intvalue<0 or @intvalue>100
			begin
				raiserror(21241, 16, -1)
				goto UNDO
			end
			update MSrepl_identity_range set threshold=@intvalue where objid=@objid
			if @@ERROR<>0
				goto UNDO
			exec  @retcode=@distproc @publisher=@@SERVERNAME,
										@publisher_db=@db_name,
										@tablename=@object,
										@threshold=@intvalue
				if @retcode<>0 or @@ERROR<>0
					goto UNDO

        END

     if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='description'
        BEGIN
        UPDATE sysmergearticles  SET description = @value WHERE artid = @artid and pubid = @pubid
            AND pubid = @pubid
        if @@ERROR <> 0 
                goto UNDO
    END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='creation_script'
        BEGIN
            update sysmergearticles set creation_script=@value where artid=@artid and pubid=@pubid
            if @@ERROR <> 0 
                goto UNDO
        END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'subset_filterclause'
        BEGIN
			if @value is not null and @value<>''
			begin
        	/* check the validity of subset_filterclause */
			select @object_view=@object
			select @quoted_object=QUOTENAME(@object)	
			
			exec @retcode = sp_MSget_qualified_name @objid, @qual_object OUTPUT
			if @@ERROR<>0 or @retcode<>0
				goto UNDO
			select @qual_object_view=@qual_object
			
			if @vertical=1
			begin
			  select @object_view='TEMP_VIEW_' + @object
			  select @qual_object_view = QUOTENAME(@object_view)
			  exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @objid
			  exec ('create view ' + @qual_object_view + ' as select ' + @column_list + ' from ' + @quoted_object)
			  if @@ERROR<>0
			  begin
			  	raiserror(21256, 16, -1, @value, @object)
				goto UNDO
			  end
			end
        	
			exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_object + ' where ' + @value)
			if @@ERROR<>0
				begin
					if @vertical=1
						exec('drop view ' + @qual_object_view)
					raiserror(21256, 16, -1, @value, @object)
					goto UNDO
				end
			end
			if @vertical=1
				exec('drop view ' + @qual_object_view)

            update sysmergearticles set subset_filterclause = @value where artid=@artid and pubid=@pubid
            if @@ERROR<>0 goto UNDO
            
            /*
            ** set the pub type to subset or full as appropriate
            */
            execute @retcode = dbo.sp_MSsubsetpublication @publication
            if @@ERROR <> 0 OR @retcode <> 0
                goto UNDO
                
        END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='article_resolver'
        BEGIN

            if @value IS NULL OR @value = 'default' OR @value = ''
                begin
                    set @article_resolver = NULL
                    set @resolver_clsid = NULL
                end                 
                    
            else
                begin
                    EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
                                      'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver',
                                      @value,
                                      @param = @resolver_clsid OUTPUT
                    IF @@ERROR <> 0 or @retcode <> 0 or @resolver_clsid IS NULL
                        BEGIN
                            RAISERROR (20020, 16, -1)
                            goto UNDO
                        END
                end                     
                    
            /*
            ** Update the appropriate column in sysmergearticles with the new article resolver name.
            ** Note this could affect multiple publication if the same table spans publications
            */

            /* NOTE: new change */
                exec @retcode = dbo.sp_MSchangearticleresolver @value, @resolver_clsid, @artid
                if @@ERROR <> 0 OR @retcode <> 0
                    begin
                        goto UNDO                          
                    end  
                
                declare one_pub CURSOR LOCAL FAST_FORWARD FOR 
                    select DISTINCT pubid from sysmergearticles where artid=@artid
                FOR READ ONLY
                open one_pub
                fetch next from one_pub into @pubid
                 
                while (@@fetch_status <> -1)
                    begin
                        select @snapshot_ready=snapshot_ready from sysmergepublications 
					        where pubid = @pubid
					    /* Insert the sp_MSchangearticleresolver schema change only if the publication's snapshot is ready */
						if (@snapshot_ready > 0)
							begin
		                        select @schemaversion = schemaversion from sysmergeschemachange
        		                if (@schemaversion is NULL) 
        		                	set @schemaversion = 1
                		        else  
		                            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
		                        set @schemaguid = newid()
		                        set @schematype = 8
		                        if @value is not NULL and @value <> ''
		                            select @schematext = 'exec dbo.sp_MSchangearticleresolver ' + quotename(@value) + ',' + '''' + @resolver_clsid + '''' + ',' + '''' + convert(nchar(36), @artid) + ''''
		                        else
		                            select @schematext = 'exec dbo.sp_MSchangearticleresolver NULL, NULL,' + '''' + convert(nchar(36), @artid) + ''''
		                             
		                        exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext 
	                            if @@ERROR <> 0 OR @retcode <> 0
									goto UNDO
							end		                                
                        fetch next from one_pub into @pubid
                    end 
                close one_pub
                deallocate one_pub

        END /* for property = 'article_resolver' */


    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) ='resolver_info'
        BEGIN
	        /* allow non-sp's as resolver info; don't change the resolver class */
            select 	@article_resolver = article_resolver, 
            		@resolver_clsid = resolver_clsid from
                    sysmergearticles where artid = @artid

            -- Convert NULL value to 'NULL' string to be used for constructing schema text
            -- we do not want to change NULL value to ''.
            select @article_resolver_str=QUOTENAME(@article_resolver)
            select @resolver_clsid_str = @resolver_clsid
            select @value_str=@value
            if @article_resolver is null set @article_resolver_str = 'NULL'
            if @resolver_clsid is null set @resolver_clsid_str = 'NULL'
            if @value is null set @value_str = 'NULL'

			/* The following resolvers expect the @resolver_info to be NON NULL */
			if  @article_resolver = @sp_resolver or 
				@article_resolver = @additive_resolver or
				@article_resolver = @average_resolver or
				@article_resolver = @minimum_resolver or
				@article_resolver = @maximum_resolver or
				@article_resolver = @mindate_resolver or
				@article_resolver = @maxdate_resolver or
				@article_resolver = @mergetxt_resolver or
				@article_resolver = @pricolumn_resolver
				begin
				    if @value IS NULL or @value = ''
				        begin
	            			RAISERROR (21301, 16, -1, @article_resolver)
							goto UNDO
						end
				end

			/* The SP resolver expect the @resolver_info to be the name of sp */
			if  @article_resolver = @sp_resolver
				begin
					if not exists (select * from sysobjects where id = object_id(@value) and ( type = 'P' or type = 'X'))
						begin
							raiserror(21343, 16, -1, @value)
							goto UNDO
						end
				end
			/*
			** If article resolver is 'mindate/maxdate resolver', make sure that resolver_info refers to a column that is of datatype 'datetime' or smalldatetime
			*/
			if  @article_resolver = @mindate_resolver or
				@article_resolver = @maxdate_resolver
				begin
					if not exists (select * from syscolumns where id = @objid and name=@value and type_name(xtype)='datetime' or type_name(xtype) = 'smalldatetime' )
						begin
				            RAISERROR (21302, 16, -1, @article_resolver)
							goto UNDO
						end
				end

			/* The following resolvers expect the article to be column trcaked - warn that the default resolver migh be used */
			if  @article_resolver = @additive_resolver or
				@article_resolver = @average_resolver
				begin
		            select @coltrack = column_tracking from sysmergearticles where artid = @artid
					if @coltrack = 0
						begin
				            RAISERROR (21303, 10, -1, @article, @article_resolver)
						end
						
				end
				

            /*
            ** Update the appropriate column in sysmergearticles with the new resolver info.
            ** Note this could affect multiple publication if the same table spans publications
            */
                exec @retcode = dbo.sp_MSchangearticleresolver @article_resolver, @resolver_clsid, @artid, @value
                if @@ERROR <> 0 OR @retcode <> 0
                    begin
                        goto UNDO                          
                    end         
                declare one_pub CURSOR LOCAL FAST_FORWARD FOR 
                    select DISTINCT pubid from sysmergearticles where artid=@artid
                FOR READ ONLY
                open one_pub
                fetch next from one_pub into @pubid
                 
                while (@@fetch_status <> -1)
                    begin
                        select @snapshot_ready=snapshot_ready from sysmergepublications 
					        where pubid = @pubid
					    /* Insert the sp_MSchangearticleresolver schema change only if the publication's snapshot is ready */
						if (@snapshot_ready > 0)
							begin
		                        select @schemaversion = schemaversion from sysmergeschemachange
		                        if (@schemaversion is NULL) set @schemaversion = 1
		                        else  
		                            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
		                        set @schemaguid = newid()
		                        set @schematype = 8
			                    select @schematext = 'exec dbo.sp_MSchangearticleresolver ' + @article_resolver_str + ',' + '''' + @resolver_clsid_str + '''' + ',' + '''' + convert(nchar(36), @artid) + '''' + ',' + '''' + @value_str + ''''
		                         
		                        exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext 
	                            if @@ERROR <> 0 OR @retcode <> 0
	                                begin
	                                	goto UNDO                          
	                                end
							end	                         
                        fetch next from one_pub into @pubid
                    end 
                close one_pub
                deallocate one_pub

        END /* for property = 'resolver_info' */


    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pre_creation_command'
        BEGIN

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

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('none', 'drop', 'delete', 'truncate')
                BEGIN
                    RAISERROR (14061, 16, -1)
                    goto UNDO
                END

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

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'none'
                select @precmdid = 0
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
                select @precmdid = 1
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'delete'
                select @precmdid = 2
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'truncate'
                select @precmdid = 3

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

            if @@ERROR <> 0 
                goto UNDO

        END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status'
        BEGIN

            /*
            ** Check to make sure that we have a valid status
            */

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('active', 'unsynced', 'new_inactive', 'new_active')
                BEGIN
                    RAISERROR (20075, 16, -1)
                    goto UNDO
                END

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

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'unsynced'
                select @statusid = 1
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'active'
                select @statusid = 2
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'new_inactive'
            	select @statusid = 5
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'new_active'
            	select @statusid = 6

            /*
            ** Update the article with the new type. The same base table might be 
            ** in multiple publications - so qualify  with pubid.
            */
            UPDATE sysmergearticles
                SET status = @statusid
                WHERE artid = @artid and pubid = @pubid

            if @@ERROR <> 0 
                goto UNDO

        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'destination_owner'
        BEGIN
            IF @value IS NULL or @value=''
                select @value = 'dbo'                      
            UPDATE sysmergearticles SET destination_owner = @value
                WHERE artid = @artid
                AND pubid = @pubid
            if @@ERROR <> 0
                BEGIN
                	goto UNDO
                END
        END
	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'schema_option'
        BEGIN
        
            IF @value IS NULL
                BEGIN
                    RAISERROR(14146, 16,1)
                    goto UNDO
                END

            CREATE TABLE #tab_changearticle (value varbinary(8) NULL)
                                 
            IF @@ERROR <> 0 
                BEGIN
                    goto UNDO
                END
            
            DECLARE @insert_command nvarchar(4000)
            EXEC('insert #tab_changearticle values (' + 
                        @value +')') 
            IF @@ERROR <> 0 
                BEGIN
                    goto UNDO
                END
                      
            SELECT @schema_option = fn_replprepadbinary8(value) 
              FROM #tab_changearticle

            DECLARE @schema_option_lodword INT
            DECLARE @old_schema_option_lodword INT
            DECLARE @xprop_schema_option INT
            DECLARE @collation_schema_option INT
            SELECT @xprop_schema_option = 0x00002000
            SELECT @collation_schema_option = 0x00001000
            SELECT @schema_option_lodword = fn_replgetbinary8lodword(@schema_option)
            SELECT @old_schema_option_lodword = CONVERT(INT, SUBSTRING(@old_schema_option, 5, 4))
            
            -- Raise warnings only when we are enabling the Shiloh specific
            -- options
            IF ((@old_schema_option_lodword & @collation_schema_option) = 0)
                AND 
               ((@schema_option_lodword & @collation_schema_option) <> 0)
            BEGIN
                RAISERROR(21389, 10, -1, @publication)
                SELECT @bump_to_80 = 1
            END
            
            IF((@old_schema_option_lodword & @xprop_schema_option) = 0)
              AND 
              ((@schema_option_lodword & @xprop_schema_option) <> 0)
            BEGIN
                RAISERROR(21390, 10, -1, @publication)
                SELECT @bump_to_80 = 1
            END

            UPDATE sysmergearticles 
               SET schema_option = fn_replprepadbinary8(tab.value) from 
                #tab_changearticle tab 
                WHERE artid = @artid
                AND pubid = @pubid
            if @@ERROR <> 0
                BEGIN
                DROP TABLE #tab_changearticle 
                goto UNDO
                END
                
            DROP TABLE #tab_changearticle 
                                 
            IF @@ERROR <> 0 
                BEGIN
                    goto UNDO
                END

        END

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'verify_resolver_signature'
        BEGIN
			if @value NOT IN ('1', '0')
                BEGIN
                    raiserror(21344, 16, -1, '"verify_resolver_signature"')
                    goto UNDO
                END

			update sysmergearticles set verify_resolver_signature = convert(int, @value) 
			where artid = @artid and pubid = @pubid
			if @@ERROR<>0
				goto UNDO
        END

	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_interactive_resolver'
        BEGIN

            /* Check to make sure that we have a true/false. */

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
                BEGIN
		            RAISERROR (14148, 16, -1, 'allow_interactive_resolver')
                    goto UNDO
                END

            /* Determine the bit value. */

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		        SET @allow_interactive_bit = 1
	        ELSE
		        SET @allow_interactive_bit = 0
	
			/* Update the subscription with the new 'allow_interactive_resolver' value. */
			update sysmergearticles set allow_interactive_resolver = @allow_interactive_bit
				where artid = @artid and pubid = @pubid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    goto UNDO
                END

        END

    IF @bump_to_80=1
    BEGIN
        EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
		IF @@ERROR<>0 or @retcode<>0
            GOTO UNDO
    END
    /*
    ** Return succeed.
    */
	COMMIT TRAN
    RETURN (0)
UNDO:
	if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION changemergearticle
        COMMIT TRANSACTION
    end
	return (1)
go
exec dbo.sp_MS_marksystemobject sp_changemergearticle
go

grant execute on dbo.sp_changemergearticle to public
go

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

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

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

    set nocount on
    /*
    ** Declarations.
    */

    declare @db_name                sysname
    declare @cmd                    nvarchar(255)
    declare @artid                  uniqueidentifier
    declare @snapshot_ready			int
    declare @objid                  int
    declare @pubid                  uniqueidentifier
    declare @pubidstr               nvarchar(38)
    declare @merge_pub_object_bit   int
    declare @unpublish_bit          int
    declare @retcode                int
    declare @replinfo               int
    declare @dbname                 sysname
    declare @distributor            sysname
    declare @distribdb              sysname
    declare @distproc               nvarchar(300)
    declare @object_name            sysname
    declare @uid                    smallint
    declare @owner                  sysname
    declare @qualified_name         nvarchar(270)
	declare @filterid				int
	declare @proc_name				sysname
    declare @implicit_transaction	int
	declare @close_cursor_at_commit int
	declare @sync_objid 	int
	declare @view_type		int
    declare @type           tinyint
	declare @allow_anonymous	int
	select @close_cursor_at_commit = 0
	select @implicit_transaction = 0
	/*
	** Save setting values first before changing them
	*/
	IF (@reserved = 0)
	BEGIN
		SELECT @implicit_transaction = @@options & 2
		SELECT @close_cursor_at_commit = @@options & 4
		SET IMPLICIT_TRANSACTIONS OFF
		SET CURSOR_CLOSE_ON_COMMIT OFF
	END
    
    /*
    ** Initializations.
    */
    -- merge uses bit 8 in replinfo
    select @merge_pub_object_bit    = 128  
    select @unpublish_bit = ~@merge_pub_object_bit


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

	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)
        
    select @pubid = pubid, @snapshot_ready=snapshot_ready, @allow_anonymous=allow_anonymous FROM sysmergepublications 
        WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
	if @pubid is NULL
		BEGIN
			RAISERROR (20026, 16, -1, @publication)
			RETURN (1)
        END

    /*
    ** Once snapshot is ready, do not allow dropping an article except
    ** when the article is schema-only
    */
    if @snapshot_ready>0 and 
       (@allow_anonymous=1 or 
       exists (select * from sysmergesubscriptions 
                where pubid=@pubid and subid<>pubid and status=1)) and
       not exists (select * from sysmergeschemaarticles 
                    where pubid = @pubid and name = @article) 
        begin
            RAISERROR (21338, 16, -1, @article, @publication)
            RETURN (1)
        end

	if @snapshot_ready>0
		begin
			if @force_invalidate_snapshot = 0
				begin
					raiserror(21379, 16, -1, @article, @publication)
					return (1)
				end
			update sysmergepublications set snapshot_ready=2 where pubid=@pubid
			if @@ERROR<>0
				return (1)
		end
	
    
    set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''

    /*
    ** 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 sysmergeextendedarticlesview WHERE pubid=@pubid FOR READ ONLY
            
            OPEN hC
            FETCH hC INTO @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergearticle @publication, @article,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = 1
                    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

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

    /*
    ** Ascertain the existence of the article.
    */
    select @type = NULL
    select @type = type ,
		   @artid = artid
	  from sysmergeextendedarticlesview 
     where name = @article
       and pubid = @pubid

    if @type is NULL
        begin
            raiserror (20027, 16, -1, @article)
            return (1)
        end

	-- if all articles are to be dropped, ignore this checking.
	if @reserved=0 and exists (select * from sysmergesubsetfilters where pubid=@pubid and join_articlename=@article)
		begin
			raiserror(21421, 16, -1, @article)
			return (1)
		end

    /*
    **  Delete article from sysmergearticles and clear publish bit in
    **  sysobjects.
    */

    begin tran 
    save TRAN dropmergearticle
        /*
        ** Remove the corresponding rows from sysmergeschemachange
        */
        DELETE FROM sysmergeschemachange WHERE artid = @artid AND pubid = @pubid
        if @@ERROR <> 0
            goto FAILURE
        /*
        ** Removing a schema only article is a lot simpler than 
        ** removing a table article so a different code path is created
        ** to handle this.  
        */
        if @type in (0x20, 0x40, 0x80)
            begin
            /*
            ** Retrieve the object id of the underlying proc or view object.
            */
            select @objid = objid
        	    from sysmergeschemaarticles where name = @article and pubid = @pubid
                
            /*
            ** Remove the corresponding record in sysmergeschemaarticles
            */
            delete sysmergeschemaarticles where name = @article and pubid = @pubid

            /*
            ** If this is the last schema only article for the underlying 
            ** view or proc object, unmark the 0x200 bit in sysobject.replinfo  
            */
            if not exists (select * from sysmergeschemaarticles 
                            where objid = @objid)
                begin
                select @merge_pub_object_bit = 512
                select @unpublish_bit = ~(@merge_pub_object_bit)
                if not exists (select * from sysobjects 
                                where name = 'sysschemaarticles')
                    begin   
                    update sysobjects set replinfo = (@unpublish_bit & replinfo) where id = @objid
                    end    
                else if  not exists (select * from sysschemaarticles 
                                      where objid = @objid) 
                    begin   
                    update sysobjects set replinfo = (@unpublish_bit & replinfo) where id = @objid
                    end    
                end
            end
        else 
            begin
            /*
            ** Retrieve the object id of the underlying table.
            */
            select @sync_objid = sync_objid, @view_type = view_type, @artid = artid, @objid = objid
        	    from sysmergearticles where name = @article AND pubid = @pubid
            select @replinfo = replinfo, @object_name=name, @owner= user_name(uid) from sysobjects where id = @objid
        
            /*
            ** If this is the last article that refers to the base table, drop the 
            ** triggers and stored procs 
            */
            if NOT exists (select * from sysmergearticles WHERE artid = @artid AND pubid <> @pubid)
                begin
                /*
                ** Cleanup the triggers and stored procs
                */
                EXECUTE @retcode = dbo.sp_MSarticlecleanup @artid = @artid, @pubid = @pubid
                if @@ERROR <> 0 OR @retcode <> 0
                    BEGIN
                        GOTO FAILURE
                    END
            
                /*
                ** Clear the replication bit in sysobjects. Now merge and transactional level
                ** uses different replication bit, checking transactional level is not needed.
                */

                select @qualified_name = (QUOTENAME(@owner) + '.' + QUOTENAME(@object_name))
                exec @retcode = dbo.sp_replupdateschema @qualified_name
                if @@ERROR <> 0 OR @retcode <> 0
                    BEGIN
                        GOTO FAILURE
                    END
            
                update sysobjects set replinfo = (replinfo & @unpublish_bit) where id = @objid

                IF @@ERROR <> 0
                    goto FAILURE
                end             
		    else
			    begin
			    /* Always drop the article proc's they are not shared among publications */
	            EXECUTE @retcode = dbo.sp_MSdroparticleprocs @artid = @artid, @pubid = @pubid
                if @@ERROR <> 0 OR @retcode <> 0
                    begin
                        goto FAILURE
                    end
			    /* If the article's has a temporary ( view type = 2) or a permanent view (view_type = 1 ) drop the sync object */
			    if (@view_type = 1 OR @view_type = 2)
				    begin
				    declare @viewname sysname
				    select @viewname = sysobjects.name from sysobjects where 
					    ObjectProperty (sysobjects.id, 'IsView') = 1 
					    and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
					    and sysobjects.id = @sync_objid
				    if @viewname IS NOT NULL
					    begin
						    set @viewname = QUOTENAME(@viewname)
						    exec ('drop view ' + @viewname)
						    if @@ERROR<>0  GOTO FAILURE
					    end
				    end
			    end
            /*
            ** Remove the row from sysmergearticles.
            */
            DELETE FROM sysmergearticles WHERE artid = @artid AND pubid = @pubid
            if @@ERROR <> 0
                BEGIN
                    GOTO FAILURE
                END


            /* delete all the filter components that are defined upon the designated article */
		    select @filterid = min(join_filterid) from sysmergesubsetfilters where
			    artid = @artid AND pubid = @pubid
		    while (@filterid is not null)
			    begin
			    select @proc_name = expand_proc from sysmergesubsetfilters where
				    artid = @artid AND pubid = @pubid and join_filterid = @filterid

			    if (@proc_name IS NOT NULL) and exists (select * from sysobjects where
				    name = @proc_name and type = 'P')
				    begin
					    exec ('drop proc ' + @proc_name)
			            IF @@ERROR <> 0
            			goto FAILURE
				    end
			    delete from sysmergesubsetfilters where
				    artid = @artid AND pubid = @pubid and join_filterid = @filterid
        	    IF @@ERROR <> 0
          	 	    goto FAILURE
			    select @filterid = min(join_filterid) from sysmergesubsetfilters where
				    artid = @artid AND pubid = @pubid
			    end


            /*
            ** set the pub type to subset or full as appropriate
            */
            execute @retcode = dbo.sp_MSsubsetpublication @publication
            if @@ERROR <> 0 or @retcode <> 0 
                RETURN (1)
                
            /*
            ** 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
                        goto FAILURE
                    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
                        goto FAILURE
                    END
                end
            end            
    
    COMMIT TRAN
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END
    RETURN (0)
FAILURE:
    RAISERROR (14047, 16, -1, @article)
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION dropmergearticle
        COMMIT TRANSACTION
    end
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END
    RETURN (1)
go
exec dbo.sp_MS_marksystemobject sp_dropmergearticle
go

grant execute on dbo.sp_dropmergearticle to public
go

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


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

/*
** When calling from the wrapper stored procedure, we make sure that there is one and
** only one of the two input SP is NULL. Therefore, we do no checking here.
*/

CREATE PROCEDURE sp_MSadjustmergeidentity 
@publication		sysname = NULL,
@tablename			sysname = NULL
AS

declare @db_name				sysname
declare @pubid					uniqueidentifier
declare @next_seed				bigint
declare @pub_range				bigint
declare @objid					int
declare @qualname				nvarchar(270)
declare @retcode				int
declare @user_name				sysname		
declare @range					bigint
declare @current_max			bigint
declare @threshold				int
declare @distributor			sysname
declare @distribdb				sysname
declare @distproc				nvarchar(300)
declare @flag					smallint
declare @c_max					bigint
declare @n_seed					bigint
declare @nickname				int
declare @identity_support		int
declare @artid					uniqueidentifier
declare @identity_so_far		bigint
declare @tablelevel				bit

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

select @db_name=db_name()
select @pubid = newid()
select @objid = 0

if (@publication is NULL and @tablename is NULL) or 
 	(@publication is not NULL and @tablename is not NULL)
begin
	raiserror('internal error on nullibility', 16, -1)
	return (1)
end

if @tablename is not NULL
begin
	select @tablelevel = 1
	select @objid = id from sysobjects where name=@tablename
end
else
begin
	select @tablelevel = 0
	select @pubid = pubid from sysmergepublications 
		where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=@db_name
end

if exists (select * from sysmergearticles where identity_support<>0 and 
	((pubid=@pubid and @tablelevel=0) or (@tablelevel=1 and objid=@objid)))
begin	
	EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb   = @distribdb OUTPUT
		IF @@ERROR <> 0 or @retcode <> 0
			return (1)

	declare one_article CURSOR LOCAL FAST_FORWARD FOR 
		select DISTINCT artid from sysmergearticles where identity_support<>0 and
			((pubid=@pubid and @tablelevel=0) or (@tablelevel=1 and objid=@objid))
	open one_article
	fetch one_article into @artid
	while (@@fetch_status<>-1)
	begin
		select @objid=objid, @identity_support=identity_support from sysmergearticles 
				where pubid=@pubid and artid=@artid
		select @tablename=object_name(@objid)
		select @user_name=user_name(uid) from sysobjects where id=@objid
		select @qualname=QUOTENAME(@user_name) + '.' + QUOTENAME(@tablename)
		select @next_seed=NULL, @range=NULL, @threshold=NULL --null if not being updated later

		select @current_max=0, @next_seed=0, @threshold=0, @range=0, @pub_range=0  --make them non-NULL
		SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
		exec  @retcode=	@distproc @publisher=@@SERVERNAME,
									  @publisher_db=@db_name,
									  @tablename=@tablename,
									  @range=@range OUTPUT,
									  @current_max=@current_max OUTPUT,
									  @threshold=@threshold OUTPUT,
									  @next_seed = @next_seed OUTPUT,
									  @pub_range=@pub_range OUTPUT
		if @retcode<>0 or @@ERROR<>0
			return (1)

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

		/* To avoid div by zero errors, error out if pub_range is 0 */
		if @pub_range = 0
			begin
				return 1
			end
	
		if @flag * 100 * (@identity_so_far - (@current_max + 1 - @pub_range))/@pub_range > @threshold
		begin
			select @c_max=@next_seed + @pub_range - 1
			select @n_seed=@next_seed + @pub_range
			SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadjust_pub_identity'
			exec  @retcode=@distproc @publisher=@@SERVERNAME,
									@publisher_db=@db_name,
									@tablename=@tablename,
									@current_max=@c_max,
									@next_seed = @n_seed
			if @retcode<>0 or @@ERROR<>0
				return (1)
			exec @retcode=sp_MSreseed @objid, @next_seed, @pub_range, 1
			if @@ERROR <> 0 or @retcode<>0
				begin
					raiserror(21197, 16, -1)
					return (1)
				end
			select @next_seed=@next_seed + @pub_range
		end
	fetch next from one_article into @artid
	end
end
else
begin
	raiserror(21295, 16, -1, @publication)
	return (1)
end
GO
exec dbo.sp_MS_marksystemobject sp_MSadjustmergeidentity 
go
grant exec on sp_MSadjustmergeidentity to public
go


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

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

create procedure sp_addmergepublication (
    @publication            sysname,                /* Publication name */
    @description            nvarchar(255)= NULL,            /* Publication description */
    @retention              int         = 14,           /* Retention period of 14 days */
    @sync_mode              nvarchar(10) = 'native',    /* (bcp)native, (bcp)character */
    @allow_push             nvarchar(5)  = 'true',      /* Pulication allows push subscriptions */
    @allow_pull             nvarchar(5)  = 'true',      /* Pulication allows pull subscriptions*/
    @allow_anonymous        nvarchar(5)  = 'false',     /* Pulication allows anonymous subscriptions */
    @enabled_for_internet   nvarchar(5)     = 'false',  /* Pulication is enabled for internet */
    @centralized_conflicts  nvarchar(5)  = 'true',      /* Conflict records stored at publisher : true or false */
    @dynamic_filters        nvarchar(5) = 'false',      /* Will publication be filtered on dynamic clause? */
    @snapshot_in_defaultfolder      nvarchar(5) = 'true',       /* Will keep a copy of the snapshot files to the default location if an alternate folder is specified */
    @alt_snapshot_folder    nvarchar(255) = NULL,       /* Alternate folder for putting the snapshot file for this publication */
    @pre_snapshot_script    nvarchar(255) = NULL,		/* Pre snapshot commands */
    @post_snapshot_script   nvarchar(255) = NULL,    	/* Post snapshot commands */
    @compress_snapshot      nvarchar(5) = 'false',		/* Snapshot compression */
    @ftp_address            sysname = NULL,				/* Post 7.0 FTP Properties */
    @ftp_port               int = 21,					/* Post 7.0 FTP Properties */
    @ftp_subdirectory       nvarchar(255) = NULL,		/* Post 7.0 FTP Properties */
    @ftp_login              sysname = N'anonymous',		/* Post 7.0 FTP Properties */
    @ftp_password           sysname = NULL,				/* Post 7.0 FTP Properties */
    @conflict_retention		int = 14,					/* Conflict retention period */
    @keep_partition_changes nvarchar(5) = 'false',		/* Optimized Partition Updates/Deletes */
    @allow_subscription_copy	nvarchar(5) = 'false',	/* Allow the subscription to be copied */
    @allow_synctoalternate		nvarchar(5) = 'false',	/* Allow the subscription to be synchronize to alternate partners */
    @validate_subscriber_info	nvarchar(500) = NULL,	/* Should we validate that subscriber is using right params? */
    @add_to_active_directory	nvarchar(5) = 'false',
	@max_concurrent_merge	int = 0, 					/* value of 0 means no such limit exists */
    @max_concurrent_dynamic_snapshots int = 0           /* Maximum number of concurrent dynamic snapshot sessions */
    ) as

    set nocount on

    /*
    ** Declarations.
    */
    
    declare @retcode                    int         /* return code value for procedure execution */
    declare @push                       tinyint     /* subscription type is push */
    declare @statid                     tinyint     /* status id based on @status */
    declare @sync_modeid                tinyint     /* sync mode id based on @sync_mode */
    declare @global                     tinyint     /* subscriber type of loop-back subscription */
    declare @db_name                    sysname     /* database name */
    declare @srvid                      int         /* Server ID */
    declare @nickname                   int         /* replica nickname */
    declare @tranpublish_bit            smallint    /* online publish bit (flag) in sysdatabases */
    declare @mergepublish_bit           smallint    /* merge publish bit (flag) in sysdatabases */
    declare @found                      int         /* flag indicating if publication is found */
    declare @pubid                      uniqueidentifier    /* Publication identifier */
    declare @allow_push_id              bit
    declare @allow_pull_id              bit
    declare @allow_anonymous_id         bit
    declare @dynamic_filters_id         bit         
    declare @allow_subscription_copy_id bit         
    declare @allow_synctoalternate_id 	bit         
    declare @enabled_for_internet_id    bit
    declare @centralized_conflicts_id   bit
    declare @priority                   real        
    declare @automatic                  tinyint     
    declare @false                      bit
    declare @true                       bit
    declare @distributor                sysname
    declare @distproc                   nvarchar(300)
    declare @distribdb                  sysname
    declare @distpubid                  int
    declare @full                       int
    declare @snapshot_in_defaultfolder_bit      bit
    declare @compress_snapshot_bit      bit
    declare @keep_before_values_int	   	int
    declare @enc_ftp_password           nvarchar(524)
    declare @ad_guidname				sysname
    declare @schemaversion      		int 
    declare @schemaguid         		uniqueidentifier
    declare @schematype         		int
    declare @schematext         		nvarchar(2000)
	declare @artid						uniqueidentifier
	declare @distservername				sysname
    declare @backward_comp_level		int
    
	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    /*
    ** Initializations
    */
    select @backward_comp_level	= 10 --that of 7.0 RTM
    
    select @mergepublish_bit    = 4 
    select @tranpublish_bit     = 1
    select @priority            = 100.0
    select @automatic           = 1     /* Const: synchronization type 'automatic' */
    select @true                = 1
    select @false               = 0
    select @full                = 0     /* Const: publication type 'full' */

    /*
    ** Set the status to Active (1)
    */
    select @statid      = 1
    select @global      = 1
    select @push        = 0
    select @db_name     = DB_NAME()
    select @ad_guidname = NULL

    /*
    ** 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,
    ** 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
        
	if @max_concurrent_merge<0
		begin
			raiserror(21402, 16, -1, '@max_concurrent_merge')
			return (1)
		end

    /*
    ** Parameter Check: @retention.
    */
        
    if @retention is not NULL and @retention<0 
        begin
            raiserror(20050, 16, -1, 0)
            return(1)
        end

    if @retention is NULL
    	select @retention = 0

    /*
    ** Parameter Check: @conflict_retention.
    */
        
    if @conflict_retention is not NULL and @conflict_retention<0 
        begin
            raiserror(20050, 16, -1, 0)
            return(1)
        end

	/*
	** if it is NULL, use the default value of 14 days.
	*/
	if @conflict_retention is NULL 
		select @conflict_retention = 14

    /*
    ** Parameter Check: @sync_mode.
    ** Make sure that the sync_mode is one of the following:
    **
    **  id  sync_mode
    **  ==  ==========
    **   0  (bcp)native
    **   1  (bcp)character
    */
    
    if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS)='portable' select @sync_mode='character'

    if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) is NULL OR LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('bcp native', 'bcp character', 'native', 'character')
        begin
            raiserror (20076, 16, -1)
            return (1)
        end

    if LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS) = 'native' or 
       LOWER(@sync_mode collate SQL_Latin1_General_CP1_CS_AS)='bcp native' 
        select @sync_modeid = 0
    else 
        select @sync_modeid = 1

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

    if @allow_push IS NULL OR LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_push')
            RETURN (1)
        END

    if LOWER(@allow_push collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_pull')
            RETURN (1)
        END
    if LOWER(@allow_pull collate SQL_Latin1_General_CP1_CS_AS) = '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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_anonymous')
            RETURN (1)
        END
    if LOWER(@allow_anonymous collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        select @allow_anonymous_id = 1
    else 
        select @allow_anonymous_id = 0

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

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

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

    /*
    ** Parameter Check:  @centralized_conflicts.
    */

    if @centralized_conflicts IS NULL OR LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@centralized_conflicts')
            RETURN (1)
        END
    if LOWER(@centralized_conflicts collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        select @centralized_conflicts_id = 1
    else 
    	begin
    		raiserror(21349, 10, -1, @publication)
    		select @backward_comp_level = 30	-- that of Sphinx SP2, in which decentrailzed logging will be supported.
        	select @centralized_conflicts_id = 0
        end

    /*
    ** Parameter Check:  @dynamic_filter.
    */

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

    IF LOWER(@dynamic_filters collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        SELECT @dynamic_filters_id = 1
    ELSE 
        SELECT @dynamic_filters_id = 0

	if @validate_subscriber_info is not NULL
		begin
			if @dynamic_filters_id = 0
				begin
					raiserror(21313, 16, -1)
					return (1)
				end
			exec ('select ' + @validate_subscriber_info)
			if @@ERROR<>0
				begin
					raiserror(21299, 16, -1, @validate_subscriber_info)
					return (1)
				end
		end

    -- Portable snapshot
    IF @snapshot_in_defaultfolder IS NULL OR LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@snapshot_in_defaultfolder')
        RETURN (1)
    END
    
    IF LOWER(@snapshot_in_defaultfolder collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @snapshot_in_defaultfolder_bit = 1
    END
    ELSE
    BEGIN
        SELECT @snapshot_in_defaultfolder_bit = 0
    END

    -- Pre/Post snapshot commands
    -- If @sync_method is character mode bcp, this would indicate that
    -- this publication may support non-SQL Server subscribers. In this 
    -- case, pre- and post- snapshot commands are not allowed.
    IF @sync_modeid = 1 AND 
        ((@pre_snapshot_script IS NOT NULL AND @pre_snapshot_script <> N'' ) OR
         (@post_snapshot_script IS NOT NULL AND @post_snapshot_script <> N''))
    BEGIN
        RAISERROR (21151, 16, -1)
        RETURN (1)
    END

    -- Parameter check - @compress_snapshot
    -- @compress_snapshot can be 1 if @alt_snapshot_folder is non-null
    IF @compress_snapshot IS NULL OR LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@compress_snapshot')
        RETURN (1)
    END
    
    IF LOWER(@compress_snapshot collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @compress_snapshot_bit = 1
    END
    ELSE
    BEGIN
        SELECT @compress_snapshot_bit = 0
    END


    -- Only bump up the compatibility level if only a compressed snapshot
    -- is generated at the alternate snapshot folder
    if @snapshot_in_defaultfolder_bit = 0 and
       @compress_snapshot_bit = 1
    begin
    	raiserror(21350, 10, -1, @publication)
    	select @backward_comp_level = 40 -- this is supported starting from 7.5
    end

    -- Snapshot compression can only be enabled if an alternate 
    -- snapshot generation folder exists.
    IF (@compress_snapshot_bit = 1 AND 
        (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N''))
    BEGIN
        RAISERROR (21157, 16, -1)
        RETURN (1)
    END    

    -- Parameter check: ftp_address
    -- If the publication is enabled for internet, ftp_address cannot be null
    IF @enabled_for_internet_id = 1 AND (@ftp_address IS NULL OR @ftp_address = N'')
    BEGIN
        RAISERROR (21158, 16, -1)
        RETURN (1)
    END     


    -- Parameter check: enabled_for_internet
    -- If a publication is enabled for internet, it must have an alternate 
    -- snapshot folder defined.
    IF LOWER(@enabled_for_internet collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND 
        (@alt_snapshot_folder = N'' OR
        (@alt_snapshot_folder IS NULL))
    BEGIN
        RAISERROR (21159, 16, -1)
        RETURN (1)
    END 

    -- Parameter check: ftp_port
    IF @ftp_port IS NULL
    BEGIN
        RAISERROR (21160, 16, -1)
    END


    -- Encrypt ftp password before putting it into the sysmergepublications
    -- table if one is provided
    SELECT @enc_ftp_password = NULL
    IF @ftp_password IS NOT NULL
    BEGIN
        SELECT @enc_ftp_password = @ftp_password 
        EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
        IF @retcode <> 0
        BEGIN
            RETURN (1)
        END
    END    

    /*
    ** Parameter Check:  @keep_partition_changes.
    */

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

    if LOWER(@keep_partition_changes collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
    	begin
        	set @keep_before_values_int = 1
        end
    else 
        set @keep_before_values_int = 0

    /*
    ** Parameter Check:  @allow_subscription_copy_id.
    */

    if LOWER(@allow_subscription_copy collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_subscription_copy')
            RETURN (1)
        END
        
    IF LOWER(@allow_subscription_copy collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
    	SELECT @allow_subscription_copy_id = 1
    ELSE 
    	SELECT @allow_subscription_copy_id = 0

    /*
    ** Parameter Check:  @allow_synctoalternate_id.
    */

    if LOWER(@allow_synctoalternate collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@allow_synctoalternate')
            RETURN (1)
        END
        
    IF LOWER(@allow_synctoalternate collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
    	SELECT @allow_synctoalternate_id = 1
    ELSE 
    	SELECT @allow_synctoalternate_id = 0

    /*
    ** Parameter Check:  @add_to_active_directory.
    */

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

   /* Is AD supported? */
   DECLARE @retval  INT
   EXECUTE @retval = master.dbo.xp_MSADEnabled
   if (@retval <> 0) and LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
   begin
		RAISERROR(21253, 16, -1)
		RETURN (1)
   end


    /*
    ** Parameter Check: @max_concurrent_dynamic_snapshots
    */
    
    if @max_concurrent_dynamic_snapshots < 0 or @max_concurrent_dynamic_snapshots is null
    begin
        raiserror(21403, 16, -1)
        return (1)
    end
		
    /*
    ** Check to see if the publication name is already used.
    ** 1. check merge pubs
    ** 2. check online publications
    */
    if exists (select * from sysmergepublications 
        where name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
    begin
        RAISERROR (20025, 16, -1, @publication)
        RETURN (1)
    end

    if (select category & @tranpublish_bit from master..sysdatabases where name = @db_name collate database_default) <> 0
    begin
        EXEC @retcode = dbo.sp_helppublication @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


    /*
    **  Add the publication as the designmaster of the replica set.
    */

    /* Generate a guid for the publication ID */
    set @pubid = newid()
        
    /* Select the server's ID as 0 since this is the LOCAL server */
    select @srvid = 0

    /* Look for existing nickname from any other subscription */
    exec @retcode=sp_MSgetreplnick NULL, NULL , NULL,  @nickname out
    if (@@error <> 0) or @retcode <> 0 
        begin
	        RETURN(1)
        end                 
            
    /* Generate a new replica nickname from the @pubid */
    if (@nickname is null)
    begin
        execute @retcode = dbo.sp_MSgenreplnickname @pubid, @nickname output
        IF @@ERROR <>0 OR @retcode <> 0
        BEGIN
            RAISERROR (20077, 16, -1)
            RETURN (1)
        END
    end
    else
        select @priority=max(priority) from sysmergesubscriptions where db_name=@db_name and srvid = @srvid
    /*
    ** A change in design.
    */
    if @priority = 0 
        begin
            RAISERROR(21087, 16, -1)
            return (1)
        end

    /*
    ** Get distributor information
    */
    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUT , @distributor = @distservername  OUTPUT, 
        @distribdb = @distribdb OUTPUT
        if @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END
    
    /*
    **  add an entry into sysmergepublications
    */
    begin tran    
    save tran sp_addmergepublication
        /* Add row in the publications table */
		if @backward_comp_level > 10
		begin
			exec sp_MSBumpupCompLevel @pubid, @backward_comp_level
			if @@ERROR<>0
				goto FAILURE
        end
        	
        insert sysmergepublications
            (pubid, 
            name, 
            description, 
            designmasterid, 
            retention, 
            parentid, 
            sync_mode, 
            allow_push, 
            allow_pull, 
            allow_anonymous, 
            centralized_conflicts,
            status,
            snapshot_ready,
            enabled_for_internet,
            publication_type,
            dynamic_filters,
            snapshot_in_defaultfolder,
            alt_snapshot_folder,
            pre_snapshot_script,
            post_snapshot_script,
            compress_snapshot,
            ftp_address,
            ftp_port,
            ftp_subdirectory,
            ftp_login,
            ftp_password,
            conflict_retention,
            keep_before_values,
            allow_subscription_copy,
            allow_synctoalternate,
            validate_subscriber_info,
            ad_guidname,
            backward_comp_level,
            max_concurrent_merge,
            max_concurrent_dynamic_snapshots)
        values
            (@pubid, 
            @publication, 
            @description, 
            @pubid, 
            @retention, 
            @pubid, 
            @sync_modeid, 
            @allow_push_id, 
            @allow_pull_id, 
            @allow_anonymous_id, 
            @centralized_conflicts_id,
            @statid,
            @false,
            @enabled_for_internet_id,
            @full,
            @dynamic_filters_id,
            @snapshot_in_defaultfolder_bit,
            @alt_snapshot_folder,
            @pre_snapshot_script,
            @post_snapshot_script,
            @compress_snapshot_bit,
            @ftp_address,
            @ftp_port,
            @ftp_subdirectory,
            @ftp_login,
            @enc_ftp_password,
            @conflict_retention,
            @keep_before_values_int,
            @allow_subscription_copy_id,
            @allow_synctoalternate_id,
            @validate_subscriber_info,
            @ad_guidname, 
            @backward_comp_level,
            @max_concurrent_merge,
            @max_concurrent_dynamic_snapshots)
        if @@ERROR <> 0
            begin
                goto FAILURE
            end

        /* Add row to represent reciprocal subscription */
        insert sysmergesubscriptions(subid, partnerid, datasource_type, srvid, db_name, status, priority, pubid, subscriber_type, subscription_type, sync_type, login_name, subscriber_server, publication, distributor, last_validated)
            values (@pubid, @pubid, 0, @srvid, @db_name, @statid, @priority, @pubid, @global, @push, @automatic, suser_sname(suser_sid()), @@servername, @publication, @distservername, getdate())

        if @@ERROR <> 0
            begin
                goto FAILURE
            end
        /*
        **  Add row for merge publication to MSmerge_replinfo.
        */
        insert MSmerge_replinfo(repid, replnickname)
            values (@pubid, @nickname)
        if @@ERROR <> 0
            begin
                goto FAILURE
            end


        /*
        ** Add the publication to the distributor side
        */
        SELECT @distpubid = @nickname

        select @distproc = RTRIM(@distributor) + '.' + @distribdb + 
            '.dbo.sp_MSadd_publication'
        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @db_name,
            @publication = @publication,
            --@publication_id = NULL,
            @publication_type = 2,          -- 0 = Trans, 1 = Snapshot, 2 = Merge
            @independent_agent = @true,
            @immediate_sync = @true,
            @allow_push = @allow_push_id,
            @allow_pull = @allow_pull_id,
            @allow_anonymous = @allow_anonymous_id,
            --@snapshot_agent = NULL,
            --@logreader_agent = NULL,
            @description = @description,
            @retention = @retention,
			@allow_subscription_copy = @allow_subscription_copy_id

        IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                GOTO FAILURE
            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 FAILURE



    commit tran

    --Put this part outside of a TRANSACTION. It can fail without having to affect publication creation.
	declare @returnstring nvarchar(512) 
	set @returnstring = N''
	if LOWER(@add_to_active_directory collate SQL_Latin1_General_CP1_CS_AS)='true'
    begin
    	--no error checking needed here.    

		create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
		if @@ERROR<>0
			goto SKIP_AD
		insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @db_name
		if @retcode <> 0 or @@ERROR<>0
    	begin
			set @returnstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory)
			goto SKIP_AD	   	
		end
    	select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory
    	if @ad_guidname is not NULL
    	begin
    		update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
    		if @@ERROR<>0
    			goto SKIP_AD
    	end
	    drop table #guid_name_for_active_directory
    end
    return (0)
SKIP_AD:
	drop table #guid_name_for_active_directory
	if @returnstring is NULL
		select @returnstring = N''
	raiserror(21363, 16, -1, @publication, @returnstring)
	return (1) 
FAILURE:
    RAISERROR (14018, 16, -1)
    /* UNDONE : This code is specific to 6.X nested transaction semantics */
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION sp_addmergepublication
        COMMIT TRANSACTION
    end
    return (1)
go
exec dbo.sp_MS_marksystemobject sp_addmergepublication 
go

grant execute on dbo.sp_addmergepublication to public
go


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

CREATE PROCEDURE sp_changemergepublication (
    @publication sysname,              	/* Publication name */
    @property sysname = NULL,          	/* The property to change */
    @value nvarchar(255) = NULL,        /* The new property value */
    @force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
    @force_reinit_subscription bit = 0	/* Force reinit subscription */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @max_concurrent_merge	int
    declare @cmd                nvarchar(255)
    declare @pubid              uniqueidentifier
    declare @pubidstr           nvarchar(38)
    declare @retcode            int
    declare @retention          int
    declare @statusid           tinyint
    declare @sync_modeid        tinyint
    declare @distributor        sysname
    declare @distproc           nvarchar(300)
    declare @value_bit          bit
    declare @snapshot_ready 	tinyint
    declare @subscribed         int
    declare @dbname             sysname
    declare @distribdb          sysname
    declare @alt_snapshot_folder nvarchar(255)
    declare @enabled_for_internet bit
    declare @ftp_address        sysname
    declare @enc_ftp_password   nvarchar(524)
    declare @snapshot_in_defaultfolder bit
	declare @dynamic_filters_id	int
    declare @schemaversion      int 
    declare @schemaguid         uniqueidentifier
    declare @schematype         int
    declare @schematext         nvarchar(2000)
	declare @artid				uniqueidentifier
	declare @in_ActiveD			bit
	declare @ad_guidname		sysname
	declare @db_name			sysname
    declare @compress_snapshot  bit
    declare @numeric_value      int

    /*
    ** Initializations
    */
    select @subscribed = 1
    select @snapshot_ready = 1
	select @db_name=db_name()
    /*
    ** Security Check
    */

    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

    /* 
    ** Check if current DB is enabled for publication/subscription
    */
    
	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)
            
    /*
    ** Parameter Check:  @property.
    ** If the @property parameter is NULL, print the options.
    */
    if @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname collate database_default)
            INSERT INTO #tab1 VALUES ('description')
            INSERT INTO #tab1 VALUES ('status')
            INSERT INTO #tab1 VALUES ('retention')
            INSERT INTO #tab1 VALUES ('sync_mode')
            INSERT INTO #tab1 VALUES ('allow_push')
            INSERT INTO #tab1 VALUES ('allow_pull')
            INSERT INTO #tab1 VALUES ('allow_anonymous')
            INSERT INTO #tab1 VALUES ('enabled_for_internet')
            INSERT INTO #tab1 VALUES ('centralized_conflicts')
            INSERT INTO #tab1 VALUES ('snapshot_ready')
            INSERT INTO #tab1 VALUES ('snapshot_in_defaultfolder')
            INSERT INTO #tab1 VALUES ('alt_snapshot_folder')
            INSERT INTO #tab1 VALUES ('pre_snapshot_script')
            INSERT INTO #tab1 VALUES ('post_snapshot_script')
            INSERT INTO #tab1 VALUES ('compress_snapshot')
            INSERT INTO #tab1 VALUES ('ftp_address')
            INSERT INTO #tab1 VALUES ('ftp_port')
            INSERT INTO #tab1 VALUES ('ftp_subdirectory')
            INSERT INTO #tab1 VALUES ('ftp_login')
            INSERT INTO #tab1 VALUES ('ftp_password')
            INSERT INTO #tab1 VALUES ('conflict_retention')
            INSERT INTO #tab1 VALUES ('allow_subscription_copy')
            INSERT INTO #tab1 VALUES ('allow_synctoalternate')
            INSERT INTO #tab1 VALUES ('validate_subscriber_info')
            INSERT INTO #tab1 VALUES ('publish_to_ActiveDirectory')
            INSERT INTO #tab1 VALUES ('dynamic_filters')
            INSERT INTO #tab1 VALUES ('max_concurrent_merge')
            INSERT INTO #tab1 VALUES ('max_concurrent_dynamic_snapshots')
            select * FROM #tab1
            RETURN (0)
        END

    if @value is NULL and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) not in 
                                                  ('description', 
                                                   'alt_snapshot_folder',
                                                   'pre_snapshot_script',
                                                   'post_snapshot_script',
                                                   'ftp_address',
                                                   'ftp_subdirectory',
                                                   'ftp_login',
                                                   'ftp_password',
                                                   'max_concurrent_merge')
        begin
            RAISERROR (20081, 16, -1, @property)
            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

    select @pubid = pubid, 
           @ad_guidname=ad_guidname, --with value NULL if this publication is not in AD.
           @snapshot_ready=snapshot_ready,
    	   @dynamic_filters_id=dynamic_filters,
           @sync_modeid = sync_mode, 
           @alt_snapshot_folder = alt_snapshot_folder,
           @enabled_for_internet = enabled_for_internet,
           @ftp_address = ftp_address,
           @snapshot_in_defaultfolder = snapshot_in_defaultfolder,
           @compress_snapshot = compress_snapshot,
           @in_ActiveD = case when ad_guidname is NULL then 0 else 1 end 
      FROM sysmergepublications 
     WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''

    if @pubid IS NULL
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END
    else

    /*
    ** Parameter Check:  @property.
    ** Check to make sure that @property is a valid property in
    ** sysmergepublications.
    */
    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('description', 'status', 'retention', 'sync_mode', 'allow_push', 
        'allow_pull', 'allow_anonymous', 'enabled_for_internet', 'centralized_conflicts', 'snapshot_ready', 
        'snapshot_in_defaultfolder', 'alt_snapshot_folder', 'pre_snapshot_script', 'post_snapshot_script', 
        'compress_snapshot', 'ftp_address', 'ftp_port', 'ftp_subdirectory','ftp_login',
        'ftp_password', 'conflict_retention', 'allow_subscription_copy', 'allow_synctoalternate',
        'validate_subscriber_info','publish_to_activedirectory','dynamic_filters','max_concurrent_merge', 'max_concurrent_dynamic_snapshots') 
        BEGIN
            RAISERROR (21053, 16, -1)
            RETURN (1)
        END


    /*
    ** Parameter Check:
    ** If sync_method of the publication is character mode (an indication that it supports
    ** third party Subscribers), pre/post-snapshot setting must be null   
    **
    */
    IF @sync_modeid = 1 
    BEGIN
        IF (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'pre_snapshot_script' OR
            LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'post_snapshot_script') AND
            @value IS NOT NULL AND @value <> ''
        BEGIN
            RAISERROR (21151, 16, -1)
            RETURN (1)
        END   
    END

    /*
    ** Parameter Check:
    ** If the Publication's alt_snapshot_folder setting is null 
    ** snapshot compression cannot be enabled
    */
    IF ((@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = '')) 
        AND LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
        AND LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'   
    BEGIN
        RAISERROR (21157, 16, -1)        
        RETURN (1)
    END

    /* 
    ** Parameter Check:
    ** If enabled_for_internet is set to true, the publication must have a non-null
    ** ftp_address.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
       LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND 
       (@ftp_address IS NULL OR @ftp_address = N'')
    BEGIN
        RAISERROR(21158, 16, -1)
        RETURN (1)
    END

    /*
    ** .. and ftp_address cannot be null if the publication is enabled for 
    ** internet.
    */
/*
    IF @enabled_for_internet = 1 AND
      (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        AND (@value IS NULL OR @value = N''))
    BEGIN
        RAISERROR(21158, 16, -1)
        RETURN (1)
    END
*/
    /*
    ** .. and 'alternate snapshot folder' is not null and
    ** 'snapshot in default folder' is false
    **
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'enabled_for_internet' AND
        LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true' AND
       (@alt_snapshot_folder IS NULL OR @alt_snapshot_folder = N'')
    BEGIN
        RAISERROR(21159, 16, -1)
        RETURN (1)
    END 

/*
    IF @enabled_for_internet = 1 AND
       (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder' AND
        (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IS NULL OR LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N''))
    BEGIN
        RAISERROR(21159, 16, -1)
        RETURN (1)
    END  
*/

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='validate_subscriber_info'
	begin
		if exists (select * from sysmergesubscriptions where pubid=@pubid and subid<>@pubid and status<>0)
			begin
				raiserror(21501, 16, -1)
				return (1)
			end	
	end

    /*
    ** Parameter Check:
    ** 'ftp_port' cannot be null
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port' AND @value IS NULL
    BEGIN
        RAISERROR (14043, 16, -1, @property)
        RETURN (1)
    END

    BEGIN TRAN changemergepublication    
    save tran changemergepublication

	/*
	** Changing of the following properties would require a snapshot rerun, if snapshot is ready
	*/
	if (LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) like 'ftp%' OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('sync_mode', 'snapshot_in_defaultfolder',
			'alt_snapshot_folder', 'pre_snapshot_script', 'post_snapshot_script','compress_snapshot'))
	and @snapshot_ready>0
	begin
		if @force_invalidate_snapshot = 0
		begin
			raiserror(20607, 16, -1)
			goto UNDO
		end
		update sysmergepublications set snapshot_ready=2 where pubid=@pubid and snapshot_ready=1
		if @@ERROR<>0	GOTO UNDO
	end

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='dynamic_filters' and @snapshot_ready>0
	begin
		if @force_invalidate_snapshot = 0
		begin
			raiserror(20607, 16, -1)
			goto UNDO
		end
		if @force_reinit_subscription = 0
		begin
			raiserror(20608, 16, -1)
			goto UNDO
		end
		if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        	select @dynamic_filters_id = 1
	    else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false' 
       		select @dynamic_filters_id = 0
       	else
       		begin
       			raiserror(14137, 16, -1)
       			goto UNDO
       		end
		update sysmergepublications set dynamic_filters=@dynamic_filters_id, snapshot_ready=2 where pubid=@pubid
		if @@ERROR<>0
			goto UNDO
		exec @retcode = sp_MSreinitmergepublication @publication
		if @retcode<>0 or @@ERROR<>0
			goto UNDO
	end
	
	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='validate_subscriber_info'
	begin
		if @value is not NULL
		begin
			if @dynamic_filters_id = 0
				begin
					raiserror(21313, 16, -1)
					GOTO UNDO
				end
			exec ('select ' + @value)
			if @@ERROR<>0
				begin
					raiserror(21299, 16, -1, @value)
					GOTO UNDO
				end
		end

		UPDATE sysmergepublications  SET validate_subscriber_info = @value WHERE pubid = @pubid
		if @@ERROR <> 0 GOTO UNDO
	end

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description')
        BEGIN
            UPDATE sysmergepublications  SET description = @value WHERE pubid = @pubid
            if @@ERROR <> 0 GOTO UNDO
        END

  
    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'status'
        BEGIN

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

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

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

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'active'
                select @statusid = 1
            else
                select @statusid = 0

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

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

            if @@ERROR <> 0 GOTO UNDO
        END


    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'retention'
        BEGIN
        /*
        ** Update the publication with the new replication frequency.
        */

        select @retention = CONVERT(int, @value)

        if @retention is NULL 
        	select @retention = 0

       	if @retention < 0
       		begin
       			raiserror(20050, 16, -1, 0)
       			GOTO UNDO
       		end

        UPDATE sysmergepublications set retention = @retention WHERE pubid = @pubid
        if @@ERROR <> 0 
            GOTO UNDO

		select @schemaversion = schemaversion from sysmergeschemachange
        if (@schemaversion is NULL)
        	set @schemaversion = 1
        else
            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
            
        set @schemaguid = newid()
        set @artid = newid()
        set @schematype = 9 /* change retention */
        select @schematext = 'exec dbo.sp_MSchange_retention '+ '''' + convert(nchar(36),@pubid) + '''' + ',' + '''' + @value + ''''          
        exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
            if @@ERROR<>0 or @retcode<>0 goto UNDO    


        END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'conflict_retention'
        BEGIN
        /*
        ** Update the publication with the new conflict_retention value
        */

        select @retention = CONVERT(int, @value)
        if @@ERROR<>0
        	GOTO UNDO

        if @value is NULL 
        	select @retention = 0

       	if @retention < 0
       		begin
       			raiserror(20050, 16, -1, 0)
       			GOTO UNDO
       		end

        UPDATE sysmergepublications
            SET conflict_retention = @retention
            WHERE pubid = @pubid

        if @@ERROR <> 0 
            GOTO UNDO

        END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'max_concurrent_merge'
        BEGIN
        /*
        ** Update the publication property <max_concurrent_merge> with a new value
        */

        select @max_concurrent_merge = CONVERT(int, @value)
		if @max_concurrent_merge < 0	
		begin
			raiserror(21402, 16, -1, '@value')
			GOTO UNDO
		end

        UPDATE sysmergepublications
            SET max_concurrent_merge = @max_concurrent_merge
            WHERE pubid = @pubid

        if @@ERROR <> 0 
            GOTO UNDO

        END


    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_mode'
        BEGIN

            /*
            ** Check for a valid synchronization method.
            */
		    if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='portable' select @value='character'

            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('native', 'character', 'bcp native', 'bcp character')
                begin
                raiserror (20076, 16, -1)
                GOTO UNDO
                end

            /*
            ** Determine the integer value for the sync_mode.
            */
            if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('native', 'bcp native')
                select @sync_modeid = 0
            else if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) IN ('character', 'bcp character')
                select @sync_modeid = 1

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

            UPDATE sysmergepublications
               SET sync_mode = @sync_modeid
             WHERE pubid = @pubid

            if @@ERROR <> 0 GOTO UNDO
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
        BEGIN
            -- If the alt_snapshot_folder is set to '' or NULL,
            -- set the compress_snapshot bit to 0 and disable internet 
            -- support
  
            IF @value IS NULL OR @value = N''
            BEGIN
                UPDATE sysmergepublications
                   SET alt_snapshot_folder = @value,
                       compress_snapshot = 0,
                       enabled_for_internet = 0
                 WHERE pubid = @pubid
            END
            ELSE
            BEGIN
                UPDATE sysmergepublications
                   SET alt_snapshot_folder = @value
                 WHERE pubid = @pubid
            END
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'pre_snapshot_script'
        BEGIN
            UPDATE sysmergepublications
               SET pre_snapshot_script = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'post_snapshot_script'
        BEGIN
            UPDATE sysmergepublications
               SET post_snapshot_script = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        BEGIN
            IF @value IS NULL OR @value = N''    
            BEGIN
                UPDATE sysmergepublications
                   SET ftp_address = @value,
                       enabled_for_internet = 0
                 WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END
            END
            ELSE
            BEGIN
                UPDATE sysmergepublications
                   SET ftp_address = @value
                 WHERE pubid = @pubid
                IF @@error <> 0
                BEGIN
                    GOTO UNDO
                END
            END
        END
            
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port'
        BEGIN
            UPDATE sysmergepublications
               SET ftp_port = CONVERT(int, @value)
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_subdirectory'
        BEGIN
            UPDATE sysmergepublications
               SET ftp_subdirectory = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_login'
        BEGIN
            UPDATE sysmergepublications
               SET ftp_login = @value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_password'
        BEGIN
            SELECT @enc_ftp_password = NULL
            IF @value IS NOT NULL
            BEGIN
                SELECT @enc_ftp_password = @value
                EXEC @retcode = master.dbo.xp_repl_encrypt @enc_ftp_password OUTPUT
                IF @retcode <> 0
                BEGIN
                    GOTO UNDO
                END
            END

            UPDATE sysmergepublications
               SET ftp_password = @enc_ftp_password
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'max_concurrent_dynamic_snapshots'
        BEGIN
            SELECT @numeric_value = CONVERT(int, @value)
            IF @@ERROR<>0 OR @numeric_value < 0 OR @numeric_value IS NULL
            BEGIN
                RAISERROR(21403, 16, -1)
                GOTO UNDO
            END

            UPDATE sysmergepublications
               SET max_concurrent_dynamic_snapshots = @numeric_value
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN 
                GOTO UNDO
            END 
        END            

   if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publish_to_activedirectory'
   BEGIN
        if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14137, 16, -1)
            GOTO UNDO
        END

	    /* Is AD supported? */
	    DECLARE @retval  INT
	    EXECUTE @retval = master.dbo.xp_MSADEnabled
	    if (@retval <> 0)
	    begin
			RAISERROR(21254, 16, -1, @publication)
			RETURN (1)
	    end

   		if @in_ActiveD=0 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='true'
   		BEGIN
			create table #guid_name_for_active_directory(ad_guidname sysname collate database_default null)
			if @@ERROR<>0
			begin
				raiserror(21363, 16, -1, @publication, N'')
				goto UNDO			
			end
			insert into #guid_name_for_active_directory exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'CREATE', 'PUBLICATION', @publication, @db_name
			if @retcode <> 0 or @@ERROR<>0
	    	begin
				declare @errorstring nvarchar(512)
				select @errorstring = (select TOP 1 ad_guidname from #guid_name_for_active_directory) 
	    		drop table #guid_name_for_active_directory
	    		if @errorstring is NULL
	    			select @errorstring=N''
	    		raiserror(21363, 16, -1, @publication, @errorstring)
    			GOTO UNDO
	   		end
	    	select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_active_directory
    		if @ad_guidname is not NULL
	    	begin
    			update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
    			if @@ERROR<>0
    			begin
    				drop table #guid_name_for_active_directory
    				raiserror(21363, 16, -1, @publication, N'')
	    		    goto UNDO
    			end
    		end
    		drop table #guid_name_for_active_directory
   		END
   		else if @in_ActiveD=1 and LOWER(@value collate SQL_Latin1_General_CP1_CS_AS)='false'
   		BEGIN
			exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @db_name, @ad_guidname
			if @@ERROR<>0 or @retcode<>0
			begin
				raiserror(21369, 16, -1, @publication)	
				goto UNDO
			end
			update sysmergepublications set ad_guidname=NULL where pubid=@pubid
			if @@ERROR<>0
			begin
				raiserror(21369, 16, -1, @publication)	
				goto UNDO
			end
   		END
   END

    if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('allow_push', 'allow_pull', 'allow_anonymous', 'enabled_for_internet',
        'centralized_conflicts', 'snapshot_ready', 'snapshot_in_defaultfolder', 'compress_snapshot', 
        'allow_subscription_copy', 'allow_synctoalternate')
    BEGIN

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

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

        /*
        ** set value bit
        */
        if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            select @value_bit = 1
        else 
            select @value_bit = 0


        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_anonymous'
        BEGIN
            /* Update the allow_anonymous column */
            UPDATE sysmergepublications 
                SET allow_anonymous = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END

        END

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_push'
        BEGIN
            /* Update the allow_push column */
            UPDATE sysmergepublications 
                SET allow_push = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_pull'
        BEGIN

            /* Update the allow_pull column */
            UPDATE sysmergepublications 
                SET allow_pull = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'centralized_conflicts'
        BEGIN
            /* Update the centralized_conflicts column */
            UPDATE sysmergepublications 
                SET centralized_conflicts = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END

            if @value_bit=0 and @snapshot_ready>0
            begin            
			-- changing to decentralized conflict logging will require reinitialization but no snapshot rerun
				if @force_reinit_subscription = 0
				begin
					raiserror(20608, 16, -1)
					goto UNDO
				end
				exec @retcode = sp_MSreinitmergepublication @publication
				if @@ERROR<>0 or @retcode<>0
					goto UNDO
            end
        END

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'enabled_for_internet'
        BEGIN
            UPDATE sysmergepublications 
               SET enabled_for_internet = @value_bit
             WHERE pubid = @pubid

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

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot_ready'
        BEGIN
            /* Update the allow_anonymous column */
            UPDATE sysmergepublications 
                SET snapshot_ready = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END

        END

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'snapshot_in_defaultfolder'
        BEGIN
            -- snapshot_in_defaultfolder = 1 is only meaningful when
            -- alt_snapshot_folder is non-null, otherwise 
            -- a copy of the snapshot files is always kept
            -- at the publisher's working directory 
    
            UPDATE sysmergepublications 
               SET snapshot_in_defaultfolder = @value_bit
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
                GOTO UNDO
            END                

            -- Bump up the compatibility level if we are
            -- setting snapshot_in_defaultfolder to 0
            -- and compression is enabled. i.e. only 
            -- a compressed snapshot will be generated
            -- Note that alt_snapshot_folder is implicitly
            -- specified for the publication
            IF @value_bit = 0 and @compress_snapshot = 1 
            BEGIN
                EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
                IF @@ERROR<>0 OR @retcode<>0
                    GOTO UNDO
            END

        END
        
        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'compress_snapshot'
        BEGIN

            UPDATE sysmergepublications
               SET compress_snapshot = @value_bit
             WHERE pubid = @pubid
            IF @@error <> 0
            BEGIN
                GOTO UNDO
            END

            -- See comment for 'snapshot_in_defaultfolder'
            IF @value_bit = 1 and @snapshot_in_defaultfolder = 0
            BEGIN
                EXEC @retcode = sp_MSBumpupCompLevel @pubid, 40
                IF @@ERROR<>0 OR @retcode<>0
                    GOTO UNDO
            END
        END

        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_subscription_copy'
        BEGIN
            /* Update the allow_subscription_copy column */
            UPDATE sysmergepublications 
                SET allow_subscription_copy = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END
        if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'allow_synctoalternate'
        BEGIN
            /* Update the allow_synctoalternate column */
            UPDATE sysmergepublications 
                SET allow_synctoalternate = @value_bit
                WHERE pubid = @pubid
            if @@error <> 0
            BEGIN
               GOTO UNDO
            END
        END
    END

    /*
    ** Update merge publication property at distributor side if necessaray 
    */
    
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description','allow_push', 'allow_pull', 'allow_anonymous','retention', 'allow_subscription_copy')
	BEGIN

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('allow_push', 'allow_pull', 'allow_anonymous','allow_subscription_copy')
            
        /* Translate values */
        BEGIN            
            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
                SELECT @value = '1'
            ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false'
                    SELECT @value = '0'
        END
        /*
        ** 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

    COMMIT TRAN

	--update its registration in active directory
	if @in_ActiveD=1 and LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN ('description','allow_pull', 'allow_anonymous')
	begin
		create table #guid_name_for_ADupdate(ad_guidname sysname collate database_default null)
		if @@ERROR<>0
		begin
            goto FAILURE
		end
		insert into #guid_name_for_ADupdate exec @retcode = master.dbo.sp_ActiveDirectory_Obj N'UPDATE', N'PUBLICATION', @publication, @db_name, @ad_guidname
		if @@ERROR<>0 or @retcode<>0
    	begin
    		goto FAILURE 					
	   	end
    	select TOP 1 @ad_guidname = ad_guidname from #guid_name_for_ADupdate
    	if @ad_guidname is not NULL
    	begin
    		update sysmergepublications set ad_guidname=@ad_guidname where pubid=@pubid
    		if @@ERROR<>0
    		    goto FAILURE 					
    	end
	    drop table #guid_name_for_ADupdate
    end

    /*
    ** Return succeed.
    */
    
    RAISERROR (14077, 10, -1)
    RETURN (0)
FAILURE:
	drop table #guid_name_for_ADupdate
    raiserror(21371, 10, -1, @publication)
    return (1)   

UNDO: 
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION changemergepublication
        COMMIT TRANSACTION
    end
GO
exec dbo.sp_MS_marksystemobject sp_changemergepublication 
go

grant execute on dbo.sp_changemergepublication to public
go


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

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

CREATE PROCEDURE sp_helpmergepublication (
    @publication    sysname = '%',    /* The publication name */
    @found          int         = NULL  OUTPUT,
    @publication_id uniqueidentifier = NULL OUTPUT,
    @reserved       nvarchar(20) = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    declare @retcode            int
    declare @no_row             bit
    declare @our_srvid          int
    declare @has_subscription   bit
    /*
    ** Initializations.
    */
    select @has_subscription = 0

    if @found is NULL 
    BEGIN
        select @no_row=0
    END
    else
    BEGIN
        select @no_row=1
    END
    select @found       = 0
    select @our_srvid = max(srvid) from master.dbo.sysservers where UPPER(srvname) = UPPER(@@SERVERNAME) collate database_default

    
    /*
    ** Running sp_help is OK from everywhere, whether enabled for publishing or not
    */
    
    IF not exists (select * from sysobjects where name='sysmergesubscriptions')
        RETURN (0)


    /*
    ** 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 LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = 'internal'
        GOTO SelectPubs
    
    if  NOT EXISTS (select * FROM sysmergepublications pub, sysmergesubscriptions sub
        WHERE pub.name like @publication  
            and UPPER(pub.publisher)=UPPER(@@servername) 
            and pub.publisher_db=db_name() 
            and sub.pubid = pub.pubid  
            and sub.srvid = @our_srvid 
            and sub.db_name = db_name())
        BEGIN
            select @found = 0
            RETURN (0) 
        END
    else
        BEGIN
            select @found = 1
            select @publication_id = pubid FROM sysmergepublications 
                WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
            if exists (select * from sysmergesubscriptions where pubid<>subid and pubid in 
                (select pubid from sysmergepublications where name like @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()))
                select @has_subscription = 1
            if @no_row <> 0
                RETURN(0)
        END

SelectPubs:

    CREATE TABLE #tab1 (
        id                      int                 identity NOT NULL,
        name                    sysname             collate database_default not null,
        description             nvarchar(255)       collate database_default null,
        status                  tinyint             NOT NULL,
        retention               int                 NULL,
        sync_mode               tinyint             NULL,
        allow_push              int                 NOT NULL,
        allow_pull              int                 NOT NULL,
        allow_anonymous         int                 NOT NULL,
        centralized_conflicts   int                 NOT NULL,
        priority                float(8)            NOT NULL,
        snapshot_ready          tinyint             NOT NULL,
        publication_type        int                 NULL,
        pubid                   uniqueidentifier    NOT NULL,
        snapshot_jobid          binary(16)          NULL,
        enabled_for_internet    int                 NULL,
        dynamic_filters         int                 NULL,
        has_subscription        bit                 NULL,
        -- Portable snapshot support
        snapshot_in_defaultfolder       bit default 1       NOT NULL,
        alt_snapshot_folder     nvarchar(255)       collate database_default null,
        -- Pre/post-snapshot commands
        pre_snapshot_script     nvarchar(255)       collate database_default null,
        post_snapshot_script    nvarchar(255)       collate database_default null,
        -- Snapshot compression
        compress_snapshot       bit default 0       NOT NULL,
        -- Post 7.0 FTP support
        ftp_address             sysname             collate database_default null,
        ftp_port                int                 NOT NULL,
        ftp_subdirectory        nvarchar(255)       collate database_default null,
        ftp_login               sysname             collate database_default null,
        conflict_retention		int					NULL,
        keep_partition_changes	int					NULL,
        allow_subscription_copy int                 NULL,
        allow_synctoalternate 	int                 NULL,
        validate_subscriber_info nvarchar(500)		collate database_default null,
        backward_comp_level		int					not null default 10, --defaulted to 70 server
        publish_to_activedirectory			bit					null,
        max_concurrent_merge	int					NULL,
        max_concurrent_dynamic_snapshots int  NOT NULL default 0
        )

    /* This is valid at all sites - used for decentralized conflicts */
    IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = 'internal'
        begin
            INSERT into #tab1(name, description, status, retention, sync_mode, 
                    allow_push, allow_pull, allow_anonymous, centralized_conflicts, 
                    priority, snapshot_ready, publication_type, pubid, snapshot_jobid, 
                    enabled_for_internet, 
					dynamic_filters, snapshot_in_defaultfolder, alt_snapshot_folder, pre_snapshot_script,
                    post_snapshot_script, compress_snapshot, ftp_address, ftp_port, 
                    ftp_subdirectory, ftp_login, conflict_retention, 
                    keep_partition_changes, allow_subscription_copy, allow_synctoalternate, 
                    validate_subscriber_info,backward_comp_level, publish_to_activedirectory, max_concurrent_merge, max_concurrent_dynamic_snapshots)
            select  pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, 
                    pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, 
                    subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid,
                    pubs.enabled_for_internet, 
					pubs.dynamic_filters,
                    pubs.snapshot_in_defaultfolder,
                    pubs.alt_snapshot_folder,
                    pubs.pre_snapshot_script,
                    pubs.post_snapshot_script,
                    pubs.compress_snapshot,
                    pubs.ftp_address,
                    pubs.ftp_port,
                    pubs.ftp_subdirectory,
                    pubs.ftp_login,
                    pubs.conflict_retention,
                    pubs.keep_before_values,
                    pubs.allow_subscription_copy,
                    pubs.allow_synctoalternate,
                    pubs.validate_subscriber_info,
                    pubs.backward_comp_level,
                    case when pubs.ad_guidname is NULL then 0 else 1 end,
                    pubs.max_concurrent_merge,
                    pubs.max_concurrent_dynamic_snapshots
            FROM    sysmergesubscriptions   subs,
                    sysmergepublications    pubs,
                    MSmerge_replinfo        replinfo
                    WHERE pubs.name LIKE @publication
                        AND UPPER(pubs.publisher)=UPPER(@@servername) 
                        AND pubs.publisher_db=db_name()
                        AND subs.subid = pubs.pubid
                        AND replinfo.repid = pubs.pubid
                        AND subs.subscriber_type = 1
            ORDER BY name
        end
    /* This is valid only at publishers and republishers */
    else
        begin
            INSERT into #tab1(name, description, status, retention, sync_mode, 
                    allow_push, allow_pull, allow_anonymous, centralized_conflicts, 
                    priority, snapshot_ready, publication_type, pubid, snapshot_jobid, 
                    enabled_for_internet,
					dynamic_filters, has_subscription,
                    snapshot_in_defaultfolder, alt_snapshot_folder, pre_snapshot_script, 
                    post_snapshot_script, compress_snapshot, ftp_address,
                    ftp_port, ftp_subdirectory, ftp_login, conflict_retention, 
                    keep_partition_changes, allow_subscription_copy, allow_synctoalternate, 
                    validate_subscriber_info, backward_comp_level, publish_to_activedirectory,max_concurrent_merge,max_concurrent_dynamic_snapshots)
            select  pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, 
                    pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, 
                    subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid,
                    pubs.enabled_for_internet,
					pubs.dynamic_filters, case when exists (select * from sysmergesubscriptions where pubid<>subid and pubid in 
								                (select in_pubs.pubid from sysmergepublications in_pubs where in_pubs.name = pubs.name 
								                	and UPPER(in_pubs.publisher)=UPPER(@@servername) and in_pubs.publisher_db=db_name()))
								          then 1
								          else 0 end,
                    pubs.snapshot_in_defaultfolder, pubs.alt_snapshot_folder,
                    pubs.pre_snapshot_script, pubs.post_snapshot_script,
                    pubs.compress_snapshot, pubs.ftp_address,
                    pubs.ftp_port, pubs.ftp_subdirectory,
                    pubs.ftp_login,
                    pubs.conflict_retention,
                    pubs.keep_before_values,
                    pubs.allow_subscription_copy,
                    pubs.allow_synctoalternate,
                    pubs.validate_subscriber_info,
                    pubs.backward_comp_level,
					case when pubs.ad_guidname is NULL then 0 else 1 end ,
					pubs.max_concurrent_merge,
                    pubs.max_concurrent_dynamic_snapshots
            FROM    sysmergesubscriptions   subs,
                    sysmergepublications    pubs,
                    MSmerge_replinfo        replinfo
                    WHERE pubs.name LIKE @publication
                         and UPPER(pubs.publisher)=UPPER(@@servername) 
                         and pubs.publisher_db=db_name()
                        AND subs.subid = pubs.pubid
                        AND replinfo.repid = pubs.pubid
                        AND subs.subscriber_type = 1
                        AND subs.srvid = @our_srvid 
                        AND subs.db_name = db_name()
            ORDER BY name
        end
    if @@ERROR <> 0 
        RETURN (1)

	update #tab1 set snapshot_ready=0 where snapshot_ready>1
	if @@ERROR<>0
		RETURN (1)
    select * FROM #tab1
    RETURN (0)
go
exec dbo.sp_MS_marksystemobject sp_helpmergepublication 
go

grant execute on dbo.sp_helpmergepublication to public
go


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


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

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

    set nocount on
    /*
    ** Declarations.
    */
	declare @ad_guidname		sysname
    declare @pubid              uniqueidentifier
    declare @article            sysname
    declare @cmd                nvarchar(255)
    declare @retcode            int
    declare @distproc           nvarchar(300)
    declare @distributor        sysname
    declare @distribdb          sysname
    declare @working_dir        varchar(255)
    declare @working_dir_drive  varchar(255)
    declare @pub_dir            nvarchar(255)
    declare @db_name            sysname
	declare @implicit_transaction	int
	declare @close_cursor_at_commit int
    declare @dynamic_filters        bit
    declare @alt_snapshot_folder nvarchar(255)
    declare @pub_alt_snapshot_folder nvarchar(255)

	select @close_cursor_at_commit = 0
	select @implicit_transaction = 0
	/*
	** Save setting values first before changing them
	*/
	IF (@reserved = 0)
	BEGIN
		SELECT @implicit_transaction = @@options & 2
		SELECT @close_cursor_at_commit = @@options & 4
		SET IMPLICIT_TRANSACTIONS OFF
		SET CURSOR_CLOSE_ON_COMMIT OFF
	END

	set @ad_guidname = NULL
    /*
    ** Initializations.
    */  
    select @db_name = db_name()

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

	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    if LOWER(@publication) = 'all'
        BEGIN

            declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name 
                FROM sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() 
                    FOR READ ONLY
            
            OPEN hC1
            FETCH hC1 INTO @publication
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergepublication @publication=@publication,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = 1

                    FETCH hC1 INTO @publication
                END
            CLOSE hC1
            DEALLOCATE hC1
            RETURN (0)
        END

    if @publication IS NULL
        BEGIN
            RAISERROR (14003, 16, -1)
            RETURN (1)
        END
    /*
    ** Get the @pubid.
    */
    if NOT EXISTS (select * FROM sysmergepublications 
        WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END
    select @pubid = pubid,
           @dynamic_filters = @dynamic_filters,
           @alt_snapshot_folder = alt_snapshot_folder 
      FROM sysmergepublications 
        WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()

	select @ad_guidname=ad_guidname FROM sysmergepublications 
	        WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()	
    
    /* 
    ** Ignore external publications
    */
    if exists (select * from sysmergesubscriptions where subid=@pubid 
        and pubid=@pubid and db_name<>db_name())
    RETURN (0)

    /*
    ** Check to make sure that there are push or pull subscriptions on the publication.
    */
    if EXISTS (select * FROM sysmergesubscriptions  subs, 
                    sysmergepublications                pubs, 
                    MSmerge_replinfo                    repinfo
                WHERE   pubs.name = @publication
                    AND UPPER(pubs.publisher)=UPPER(@@servername) 
                    AND pubs.publisher_db=db_name()
                    AND subs.pubid = pubs.pubid
                    AND subs.status <> 2  -- Having a deleted subscription row is fine
                    AND repinfo.repid <> @pubid
                    AND subs.subid <> subs.partnerid)
        BEGIN
            RAISERROR (14005, 16, -1)
            RETURN (1)
        END


    begin tran
    save TRANSACTION dropmergepublication

    /*
    ** delete on-demand user script, if any
    */
	if exists (select * from sysmergeschemachange where schematype=46 and pubid=@pubid)
		begin
			exec @retcode=sp_MSremove_userscript @pubid, 1
			--we may not want to do error checking here
		end
	
    /*
    ** Delete all articles from the publication.
    */

    update sysmergepublications set snapshot_ready=0 where pubid=@pubid --so that articles can be dropped
    if @@ERROR<>0
    	goto FAILURE
    EXECUTE @retcode = dbo.sp_dropmergearticle @publication = @publication, @article = 'all',
        @ignore_distributor = @ignore_distributor

    if @@ERROR <> 0 OR @retcode <> 0
        begin
            RAISERROR (20040, 16, -1, @publication)
            goto FAILURE
        end

    /*
    ** Delete sync task of Publication.
    */
    execute @retcode = dbo.sp_MSdropmergepub_snapshot @publication = @publication,
        @ignore_distributor = @ignore_distributor

    if @@ERROR <> 0 OR @retcode <> 0
        begin
            RAISERROR (20010, 16, -1, @publication)
            goto FAILURE
        end

    /*
    ** Remove my own subscription from sysmergesubscriptions.
    */
    if exists (select * from sysmergesubscriptions where subid = @pubid)
        begin
            DELETE from sysmergesubscriptions WHERE subid = @pubid
            if @@ERROR <> 0
                goto FAILURE
        end         

    if exists (select * from MSmerge_replinfo where repid = @pubid)
        begin
            DELETE from MSmerge_replinfo WHERE repid = @pubid
            if @@ERROR <> 0
                goto FAILURE
        end             

    /*
    ** 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,
                                           @directory = @working_dir OUTPUT
        IF @@ERROR <> 0 OR  @retcode <> 0
            BEGIN
                RAISERROR (14071, 16, -1)
                goto FAILURE
            END

        /*
        ** Drop the publication info from the distributor
        */
        select @distproc = RTRIM(@distributor) + '.' + @distribdb + 
            '.dbo.sp_MSdrop_publication'
        EXECUTE @retcode = @distproc
            @publisher = @@SERVERNAME,
            @publisher_db = @db_name,
            @publication = @publication

        if @@ERROR <> 0 OR @retcode <> 0
        begin
            goto FAILURE
        end

        /*
        ** If alternate snapshot folder is specified for this publication,
        ** try to remove the publication's snapshot folder underneath the
        ** the alternate snapshot location in Distributor's context
        */
        if @alt_snapshot_folder is not null and
           @alt_snapshot_folder <> N''
        begin

            /* Append publication specific folder name */
            if substring(@alt_snapshot_folder,len(@alt_snapshot_folder),1)<>
                N'\' 
            begin
                select @alt_snapshot_folder = @alt_snapshot_folder + N'\'
            end 

            -- UNC version
            select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'unc\' + fn_replcomposepublicationsnapshotfolder(@@servername,@db_name,@publication) collate database_default
            select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + '.'  + fn_replquotename(@distribdb) collate database_default + 
                '.dbo.sp_MSreplremoveuncdir'
            -- Ignore errors as the snapshot folder may not exist at all
            EXECUTE @distproc
                @dir = @pub_alt_snapshot_folder

            -- FTP-enabled version
            select @pub_alt_snapshot_folder = @alt_snapshot_folder + N'ftp\' + fn_replcomposepublicationsnapshotfolder(@@servername,@db_name,@publication) collate database_default
            select @distproc = fn_replquotename(RTRIM(@distributor)) collate database_default + '.'  + fn_replquotename(@distribdb) collate database_default + 
                '.dbo.sp_MSreplremoveuncdir'
            -- Ignore errors as the snapshot folder may not exist at all
            EXECUTE @distproc
                @dir = @pub_alt_snapshot_folder
        end         
    end

    /* Remove all dynamic snapshot jobs of this publication */
    exec @retcode = sp_MSdropmergedynamicsnapshotjob 
        @publication = @publication,
        @ignore_distributor = @ignore_distributor

    if @@ERROR <> 0 OR @retcode <> 0
    begin
        goto FAILURE
    end

    /*
    ** Execute the cleanup routine for the publication
    */
	exec dbo.sp_MSpublicationcleanup @publisher=@@SERVERNAME, 
			@publisher_db = @db_name,
			@publication = @publication
    
	if @@ERROR <> 0
        goto FAILURE

	DECLARE @retval  INT
	EXECUTE @retval = master.dbo.xp_MSADEnabled
    if @ad_guidname is not NULL 
    begin
    	if @retval = 0
		begin
    		exec @retcode=master.dbo.sp_ActiveDirectory_Obj 'DELETE', 'PUBLICATION', @publication, @db_name, @ad_guidname
			if @@ERROR<>0 or @retcode<>0
			begin
				raiserror(21369, 16, -1, @publication)
				goto FAILURE
			end
    	end
    	else
    	begin
			RAISERROR(21254, 16, -1, @publication)
    		GOTO FAILURE
    	end
    end

    COMMIT TRANSACTION
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END
    return (0)

FAILURE:            
    RAISERROR (14006, 16, -1)
    /* UNDONE : This code is specific to 6.X nested transaction semantics */
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION dropmergepublication
        COMMIT TRANSACTION
    end
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END        
    RETURN (1)
go
exec dbo.sp_MS_marksystemobject sp_dropmergepublication
go

grant execute on dbo.sp_dropmergepublication to public
go

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

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

CREATE PROCEDURE sp_mergearticlecolumn (
        @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 */
        @schema_replication nvarchar(5) = 'false',	/* reserved for internal use */
        @force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
		@force_reinit_subscription bit = 0	/* Force reinit subscription */
        ) AS

	SET NOCOUNT ON
    /*
    ** Declarations.
    */
	declare @mergepublish	int
	declare @iscomputed		int
	declare @xtype			int
    declare @sync_mode		int
	declare @index_cnt		int
    declare @v_unique_constraint			int
	declare @v_unique_index			int
	declare @indid			int
    declare @in_partition 	bit
	declare @colid	int
    DECLARE @cnt int, @idx int  /* Loop counter, index */
    DECLARE @columnid smallint   /* Columnid-1 = bit to set */
    DECLARE @columns binary(128)         /* Temporary storage for the converted column */
    DECLARE @pubid uniqueidentifier                  /* Publication identification number */
    DECLARE @retcode int                /* Return code for stored procedures */
    DECLARE @artid uniqueidentifier
	declare @object_view 	sysname
    declare @filter_clause nvarchar(1000)
    DECLARE @objid int            /* Article base table id */    
	declare @tmp_artid	uniqueidentifier
	declare @tmp_object	sysname
    declare @publisher	sysname
    declare @publisher_db	sysname
	declare @pkkey		sysname
	declare @conflict_table	sysname
	declare @status_value	int
	declare @column_list	nvarchar(4000)
	declare @ins_conflict_proc sysname
	declare @qual_source_object	nvarchar(270)
	declare @qual_object_view	nvarchar(270)
	declare @qual_tmp_object	nvarchar(270)
	declare @v_foreign_key int
	declare @source_object	nvarchar(300)
	declare @quoted_source_object nvarchar(270)
	select @publisher = @@SERVERNAME
	select @publisher_db = db_name()
    /*
    ** Security Check
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

	select @mergepublish = 0x4000
	select @v_unique_index 	 = 2 		-- status in sysindexes
	select @v_foreign_key = 3			-- status in sysconstraints
	select @v_unique_constraint 	 = 4096 --status in sysindexes

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

    IF ( (SELECT category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default) = 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 or @@ERROR<>0
            RETURN (1)

    SELECT @pubid = pubid, @sync_mode = sync_mode FROM sysmergepublications WHERE name = @publication 
    													and LOWER(publisher)=LOWER(@publisher)
												    	and publisher_db = @publisher_db
    																
    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 or @@ERROR<>0
            RETURN (1)

    /*
    ** Make sure the article exists.
    */
    SELECT @artid = artid FROM sysmergearticles
       WHERE pubid = @pubid AND name = @article
    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 16, -1, @article)
            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 collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('add', 'drop')
        BEGIN
            RAISERROR (14019, 16, -1)
            RETURN (1)
        END
        
	/*
	** column name can not be null for 'drop' operation. OK for 'add' operation
	*/
	IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS)='drop' and @column is NULL
		BEGIN
			RAISERROR(14043, 16, -1, '@column')
			RETURN (1)
		END	
	/*
	** Can not drop non-identity, non-timestamp, non-computed columns that are not nullable and have no default value
	*/
    SELECT @status_value=status, @objid = objid, 
    	@source_object = object_name(objid) FROM sysmergearticles WHERE artid = @artid
	select @colid=colid from syscolumns where id=@objid and name=@column
	if not exists (select * from syscolumns where id = @objid and name=@column and (isnullable=1 
					OR type_name(xtype)='timestamp' OR iscomputed=1))
		and not exists (select * from sysconstraints where id=@objid and colid=@colid and status & 5 = 5)
			and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS)='drop' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
			and ColumnProperty(@objid, @column, 'IsIdentity') <> 1
		BEGIN
			RAISERROR(21165, 16, -1, @column)
			return (1)
		END
		
	
	if LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
	begin		
		select @indid = indid from sysindexes where id = @objid and (status & 2048) <> 0    /* PK index */
		select @index_cnt = 1
		while (@index_cnt <= 16)
			begin
				select @pkkey = INDEX_COL(@source_object, @indid, @index_cnt)
				if @pkkey is NULL
					break
				if @pkkey=@column
					begin
						raiserror(21250, 16, -1, @column)
						return (1)
					end
				select @index_cnt = @index_cnt + 1
			end
	
		/*
		** Check for unique index defined on this column - to disallow such a column from being dropped
		*/	
		if exists (select * from sysindexes where id=@objid 
					and (status & @v_unique_index = @v_unique_index 
						or status & @v_unique_constraint = @v_unique_constraint))
		begin
			declare @keys varbinary(816)
			declare @i 		int
			declare #check_unique CURSOR LOCAL FAST_FORWARD for 
			select indid from sysindexes where id=@objid 
				and (status & @v_unique_index = @v_unique_index 
					or status & @v_unique_constraint = @v_unique_constraint)
			open #check_unique
			fetch #check_unique into @indid
			while (@@fetch_status<>-1)
			begin
				SELECT @i = 1
				WHILE (@i <= 16)
				BEGIN
        		        SELECT @pkkey = INDEX_COL(@source_object, @indid, @i)
            		    if @pkkey is NULL
                		    break
						if @pkkey=@column
    		            BEGIN
    		            	if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='true'
								raiserror(21265, 16, -1, @column, @source_object)
							else
								raiserror(21347, 16, -1, @column)							
							close #check_unique
							deallocate #check_unique
							return (1)
						END
	        	        select @i = @i + 1
				END	
				fetch #check_unique into @indid
			end
			close #check_unique
			deallocate #check_unique
		end

		/*
		** Check for foreign key constraints
		*/
		if exists (select * from sysconstraints where status & @v_foreign_key=@v_foreign_key and id=@objid)
		begin
			if @column in (select name from syscolumns where id=@objid and colid in
				(select colid from sysconstraints where status & @v_foreign_key=@v_foreign_key and id=@objid))
			begin
				raiserror(21513, 16, -1, @column)
				return (1)
			end
		end		
	end

    begin tran
    save TRANSACTION articlecolumn

    /*
    ** Make sure that the column <columns> is not NULL - if NULL set to 0x00.
    */
    SELECT @columns = columns FROM sysmergearticles WHERE artid = @artid and pubid=@pubid
    IF @columns IS NULL
        UPDATE sysmergearticles SET columns = 0x00 WHERE artid = @artid and pubid=@pubid
	
    /*
    ** 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
    	SELECT @cnt = max(colid), @idx = 1 FROM syscolumns WHERE id = @objid 
    	SELECT @columns = NULL
		WHILE @idx <= @cnt
		BEGIN
			/* to make sure column holes will not be included */
			if exists (select * from syscolumns where colid=@idx and id=@objid and 
				(@sync_mode=0 OR (iscomputed<>1 and type_name(xtype) <>'timestamp')))
				begin
					exec sp_MSsetbit @bm=@columns OUTPUT, @coltoadd=@idx, @toset = 1
					if @@ERROR<>0 or @retcode<>0
						goto FAILURE
					update syscolumns set colstat=colstat | @mergepublish where id=@objid and colid=@idx
					if @@ERROR<>0
						goto FAILURE

				end
			SELECT @idx = @idx + 1
		END
		UPDATE sysmergearticles SET columns = @columns WHERE name = @article AND pubid = @pubid
		if @sync_mode=1 and exists (select * from syscolumns where id=@objid and (iscomputed=1 or type_name(xtype)='timestamp'))
			UPDATE sysmergearticles SET vertical_partition = 1 WHERE name = @article AND pubid = @pubid
	END
    ELSE
	BEGIN
		/* if @column is NULL, meanning all columns are in, do not bump up version to Shiloh. */
		if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
			raiserror(21351, 10, -1, @publication)
		else
			raiserror(21352, 10, -1, @publication)
		exec @retcode = sp_MSBumpupCompLevel @pubid, 40
		if @@ERROR<>0 or @retcode<>0
			GOTO FAILURE

		SELECT @columnid = colid, @iscomputed=iscomputed, @xtype=xtype  
			FROM syscolumns WHERE id = @objid AND name = @column
		IF ((@@error <> 0) OR (@columnid IS NULL))
		BEGIN
			RAISERROR (21166, 16, -1, @column)
			GOTO FAILURE
		END

		/*
		** for character mode publications, we do not allow adding computed column or timestamp columns
		** into the vertical parititioning. 
		*/
		if @sync_mode=1 and (@iscomputed = 1 or type_name(@xtype) ='timestamp') and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add'
		begin
			if LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
				begin
					raiserror(21269, 16, -1)
					GOTO FAILURE
				end
			else
			begin	
		    	if @@TRANCOUNT >0 
    			begin
        			ROLLBACK TRANSACTION articlecolumn
        			COMMIT TRAN
        		end
        		return (0)
        	end
		end
		
		if ColumnProperty(@objid, @column, 'isrowguidcol') = 1 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
		begin
			RAISERROR(21162, 16, -1)
			GOTO FAILURE
		end

		exec @in_partition = sp_MStestbit @bm=@columns, @coltotest=@columnid

		if @in_partition=1 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
		begin
			RAISERROR(21335, 10, -1, @column)
			GOTO FAILURE
		end
		
		if @in_partition=0 and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop' and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
		begin
			RAISERROR(21336, 10, -1, @column)
			GOTO FAILURE
		end

		SELECT @columns = columns, @filter_clause=subset_filterclause, @ins_conflict_proc=ins_conflict_proc, @conflict_table=conflict_table FROM sysmergearticles WHERE name = @article AND pubid = @pubid
		IF LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'add'
			begin
				exec @retcode = sp_MSsetbit @bm = @columns OUTPUT, @coltoadd=@columnid, @toset=1
				if @@ERROR<>0 or @retcode<>0 
					GOTO FAILURE
				update syscolumns set colstat=colstat | @mergepublish where id=@objid and colid=@colid
				if @@ERROR<>0
					goto FAILURE
			end
		ELSE
			begin
				
				exec @retcode = sp_MSsetbit @bm = @columns OUTPUT, @coltoadd=@columnid, @toset=0
				if @@ERROR<>0 or @retcode<>0 
					GOTO FAILURE
				if @columns = 0x00
					begin
						raiserror(21345, 16, -1)
						goto FAILURE
					end
				exec @retcode = sp_MSclearcolumnbit @pubid, @artid, @column
				if @@ERROR<>0 or @retcode<>0
					goto FAILURE
			end

		/*
		** Set vertical_partitioning flag so that publication view would be re-generated even
		** if there is not subsetfilters nor join filters
		*/
		UPDATE sysmergearticles  SET columns = @columns, vertical_partition=1 
			WHERE name = @article AND pubid = @pubid
		IF @@ERROR <> 0
		BEGIN
			RAISERROR (14021, 16, -1)
			GOTO FAILURE
		END

		select @column_list = NULL
		
		/*
		** check to see if that column can be dropped based on current article's filter clause
		** and if the article is involved in any join_filter_clauses - to make sure the drop of
		** one column does not cripple any such joins
		*/ 
		if ((@filter_clause is not NULL and @filter_clause <>'' ) or 
			exists (select * from sysmergesubsetfilters where pubid=@pubid and 
			(artid=@artid or join_articlename=@article))) and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
		begin
			exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @objid
			if @@ERROR<>0 or @retcode<>0
				GOTO FAILURE
			select @object_view='TEMP_VIEW_' + @source_object  --@source_object is not quoted
            select @qual_object_view=quotename(@object_view)

            exec @retcode = sp_MSget_qualified_name @objid, @qual_source_object OUTPUT
            if @@ERROR<>0 or @retcode<>0
            	goto FAILURE
            select @quoted_source_object=QUOTENAME(@source_object)
            
			exec ('create view ' + @qual_object_view + ' as select ' + @column_list + ' from ' + @qual_source_object)
			if @@ERROR<>0
				GOTO FAILURE
			if @filter_clause is not NULL and @filter_clause <>'' 
			begin
				exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_source_object + ' where ' + @filter_clause)
				if @@ERROR<>0
					begin
						exec('drop view ' + @qual_object_view)
						raiserror(21256, 16, -1, @filter_clause, @source_object)
						GOTO FAILURE
					end
			end			
		end
		
		/*
		** Check to make sure dropping a column will not breaking any other articles that using current article as join_article
		*/
		if exists (select * from sysmergesubsetfilters where pubid=@pubid and 
			(artid=@artid or join_articlename=@article)) and LOWER(@operation collate SQL_Latin1_General_CP1_CS_AS) = 'drop'
		begin
			declare @join_articlename sysname
			declare per_article CURSOR LOCAL FAST_FORWARD FOR 
				select artid, join_filterclause, join_articlename from sysmergesubsetfilters 
					where pubid=@pubid and (join_articlename=@article or artid=@artid)
			for READ ONLY
			open per_article
			fetch per_article into @tmp_artid, @filter_clause, @join_articlename
			while (@@fetch_status<>-1)
			begin
				if @artid<>@tmp_artid
					select @tmp_object=object_name(objid) from sysmergearticles where pubid=@pubid and artid=@tmp_artid
				else
					select @tmp_object=object_name(objid) from sysmergearticles where pubid=@pubid and name=@join_articlename
				select @qual_tmp_object=QUOTENAME(@tmp_object)
				if @tmp_object is not NULl and @tmp_object<>''
					begin
						exec ('declare @test int select @test=1 from ' + @qual_object_view + ' ' + @quoted_source_object + ', ' + @qual_tmp_object + ' where ' + @filter_clause)					
						if @@ERROR<>0
						begin
							close per_article
							deallocate per_article
							raiserror(21256, 16, -1, @filter_clause, @source_object)
							GOTO FAILURE
						end
					end
				fetch per_article into @tmp_artid, @filter_clause, @join_articlename	
			end
			close per_article
			deallocate per_article		
		end			
	END   

	/*
    ** if snapshot is ready, change it to obsolete to force another snapshot run.	
    ** Note this is the third value of snapshot_ready. 0 for not ready, 1 for OK, 2 for obsolete
    */   
    IF EXISTS (SELECT * FROM sysmergepublications WHERE pubid=@pubid and snapshot_ready>0) 
    		and LOWER(@schema_replication collate SQL_Latin1_General_CP1_CS_AS)='false'
        BEGIN
	        update sysmergearticles set status=1, conflict_table=NULL where pubid=@pubid and artid=@artid and status<>5 and status <>6
	        if @@ERROR<>0
	        	goto FAILURE
		/*
		** Force a re-generation of conflict table and its ins_proc
		*/
	        if object_id(@ins_conflict_proc) is not NULL
	        	begin
	        		exec ('drop proc ' + @ins_conflict_proc)
	        		if @@ERROR<>0
	        			goto FAILURE
	        	end
	        if object_id(@conflict_table) is not NULL
	        	begin
	        		exec ('drop table ' + @conflict_table)
	        		if @@ERROR<>0
	        			goto FAILURE
	        	end
	        /*
			** make sure we know we really want to do this.
			*/
			if @force_invalidate_snapshot = 0
				begin
					raiserror(20607, 16, -1)
					goto FAILURE
				end
			update sysmergepublications set snapshot_ready=2 where pubid=@pubid
			if @@ERROR<>0
				goto FAILURE

			if @force_reinit_subscription = 0 and @status_value<>5 --5 is the value for new_inactive
				begin
					raiserror(20608, 16, -1)
					goto FAILURE
				end

			--do a global re
			
			if @force_reinit_subscription = 1
				begin
					--global reinitialization will bump up backward-comp-level to SP2.
				exec @retcode = sp_MSreinitmergepublication @publication
				if @retcode<>0 or @@ERROR<>0
					goto FAILURE
				end
			/*
			** Even for vertical partitioning on new article - we do not need to bumpup backward-comp-level
			**
			else
				begin	--bump up the backward-comp-level so that only 80 subscribers can use it.
				exec @retcode = sp_MSBumpupCompLevel @pubid, 40
				if @@ERROR<>0 or @retcode<>0
					GOTO FAILURE
				end
			*/
        END

    COMMIT TRANSACTION
    if exists (select * from sysobjects where id = object_id(@qual_object_view))
        begin
            exec ('drop view ' + @qual_object_view)
        end
    return (0)
FAILURE:

    if @@TRANCOUNT >0 
    	begin
        	ROLLBACK TRANSACTION articlecolumn
        	COMMIT TRAN
        end

    if exists (select * from sysobjects where id = object_id(@qual_object_view))
        begin
            exec ('drop view ' + @qual_object_view)
        end

    return (1)
go
 
EXEC dbo.sp_MS_marksystemobject sp_mergearticlecolumn
GO


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

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

create procedure sp_MSreinitmergepublication
    @publication    sysname,
    @upload_first	bit = 0
AS
    declare @pubid				uniqueidentifier
	declare @schematext 		nvarchar(4000)
	declare @schemaversion 		int
	declare @schemaguid			uniqueidentifier
	declare @schematype			int
	declare @publisher			sysname
	declare @retcode			int
	declare @publisher_db		sysname

	set nocount on
	/* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */
	exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)
        
	select @publisher=@@servername
	select @publisher_db = db_name()
	
    select @pubid=pubid from sysmergepublications 
    	where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()

	raiserror(21353,10, -1,@publication)
	exec @retcode=sp_MSBumpupCompLevel @pubid, 30 --for 7.0 SP2, which has limited support for this
	if @@ERROR<>0 or @retcode<>0		
		return (1)
	select @schematext = 'exec sp_MSreinit_hub '+ QUOTENAME(@publisher) + ', ' + QUOTENAME(@publisher_db) + ', ' + QUOTENAME(@publication) + ', ' + convert(nvarchar, @upload_first)
	select @schemaversion = schemaversion from sysmergeschemachange
	if (@schemaversion is NULL)
		set @schemaversion = 1
	else
		select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
	set @schemaguid = newid()
	if @upload_first = 0
		set @schematype = 12 /* reinit_all */
	else
		set @schematype = 14 /* reinit_with_upload*/
	exec @retcode=sp_MSinsertschemachange @pubid, @schemaguid, @schemaversion, @schemaguid, @schematype, @schematext
	if @@ERROR<>0 or @retcode<>0 
		return (1)
		
	update MSmerge_replinfo set schemaversion=0, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
		where repid in (select subid from sysmergesubscriptions where subid<>pubid and pubid=@pubid and subscription_type=0)
	if @@ERROR<>0 
		return (1)

	-- set all article status to inactive as a starting point - which sort or cleanup the newly added status
	-- 5 and 6.

	if @upload_first=0 --do not reset status is upload_first is true. Otherwise, 
					   --creating triggers would fail.	
	begin
		update sysmergearticles set status=1 where pubid=@pubid 
		if @@ERROR<>0
			return (1)
	end
	update MSmerge_replinfo set schemaversion=-1, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
		where repid in (select subid from sysmergesubscriptions where subid<>pubid and pubid=@pubid and subscription_type>0)
		
	if @@ERROR<>0 
		return (1)

GO

exec dbo.sp_MS_marksystemobject sp_MSreinitmergepublication
go  

grant execute on dbo.sp_MSreinitmergepublication to public
go


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

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

create procedure sp_reinitmergesubscription
    @publication    sysname  = 'all',
    @subscriber     sysname  = 'all',
    @subscriber_db  sysname  = 'all',
    @upload_first	nvarchar(5) = 'FALSE'
AS
    declare @pubid                  uniqueidentifier
    declare @subid                  uniqueidentifier
    declare @subscription_type		int
    declare @reinit_bit				int
    declare @publisher				sysname
    declare @publisher_db			sysname
    declare @distribdb				sysname
	declare @distributor			sysname
	declare @distproc				nvarchar(300)
	declare @retcode				int
	declare @uploadbit				bit
	declare	@pubname				sysname
	declare @subsrvid				int
	declare @subdb					sysname 
	declare @subname				sysname
    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */
	exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

	set nocount on
    /*
    ** Replace 'all' with '%'
    */

	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    if LOWER(@publication) = 'all'
        SELECT @publication = '%'

    if LOWER(@subscriber) = 'all'
        SELECT @subscriber = '%'

    if LOWER(@subscriber_db) = 'all'
        SELECT @subscriber_db = '%'

	select @publisher = @@SERVERNAME
	select @publisher_db=db_name()
	
    /*
    ** At publisher side, publication name is unique
    */
    IF NOT EXISTS (SELECT * FROM sysmergepublications 
        WHERE name LIKE @publication)
        BEGIN
        IF @publication = '%'
                RAISERROR (14008, 11, -1)
        ELSE
                RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
        END

	/* if snapshot has not been ran yet, there is no point doing reinitialization */
	if not exists (select * from sysmergepublications where name like @publication and snapshot_ready>0)
		return (0)
        
	if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    	select @uploadbit  = 1
    else
    	select @uploadbit  = 0

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

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

	if @subscriber = '%' and @subscriber_db = '%'
	begin
		exec @retcode = @distproc @publication, @publisher, @publisher_db 
		if @@ERROR<>0 or @retcode<>0
				return (1)
				
		declare reinit_all CURSOR LOCAL FAST_FORWARD FOR 
			select name from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and 
				publisher_db=db_name() and snapshot_ready>0 and name like @publication
		For READ only
		open reinit_all
		fetch reinit_all into @pubname
		while (@@fetch_status<>-1)
		begin
			exec @retcode = sp_MSreinitmergepublication @pubname, @uploadbit
			if @@ERROR<>0 or @retcode<>0
			begin
				close reinit_all
				deallocate reinit_all
				return (1)
			end
			
			fetch next from reinit_all into @pubname
		end
		close reinit_all
		deallocate reinit_all
	end

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

	BEGIN TRAN
	SAVE TRAN reinitsubscription
	
    Declare SYN_CUR CURSOR LOCAL FAST_FORWARD FOR 
        select subs.subid, subs.subscription_type, pubs.publisher, pubs.publisher_db, pubs.name, 
        		subs.srvid, subs.db_name
            from sysmergepublications pubs, sysmergesubscriptions subs
                where pubs.name LIKE  @publication 
                     and UPPER(pubs.publisher)=UPPER(@@servername) 
                     and pubs.publisher_db=db_name()
                    AND pubs.pubid=subs.pubid
                    AND subs.pubid<>subs.subid
                    AND subs.status <>0 --for unsynced subscription, there is no need to reinit.
                    AND ((@subscriber_db = N'%') or (db_name = @subscriber_db))
                    AND srvid in (select srvid from master..sysservers where ((@subscriber = N'%') or (UPPER(srvname) = UPPER(@subscriber) collate database_default)))
    FOR READ ONLY
    open SYN_CUR
    fetch SYN_CUR into @subid, @subscription_type, @publisher, @publisher_db, @pubname, @subsrvid, @subdb
    while (@@fetch_status<>-1)
    BEGIN  
	-- Security check 
        if not exists (select * from sysmergesubscriptions subs1 where
		(suser_sname(suser_sid()) = subs1.login_name OR 
		is_member('db_owner')=1 OR 
		is_srvrolemember('sysadmin') = 1) and
		subid = @subid)
		continue		

		select @subname = srvname from master..sysservers where srvid = @subsrvid
	
			if @subscription_type = 0 
				 update MSmerge_replinfo set schemaversion=0, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
					  where repid=@subid and schemaversion is NOT NULL
			else
       			 update MSmerge_replinfo set schemaversion= -1, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
        	 		  where repid=@subid and schemaversion is NOT NULL
		
		if @@rowcount <> 0 and @uploadbit = 1
		begin
			update sysmergesubscriptions set status = 5 where subid=@subid
			if @@ERROR<>0
				goto Failure
		end

		-- If subscriber was preventing us from cleaning up metadata, set the status
		update sysmergesubscriptions set status = 8 where subid = @subid and status = 7
		if @@rowcount <> 0
			exec sp_MSquiescecheck
			
	    -- 0 for push and -1 for pull
		exec @distproc @publisher, @publisher_db, @pubname, @subname, @subdb, 1
	    if @@ERROR<>0
		BEGIN
			goto Failure
		END        	
		fetch next from SYN_CUR into @subid, @subscription_type, @publisher, 
        	@publisher_db, @pubname, @subsrvid, @subdb        
    END
    close SYN_CUR
    deallocate SYN_CUR
    commit TRAN
    return (0)
Failure:
    close SYN_CUR
    deallocate SYN_CUR
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION reinitsubscription
        COMMIT TRANSACTION
    end
    return (1)

GO

exec dbo.sp_MS_marksystemobject sp_reinitmergesubscription
go  

grant execute on dbo.sp_reinitmergesubscription to public
go


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

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

CREATE PROCEDURE sp_addmergesubscription (
    @publication                    sysname,                    /* Publication name */
    @subscriber                     sysname = NULL,             /* Subscriber server */
    @subscriber_db                  sysname = NULL,             /* Subscription database */
    @subscription_type              nvarchar(15) = 'push',          /* Subscription type - push, pull */ 
    @subscriber_type                nvarchar(15) = 'local',         /* Subscriber type */ 
    @subscription_priority          real        = NULL,             /* Subscription priority */
    @sync_type                      nvarchar(15) = 'automatic',     /* subscription sync type */
    @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,
    @description                    nvarchar(255) = NULL,
    @enabled_for_syncmgr            nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
    -- Agent offload
    @offloadagent                   bit = 0,
    @offloadserver                  sysname = NULL,
	@use_interactive_resolver		nvarchar(5) = 'false',
	@merge_job_name					sysname = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @retcode                int
    declare @subnickname            int
    declare @subscriber_srvid       int 
    declare @publisher_srvid        int 
    declare @priority               real
    declare @subid                  uniqueidentifier
    declare @pubid                  uniqueidentifier    /* Publication id */
    declare @subscriber_typeid      smallint
    declare @merge_jobid            binary(16)          /* Scheduler jobid for the merge agent */
    declare @subscription_type_id   int   
    declare @distproc               nvarchar(300)
    declare @command                nvarchar(255)
    declare @inactive               tinyint
    declare @subscriber_bit         smallint
    declare @global                 tinyint     /* subscriber type is global */
    declare @push                   tinyint     /* subscription type is push */
    declare @partnerid              uniqueidentifier    /* Partner replica identifier */
    declare @sync_typeid            tinyint
    declare @nosync                 tinyint     
    declare @automatic              tinyint     
    declare @distributor            sysname
    declare @distribdb              sysname
    declare @publisher              sysname
    declare @publisher_db           sysname
    declare @found                  int
    declare @datasource_type        int
    declare @datasource_path        sysname
    DECLARE @platform_nt            binary
    declare @datasrctype	        int
    declare @datasrcpath		    sysname
	declare @use_interactive_bit	bit

    
	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    /*
    ** Initializations.
    */
    set @datasource_type = 0    /* Default SQL Server */
    set @datasource_path = NULL 
	set @datasrctype = 0    /* Default SQL Server */
    set @datasrcpath = NULL 
    set @platform_nt = 0x1  
    SET @nosync             = 2       /* Const: synchronization type 'none' */
    SET @automatic          = 1       /* Const: synchronization type 'automatic' */
    set @inactive           = 0
    SET @subscriber_bit     = 4  
    set @global             = 1
    set @push               = 0
    set @pubid              = NULL         
    set @publisher          = @@SERVERNAME
    set @publisher_db       = DB_NAME()
    select @found           = 1    /* Any non-NULL value is fine */
    /*
    ** Parameter Check: @subscription_type.
    ** Set subscriber_typeid based on the @subscription_type specified.
    **
    **   subscription_type    subscription_type
    **   =================    ===============
    **             0            push
    **             1            pull
    */
    if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull')
        BEGIN
            RAISERROR (14128, 16, -1)
            RETURN (1)
        END
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        set @subscription_type_id = 0
    else 
        set @subscription_type_id = 1


    /*
    ** Parameter check: @offloadagent
    ** If @offloadagent = 1 then @subscription_type_id must be 0 
    */
    IF (@offloadagent = 1) AND (@subscription_type <> N'push') 
    BEGIN
        RAISERROR(21138, 16, -1)
        RETURN (1)
    END 

    /*
    ** 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
        begin
            return(1)
        end
    END

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

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

     IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
                     AND (srvstatus & @subscriber_bit) <> 0)
               BEGIN
                   RAISERROR (14010, 16, -1)
                   RETURN (1)
               END

    IF @subscriber = 'all'
        BEGIN
            RAISERROR (14136, 16, -1)
            RETURN (1)
        END

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

        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + 
            '.dbo.sp_MShelp_subscriber_info '
    exec @distproc @publisher, @subscriber, @found output
    if (@found <> 1) 
        BEGIN
            RAISERROR (14085, 16, -1)
            RETURN (1)
        END

	exec @retcode = dbo.sp_MSget_subtypedatasrc @subscriber, @distributor, @distribdb, @datasrctype OUTPUT, @datasrcpath OUTPUT
	if @retcode<>0
		return (1)
	if (@datasrctype = 2) or (@datasrctype = 4) or (@datasrctype = 5)
	BEGIN
		select @datasource_type = @datasrctype
		select @datasource_path = @datasrcpath
	END
	
    EXECUTE @retcode = dbo.sp_validname @subscriber
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)

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

    IF @subscriber_db = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    /*
    **  Check to see if system tables exist. If not create them. Since under current
    **  design every database is qualified for subscribing.
    */
    
    IF not exists (select name from sysobjects where name='sysmergesubscriptions')
        BEGIN
            execute @retcode = dbo.sp_MScreate_mergesystables
                if @@ERROR <> 0 or @retcode <> 0
                    begin
                        return (1)
                    end
        END 
        
    /*
    ** Parameter Check: @publication.
    ** Check to make sure that the publication exists and that it conforms
    ** to the rules for identifiers.
    */
    if NOT EXISTS (select * FROM sysmergepublications 
        WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END

    if @pubid IS NULL
        select @pubid = pubid FROM sysmergepublications 
            WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    if @partnerid IS NULL
        begin
            select @partnerid = subid FROM sysmergesubscriptions 
                WHERE srvid = @publisher_srvid and db_name = @publisher_db and pubid = @pubid
        end                     

    /*
    ** Parameter Check: @subscriber_type.
    ** Set subscriber_typeid based on the @subscriber_type specified.
    **
    **   subscriber_type     subscriber_type
    **   =================    ===============
    **             1            global
    **             2            local
    **             3            anonymous
    **                          Type 'republisher' is taken out for B3. We may want to add this back later.
    */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('local', 'global')
        BEGIN
            RAISERROR (20037, 16, -1)
            RETURN (1)
        END

    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('global')
        set @subscriber_typeid = 1
    else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local')
        set @subscriber_typeid = 2

   	/*
    ** Parameter Check: @use_interactive_resolver  
    */
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@use_interactive_resolver')
            RETURN (1)
        END
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        set @use_interactive_bit = 1
    else 
        set @use_interactive_bit = 0

	
    /* 
    ** Assign priority appropriately - choose 0.99 times the minimum priority
    ** of the global replicas.
    */
    if (@subscription_priority >= 100.0 or @subscription_priority < 0.0)
        BEGIN
            RAISERROR (20088, 16, -1)
            RETURN (1)
        END
    if (@subscription_priority IS NULL)
        begin
            select @priority = 0.99 * min(priority) from sysmergesubscriptions where subscriber_type = 1
            if (@priority IS NOT NULL)
                select @subscription_priority = @priority
            if (@subscription_priority IS NULL) 
                select @subscription_priority = 0.0
        end
    /*
    ** For local and anonymous subscriptions the priority is 0.0
    */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local', 'anonymous')
        select @subscription_priority = 0.0
    
    /*
    ** Validate that the subscriber is a valid server
    */
    select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
    IF @subscriber_srvid IS NULL
        BEGIN
            RAISERROR (14010, 16, -1)
            RETURN (1)
        END

    IF exists (select * from sysobjects where name= 'syssubscriptions')
    begin
        if exists (select name from sysmergeextendedarticlesview where pubid=@pubid and objid in
            (select objid from sysextendedarticlesview where artid in
                (select artid from syssubscriptions where dest_db=@subscriber_db and srvid=@subscriber_srvid)))
        begin
            RAISERROR(21280, 16, -1, @publication, @subscriber_db)
            RETURN (1)
        end
    end


    /* 
    ** Make sure that @offloadserver doesn't contain invalid characters
    */
    exec @retcode = sp_MSreplcheckoffloadserver @offloadserver
    if @retcode<>0 or @@error<>0
        return (1)

    /*
    ** Making it possible for a deleted subscription to come back.
    ** UNDONE : This disallows second pull subscription from being added unless the previous 
    ** subscription was initial synced.
    */
    if EXISTS (select db_name, srvid
            FROM sysmergesubscriptions
            WHERE db_name = @subscriber_db
            AND srvid = @subscriber_srvid                          
            AND pubid = @pubid AND status <>2) --We can definitely add back subscriptions that were deleted.
        BEGIN
            RAISERROR (14058, 16, -1)
            RETURN (1)
        END
        
    IF EXISTS (select db_name, srvid FROM sysmergesubscriptions 
        WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid AND status = 2) 
            BEGIN
            	select @subid = subid from sysmergesubscriptions 
            		WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid
				delete  from sysmergesubscriptions where subid = @subid
				delete from MSmerge_replinfo where repid = @subid
            END
	select @subid = newid()    
	
   /*
   ** Parameter Check: @sync_type.
   ** Set sync_typeid based on the @sync_type specified.
   **
   **   sync_typeid     sync_type
   **   ===========     =========
   **             1     automatic
   **             2     none
   */


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


    /*
    ** If current publication contains an article without rowguidcol, do not allow no-sync subscription
    */
   IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
   BEGIN
        SET @sync_typeid = @automatic
   END
   ELSE
   BEGIN
        if exists (select * from sysmergearticles a where pubid=@pubid and 
            not exists (select * from syscolumns c where c.id = a.objid and ColumnProperty(c.id, c.name, 'IsRowGuidCol') = 1))
            
            BEGIN
                Raiserror(20086, 16, -1, @publication)
                RETURN (1)
            END
        else 
            SET @sync_typeid = @nosync
   END


    /*
    ** UNDONE: Validate that the publisher is of type "republisher"
    */
    begin tran
    save TRAN addmergesubscription
        /* Generate a guid for the Subscriber ID */
    
        /* Look for existing nickname from any other subscription */
        exec @retcode = dbo.sp_MSgetreplnick @subscriber, @subscriber_db , NULL,  @subnickname out
        if (@@error <> 0) or @retcode <> 0 
			GOTO FAILURE
            
        /* Generate a new replica nickname from the @subid */
        if (@subnickname is null)
        begin
            EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output
            if @@ERROR<>0 
                GOTO FAILURE
        end
            
        /*
        ** The subscription doesn't exist, so let's add it to sysmergesubscriptions 
        */
        INSERT sysmergesubscriptions (subid, 
                                      partnerid,
                                      datasource_type, 
                                      datasource_path, 
                                      srvid, 
                                      db_name, 
                                      pubid,
                                      status, 
                                      subscriber_type,
                                      subscription_type,
                                      priority, 
                                      sync_type, 
                                      description,
                                      login_name,
                                      subscriber_server,
                                      use_interactive_resolver,
                                      publication,
                                      distributor)
                        VALUES (@subid,
                            @partnerid,
                            @datasource_type,
                            @datasource_path,
                            @subscriber_srvid,
                            @subscriber_db,
                            @pubid,
                            @inactive,
                            @subscriber_typeid,
                            @subscription_type_id,
                            @subscription_priority,
                            @sync_typeid,
                            @description,
                            suser_sname(suser_sid()),
                            @subscriber,
                            @use_interactive_bit,
                            @publication,
                            @distributor)          
        if @@ERROR <> 0
            BEGIN
                GOTO FAILURE
            END
                
        /*
        ** 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 FAILURE
            END

        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + 
            '.dbo.sp_MSadd_merge_subscription'
        EXEC @retcode = @distproc 
            @publisher = @@SERVERNAME, 
            @publisher_db = @publisher_db, 
            @publication = @publication,
            @subscriber = @subscriber, 
            @subscriber_db = @subscriber_db, 
            @subscription_type = @subscription_type_id,
            @sync_type = @sync_typeid, 
            @status = @inactive,
            @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,
            @merge_jobid = @merge_jobid OUTPUT,
            @offloadagent = @offloadagent,
            @offloadserver = @offloadserver,
			@agent_name = @merge_job_name  
            
        IF @@ERROR <> 0 OR @retcode <> 0
            begin   
                goto FAILURE
            end
            
        /*
        **  Add row for subscription in MSmerge_replinfo.
        */
        insert MSmerge_replinfo(repid, replnickname, merge_jobid)
                values (@subid, @subnickname, @merge_jobid)
        if @@ERROR <> 0
        	BEGIN
                GOTO FAILURE
            END

        /* Conditional support for MobileSync */
        if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        BEGIN

            /* MobileSync Support */
            declare @distributor_server                 sysname
            declare @distributor_security_mode          int
            declare @distributor_login                  sysname
            declare @distributor_password               nvarchar(524)

            /* 
            ** 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 @subscription_type_id = 0 
            BEGIN
                EXECUTE @retcode = dbo.sp_helpdistributor
                    @distributor = @distributor_server OUTPUT               /* Distributor RPC server name */
                IF @@ERROR <> 0 or @retcode <> 0
                    BEGIN
                        GOTO FAILURE
                    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 = password
                        from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername) collate database_default
                    end

                /* Call sp_MSregistersubscription so that the subscription can be synchronized via Onestop etc. */
                exec @retcode = dbo.sp_MSregistersubscription @replication_type = 2,
                                    @publisher = @@SERVERNAME,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @subscriber = @subscriber,
                                    @subscriber_db = @subscriber_db,
                                    @distributor = @distributor,
                                    @distributor_security_mode = @distributor_security_mode,
                                    @distributor_login = @distributor_login,
                                    @distributor_password = @distributor_password,
                                    @subscription_id = @subid,
                                    @subscription_type = @subscription_type_id,
									@use_interactive_resolver = @use_interactive_bit
                IF @@error <> 0 OR @retcode <> 0
                    BEGIN
                        GOTO FAILURE
                    END

            END                                    
        END     
    COMMIT TRAN
    return (0)

FAILURE:
    RAISERROR (14057, 16, -1)
    /* UNDONE : This code is specific to 6.X nested transaction semantics */
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION addmergesubscription
        COMMIT TRANSACTION
    end
    RETURN (1)

go
exec dbo.sp_MS_marksystemobject sp_addmergesubscription 
go

grant execute on dbo.sp_addmergesubscription to public
go

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

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

CREATE PROCEDURE sp_changemergesubscription (
    @publication        sysname = NULL, /* Publication name */
    @subscriber         sysname = NULL,  /* Subscriber server */
    @subscriber_db      sysname = NULL,  /* Subscription database */
    @property           sysname = NULL, /* The property to change */
    @value              nvarchar(255) = NULL,    /* The new property value */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @subscriber_bit         smallint
    declare @subscriber_srvid       int
    declare @publisher_srvid        int
    declare @retcode                int
    declare @pubid                  uniqueidentifier
    declare @subid                  uniqueidentifier
    declare @partnerid              uniqueidentifier
    declare @sync_typeid            tinyint
    declare @nosync                 tinyint
    declare @automatic              tinyint
     
    declare @artid                  uniqueidentifier
    declare @schematype             int
    declare @schemaversion          int
    declare @schemaguid             uniqueidentifier
    declare @db_name                sysname
    declare @subscriber_type        int
    declare @schematext             nvarchar(2000)
    declare @publisher              sysname
    declare @publisher_db           sysname
	declare @use_interactive_bit	bit 
	declare @enabled_for_syncmgr	int
	declare @regkey					nvarchar(1000)
	declare @snapshot_ready			int
     

    /*
    ** Initializations.
    */
    SET @nosync         = 2     /* Const: synchronization type 'none' */
    SET @automatic      = 1     /* Const: synchronization type 'automatic' */
    set @publisher      = @@SERVERNAME
    set @publisher_db   = DB_NAME()

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


    /*
    **  Check to see if current database is doing publishing/subscribing
    */
    IF not exists (select name from sysobjects where name='sysmergesubscriptions')
        BEGIN
            RAISERROR (14055, 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 collate database_default)
            INSERT INTO #tab1 VALUES ('sync_type')
            INSERT INTO #tab1 VALUES ('priority')
            INSERT INTO #tab1 VALUES ('description') 
			INSERT INTO #tab1 VALUES ('use_interactive_resolver') 
            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

    select @pubid = pubid, @snapshot_ready=snapshot_ready FROM sysmergepublications 
        WHERE name = @publication  and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

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

    /*
    ** Parameter Check:  @subscriber.
    ** Check to make sure we have a valid subscriber.
    */
    IF @subscriber IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@subscriber')
            RETURN (1)
        END
    /*
    ** Validate that the subscriber is a valid server
    */
    select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
    IF @subscriber_srvid IS NULL
        BEGIN
            RAISERROR (14010, 16, -1)
            RETURN (1)
        END

    /*
    ** Check to see if you have a local / global subscription on this publication
    */
    set @subid = NULL
    select @subid = subs1.subid, 
     
    @pubid = pubs.pubid, /* identified from publication name */
    @subscriber_type=subs1.subscriber_type,
     
        @partnerid = subs2.subid from
        sysmergesubscriptions   subs1,
        sysmergesubscriptions   subs2,
        sysmergepublications    pubs
        where subs1.srvid = @subscriber_srvid
            and subs1.db_name = @subscriber_db
            and subs2.srvid = @publisher_srvid
            and subs2.db_name = @publisher_db
            and subs1.pubid = subs2.subid
            and subs2.pubid = pubs.pubid
            and pubs.name = @publication 
            and UPPER(pubs.publisher)=UPPER(@@servername) 
            and pubs.publisher_db=db_name()

    if @subid IS NULL 
        begin
            RAISERROR (14050, 11, -1)
            RETURN(1)
        end                 

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

    
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('sync_type', 'priority', 'description', 'use_interactive_resolver')
        BEGIN
            RAISERROR (20078, 16, -1)
            RETURN (1)
        END


	BEGIN TRANSACTION change_subscription
	save TRAN change_subscription
	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_interactive_resolver'
        BEGIN

            /* Check to make sure that we have a true/false. */

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
                BEGIN
		            RAISERROR (14148, 16, -1, 'use_interactive_resolver')
                    goto UNDO	
                END

            /* Determine the bit value. */

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		        SET @use_interactive_bit = 1
	        ELSE
		        SET @use_interactive_bit = 0
	
			/* Update the subscription with the new 'use_interactive' value. */

            UPDATE sysmergesubscriptions
               	SET use_interactive_resolver = @use_interactive_bit
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    goto UNDO
                END

			/* If the subscription is enable for Sync Manager, then update the reg value */
			exec sp_MSsubscription_enabled_for_syncmgr
				@publisher, @publisher_db, @publication, @subscriber, @subscriber_db, 
				@enabled_for_syncmgr OUT, @regkey OUT
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    goto UNDO
                END
			if @enabled_for_syncmgr = 1
				begin
					EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
			                               @regkey,
			                               'UseInteractiveResolver',
			                               'REG_DWORD',
			                                @use_interactive_bit
					if @retcode <> 0 OR @@ERROR <> 0
		                BEGIN
		                    RAISERROR (14053, 16, -1)
		                    goto UNDO
		                END
				end
        END

    /*
    ** Change the property.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_type'
        BEGIN 
            /*
            ** Check to make sure that we have a valid sync_type.
            */
            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'none')
                BEGIN
                    RAISERROR (14052, 16, -1)
                    goto UNDO
                END

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
                SET @sync_typeid = @automatic
            ELSE
            BEGIN

		    /*
    		**  If current publication contains an article without rowguidcol, do not allow no-sync subscription
	    	*/	
			if exists (select * from sysmergearticles a where pubid = @pubid and 
                    not exists (select * from syscolumns c where c.id=a.objid and columnproperty (c.id, c.name, 'isrowguidcol')=1))
                begin
                    Raiserror(20086, 16, -1, @publication)
                    goto UNDO
                end
                else 
                	SET @sync_typeid = @nosync
            END

            /*
            ** Update the subscription with the new sync_type.
            */

            UPDATE sysmergesubscriptions
                SET sync_type = @sync_typeid
                WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    goto UNDO
                END

			if @snapshot_ready>0
			begin
				--if there is one article in this publication with pre_command of other than 'drop',
				--do not allow changing subscription property.
				if exists (select * from sysmergearticles where pubid=@pubid and pre_creation_command<>1)
					begin
	                    RAISERROR (21420, 16, -1, @property)
    	                goto UNDO				
					end
				/*
				** make sure we know we really want to do this.
				*/
				if @force_reinit_subscription = 0
					begin
						raiserror(20608, 16, -1)
						goto UNDO
					end
				exec @retcode=sp_MSreinitmergepublication @publication
				if @@ERROR<>0 or @retcode<>0
					GOTO UNDO 
			end
        END
        
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'description'
        BEGIN
        UPDATE sysmergesubscriptions
                SET description = @value
                WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1) 
              
                    goto UNDO
                END

        END
        
     
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'priority'
    BEGIN

    select @db_name = db_name from sysmergesubscriptions
        where (pubid=@pubid) and (subid=@pubid)
        IF @db_name <> db_name()
        BEGIN
            RAISERROR (20047, 16, -1)
            goto UNDO
        END  

    /* Only the original publisher can change priority of a global subscriptions */

        IF @subscriber_type<>1  
            BEGIN
                RAISERROR (20044, 16, -1)  /* Local subscriber does not have priority*/
                goto UNDO
            END

        IF convert(real, @value)>100.0
            BEGIN
                RAISERROR (20049, 16, -1)  /* Don't accept priority greater than 100 */
                goto UNDO
            END
        
		exec dbo.sp_MSchange_priority @subid,  @value
        if @@ERROR<>0 goto UNDO
	   	/* Insert the sp_MSchange_priority schema change only if the publication's snapshot is ready */
		if (@snapshot_ready > 0)
			begin
		        select @schemaversion = schemaversion from sysmergeschemachange
		        if (@schemaversion is NULL)
		        set @schemaversion = 1
		        else
		            select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
		            
		         
		        set @schemaguid = newid()
		        set @artid = newid()
		        set @schematype = 8 /* change priority */
		        select @schematext = 'exec dbo.sp_MSchange_priority '+ '''' + convert(nchar(36),@subid) + '''' + ',' + '''' + @value + '''' 
		        exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
				if @@ERROR<>0 or @retcode<>0 goto UNDO
			end				    
    END

	COMMIT TRANSACTION

    /*
    ** Return succeed. It is not an error message.
    */

    RAISERROR (14054, 10, -1)
    RETURN (0)
UNDO:
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION change_subscription
        COMMIT TRANSACTION
    end
	return (1)
go

exec dbo.sp_MS_marksystemobject sp_changemergesubscription 
go

grant execute on dbo.sp_changemergesubscription to public
go

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


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

CREATE PROCEDURE sp_helpmergesubscription(
    @publication            sysname = '%',      /* Publication name */
    @subscriber             sysname = '%',      /* Subscriber server */
    @subscriber_db          sysname = '%',      /* Subscription database */
    @publisher              sysname = '%',      /* Publisher server */
    @publisher_db           sysname = '%',      /* Publisher database */
    @subscription_type      nvarchar(15) = 'both', /* Subscription type - push or pull */ 
    @found int = NULL OUTPUT
    )AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    declare @db                 sysname
    declare @retcode            int
    declare @subscriber_bit     smallint
    declare @srvid              int
    declare @pubid              uniqueidentifier
    declare @subid              uniqueidentifier
    declare @partnerid          uniqueidentifier
    declare @cursor_open        int
    declare @no_row             bit
    declare @subscription_type_id int

    declare @distributor    sysname
    declare @distributiondb sysname
    declare @distproc       nvarchar(300)
    declare @dbname         sysname

    select @distributor = null
    select @distributiondb = null
    select @distproc = null
    select @dbname = null    

    /*
    ** Initializations.
    */
    set @subscriber_bit     = 4
    set @cursor_open        = 0                 

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

    select @db=db_name() -- so that it can appear in dynamic query

    /*
    **  Calling sp_help* is all right whether current database is enabled for pub/sub or not
    */

    IF not exists (select * from sysobjects where name='sysmergesubscriptions')
        RETURN (0)
    
    /* Security check */
    EXEC @retcode = dbo.sp_MSreplcheck_pull @publication = @publication, 
        @raise_fatal_error = 0
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** Parameter Check: @subscription_type.
    ** Set subscription_typeid based on the @subscription_type specified.
    **
    **   subscription_type    subscription_type
    **   =================    ===============
    **             0            push
    **             1            pull
    **            2         both
    */
    if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull', 'both')
        BEGIN
            RAISERROR (20079, 16, -1)
            RETURN (1)
        END
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
        set @subscription_type_id = 2
    else IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        set @subscription_type_id = 0
    else 
        set @subscription_type_id = 1

    /*
    ** Parameter Check: @publisher
    ** Check to make sure that the publisher is defined
    */
    IF @publisher <> '%'
    BEGIN
        EXECUTE @retcode = dbo.sp_validname @publisher
        IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
    END

    /*
    ** Parameter Check:  @subscriber.
    ** If remote server, limit the view to the remote server's subscriptions.
    ** Make sure that the name isn't NULL.
    */
    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

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

            if NOT EXISTS (select *
                            FROM master..sysservers
                            WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
                            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

    /*
    ** Get subscriptions
    */
    if @publication <>'%'
    begin
        execute @retcode = dbo.sp_MSsubsetpublication @publication
        if @@ERROR <> 0 or @retcode<>0
                Return (1)
    end
    
    create table #helpsubscription
                (
                    publication             sysname     collate database_default not null,
                    publisher               sysname     collate database_default not null,
                    publisher_db            sysname     collate database_default not null,
                    subscriber              sysname     collate database_default not null,
                    subscriber_db           sysname     collate database_default not null,
                    status                  int         NOT NULL,
                    subscriber_type         int         NOT NULL,
                    subscription_type       int         NOT NULL,
                    priority                float(8)    NOT NULL,
                    sync_type               tinyint     NOT NULL,
                    description             nvarchar(255) collate database_default null,
                    merge_jobid             binary(16)  NULL,
                    full_publication        tinyint 	NULL,
                    use_interactive_resolver 	int		NULL
                )


    /* 
    ** 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 <> '%')
        insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
                        subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
                        subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type,
                        subs1.use_interactive_resolver

                FROM  sysmergesubscriptions     subs1,
                      sysmergesubscriptions     subs2,
                      MSmerge_replinfo      replinfo,
                      master..sysservers        servers1,
                      master..sysservers        servers2,
                      sysmergepublications  pubs
                    where subs1.subid <> subs2.subid 
                        and subs1.status <> 2 
                        and subs2.subid = subs1.partnerid
                        and pubs.pubid = subs1.pubid
                        and pubs.pubid = subs2.pubid
                        and servers1.srvid = subs1.srvid
                        and servers2.srvid = subs2.srvid
                        and pubs.name =  @publication 
                        and replinfo.repid = subs1.subid
                        and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)
                        and ((@subscriber_db = N'%') or (subs1.db_name = @subscriber_db collate database_default))
                        and ((@publisher_db = N'%') or (subs2.db_name = @publisher_db collate database_default))
                        and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber) collate database_default)) 
                        and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher) collate database_default))
                        and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2)
    ELSE
        insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
                        subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
                        subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type,
                        subs1.use_interactive_resolver

                FROM  sysmergesubscriptions     subs1,
                      sysmergesubscriptions     subs2,
                      MSmerge_replinfo      replinfo,
                      master..sysservers        servers1,
                      master..sysservers        servers2,
                      sysmergepublications  pubs
                    where subs1.subid <> subs2.subid 
                        and subs1.status <> 2 
                        and subs2.subid = subs1.partnerid
                        and pubs.pubid = subs1.pubid
                        and pubs.pubid = subs2.pubid
                        and servers1.srvid = subs1.srvid
                        and servers2.srvid = subs2.srvid
                        and replinfo.repid = subs1.subid
                        and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)
                        and ((@subscriber_db = N'%') or (subs1.db_name = @subscriber_db collate database_default))
                        and ((@publisher_db = N'%') or (subs2.db_name = @publisher_db collate database_default)) 
                        and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber) collate database_default)) 
                        and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher) collate database_default))
                        and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2)
        

    if exists (select * from #helpsubscription)
        select @found = 1
    else
        select @found = 0 
        
    if @no_row = 1
        goto DONE

    CREATE TABLE #merge_agent_properties
    (
        job_id                VARBINARY(16) NOT NULL,
        offload_enabled       bit NULL,
        offload_server        sysname collate database_default null
    )

    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distributiondb OUTPUT
    IF @retcode <> 0
        GOTO DONE

    SELECT @distributor = RTRIM(@distributor)

    -- Get distribution agent properties 
    IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
    BEGIN
        SELECT @distproc = @distributor + '.' + @distributiondb + 
                           '.dbo.sp_MSenum_merge_agent_properties'
    END    
    ELSE
    BEGIN
        SELECT @distproc = @distributiondb + 
                           '.dbo.sp_MSenum_merge_agent_properties'
    END

    SELECT @dbname = db_name()

    INSERT INTO #merge_agent_properties
      EXEC @retcode = @distproc @publisher = @@SERVERNAME, 
                                @publisher_db = @dbname, 
                                @publication = @publication            

    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push' or LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
        begin
            select 'subscription_name'  = subscriber + ':' + subscriber_db,
                hs.publication, hs.publisher, hs.publisher_db, 
                hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type,
                hs.subscription_type, hs.priority, hs.sync_type, hs.description,
                hs.merge_jobid, hs.full_publication,
                ap.offload_enabled, ap.offload_server,
                hs.use_interactive_resolver
                from #helpsubscription hs
                left outer join #merge_agent_properties ap
                on hs.merge_jobid = ap.job_id
                order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
        end
    else 
        begin
            select 'subscription_name' = hs.publisher + ':' + hs.publisher_db + ':' + hs.publication, 
                hs.publication, hs.publisher, hs.publisher_db, 
                hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type,
                hs.subscription_type, hs.priority, hs.sync_type, hs.description,
                hs.merge_jobid, hs.full_publication,
                ap.offload_enabled, ap.offload_server,                 
                hs.use_interactive_resolver
                from #helpsubscription hs
                left outer join #merge_agent_properties ap
                on hs.merge_jobid = ap.job_id
                order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
        end

    drop table #merge_agent_properties
    select @retcode = 0
DONE:
    if (@cursor_open = 1)
        begin
            close #cursor
            deallocate #cursor
        end         
    drop table #helpsubscription
    return @retcode 
go
exec dbo.sp_MS_marksystemobject sp_helpmergesubscription
go

grant execute on dbo.sp_helpmergesubscription to public
go

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


raiserror('Creating procedure sp_dropmergesubscription', 0,1)
GO
CREATE PROCEDURE sp_dropmergesubscription(
    @publication        sysname = NULL,             /* Publication name */
    @subscriber         sysname = NULL,             /* Subscriber server */
    @subscriber_db      sysname = NULL,             /* Subscription database */
    @subscription_type  nvarchar(15) = 'both',          /* Subscription type - push, pull, both */ 
    @ignore_distributor bit = 0,
    @reserved 			bit = 0
    )AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @retcode                int
    declare @subscriber_bit         smallint
    declare @subscriber_type        smallint
    declare @subscriber_srvid       int
    declare @publisher_srvid        int
    declare @pubid                  uniqueidentifier
    declare @subid                  uniqueidentifier
    declare @partnerid              uniqueidentifier
    declare @subscription_type_id   int   
    declare @found_subscription     int   
    declare @local_server           sysname
    declare @local_db               sysname
    declare @cmd                    nvarchar(290)
    declare @distributor            sysname
    declare @distribdb              sysname
    declare @distproc               nvarchar(300)
    declare @pubidstr               nvarchar(38)
    declare @publisher              sysname
    declare @publisher_db           sysname

    declare @implicit_transaction	int
	declare @close_cursor_at_commit int

	select @close_cursor_at_commit = 0
	select @implicit_transaction = 0

	/*
	** Save setting values first before changing them
	*/
	IF (@reserved = 0)
	BEGIN
		SELECT @implicit_transaction = @@options & 2
		SELECT @close_cursor_at_commit = @@options & 4
		SET IMPLICIT_TRANSACTIONS OFF
		SET CURSOR_CLOSE_ON_COMMIT OFF
	END

     /*
    ** Initializations.
    */
    set @subscriber_bit     = 4
    set @subscription_type_id = -1
    set @found_subscription = 0                     
    set @local_db           = DB_NAME()
    set @local_server       = @@SERVERNAME
    set @publisher          = @@SERVERNAME
    set @publisher_db       = DB_NAME()

    /*
    **  Check to see if current database is enabled for publishing/subscribing
    */
    IF not exists (select name from sysobjects where name='sysmergesubscriptions')
        BEGIN
            RAISERROR (14055, 16, -1)
            RETURN (1)
        END

    /*
    ** Parameter Check: @subscription_type.
    ** Set subscription_typeid based on the @subscription_type specified.
    **
    **   subscription_type    subscription_type
    **   =================    ===============
    **             0            push
    **             1            pull
    */
    if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('both', 'push', 'pull')
        BEGIN
            RAISERROR (14128, 16, -1)
            RETURN (1)
        END
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
        begin
            EXECUTE @retcode = dbo.sp_dropmergesubscription @publication = @publication,
                            @subscriber = @subscriber,
                            @subscriber_db = @subscriber_db,
                            @subscription_type = 'push',
                            @ignore_distributor = @ignore_distributor,
                            @reserved = 1
			if @retcode<>0 or @@ERROR<>0
				return (1)
            EXECUTE @retcode = dbo.sp_dropmergesubscription @publication = @publication,
                            @subscriber = @subscriber,
                            @subscriber_db = @subscriber_db,
                            @subscription_type = 'pull',
                            @ignore_distributor = @ignore_distributor,
							@reserved = 1
			if @retcode<>0 or @@ERROR<>0
				return (1)
			return (0)
        end 
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        set @subscription_type_id = 0
    else 
        set @subscription_type_id = 1

    /*
    ** Parameter validation (different for push and pull modes)
    */

    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        begin
            /*
            ** Assign parameter values appropriately
            */
            if @publisher IS NULL
                set @publisher = @@SERVERNAME
            if (@publisher_db IS NULL)
                set @publisher_db = DB_NAME()

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

            /*
            ** Parameter Check: @subscriber_db
            */
            IF @subscriber_db IS NULL
            BEGIN
                select @subscriber_db = 'all'
            END
                
        end
    else
        begin
            /*
            ** Assign parameter values appropriately
            */
            if @subscriber IS NULL
                set @subscriber = @@SERVERNAME
            if @subscriber_db IS NULL
                set @subscriber_db = DB_NAME()

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

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

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

        end     

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

    IF LOWER(@publication) = 'all'
        BEGIN
            declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications 
                where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() 
                FOR READ ONLY
            
            OPEN hC1
            FETCH hC1 INTO @publication
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
                                                @subscriber = @subscriber,
                                                @subscriber_db = @subscriber_db,
                                                @subscription_type = @subscription_type,
                                                @ignore_distributor = @ignore_distributor,
												@reserved = 1
                    FETCH hC1 INTO @publication
                END
            CLOSE hC1
            DEALLOCATE hC1
            RETURN (0)
        END
        
    if NOT EXISTS (select * FROM sysmergepublications 
        WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END
    select @pubid = pubid from sysmergepublications 
        where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
    if @pubid is null
        BEGIN
            RAISERROR (20026, 16, -1, @publication)
            RETURN (1)
        END

       
    IF LOWER(@subscriber) = 'all'
        BEGIN
            declare hC2 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT srvname 
            FROM master..sysservers 
            WHERE (srvstatus & 4 <> 0) FOR READ ONLY
    
            OPEN hC2
            FETCH hC2 INTO @subscriber
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
                                                @subscriber = @subscriber,
                                                @subscriber_db = @subscriber_db,
                                                @subscription_type = @subscription_type,
                                                @ignore_distributor = @ignore_distributor,
												@reserved = 1
                    FETCH hC2 INTO @subscriber
                END
            CLOSE hC2
            DEALLOCATE hC2
            RETURN (0)
        END

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

    /*
    ** NOTE: remove this batch
    */
    IF LOWER(@subscriber_db) = 'all'
        BEGIN
                declare hC3 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT db_name FROM sysmergesubscriptions
                WHERE srvid =  @subscriber_srvid 
                    AND subid <> pubid 
                    AND sysmergesubscriptions.pubid = @pubid
                    AND sysmergesubscriptions.subscription_type = @subscription_type_id
                FOR READ ONLY       

            OPEN hC3
            FETCH hC3 INTO @subscriber_db
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropmergesubscription @publication = @publication,
                                                @subscriber = @subscriber,
                                                @subscriber_db = @subscriber_db,
                                                @subscription_type = @subscription_type,
                                                @ignore_distributor = @ignore_distributor,
												@reserved = 1

                    FETCH hC3 INTO @subscriber_db
                END
            CLOSE hC3
            DEALLOCATE hC3
            RETURN (0)
        END

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

    select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    if @pubid is NULL return (0)
    
    if exists (select * from sysmergesubscriptions where subid=@pubid 
        and pubid=@pubid and db_name<>db_name())
    RETURN (0)
    
    /*
    ** Get subscriptions from either local replicas or global replicas
    */
    select @subid = subs1.subid, @partnerid = subs2.subid, @subscriber_type = subs1.subscriber_type from
        sysmergesubscriptions   subs1,
        sysmergesubscriptions   subs2,
        sysmergepublications        pubs
        where subs1.srvid = @subscriber_srvid
            and subs1.db_name = @subscriber_db
            and subs2.srvid = @publisher_srvid
            and subs2.db_name = @publisher_db
            and subs1.pubid = subs2.subid
            and subs2.pubid = pubs.pubid
            and pubs.name = @publication
            and UPPER(pubs.publisher)=UPPER(@@servername)
            and pubs.publisher_db=db_name()
            and subs1.subscription_type = @subscription_type_id
            and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1)

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

    begin tran
    save TRAN dropmergesubscription

        /*
        ** Do not drop the subscription corresponding to the loopback subscription 
        */
        if (@subid <> @partnerid) 
            begin
                /*
                ** global/republisher subscriptions have to stay for a while even after being
                ** dropped so that they won't regain lives for themselves. They would be cleanup eventually.
                */
                
                if (@subscriber_type<>1) 
                    begin
                        delete from sysmergesubscriptions where subid = @subid
                        IF @@ERROR <> 0
                            GOTO FAILURE        
                        delete MSmerge_replinfo WHERE repid = @subid 
                        IF @@ERROR <> 0
                            GOTO FAILURE
                    end
                else
                    begin
                        update sysmergesubscriptions set status=2 where subid=@subid
                        IF @@ERROR<>0
                            GOTO FAILURE
                    end 

                /* 
                ** The MobileSync registry entry needs to be dropped 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 collate SQL_Latin1_General_CP1_CS_AS) = 'push'
                begin
                    /* Call sp_MSunregistersubscription so that the reg entries get deleted */
                    exec @retcode = dbo.sp_MSunregistersubscription @publisher = @@SERVERNAME,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @subscriber = @subscriber,
                                    @subscriber_db = @subscriber_db
                    IF @retcode<>0 or @@ERROR<>0
                        GOTO FAILURE

                END             
            end     

        /*
        ** 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
                    GOTO FAILURE
                END

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

            EXEC @retcode = @distproc 
                @@SERVERNAME, 
                @publisher_db, 
                @publication,
                @subscriber, 
                @subscriber_db,
                @subscription_type
            IF @@ERROR <> 0 OR @retcode <> 0
                begin   
                    goto FAILURE
                end 
        end 

        /* 
        ** If last subscription is dropped and the DB is not enabled for publishing,
        ** then remove the merge system tables
        */

        IF (not exists (select * from sysmergesubscriptions )) 
            AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default)=0
            BEGIN
                execute @retcode = dbo.sp_MSdrop_mergesystables
                if @@ERROR <> 0 or @retcode <> 0
                    begin
                        return (1)
                    end
            END         

    COMMIT TRAN
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END
    RETURN(0)       

FAILURE:
    /* UNDONE : This code is specific to 6.X nested transaction semantics */
    RAISERROR (14056, 16, -1)
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION dropmergesubscription
        COMMIT TRANSACTION
    end
    /*
	** Set back original settings
	*/	
	IF @reserved = 0
	BEGIN
		IF @implicit_transaction <>0 
			SET IMPLICIT_TRANSACTIONS ON
		IF @close_cursor_at_commit <>0 
			SET CURSOR_CLOSE_ON_COMMIT ON
	END
    return (1)
go
exec dbo.sp_MS_marksystemobject sp_dropmergesubscription
go

grant execute on dbo.sp_dropmergesubscription to public
go


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

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

CREATE PROCEDURE sp_MSmergepublishdb(
      @value     sysname,
      @ignore_distributor bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @command        nvarchar(255)
    declare @description    nvarchar(500)
    declare @cmptlevel      tinyint
    declare @db_name        sysname 
    declare @retcode        int
    declare @distributor    sysname
    declare @distribdb      sysname
    declare @category_name  sysname
    declare @agentname      sysname
	declare @working_directory nvarchar(255)
    /*
    ** Initialization
    */

    select @db_name = DB_NAME()


    /*
    ** Parameter check
    ** @value
    */
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) 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, @directory=@working_directory OUTPUT,
           @distribdb   = @distribdb OUTPUT

        IF @@ERROR <> 0 or @retcode <> 0 or @distributor IS NULL or @distribdb IS NULL
        BEGIN
            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
                RAISERROR (20028, 16, -1)
            ELSE
                RAISERROR (20029, 16, -1)
            RETURN (1)
        END
    end

    /*
    ** Enable the database for publishing.
    */
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        BEGIN
            select @cmptlevel = cmptlevel from master..sysdatabases where name=db_name() collate database_default
            if @cmptlevel<70 OR @cmptlevel is NULL 
                begin
                    RAISERROR(20061, 16, -1)
                    goto FAILURE
                end
            execute @retcode = dbo.sp_MScreate_mergesystables
            if @@ERROR <> 0 or @retcode <> 0
                begin
                    goto FAILURE
                end

		    END

    ELSE    /* Disable the database for publishing. */
        BEGIN 
           
          /*
          ** Remove all the registration entries for subscriptions
          */
            if not exists(select * from sysobjects where name = 'sysmergesubscriptions')
                goto FAILURE
            exec @retcode = dbo.sp_dropmergesubscription @publication = 'all', 
                                            @subscriber = 'all', 
                                            @subscriber_db = 'all', 
                                            @subscription_type = 'both',
                                            @ignore_distributor = @ignore_distributor
            IF @@ERROR <> 0 or @retcode <> 0 
                begin
                    goto FAILURE
                end
            /*
            ** Remove all publications and articles in the database.
            */
            EXEC @retcode = dbo.sp_dropmergepublication @publication = 'all',
                @ignore_distributor = @ignore_distributor
            IF @@ERROR <> 0 or @retcode <> 0 
                begin
                    -- sp_dropmergepublication will raiserror 
                    goto FAILURE
                end
                
            If NOT EXISTS (select * from sysmergepublications)
                BEGIN
                    execute @retcode = dbo.sp_MSdrop_mergesystables
                    if @@ERROR <> 0 or @retcode <> 0
                        begin
                            goto FAILURE
                        end
                END
    
    END
        
        
        return 0
FAILURE:
    
    return (1)  

GO
exec dbo.sp_MS_marksystemobject sp_MSmergepublishdb
go


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

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

create procedure sp_changemergefilter(
    @publication            sysname,
    @article                sysname,
    @filtername             sysname,
    @property               sysname,
    @value                  nvarchar(2000),
	@force_invalidate_snapshot bit = 0,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
    )AS

    set nocount on

	declare @pre_command		int
	declare @qual_object		nvarchar(132)
	declare @qual_join_object	nvarchar(132)
	declare @join_articlename	nvarchar(4000)
    declare @db_name        sysname
    declare @pubid          uniqueidentifier
    declare @artid          uniqueidentifier
    declare @object			sysname
    declare @join_object	sysname
    declare @retcode        int
    declare @join_filterid  int
    declare @join_objid     int
    declare @join_nickname  int
    declare @snapshot_ready int

    /*
    ** Security Check.
    ** Only the System Administrator (SA) or the Database Owner (dbo) can
    ** call this procedure
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

    /*
    ** Parameter Check: @join_articlename.
    ** The join_articlename cannot be NULL 
    */
    if @filtername is NULL
        begin
            raiserror (14043, 11, -1, '@filtername')
            return (1)
        end

    if @value is NULL or @value = ''
        begin
            raiserror (14043, 11, -1, '@value')
            return (1)
        end

    /*
    ** Parameter Check: @publication.
    ** The @publication id cannot be NULL and must conform to the rules
    ** for identifiers.
    */
    if @publication is NULL
        begin
            raiserror (14043, 11, -1, '@publication')
            return (1)
        end
    /*
    ** Get the pubid and make sure the publication exists
    */
    select @pubid = pubid, @snapshot_ready=snapshot_ready from sysmergepublications where 
        name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
    if @pubid is NULL
        begin
            raiserror (20026, 16, -1, @publication)
            return (1)
        end

    select @db_name = db_name from sysmergesubscriptions
        where (pubid=@pubid) and (subid=@pubid)
        IF @db_name <> db_name()
        BEGIN
            RAISERROR (20047, 16, -1)
            RETURN (1)
        END

    /*
    ** Parameter Check: @article.
    ** Check to see that the @article is valid and does exist 
    */
    if @article is NULL
        begin
            raiserror (20045, 16, -1)
            return (1)
        end
        
    select @artid = artid, @object=object_name(objid), @pre_command=pre_creation_command from sysmergearticles where name = @article and pubid = @pubid  
    if @artid is NULL
        begin
            raiserror (20046, 16, -1)
            return (1)
        end

    
    select @join_filterid=join_filterid, @join_articlename=join_articlename from sysmergesubsetfilters
        where pubid=@pubid and artid=@artid and filtername=@filtername

    if @join_filterid is null
        begin
            raiserror (21362, 16, -1, @filtername) 
            return (1)
        end

     IF @property IS NULL
        BEGIN
            CREATE TABLE #temp (properties sysname collate database_default)
            INSERT INTO #temp VALUES ('filtername')
            INSERT INTO #temp VALUES ('join_filterclause')
            INSERT INTO #temp VALUES ('join_articlename')
            INSERT INTO #temp VALUES ('join_unique_key')
            select * FROM #tab1
            RETURN (0)
        END 


    if @value is null
        begin
	        RAISERROR (14043, 16, -1, @property)
            return (1)
        end

	begin TRAN
	save TRAN change_filter

	if LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) in ('join_filterclause','join_articlename','join_unique_key')
		and @snapshot_ready>0
	begin
			-- 1 means'drop': which is the only option that support reintialization
			if @pre_command<>1 				
				begin
					raiserror(21419, 16, -1, @filtername, @article)
					goto FAILURE			
				end
			/*
			** make sure we know we really want to do this.
			*/
			if @force_invalidate_snapshot = 0
				begin
					raiserror(20607, 16, -1)
					goto FAILURE
				end
			if @force_reinit_subscription = 0
				begin
					raiserror(20608, 16, -1)
					goto FAILURE
				end

			update sysmergepublications set snapshot_ready=2 where pubid=@pubid
			if @@ERROR<>0
				goto FAILURE
			exec @retcode = sp_MSreinitmergepublication @publication
			if @retcode<>0 or @@ERROR<>0
				goto FAILURE

	end
	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_filterclause'
        BEGIN
		/* check the validity of join_filterclause */
		select @join_object=object_name(objid) from sysmergearticles where name=@join_articlename and pubid=@pubid
		select @qual_object=QUOTENAME(@object)
		select @qual_join_object=QUOTENAME(@join_object)
		exec ('declare @test int select @test=1 from ' + @qual_object + ', ' + @qual_join_object + ' where ' + @value)
		if @@ERROR<>0
			begin
				raiserror(21256, 16, -1, @value, @object)
				goto FAILURE
			end
		update sysmergesubsetfilters set join_filterclause=@value
                where join_filterid=@join_filterid
		execute @retcode = dbo.sp_MSsubsetpublication @publication
		if @@ERROR <> 0 or @retcode<>0
			goto FAILURE
        END

       IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_unique_key'
		BEGIN
			IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false')
    			BEGIN
     				 RAISERROR(14137,16,-1)
     				 RETURN(1)
 		    	END
			if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
				update sysmergesubsetfilters set join_unique_key=1 where join_filterid=@join_filterid
			else
				update sysmergesubsetfilters set join_unique_key=0 where join_filterid=@join_filterid
			if @@ERROR <> 0 or @retcode<>0
				goto FAILURE
		END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='filtername'
        BEGIN
            update sysmergesubsetfilters set filtername=@value
                where join_filterid=@join_filterid
			if @@ERROR<>0
				goto FAILURE
        END

    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS)='join_articlename'
        BEGIN
            select @join_objid = objid from sysmergearticles where name = @value and pubid = @pubid
            
            IF @join_objid is NULL
            BEGIN
                raiserror (14027, 11, -1, @value)
                goto FAILURE
            END

            select @join_nickname = nickname from sysmergearticles where pubid = @pubid AND objid = @join_objid 
            if @join_nickname is NULL
            begin
                raiserror (20001, 11, -1, @article, @publication)
                goto FAILURE
            end
            
            update sysmergesubsetfilters set join_articlename=@value, join_nickname=@join_nickname
                where join_filterid=@join_filterid
			if @@ERROR<>0
				goto FAILURE
        END
        
	Commit TRAN
    return(0)

FAILURE:
    if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION change_filter
        COMMIT TRANSACTION
    end
    RAISERROR (20038, 16, -1, @article, @publication)
    return(1)
 
go
exec dbo.sp_MS_marksystemobject sp_changemergefilter
go

grant execute on dbo.sp_changemergefilter to public
go

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

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

create procedure sp_mergecleanupmetadata
	@publication		sysname = '%',
	@reinitialize_subscriber	nvarchar(5) = 'true'
AS
declare @pubid					uniqueidentifier
declare @retcode				int
declare @pubname  				sysname
declare @snapshot_ready 		int
declare @make_generation 		int
declare @artid                  uniqueidentifier
declare @schematype             int
declare @schemaversion          int
declare @schemaguid             uniqueidentifier
declare @schematext             nvarchar(2000)

set @make_generation = 0
/*
** Security Check
*/
EXEC @retcode = dbo.sp_MSreplcheck_publish
IF @@ERROR <> 0 or @retcode <> 0
	return (1)
/* make sure current database is enabled for merge replication */
exec @retcode=dbo.sp_MSCheckmergereplication
if @@ERROR<>0 or @retcode<>0
	return (1)
	

/* Validate the publication name if one is provided */
if @publication <> '%'
	begin
		select @pubid = pubid from sysmergepublications 
			where name = @publication
		if @pubid is NULL
			begin
    			raiserror (20026, 11, -1, @publication)
			    return (1)
		    end
	end

if not exists (select * from sysobjects where name='sysmergearticles')
	return (1)
	
begin TRAN
save TRAN cleanupmetadata
declare #per_publication CURSOR LOCAL FAST_FORWARD for select pubid
	from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name() and name like @publication
open #per_publication
fetch #per_publication into @pubid
while @@fetch_status<>-1
begin
	select @pubname=name, @snapshot_ready=snapshot_ready from sysmergepublications where pubid=@pubid
	if @publication <> '%' and exists (select * from sysmergearticles where pubid<>@pubid and objid in
		(select objid from sysmergearticles where pubid=@pubid))
	begin
		raiserror(21272, 16, -1, @pubname)
		goto FAILURE
	end

	/* Only do this when snapshot has been ran before this operation */
	if @snapshot_ready>0
	begin
		/* If there are any inprocess generations defer the cleanup of metadata */
		if exists (select top 1 guidsrc from dbo.MSmerge_genhistory h
			where	guidlocal='00000000-0000-0000-0000-000000000000'  -- incomplete gen
				and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
				and coldate in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
				and h.art_nick in (select nickname from sysmergearticles where pubid = @pubid)) -- generations relevant to current publication 
			begin
				RAISERROR(21503, 16, -1)
				close #per_publication
				deallocate #per_publication
				goto FAILURE
			end
		if LOWER(@reinitialize_subscriber collate SQL_Latin1_General_CP1_CS_AS)='true'		
		begin
			-- backward-comp-level is bump'd up by calling this stored procedure			
			exec @retcode = sp_MSreinitmergepublication @pubname
			if @@ERROR<>0 or @retcode<>0
			begin
				close #per_publication
				deallocate #per_publication
				goto FAILURE
			end

			update sysmergepublications set snapshot_ready=2 where pubid=@pubid
			if @@ERROR<>0
			begin
				close #per_publication
				deallocate #per_publication
				goto FAILURE
			end
		end
		else
		begin
			raiserror(21355, 10, -1,@publication)
			exec @retcode=sp_MSBumpupCompLevel @pubid, 30 --SP2 subscribers support this, but do not propagate
			if @@ERROR<>0 or @retcode<>0
			begin
				close #per_publication
				deallocate #per_publication
				goto FAILURE
			end

			select @schemaversion = schemaversion from sysmergeschemachange
	        if (@schemaversion is NULL)
    	    set @schemaversion = 1
        	else
            	select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
	        set @schemaguid = newid()
    	    set @artid = newid()
        	set @schematype = 16 /* metadata cleanup */
        	select @schematext = 'exec dbo.sp_MScleanup_metadata '+ '''' + convert(nchar(36),@pubid) + '''' 
			exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
            if @@ERROR<>0 or @retcode<>0 
            begin
				close #per_publication
				deallocate #per_publication
				goto FAILURE            
            end
			
		end
	end
	set @make_generation = 1
	fetch next from #per_publication into @pubid
end
close #per_publication
deallocate #per_publication
COMMIT TRAN

if @publication = '%'
	begin
		set @pubid = NULL
	end
else
	begin
		select @pubid = pubid from sysmergepublications 
			where name = @publication
	end

	exec @retcode = dbo.sp_MScleanup_metadata @pubid
	if @@ERROR <> 0 or @retcode <> 0
   	    goto FAILURE
if @make_generation = 1
	begin
		execute @retcode = dbo.sp_MSmakegeneration 
		if @@ERROR <> 0 or @retcode <> 0
       	    goto FAILURE
	end
return (0)
FAILURE:
	if @@TRANCOUNT > 0
    begin
        ROLLBACK TRANSACTION cleanupmetadata
        COMMIT TRANSACTION
    end
	return (1)

GO

exec dbo.sp_MS_marksystemobject sp_mergecleanupmetadata
go
grant execute on dbo.sp_mergecleanupmetadata to public
go


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

/*
** Name :       sp_MShelpmergeconflictcounts
** Description: This sp returns the count of conflicts (from MSmerge_delete_conflicts and 
**              each conflict table) in each publication. Results can optionally be filtered
**				to include only a single publication. Results are always ordered by article
**				name. Only articles with non-zero conflict counts are returned.
** Parameters:  1. Publication Name( sysname; default '%'==ALL PUBLICATIONS)
** Output Result Set has the following structure 
**  ----------------------------------------------------------------------------------
**      Name                Datatype                Description
**  ----------------------------------------------------------------------------------
**  a. article				(sysname)		    Article name
**  b. conflict_table		(sysname)			Associated conflict table
**  c. guidcolname			(sysname)			Article's rowguidcol name
**  d. centralized_conflicts(integer)			Centralized (1) or Decentralized (0) 
**												conflicts specified by the article
**  e. conflict_ucount		(integer)           Count of (update) conflicts in the 
**												conflict table for this article
**  f. conflicts_dcount		(integer)           Count of (delete) conflicts in the 
**												MSmerge_delete_conflicts table for this article
*/
raiserror('Creating procedure sp_MShelpmergeconflictcounts', 0,1)
GO

create procedure sp_MShelpmergeconflictcounts ( 
	@publication_name sysname = '%' ,
    @publisher		sysname = NULL,
	@publisher_db	sysname = NULL)
as 
begin

	set nocount on 

	declare	@aname 		sysname
	declare	@cmd 		nvarchar(2000) 
	declare	@conflict_table sysname 
	declare	@count 		integer
    declare @pubid          uniqueidentifier
    declare @pubidstr       nvarchar(38)

    if @publisher IS NULL
    	select @publisher = @@SERVERNAME
    	
    if @publisher_db IS NULL
	    select @publisher_db = db_name()

	if @publication_name <> '%'
        begin
            /*
            ** Parameter Check:  @publication.
            ** Make sure that the publication exists.
            */
            select @pubid = pubid from sysmergepublications 
            	where name = @publication_name and 
            		LOWER(publisher) = LOWER(@publisher) and
            		publisher_db = @publisher_db
            if @pubid IS NULL
                BEGIN
                    RAISERROR (20026, 16, -1, @publication_name)
                    RETURN (1)
                END
		    set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' 
		end

	-- make sure current db has merge publishing tables (true on both pub and sub)
	if not exists ( select * from sysobjects where name = 'sysmergearticles')
	begin
		raiserror( 18757, 16, -1 )
		return(1)
	end

	-- allow null conflict table name to handle case where there are delete conflicts but no update conflicts
	create table #result_list ( article sysname collate database_default, source_object sysname collate database_default, conflict_table sysname collate database_default null, guidcolname sysname collate database_default, centralized_conflicts integer, conflicts_ucount integer, conflicts_dcount integer )
	create table #conflict_list ( article_name sysname collate database_default, conflicts_ucount integer, conflicts_dcount integer )
	create table #update_list ( article_name sysname collate database_default, conflicts_ucount integer )

	-- get delete counts
	if ( @publication_name = '%' )
		declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for 
			select distinct a.name 
				from MSmerge_delete_conflicts d
				inner join sysmergepublications p on p.pubid = d.pubid
				inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
	else
		declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for 
			select distinct a.name 
				from MSmerge_delete_conflicts d
				inner join sysmergepublications p on p.pubid = d.pubid
				inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
				where p.pubid = @pubid
	open hCdcount
	fetch hCdcount into @aname
	while ( @@fetch_status <> -1 )
	begin

		select @cmd = 'select N''' + @aname + ''', 0, count(*) 
				from MSmerge_delete_conflicts d
					inner join sysmergepublications p on p.pubid = d.pubid
					inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick
				where a.name = N''' + @aname + ''' '

		if ( @publication_name <> '%' ) 
			select @cmd = @cmd + ' and p.pubid = ' + @pubidstr

		insert #conflict_list ( article_name, conflicts_ucount, conflicts_dcount )
			exec ( @cmd )

		fetch hCdcount into @aname
	end
	close hCdcount
	deallocate hCdcount

	-- get update counts
	if ( @publication_name = '%' )
		declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for 
			select distinct a.name, a.conflict_table
				from sysmergepublications p
				inner join sysmergearticles a on a.pubid = p.pubid
			where a.conflict_table is not null
	else
		declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for 
			select distinct a.name, a.conflict_table
				from sysmergepublications p
				inner join sysmergearticles a on a.pubid = p.pubid
			where a.conflict_table is not null
			  	and p.pubid = @pubid
	open hCucount
	fetch hCucount into @aname, @conflict_table
	while ( @@fetch_status <> -1 )
	begin
		select @cmd = N'select N''' + @aname + N''', count(*) from ' + QUOTENAME( @conflict_table ) + N' ct inner join sysmergepublications p on p.pubid = ct.pubid '

		if ( @publication_name <> '%' ) 
			select @cmd = @cmd + ' where p.name = N''' + @publication_name + ''''

		insert #update_list ( article_name, conflicts_ucount )
			exec( @cmd )

		fetch hCucount into @aname, @conflict_table
	end
	close hCucount
	deallocate hCucount

	update #conflict_list set conflicts_ucount = isnull( ul.conflicts_ucount, 0 )
		from #conflict_list cl
		inner join #update_list ul on ul.article_name = cl.article_name

	delete #update_list 
		from #update_list ul 
		inner join #conflict_list cl on ul.article_name = cl.article_name

	insert #conflict_list
		select *, 0 from #update_list where conflicts_ucount > 0

	drop table #update_list
	select @cmd = N'select distinct t.article_name, N'''' + quotename(user_name( o.uid )) + ''.'' + quotename(o.name) + '''',' + ' a.conflict_table, c.name, p.centralized_conflicts, t.conflicts_ucount, t.conflicts_dcount
			from #conflict_list t
				inner join sysmergearticles a on a.name = t.article_name
				inner join sysmergepublications p on p.pubid = a.pubid
				inner join sysobjects o on o.id = a.objid 
				inner join syscolumns c on c.id = o.id and ColumnProperty (o.id, c.name, ''IsRowGuidCol'') = 1
			where (t.conflicts_ucount > 0 or t.conflicts_dcount > 0) and a.conflict_table is NOT NULL'

	insert #result_list
		exec ( @cmd )		
	if ( @@error <> 0 )
		return (1)

	drop table #conflict_list

	select * from #result_list
	drop table #result_list

return (0)
end
go

exec dbo.sp_MS_marksystemobject sp_MShelpmergeconflictcounts
go

grant execute on dbo.sp_MShelpmergeconflictcounts to public
go



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

/*
** Name :       sp_deletemergeconflictrow
** Description: This sp deletes the row matching rowguid and origin_datasource
**              If now rows are left in conflict_table
**                  --Set the conflict_table property of the article(s) to NULL
**                  --Drop the conflict table (optionally)
**              If the conflict_table is specified as NULL, the conflict is assumed
**              to be a delete conflict and the row matching rowguid and origin_datasource
**              and source_object is deleted from the MSmerge_delete_conflicts table. The
**              MSmerge_delete_conflicts table is a system table and is not deleted 
**              from the database even if it is empty.
** Parameters:  
**  ----------------------------------------------------------------------------------
**      Name                Datatype                Description
**  ----------------------------------------------------------------------------------
**  a. conflict_table       (sysname)           Indicates the conflict table name. If
                                                '%' then delete from MSmerge_delete_conflicts
**  b. source_object        (nvarchar(386))     Source table 
**  c. rowguid              (uniqueidentifier)  Row identifier for the delete conflict
**  d. origin_datasource    (varchar(255))      Indicates the origin of the conflict                                                         
**  e. drop_table_if_empty  (varchar(10))       Flag indicating if the Conflict_<table>
**                                              is to be dropped if is empty
*/
raiserror('Creating procedure sp_deletemergeconflictrow', 0,1)
GO

CREATE PROCEDURE sp_deletemergeconflictrow(
    @conflict_table         sysname = '%',
    @source_object          nvarchar(386) = NULL,
    @rowguid                uniqueidentifier,
    @origin_datasource      varchar(255),
    @drop_table_if_empty    varchar(10) = 'false')
as
    declare @retcode        smallint
    declare @cmd            nvarchar(4000)  
    declare @rowguidstr     nvarchar(40)
    declare @object         sysname  
    declare @owner          sysname  
    declare @tablenick      int
    declare @tablenickstr   nvarchar(11)


    set @rowguidstr = convert(nchar(36), @rowguid)

    /* Delete conflict from Conflict_<Table> */
    if @conflict_table <> '%'
        begin
            select @cmd = 'delete from '
            select @cmd = @cmd + quotename(@conflict_table) 
            select @cmd = @cmd + ' where origin_datasource = '''
            select @cmd = @cmd + @origin_datasource 
            select @cmd = @cmd + ''' and rowguidcol = '''
            select @cmd = @cmd + @rowguidstr
            select @cmd = @cmd + ''''
            
            exec (@cmd)
            if @@ERROR<>0 return (1)

            if LOWER(@drop_table_if_empty collate SQL_Latin1_General_CP1_CS_AS) = 'true'
                begin
		            select @cmd = 'if not exists (select 1 from ' 
		            select @cmd = @cmd + quotename(@conflict_table) 
		            select @cmd = @cmd + ')'
		            select @cmd = @cmd + ' update sysmergearticles set ins_conflict_proc = NULL, conflict_table = NULL where conflict_table = ' + quotename(@conflict_table)
		            
		            exec (@cmd)
		            if @@ERROR<>0 
		            	return (1)
		            	
                    select @cmd = 'if not exists (select 1 from ' 
                    select @cmd = @cmd + quotename(@conflict_table)
                    select @cmd = @cmd + ')'
                    select @cmd = @cmd + ' drop table '
                    select @cmd = @cmd + quotename(@conflict_table)
                    select @cmd = @cmd + ''
                    
                    exec (@cmd)
                    if @@ERROR<>0 return (1)
                end
        end
    /* Delete conflict from MSmerge_delete_conflicts */
    else
        begin
        	if @source_object is NULL
        		begin
        			raiserror(14043, 16, -1, '@source_object')
        			return (1)
        		end
            select @object = PARSENAME(@source_object, 1)
            select @owner = PARSENAME(@source_object, 2)
            execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
        
            if @tablenick IS NULL or @@ERROR<>0 or @retcode<>0
                BEGIN
                    raiserror (20003, 11, -1, @object)
                    RETURN (1)
                END

            set @tablenickstr = convert(nchar, @tablenick)

            
            select @cmd = 'delete from MSmerge_delete_conflicts'
            select @cmd = @cmd + ' where origin_datasource = '''
            select @cmd = @cmd + @origin_datasource 
            select @cmd = @cmd + ''' and tablenick = '
            select @cmd = @cmd + @tablenickstr
            select @cmd = @cmd + ' and rowguid = '''
            select @cmd = @cmd + @rowguidstr
            select @cmd = @cmd + ''''
            
            exec (@cmd)
            if @@ERROR<>0 return (1)

        end

go

exec dbo.sp_MS_marksystemobject sp_deletemergeconflictrow 
go

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

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

create procedure sp_addtabletocontents 
    (@table_name sysname,
     @owner_name sysname = NULL)
AS

    declare @qualified_table_name nvarchar(270)
    declare @tablenick int
    declare @tablenickstr nvarchar(12)
    declare @repl_nick int
    declare @lineage varbinary(249)
    declare @colv varbinary(2000)
    declare @coltrack int
    declare @objid int
    declare @maxcolid int
    declare @retcode int
    declare @gen int
    
    set nocount on
    create table #temp_cont(rowguid uniqueidentifier)
    execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output
    if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

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

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

    set @tablenickstr = convert(nchar, @tablenick)

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

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

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

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

raiserror(15339,-1,-1,'sp_MSget_subtypedatasrc')
GO
CREATE PROCEDURE sp_MSget_subtypedatasrc
@subscriber				sysname,
@distributor			sysname,
@distribdb				sysname,
@datasrctype			int OUTPUT,
@datasrc				sysname OUTPUT
AS
	SET NOCOUNT ON

	DECLARE @provider_name		sysname
	DECLARE @jet_subscriber     tinyint
    DECLARE @oledb_subscriber   tinyint
	DECLARE @oracle_subscriber  tinyint
	DECLARE @db2universal_subscriber tinyint
	DECLARE @distproc           nvarchar(300)
	DECLARE @cmd 				nvarchar(512)
    
	set @jet_subscriber = 2   
    set @oledb_subscriber = 3 
	set @oracle_subscriber = 5 
	set @db2universal_subscriber = 6
	
	create table #subtype
    (
		type tinyint not null,   
    )

	create table #server_info 
	(
		providername nvarchar(256) collate database_default null,
		datasource nvarchar(3750) collate database_default null,			-- this column is nvarchar(4000) in sysservers, but we want to avoid info msg
												                            -- from create table when row size > 8060 bytes.
	)

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

	SELECT @cmd = 'select type from MSsubscriber_info where UPPER(subscriber) = ''' + UPPER(@subscriber) + ''' and UPPER(publisher) = ''' + @@servername + ''''
	
	insert into #subtype exec @distproc @cmd
	if (@@error <> 0 or @@rowcount <> 1)
	begin
		drop table #subtype
		drop table #server_info
		raiserror(14085, 16, -1)
		return 1
	end
	
	select @datasrctype = type from #subtype
	
	SELECT @cmd = 'select providername, datasource from master..sysservers where UPPER(srvname) = ''' + UPPER(@subscriber) + ''''
	
	insert into #server_info exec @distproc @cmd
	if (@@error <> 0 or @@rowcount <> 1)
	begin
		drop table #subtype
		drop table #server_info
		raiserror(14085, 16, -1)
		return 1
	end
	
	select @datasrc = datasource, @provider_name =  providername from #server_info
	
	/*
	** Jet and Oracle subscribers are actually added to MSsubscriber_info as OLE DB subscribers,
	** since they can be used in transactional replication also.
	** Map the type to Jet or Oracle based on OLE DB provider name.
	*/
	
	if (@datasrctype = @oledb_subscriber) 
	BEGIN
		if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'MICROSOFT.JET.OLEDB.4.0')
			select @datasrctype = @jet_subscriber
		else if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'MSDAORA')
			select @datasrctype = @oracle_subscriber
		else if (upper(@provider_name collate SQL_Latin1_General_CP1_CS_AS) = 'DB2OLEDB')
			select @datasrctype = @db2universal_subscriber
	END
    
	drop table #subtype
	drop table #server_info

	return 0
GO
exec dbo.sp_MS_marksystemobject sp_MSget_subtypedatasrc 
go
grant exec on dbo.sp_MSget_subtypedatasrc to public
go


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

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

CREATE PROCEDURE sp_addmergealternatepublisher (
    @publisher            		sysname,             		/* Publisher server */
    @publisher_db           	sysname,             		/* Publisher database */
    @publication                sysname,                    /* Publication name */
    @alternate_publisher	    sysname,                    /* Alternate publisher */
    @alternate_publisher_db     sysname,                    /* Alternate publisher_db */
    @alternate_publication		sysname,					/* Alternate publication */
    @alternate_distributor		sysname,					/* Alternate publisher's Distributor */
    @friendly_name				nvarchar(255)	= NULL,		/* Friendly Name for the association */
    @reserved       			nvarchar(20) = NULL			/* Reserved param for internal use only */
	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @retcode                int
    declare @pubid					uniqueidentifier
    declare @subid					uniqueidentifier
    declare @alternate_subid		uniqueidentifier
    declare	@description			nvarchar(255)
	declare	@allow_synctoalternate	bit
	declare @at_publisher			bit
    declare @subscriber_type        smallint

	set @at_publisher = 1
 	/*
    ** Security Check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)
    
	/*
	** Select the subscription's pubid and subid
	*/
    select @pubid = pubid, @allow_synctoalternate = allow_synctoalternate from sysmergepublications  
    	where name = @publication and publisher_db = @publisher_db and LOWER(publisher) = LOWER(@publisher)
    if @pubid is NULL
        begin
            raiserror (20026, 11, -1, @publication)
            return (1)
        end

	/* If this is an external call, make the AtPublisher and allows syncto alternate  check */
    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
    IF @@ERROR <> 0 or @retcode <>  0
    	set @at_publisher = 0
    	
    IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) <> 'internal'
    	begin
		    IF @at_publisher = 0
		        BEGIN
		            RAISERROR (21215, 16, -1)
		            RETURN (1)
		        END
		    if @allow_synctoalternate = 0
		        begin
		            raiserror (21502, 11, -1, @publication)
		            return (1)
		        end

    	end
    select @subid = subid from sysmergesubscriptions  
    	where LOWER(subscriber_server) = LOWER(@publisher) and db_name = @publisher_db and pubid = @pubid
	/*
	** Select the alternate publisher's subid 
	*/
    select @alternate_subid = subid, @subscriber_type = subscriber_type from sysmergesubscriptions
        where publication = @alternate_publication
        and LOWER(subscriber_server) = LOWER(@alternate_publisher) and db_name = @alternate_publisher_db
    IF @subid is NULL or @alternate_subid IS NULL
        BEGIN
			RAISERROR(21216, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
            RETURN (1)
        END
    IF @subscriber_type  <> 1
        BEGIN
			RAISERROR(21216, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
            RETURN (1)
        END

    IF @friendly_name IS NULL
    	begin
		    select @description = description from sysmergesubscriptions where subid = @alternate_subid
			if @description IS NULL
				begin
					select @description = formatmessage(21217, @alternate_publication, @alternate_publisher)
				end
				
		end	    		
	else
		select @description = @friendly_name


	if not exists (select * from MSmerge_altsyncpartners where subid = @subid and alternate_subid = @alternate_subid)
		begin
			insert into MSmerge_altsyncpartners(subid, alternate_subid, description)
				values(@subid, @alternate_subid, @description)
			if @@ERROR <> 0
			    BEGIN
				    GOTO FAILURE
			    END

			update sysmergesubscriptions set distributor = @alternate_distributor where subid = @alternate_subid
			if @@ERROR <> 0 or @@ROWCOUNT <> 1
			    BEGIN
				    GOTO FAILURE
			    END
		end			    
	if not exists (select * from MSmerge_altsyncpartners where subid = @alternate_subid and alternate_subid = @subid)
		begin
			insert into MSmerge_altsyncpartners(subid, alternate_subid, description)
				values(@alternate_subid, @subid, @description)
			if @@ERROR <> 0
			    BEGIN
				    GOTO FAILURE
			    END
		end			    
    return (0)

FAILURE:

	RAISERROR(21243, 11, -1,  @alternate_publisher, @alternate_publisher_db, @alternate_publication)
    RETURN (1)
    
go
exec dbo.sp_MS_marksystemobject sp_addmergealternatepublisher 
go
grant exec on dbo.sp_addmergealternatepublisher to public
go

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

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

CREATE PROCEDURE sp_MSgetpubinfo (
    @publication    sysname,    /* The publication name */
    @publisher		sysname,
    @pubdb			sysname
    ) AS

    SET NOCOUNT ON

	select pubid from sysmergepublications where name = @publication and
			LOWER(publisher) = LOWER(@publisher) and LOWER(publisher_db) = LOWER(@pubdb)
			
go
exec dbo.sp_MS_marksystemobject sp_MSgetpubinfo
go

grant execute on dbo.sp_MSgetpubinfo to public
go

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

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


create procedure sp_MSremove_userscript(
@pubid				uniqueidentifier,
@drop_publication	bit = 0
)as
	declare @retention			int
	declare @last_snapshot		datetime
	declare @post_snapshot_ver	int
	declare @post_snapshot_type	int
	declare @user_script_type	int
	declare @retcode			int
	declare @len				int

	declare @file_path			nvarchar(4000)
	declare @delfile_cmd		nvarchar(4000)
	declare @rmdir_cmd			nvarchar(4000)
	
	select @post_snapshot_type=52
	select @user_script_type=46
	
	if not exists (select * from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type)
		return (0)
	select @retention=retention from sysmergepublications where pubid=@pubid
	select @last_snapshot=last_validated from sysmergesubscriptions where pubid=@pubid and subid=@pubid

	--I do not want to remove  script files by setting retention to 0
	if (@retention=0 or dateadd(day, -@retention, getdate()) < @last_snapshot) and @drop_publication = 0
		return (0)

	select @post_snapshot_ver=schemaversion from sysmergeschemachange 
		where schematype=@post_snapshot_type and pubid=@pubid
		
	--only get those script that can be safely removed
	
	declare #per_script cursor local fast_forward for
		select schematext from sysmergeschemachange 
			where pubid=@pubid and schematype=@user_script_type 
			and (schemaversion<@post_snapshot_ver or @drop_publication = 1)
	open #per_script
	fetch #per_script into @file_path
	while (@@fetch_status<>-1)
	begin
	if(left(@file_path, 1) = N'0' or left(@file_path, 1) = N'1')
		select @file_path = right(@file_path, len(@file_path) - 1)
        select @delfile_cmd = N'del "' + @file_path + N'"'
        EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
		if @@ERROR<>0
			goto FAILURE
		select @len=CHARINDEX ( '\' , reverse(@file_path) ) 
		select @file_path=SUBSTRING(@file_path , 1 , len(@file_path)-@len + 1)
		
        select @delfile_cmd = N'rmdir "' + @file_path + N'"'
        EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
		if @@ERROR<>0
			goto FAILURE
		fetch next from #per_script into @file_path
	end
	
	close #per_script
	deallocate #per_script
	return (0)
FAILURE:
	close #per_script
	deallocate #per_script
	return (1)
go
EXEC dbo.sp_MS_marksystemobject 'sp_MSremove_userscript'
go
grant execute on sp_MSremove_userscript to public
go

--------------------------------------------------------------------------------
--.	Merge Replication objects (rlcore.sql)
--------------------------------------------------------------------------------

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

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

raiserror('Creating procedure sp_MSdrop_rlcore', 0,1)
GO
create procedure sp_MSdrop_rlcore
as

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

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

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

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

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

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

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

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

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

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

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

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSrefcnt')
		drop procedure sp_MSrefcnt
	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSgentablenickname')
		drop procedure sp_MSgentablenickname
	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MStablenickname')
		drop procedure sp_MStablenickname
	
	if exists (select * from sysobjects
		where type = 'P'
			and name = 'sp_MStablenamefromnick')
		drop procedure sp_MStablenamefromnick

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

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

	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSmakegeneration')
		drop procedure sp_MSmakegeneration
	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSfixlineageversions')
		drop procedure sp_MSfixlineageversions
	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSaddupdatetrigger')
		drop procedure sp_MSaddupdatetrigger
	
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSaddmergetriggers')
		drop procedure sp_MSaddmergetriggers
	
	if exists (select * from sysobjects
				where type = 'P' and
				name = 'sp_MSmaptype')
		drop procedure sp_MSmaptype 

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

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

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

	if exists( select * from sysobjects where type = 'P ' and name = 'sp_mergemetadataretentioncleanup')
	begin
		drop procedure sp_mergemetadataretentioncleanup
	end
go
exec dbo.sp_MS_marksystemobject sp_MSdrop_rlcore
go

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

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

create procedure sp_MSsethighestversion (@artnick int)
as
	set nocount on
	declare @minlineagelength int
	set @minlineagelength= 8

	declare @maxversion int
	declare @maxversiontombstone int

	set @maxversion= (select max({fn GETMAXVERSION(mc.lineage)}) 
			from MSmerge_contents as mc inner join #oldgens as og on (mc.generation = og.gen) where
				tablenick = @artnick and
				lineage is not null and
				datalength(lineage) >= @minlineagelength)
	if @@error<>0 goto Failure

	set @maxversiontombstone= (select max({fn GETMAXVERSION(mt.lineage)}) 
			from MSmerge_tombstone as mt inner join #oldgens as og on (mt.generation = og.gen) where
				tablenick = @artnick and
				lineage is not null and
				datalength(lineage) >= @minlineagelength)
	if @@error<>0 goto Failure

	if @maxversion is null
	begin
		set @maxversion= @maxversiontombstone
	end

	if @maxversiontombstone is not null and @maxversiontombstone > @maxversion
	begin
		set @maxversion= @maxversiontombstone
	end

	if @maxversion is not null
	begin
		update sysmergearticles set maxversion_at_cleanup= @maxversion where
			nickname = @artnick and
			maxversion_at_cleanup < @maxversion
		if @@error<>0 goto Failure
	end

	return 0

Failure:
	return 1
go
exec dbo.sp_MS_marksystemobject sp_MSsethighestversion
go
grant execute on dbo.sp_MSsethighestversion to public
go

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

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

create procedure sp_mergemetadataretentioncleanup
	(@num_genhistory_rows int = 0 output, 
	 @num_contents_rows int = 0 output, 
	 @num_tombstone_rows int = 0 output)
as
	declare @maxretention int
	declare @artnick int
	declare @gen int
	declare @retcode smallint
	declare @bi_objid int
	declare @cmd nvarchar(200)
	declare @guidnull uniqueidentifier
	declare @delbatchsize int
	declare @delcount int
   	declare @applockname nvarchar(255)

	set @num_genhistory_rows= 0
	set @num_contents_rows= 0
	set @num_tombstone_rows= 0

	-- if somebody else is already cleaning up in this database, we simply return
   	set @applockname= 'MS_sp_mergemetadataretentioncleanup' + convert(nvarchar(11), db_id())
	exec @retcode= sp_getapplock @Resource= @applockname, @LockMode= 'Exclusive', @LockOwner= 'Session', @LockTimeout= 0 
	if @@error <> 0 or @retcode < 0 return (0)
	
	set @guidnull= '00000000-0000-0000-0000-000000000000'
	set @delbatchsize= 5000

	create table #oldgens (gen int unique clustered)

	-- iterate over all articles that do not belong to a publication with infinite retention
	declare article_curs cursor local fast_forward for 
		select distinct nickname from sysmergearticles where 
			nickname not in (select distinct a.nickname from sysmergearticles as a inner join sysmergepublications as p on (a.pubid = p.pubid) 
								where p.retention = 0)

	open article_curs
	fetch next from article_curs into @artnick

	while (@@fetch_status <> -1)
	begin
		-- find max retention of all pubs the article belongs to
		select @maxretention= max(retention) from sysmergepublications where
								pubid in (select pubid from sysmergearticles where nickname = @artnick)
		-- add one to make up for maximal possible timezone differences, plus one to compensate for clock inaccuracies
		set @maxretention= @maxretention + 1

		delete from #oldgens
		insert into #oldgens select distinct generation from MSmerge_genhistory where
	 							art_nick = @artnick and
								guidlocal <> @guidnull and
								coldate < dateadd(day, -@maxretention, getdate())

		-- go to next article if this one has no stale generations
		if @@rowcount = 0
		begin
			fetch next from article_curs into @artnick
			continue
		end

		-- set highest version in sysmergearticles
		exec @retcode= sp_MSsethighestversion @artnick= @artnick
		if @retcode<>0 or @@error<>0 goto Failure

		-- clean up contents, tombstone, before image (if it exists), genhistory
		set rowcount @delbatchsize
		set @delcount= @delbatchsize
		while @delcount = @delbatchsize
		begin
			delete mc from MSmerge_contents as mc inner join #oldgens as og on (mc.generation = og.gen) where mc.tablenick = @artnick
			set @delcount= @@rowcount
			set @num_contents_rows= @num_contents_rows + @delcount
		end

		set @delcount= @delbatchsize
		while @delcount = @delbatchsize
		begin
			delete mt from MSmerge_tombstone as mt inner join #oldgens as og on (mt.generation = og.gen) where tablenick = @artnick
			set @delcount= @@rowcount
			set @num_tombstone_rows= @num_tombstone_rows + @delcount
		end

		set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @artnick)
		if @bi_objid is not null
		begin
			set @cmd= 'delete bi from ' + object_name(@bi_objid) + ' as bi inner join #oldgens as og on (bi.generation = og.gen)'
			set @delcount= @delbatchsize
			while @delcount = @delbatchsize
			begin
				exec dbo.sp_executesql @cmd
				set @delcount= @@rowcount
			end
		end

		set @delcount= @delbatchsize
		while @delcount = @delbatchsize
		begin
			delete gh from MSmerge_genhistory as gh inner join #oldgens as og on (gh.generation = og.gen) where art_nick = @artnick
			set @delcount= @@rowcount
			set @num_genhistory_rows= @num_genhistory_rows + @delcount
		end

		set rowcount 0

		-- get next article
		fetch next from article_curs into @artnick
	end

	close article_curs
	deallocate article_curs
	drop table #oldgens
	exec @retcode= sp_releaseapplock @Resource= @applockname, @LockOwner= 'Session'
	if @@error <> 0 or @retcode < 0
		return (1)
	else
		return (0)

Failure:
	close article_curs
	deallocate article_curs
	drop table #oldgens
	exec sp_releaseapplock @Resource= @applockname, @LockOwner= 'Session'
	return (1)

go
exec dbo.sp_MS_marksystemobject sp_mergemetadataretentioncleanup
go
grant execute on dbo.sp_mergemetadataretentioncleanup to public
go


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

create procedure sp_MSgetmakegenerationapplock
	@head_of_queue int OUTPUT
	as
	set nocount on

	declare @retcode smallint
   	declare @lock_resource nvarchar(255)

   	select @retcode = 0
	select @head_of_queue = 0
	
	select @lock_resource = N'MSinternal_makegeneration_inprogress' + 
				convert(nvarchar(11), db_id())

	
	-- If someone else is making generations / has just made one, exit so
	-- that we won't deadlock
	exec @retcode = sp_getapplock @Resource = @lock_resource,
                                  @LockMode = N'Exclusive',
                                  @LockOwner = N'Session',
                                  @LockTimeout = 0 -- do not wait at all. 

	if @@error <> 0 or @retcode < 0
    begin
		-- If the previous applock request timed out, then try again, this time using the default timeout.
		-- Note that even though the -1 lock timeout means indefinite timeout, the query timeout set on the 
		-- session overrides the lock timeout. So it's okay even if the default @@lock_timeout is -1.
		if (@retcode = -1)
		begin
			exec @retcode = sp_getapplock @Resource = @lock_resource,
                        @LockMode = N'Exclusive',
                        @LockOwner = N'Session'
			-- If we succeeded to get the lock, set @lock_acquired to 1 so that the exit code releases the lock.
			if (@retcode >= 0)
			begin
				goto EXIT_PROC
			end
		end
    end
    else
	begin
		select @head_of_queue = 1
	end

EXIT_PROC:
	return @retcode

go

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



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

create procedure sp_MSreleasemakegenerationapplock
	as
	set nocount on

	declare @retcode smallint
   	declare @lock_resource nvarchar(255)

   	select @retcode = 0
	select @lock_resource = N'MSinternal_makegeneration_inprogress' + 
				convert(nvarchar(11), db_id())

   	exec @retcode = sp_releaseapplock @Resource = @lock_resource, @LockOwner = N'Session'
   	if @@error <> 0 or @retcode < 0
		return (1)	
	else
		return (0)
				
go
exec dbo.sp_MS_marksystemobject sp_MSreleasemakegenerationapplock 
go
grant exec on dbo.sp_MSreleasemakegenerationapplock to public
go


--------------------------------------------------------------------------------
--. sp_MSmakegeneration 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSmakegeneration')
    drop procedure sp_MSmakegeneration
go
raiserror('Creating procedure sp_MSmakegeneration', 0,1)
GO
create procedure sp_MSmakegeneration
	@gencheck int = 0
	as
	set nocount on

	declare @gen int
	declare @nick int
	declare @genguid uniqueidentifier
	declare @dt datetime
	declare @dt2 datetime
	declare @art_nick int
	declare @first_ts int
	declare @makenewrow bit
	declare @retcode smallint
	declare @guidnull uniqueidentifier
	declare @nickbin varbinary(255)
	declare @maxgendiff_fornewrow int
	declare @count_of_articles int
	declare @lock_acquired bit
   	declare @lock_resource nvarchar(255)
	declare @procfailed bit
	declare @delete_old_genhistory bit
	declare @close_old_genhistory bit
		
	select @procfailed = 1
   	select @retcode = 0

	set @guidnull = '00000000-0000-0000-0000-000000000000'
		
	/*
	** Check to see if current publication has permission
	*/
	exec @retcode=sp_MSreplcheck_connection
	if @retcode<>0 or @@ERROR<>0 goto EXIT_PROC
	
	set @genguid = newid()
	exec @retcode=sp_MSgetreplnick @nickname = @nick out
	if @retcode<>0 or @@error<>0 goto EXIT_PROC

	-- convert @nick into binary and add a guard byte if needed
	if @nick % 256 = 0
		set @nickbin = convert(binary(4), @nick) + 0x01
	else
		set @nickbin = convert(binary(4), @nick)

	select @dt2 = max(coldate) from dbo.MSmerge_genhistory where guidsrc = guidlocal
	set @dt = getdate()

	if datediff(dd, @dt2, @dt) = 0
	begin
		if 500 > datediff(ms, @dt2, @dt) and 0 < datediff(ms, @dt2, @dt)
		begin
			select @procfailed = 0
			goto EXIT_PROC
		end
	end

	-- localize interrupted generations
	exec @retcode= sp_MSlocalizeinterruptedgenerations
	if @retcode<>0 or @@error<>0 goto EXIT_PROC

	-- If @gencheck param is set to 1 ( = ForceConvergence), look for rows with missing generation numbers and set their
	-- gen to 0
	if @gencheck = 1 or @gencheck = 2
	begin
		update dbo.MSmerge_contents set generation = 0 where generation not in
			(select generation from dbo.MSmerge_genhistory)
		update dbo.MSmerge_tombstone set generation = 0 where generation not in
			(select generation from dbo.MSmerge_genhistory)
	end
	/*
	** If there are no zero generation tombstones or rows, add a dummy row in there. 
	*/
   	if not exists (select * from dbo.MSmerge_genhistory)
	begin
	   	insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
			(@genguid, @genguid, 1, 0, @nickbin, @dt)
		if (@@error <> 0) goto EXIT_PROC
	end

	select @art_nick = min(nickname), @count_of_articles = count(*) from sysmergearticles

	-- Calculate how much less than the max generation in MSmerge_genhistory are we willing to have the minimum open generation in MSmerge_genhistory.
	-- Having a number smaller than or roughly equal to the number of articles will cause more aggressive closing of existing open gens (and making new rows) with 0 changes
	-- and hence more generations for merge agents to deal with. Having a very high number will cause less aggressive closing of open gens but will cause the
	-- common gens of replicas to be stuck at lower numbers because of the existence of "holes" at much lower gen values. An optimization that works well
	-- and is a compromise between the two extremes is to have the max of 100 or (2 * @count_of_articles) + 1 as the max diff we allow before deciding to make a new row.
	if ((2 * @count_of_articles) + 1) > 100
		select @maxgendiff_fornewrow = (2 * @count_of_articles) + 1
	else
		select @maxgendiff_fornewrow = 100

	while @art_nick is not null
	begin
		declare @cmd nvarchar(200)
		declare @old_bi_gen int
		declare @bi_objid int

		set @old_bi_gen= NULL -- if @old_bi_gen stays NULL: no need to move bi-rows
		set @bi_objid= NULL
		set @delete_old_genhistory = 0
		set @close_old_genhistory = 0
		set @makenewrow = 0
		
		set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @art_nick)
		if @bi_objid is not null
		begin
			set @cmd= 'update dbo.' + object_name(@bi_objid) + ' set generation= @gen where generation = @oldgen'
		end
		
		begin tran
		save tran sp_MSmakegeneration
		select @gen = max(gen_cur) from sysmergearticles (updlock holdlock) where nickname = @art_nick and gen_cur is not null

		-- if either we have no gen_cur set yet, or if we have one but no corresponding genhistory row or we have a closed one which
		-- was bcp-ed in after a reinit, we need to create a new one.
		if @gen is null or 
			(	@gen is not null 
				and not exists (select generation from dbo.MSmerge_genhistory where generation = @gen and guidlocal = @guidnull)
			)
		begin
			declare @oldgen int
			declare @maxgencur int

			set @genguid = newid()
			set @oldgen = @gen

			select @gen = COALESCE(1 + max(generation), 1) from dbo.MSmerge_genhistory (updlock)
			
			-- Make sure that the new generation value is not smaller than any existing sysmergearticles.gen_cur.
			select @maxgencur = isnull(max(gen_cur),0) from sysmergearticles where gen_cur is not null

			if (@gen <= @maxgencur)
			begin
				set @gen = @maxgencur + 1
				-- Now we are guaranteed to not collide with an existing gen_cur
			end
			
			insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
				values(@genguid, @guidnull, @gen, @art_nick, @nickbin, @dt)
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
			
			update sysmergearticles set gen_cur = @gen where nickname = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	

			-- if this was the case of a gen_cur with no matching genhistory rows, then update the contents and tombstones rows with the new generation value.
			if @oldgen is not null
			begin
				update dbo.MSmerge_contents set generation = @gen, partchangegen = @gen, joinchangegen = @gen
			 		where generation = @oldgen and partchangegen = @oldgen and tablenick = @art_nick
				if (@@error <> 0)
				begin
					goto EXIT_RELEASE_TRAN
				end	
				update dbo.MSmerge_contents set generation = @gen, joinchangegen = @gen
				 	where generation = @oldgen and joinchangegen = @oldgen and tablenick = @art_nick
				if (@@error <> 0)
				begin
					goto EXIT_RELEASE_TRAN
				end	
				update dbo.MSmerge_contents set generation = @gen where generation = @oldgen and tablenick = @art_nick
				if (@@error <> 0)
				begin
					goto EXIT_RELEASE_TRAN
				end
				update dbo.MSmerge_tombstone set generation = @gen where generation = @oldgen and tablenick = @art_nick
				if (@@error <> 0)
				begin
					goto EXIT_RELEASE_TRAN
				end

				if @bi_objid is not null
				begin
					exec dbo.sp_executesql @cmd, N'@gen int, @oldgen int', @gen= @gen, @oldgen= @oldgen
					if @@ERROR <> 0 goto EXIT_RELEASE_TRAN
				end
			end
		end
			
		-- these updates should be hitting zero rows...
		if exists (select * from dbo.MSmerge_contents (readpast readcommitted) where generation = 0 and tablenick = @art_nick)
		begin
			update dbo.MSmerge_contents set generation = @gen, partchangegen = @gen, joinchangegen = @gen
			 	where generation = 0 and partchangegen = 0 and tablenick = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
			update dbo.MSmerge_contents set generation = @gen, joinchangegen = @gen
			 	where generation = 0 and joinchangegen = 0 and tablenick = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
			update dbo.MSmerge_contents set generation = @gen where generation = 0 and tablenick = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end
		end
			
		if exists (select * from dbo.MSmerge_tombstone (readpast readcommitted) where generation = 0 and tablenick = @art_nick)
		begin
			update dbo.MSmerge_tombstone set generation = @gen where generation = 0 and tablenick = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end
		end
		if not exists (select * from dbo.MSmerge_contents where tablenick = @art_nick and
						generation = @gen) and
		   not exists (select * from dbo.MSmerge_tombstone where tablenick = @art_nick and
						generation = @gen)
		begin

			select @dt2 = coldate from dbo.MSmerge_genhistory where generation = @gen
			if datediff(dd, @dt2, @dt) = 0 and not exists (select * from dbo.MSmerge_genhistory
					where generation > @maxgendiff_fornewrow + @gen)
			begin
				-- If @gencheck param is set to 3 (= OverrideMakeNewGenerations), set the @makenewrow flag
				-- This is done for message based merges to ensure that the incomplete gens always get closed
				-- during every merge if there are completed generations > than this one.
				if @gencheck = 3 and exists (select * from dbo.MSmerge_genhistory
						where generation > @gen and guidlocal <> @guidnull)
				begin
					set @makenewrow = 1
					set @old_bi_gen= @gen -- we will move bi-rows
					set @delete_old_genhistory = 1
				end						
				else
				begin
					set @makenewrow = 0
					set @delete_old_genhistory = 0
				end						
			end
			else
			begin
				set @makenewrow = 1
				set @old_bi_gen= @gen -- we will move bi-rows
				set @delete_old_genhistory = 1
			end
		end
		else
		begin
			set @makenewrow = 1
			set @delete_old_genhistory = 0	-- don't delete existing genhistory row. just mark it as closed.
			set @close_old_genhistory = 1
		end

		if (@makenewrow = 1)
		begin
			declare @newgen int

			/* reset next generation for this article */
			set @genguid = newid()
			insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) 
				select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @art_nick, @nickbin, @dt from dbo.MSmerge_genhistory (updlock)
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
			select @newgen  =  generation  from dbo.MSmerge_genhistory where guidsrc = @genguid
			update sysmergearticles set gen_cur = @newgen where nickname = @art_nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	

			if @bi_objid is not null and @old_bi_gen is not NULL
			begin
				exec dbo.sp_executesql @cmd, N'@gen int, @oldgen int', @gen = @newgen, @oldgen = @old_bi_gen
				if @@ERROR <> 0 goto EXIT_RELEASE_TRAN
			end
		end

		if (@delete_old_genhistory = 1)
		begin
			declare @error int
			declare @genhistory_rowsdeleted int

			-- delete the old genhistory row only if there still aren't any rows in contents or 
			-- tombstone with this generation value. Note that after the previous update statement on sysmergearticles
			-- no new spids can take locks on sysmergearticles and hence cannot 
			-- insert any new rows with the old gen_cur.
			delete from dbo.MSmerge_genhistory 
			where generation = @gen
			and not exists (select * from dbo.MSmerge_contents where tablenick = @art_nick and generation = @gen) 
			and not exists (select * from dbo.MSmerge_tombstone where tablenick = @art_nick and generation = @gen)

			select @genhistory_rowsdeleted = @@rowcount, @error = @@error

			-- If the genhistory row which we previously thought could be deleted, now has changes in contents or 
			-- tombstone, it's okay to not delete it and still leave it as open. In future this open generation
			-- will be treated as an interrupted generation and the changes in it will be moved to a new local 
			-- generation. So there will be convergence. Deleting the genhistory row based on incorrect past determination
			-- of 0 changes is dangerous and can easily cause non-convergence.
			-- The best solution is to close this generation if we finally didn't delete it. The reason is that it
			-- allows subscribers to move their last received watermark higher than this open generation.
			if @genhistory_rowsdeleted = 0
			begin
				set @close_old_genhistory = 1
			end

			if (@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
		end

		if (@close_old_genhistory = 1)
		begin
			set @genguid = newid()
			update dbo.MSmerge_genhistory set guidsrc = @genguid, guidlocal = @genguid, coldate = @dt
				where generation = @gen
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
			update MSmerge_replinfo set recgen = @gen, recguid = @genguid, 
				sentgen = @gen, sentguid = @genguid where replnickname = @nick
			if (@@error <> 0)
			begin
				goto EXIT_RELEASE_TRAN
			end	
		end

		commit transaction		

		-- set up for next time through the loop
		select @art_nick = min(nickname) from sysmergearticles where nickname > @art_nick
		
		set @dt = getdate()
	end

	select @procfailed = 0
		
EXIT_RELEASE_TRAN:

	if (@procfailed = 1)
	begin
		rollback tran sp_MSmakegeneration
		commit transaction
	end

EXIT_PROC:

	if (@procfailed = 1)
		return (1)	
	else
		return (0)
go

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

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

CREATE PROCEDURE sp_MSaddupdatetrigger 
	@source_table		nvarchar(270),		/* source table name */
	@owner				sysname,			/* Owner name of source table */
	@object 			sysname,			/* Object name */
	@artid				uniqueidentifier,	/* Article id */
	@column_tracking		int,
	@viewname			sysname 			/* name of view on syscontents */
    
AS
	declare @command1 nvarchar(4000)
	declare @command2 nvarchar(4000)
	declare @command3 nvarchar(4000)
    declare @command4 nvarchar(4000)
	declare @inscommand nvarchar(2000)
	declare @tablenick int	
	declare @nickname int
	declare @viewcols int
	declare @trigname sysname
	declare @ext nvarchar(10)
	declare @gstr sysname
	declare @tablenickchar nvarchar(11)
	declare @ccols int
	declare @guidstr	nvarchar(32)
	declare @colid smallint
	declare @colordinal		smallint
	declare @colordstr		varchar(4)

	declare @colname 	sysname
	declare @cur_name	sysname
	declare @colpat nvarchar(130)
	declare @colchar nvarchar(5)
	declare @piece nvarchar(400)

	declare @retcode int
	declare @ifcol nvarchar(4000)
	declare @ccolchar nvarchar(5)
	declare @partchangecnt int
	declare @joinchangecnt int
	declare @partchangecnt2 int
	declare @cvstr1	nvarchar(500)
	declare @cvstr2 nvarchar(500)
	declare @flag smallint
	declare @missingbm varbinary(500)
	declare @missing_cols	varbinary(32)
	declare @mapdownbm varbinary(500)
	declare @mapupbm   varbinary(500)
	declare @missingcolid int
	declare @maxcolid int
	declare @missingbmstr varchar(1000)
	declare @mapdownbmstr varchar(1000)
	declare @mapupbmstr   varchar(1000)
	declare @objid int
	declare @sync_objid int
	declare @partchbm varbinary(500)
	declare @missing_col_count	int
	declare @excluded_col_count int
	declare @joinchbm varbinary(500)
	declare @partchstr varchar(1002)
	declare @joinchstr varchar(1002)
	declare @column_hole bit
	declare @notforrepl_bit bit
	declare @notforrepl_str nvarchar(200)
	declare @owner_is_admin bit
	
	set @notforrepl_bit = 1
	set @ifcol = ''
	set @column_hole = 0
	set @owner_is_admin = 0
	
	select @owner_is_admin=sysadmin from master..syslogins l, sysusers u where l.sid=u.sid and u.name=@owner collate database_default
	select @flag = 0
	set @objid = OBJECT_ID(@source_table)
	select @sync_objid = sync_objid, @missing_cols = missing_cols, @excluded_col_count = excluded_col_count,
									@missing_col_count=missing_col_count 
					from sysmergearticles where artid= @artid and objid=@objid
	select @ccols =  count(*) from syscolumns where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp'
	/* Figure out if there are any holes in the colid sequence */
	select @maxcolid = max(colid) from syscolumns where id = @objid
	if @ccols <> @maxcolid
		select @column_hole = 1
	/*
	** adjust the number of columns in the original table by adding up missing columns; in both Pub/Sub sides.
	*/
	if @missing_col_count>0
		select @ccols = @ccols + @missing_col_count
	select @ccolchar = convert(nchar, @ccols)
	set @colordinal = 0
	
	execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
	if @@ERROR<>0 or @retcode<>0 return (1)
	set @tablenickchar = convert(nchar, @tablenick)
	set @joinchbm = 0x0
	set @partchbm = 0x0

	-- Check if the update trigger can be made NOT FOR REPLICATION
	if exists (select * from sysmergearticles 
			   where nickname = @tablenick 
			   and
			   (before_image_objid is not null or
			    before_view_objid is not null or
			    datalength (subset_filterclause) > 1
			   ))
	begin
		select @notforrepl_bit = 0
	end
	else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick or join_nickname = @tablenick)
	begin
		select @notforrepl_bit = 0
	end
	else
	begin
		select @notforrepl_bit = 1
	end
	
	select @notforrepl_str = ' 
	if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1 -- and master.dbo.fn_isreplmergeagent() = 1
		return '
		
	declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, colid from syscolumns where
		id = @objid  and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
	FOR READ ONLY
	
	/* Try to set the ifcol pieces of the trigger */
	open col_cursor
	fetch next from col_cursor into @colname, @colid
	while (@@fetch_status <> -1)
		begin
		set @colordinal = @colordinal + 1
		set @colpat = '%' + @colname + '%'
		/* Don't let them update the rowguid column */
		if columnproperty( @objid, @colname , 'isrowguidcol')=1
			set @ifcol = 'if update(' + QUOTENAME(@colname) +	')
			begin
			if @@trancount > 0
				rollback tran
				
			RAISERROR (20062, 16, -1)
			end
				'
		/* does updating this column change membership in a partial replica? */
		select @partchangecnt = count(*) from sysmergearticles 
			where nickname = @tablenick and subset_filterclause like @colpat
		select @partchangecnt2 = count(*) from sysmergesubsetfilters
			where art_nickname = @tablenick and join_filterclause like @colpat
		select @joinchangecnt = count(*) from sysmergesubsetfilters
		 	where join_nickname = @tablenick and join_filterclause like @colpat
		if @partchangecnt > 0 or @partchangecnt2 > 0
			exec dbo.sp_MSsetbit @partchbm out, @colid
		else if @joinchangecnt > 0
			exec dbo.sp_MSsetbit @joinchbm out, @colid
		/* Repeat the loop with next column */
		fetch next from col_cursor into @colname, @colid
		end
	close col_cursor
	deallocate col_cursor

	-- Initialize string for inserting to before_image table
	exec sp_MSgetbeforetableinsert @objid, @inscommand output

	/* Make strings to initialize variables for partchange, joinchange bitmaps */
	exec master..xp_varbintohexstr @partchbm, @partchstr out
	exec master..xp_varbintohexstr @joinchbm, @joinchstr out

	select @mapdownbm =0x00
	select @mapupbm = 0x00
	/*
	** To see if there is a need for map down.
	*/
	if @column_hole<>0
	begin
		set @missingcolid = 1
		while (@missingcolid <= @maxcolid)
			begin
			if not exists (select * from syscolumns where colid = @missingcolid and
						id = OBJECT_ID(@source_table) and iscomputed <> 1 and type_name(xtype) <> 'timestamp')
					exec dbo.sp_MSsetbit @mapdownbm out, @missingcolid
			set @missingcolid = @missingcolid + 1
			end
	end
	set @mapupbm = @missing_cols -- do this at both sides, good for republishing.
	
	exec master..xp_varbintohexstr @mapdownbm, @mapdownbmstr out
	exec master..xp_varbintohexstr @mapupbm, @mapupbmstr out
	
	execute @retcode=sp_MSgetreplnick @nickname = @nickname output
	if @retcode<>0 or @@error<>0 return (1)
	set @ext = 'upd_'

	exec @retcode=sp_MSguidtostr @artid, @guidstr out
	if @retcode<>0 or @@error<>0 return (1)

	set @trigname =  @ext + @guidstr 

	/* Make sure trigger name is unique */
	exec @retcode=sp_MSuniqueobjectname @trigname, @trigname output
	if @retcode<>0 or @@error<>0 return (1)
	if @column_tracking <> 0
		begin
		/* Set cv pieces appropriately */
		set @cvstr1 = ' 
		    set @lineage = { fn UPDATELINEAGE(0x0, @nick, @oldmaxversion+1) }
		    set @cv = { fn INITCOLVS(@ccols, @nick) }
			if (@@error <> 0)
				begin
				goto FAILURE
				end
		    set @cv = { fn UPDATECOLVBM(@cv, @nick, @bm, @missingbm, { fn GETMAXVERSION(@lineage) }) }
		'
		set @cvstr2 = '
				colv1 = { fn UPDATECOLVBM(colv1, @nick, @bm, @missingbm, { fn GETMAXVERSION({ fn UPDATELINEAGE(lineage, @nick, @oldmaxversion+1) }) }) } '
		end
	else
		begin
		set @cvstr1 = '   set @lineage = { fn UPDATELINEAGE(0x0, @nick, @oldmaxversion+1) }
			set @cv = NULL
 	'
		set @cvstr2 = ' colv1 = NULL '
		end
	/* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */
	select @command1 = 'create trigger ' + @trigname + ' on ' + @source_table +
	' FOR UPDATE AS '

	if (@notforrepl_bit = 1)
		select @command1 = @command1 + @notforrepl_str

	select @command1 = @command1 + ' 
	/* Declare variables */

	declare @article_rows_updated int
	select @article_rows_updated = count(*) from inserted
	declare @contents_rows_updated int, @updateerror int
	declare @bm varbinary(500), @missingbm varbinary(500), @lineage varbinary(255), @cv varbinary(2048)
	declare @tablenick int, @nick int, @ccols int, @partchange int, @joinchange int
	declare	@partchangebm varbinary(500), @joinchangebm varbinary(500)
	declare @oldmaxversion int
		
	set nocount on
	set @tablenick = ' + @tablenickchar + '
	select @oldmaxversion= maxversion_at_cleanup from sysmergearticles where nickname = @tablenick
	
	/* Use intrinsic funtion to set bits for updated columns */
	set @bm = columns_updated()

	/* only do the map down when needed */
	set @missingbm = ' 

	select @command2 = '  

	/* See if the partition might have changed */
	if @partchangebm = 0x0
		set @partchange = 0
	else
		set @partchange= { fn INTERSECTBITMAPS (@bm, @partchangebm) }
	
	/* See if a column used in a join filter changed */
	if @joinchangebm = 0x0
		set @joinchange = 0
	else
		set @joinchange= { fn INTERSECTBITMAPS (@bm, @joinchangebm) }
	'

	if @mapdownbm<>0x00
		select @command2 = @command2 + 
				' execute master..xp_mapdown_bitmap ' + @mapdownbmstr +', @bm output '

	select @command2 = @command2 + '

	exec dbo.sp_MSgetreplnick @nickname = @nick output
	select @ccols = ' + @ccolchar + '
	' + @cvstr1 + '
		' 
	set @command3 = '

	update ' + @viewname + ' 
	set lineage = { fn UPDATELINEAGE(lineage, @nick, @oldmaxversion+1) }, 
		generation = A.gen_cur, 
		joinchangegen = case when (@joinchange = 1) then A.gen_cur else joinchangegen end, 
		partchangegen = case when (@partchange = 1) then A.gen_cur else partchangegen end, 
		' + @cvstr2 + ' 
	FROM inserted as I JOIN ' + @viewname + ' as V 
	ON (I.rowguidcol=V.rowguid)
	and V.tablenick = @tablenick
	JOIN (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as A
	ON V.tablenick = A.nickname

	select @updateerror = @@error, @contents_rows_updated = @@rowcount

	 ' + isnull(@inscommand, ' ') + ' 
	
	if @article_rows_updated <> @contents_rows_updated
	begin

		insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, partchangegen, joinchangegen) 
			select @tablenick, rowguidcol, @lineage, @cv, A.gen_cur, 
			case when (@joinchange = 1 or @partchange = 1) then A.gen_cur else NULL end, 
			case when @joinchange = 1 then A.gen_cur else NULL end
			from inserted,
			(select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as A
			where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick)

		if @@error <> 0
			GOTO FAILURE
	end

	return
FAILURE:
				if @@trancount > 0
					rollback tran
				raiserror (20041, 16, -1)
				return
					'
			
	execute (@command1 + @mapupbmstr + '
		set @partchangebm = ' + @partchstr + '
		set @joinchangebm = ' + @joinchstr + '
			' + @ifcol +  
			@command2 + @command3)
	if @@ERROR <> 0 
		begin
			raiserror(20064, 16, -1)
			return (1)
		end
	
    select @command4 = 'sp_MS_marksystemobject ''' + REPLACE(@owner, '''', '''''') + '.' + @trigname + ''''
	if @owner_is_admin=1
		execute (@command4)		
GO

exec dbo.sp_MS_marksystemobject sp_MSaddupdatetrigger
go

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

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

CREATE PROCEDURE sp_MSaddmergetriggers 
    @source_table 		nvarchar(270),				/* was type varchar(92), table name */
    @table_owner		sysname = NULL,
    @column_tracking 	int = NULL				/* Is column tracking on - default is FALSE */
AS
	set nocount on
	declare @command		nvarchar(4000)
	declare @command2 nvarchar(4000)
	declare @inscommand nvarchar(2000)
	declare @ifcoltracking 	nvarchar(255)
	declare @tablenick 		int	
	declare @nickname 		int
	declare @artid 			uniqueidentifier
	declare @guidstr		nvarchar(32)
	declare @owner 			sysname
	declare @site 			sysname
	declare @db 			sysname
	declare @object 		sysname
	declare @updtrigname 		sysname
	declare @instrigname 		sysname
	declare @deltrigname 		sysname
	declare @ext 				nvarchar(10)
	declare @ext2 				nvarchar(10)
	declare @tablenickchar 		nvarchar(11)
	declare @missing_col_count	int
	declare @ccols 			int
	declare @ccolchar 		nvarchar(5)
	declare @retcode 		int
	declare @objid			int
	declare @bitmap 		varbinary(40)
	declare @missing_count	int
	declare @viewname		sysname
	declare @tsview			sysname
	declare @sync_objid		int
    declare @command3       nvarchar(4000)
	declare @notforrepl_str	nvarchar(200)
	declare @notforrepl_bit bit
	declare @owner_is_admin bit
	
	set @notforrepl_bit = 1
	set @owner_is_admin = 0
	set @bitmap = 0x0
	set @missing_count = 0

    -- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
    -- END PARSENAME VARS

	execute @retcode=sp_MSgetreplnick @nickname = @nickname output
	if @retcode<>0 or @@ERROR<>0 return (1)

	select @ext = 'ins_'
	select @ext2 = 'del_'
	if @table_owner is not NULL
		select @source_table=QUOTENAME(@table_owner) + '.' + QUOTENAME(@source_table)
	set @objid =  OBJECT_ID(@source_table)

	-- set up the before image table if one is desired
	exec dbo.sp_MScreatebeforetable @objid

	-- Initialize string for inserting to before_image table
	exec sp_MSgetbeforetableinsert @objid, @inscommand output

	select @ccols =  count(*) from syscolumns where id = @objid  and iscomputed <> 1 and type_name(xtype) <> 'timestamp'
	select @missing_col_count=missing_col_count, @sync_objid=sync_objid from sysmergearticles where objid=@objid
	/*
	** increase the # of columns at subscriber side by adding the missing columns
	** Note that publisher side also needs to increase this value due to the possible column holes.
	*/
	select @ccols = @ccols + @missing_col_count
	select @ccolchar = convert(nchar, @ccols)

    select @UnqualName = PARSENAME(@source_table, 1)
    select @QualName1 = PARSENAME(@source_table, 2)
    if @UnqualName IS NULL
         return 1

    if @QualName1 is NULL
 		select @QualName1 = user_name(uid) from sysobjects where id = object_id(@UnqualName)

	-- fixup for variable length differences.  remove when vars expanded
	-- to new SQL SERVER 7.0 lengths

	select @owner = @QualName1
	select @object = @UnqualName

	--this is to find out if table owner is a system user
	select @owner_is_admin=sysadmin from master..syslogins l, sysusers u where l.sid=u.sid and u.name=@owner collate database_default
		
	execute @retcode=sp_MStablenickname @owner, @object, @tablenick output
	if @retcode<>0 or @@ERROR<>0 return (1)
	select @artid = artid from sysmergearticles 
		where objid = @objid
		
	/* If column tracking wasn't passed in, just figure it out */
	if @column_tracking is null
		select @column_tracking = column_tracking from sysmergearticles 
		where artid = @artid
		
	select @tablenickchar = convert(nchar, @tablenick)
	exec @retcode=sp_MSguidtostr @artid, @guidstr out
	if @retcode<>0 or @@ERROR<>0 return (1)

	-- Check if the triggers can be made NOT FOR REPLICATION
	if exists (select * from sysmergearticles 
			   where nickname = @tablenick 
			   and
			   (before_image_objid is not null or
			    before_view_objid is not null or
			    datalength (subset_filterclause) > 1
			   ))
	begin
		select @notforrepl_bit = 0
	end
	else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick or join_nickname = @tablenick)
	begin
		select @notforrepl_bit = 0
	end
	else
	begin
		select @notforrepl_bit = 1
	end
	
	select @notforrepl_str = ' 
	if sessionproperty(''replication_agent'') = 1 and (select trigger_nestlevel()) = 1 -- and master.dbo.fn_isreplmergeagent() = 1
		return '

	/* Drop the article's replication triggers if they preexist */
	exec dbo.sp_MSdroparticletriggers @source_table, @table_owner
	if @@ERROR <> 0
		return 1
	
	-- owner name removed
	set @instrigname = @ext + @guidstr 
	set @deltrigname = @ext2 + @guidstr
	set @updtrigname = 'upd_' + @guidstr
	set @viewname = 'ctsv_' + @guidstr
	set @tsview = 'tsvw_' + @guidstr
	
	/* Make sure trigger name is unique */
	exec @retcode=sp_MSuniqueobjectname @instrigname, @instrigname output
	if @retcode<>0 or @@ERROR<>0 return (1)
	exec @retcode=sp_MSuniqueobjectname @deltrigname, @deltrigname output
	if @retcode<>0 or @@ERROR<>0 return (1)
	exec @retcode=sp_MSuniqueobjectname @updtrigname, @updtrigname output
	if @retcode<>0 or @@ERROR<>0 return (1)

	/* Create the view if it doesn't already exist. */
	if not exists (select * from sysobjects where type = 'V' and name = @viewname)
		begin

		exec @retcode=sp_MSuniqueobjectname @viewname, @viewname output
		if @retcode<>0 or @@ERROR<>0 return (1)
		set @command = 'create view dbo.' + @viewname + ' as
			select * from dbo.MSmerge_contents where
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@instrigname) + ''')) > 0 or
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@updtrigname) + ''')) > 0 or
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@deltrigname) + ''')) > 0
				with check option'
		execute (@command)
		if @@ERROR<>0 return (1)
		set @command = 'grant update, insert, select, delete on ' + @viewname + ' to public'
		execute (@command)
		if @@ERROR<>0 return (1)
		execute ('sp_MS_marksystemobject ''' + @viewname + '''')	
		if @@ERROR<>0 return (1)	
		end


	/* Create the view if it doesn't already exist. */
	if not exists (select * from sysobjects where type = 'V' and name = @tsview)
		begin
		exec @retcode=sp_MSuniqueobjectname @tsview, @tsview output
		if @retcode<>0 or @@ERROR<>0 return (1)
		set @command = 'create view dbo. ' + @tsview + ' as
			select * from dbo.MSmerge_tombstone where
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@instrigname) + ''')) > 0 or
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@updtrigname) + ''')) > 0 or
				trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(REPLACE(@owner, '''', '''''')) + '.'  + QUOTENAME(@deltrigname) + ''')) > 0
				with check option'
		execute (@command)
		if @@ERROR<>0 return (1)
		set @command = 'grant update, insert, select, delete on ' + @tsview + ' to public'
		execute (@command)
		if @@ERROR<>0 return (1)		
		execute ('sp_MS_marksystemobject ''' + @tsview + '''')	
		if @@ERROR<>0 return (1)	
		end
		
	/* If column tracking is on, construct the string to initialize colv's */
	if (@column_tracking <> 0)
		select @ifcoltracking = '	set @colv1 = { fn INITCOLVS(@ccols, @nickname) }'
	else
		select @ifcoltracking = '	set @colv1 = NULL'
		
	/* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */
	select @command = 'create trigger ' + @instrigname + ' on ' + @source_table +
		' for insert as ' + @notforrepl_str + ' 
		/* Declare variables */
		declare @article_rows_inserted int
		select @article_rows_inserted = count(*) from inserted
		declare @tablenick int, @nickname int
		declare @lineage varbinary(255), @colv1 varbinary(2048)
		declare @ccols int, @retcode smallint, @version int, @curversion int, @oldmaxversion int
		
		set nocount on
		set @tablenick = ' + @tablenickchar + '
		select @ccols = ' + @ccolchar + '
		set @lineage = 0x0
		set @retcode = 0
		select @oldmaxversion= maxversion_at_cleanup from sysmergearticles where nickname = @tablenick
		
		execute dbo.sp_MSgetreplnick @nickname = @nickname output
		if (@@error <> 0)
			begin
			goto FAILURE
			end
		set @lineage = { fn UPDATELINEAGE (0x0, @nickname, 1) }
		' + @ifcoltracking + '
		if (@@error <> 0)
			begin
			goto FAILURE
			end

		if exists (select ts.rowguid from ' + @tsview + ' ts, inserted i where ts.tablenick = @tablenick and ts.rowguid = i.rowguidcol)
		begin
			select @version = max({fn GETMAXVERSION(lineage)}) from ' + @tsview + ' where 
				tablenick = @tablenick and rowguid in (select rowguidcol from inserted)

			if @version is not null
			begin
				-- reset lineage and colv to higher version...
				set @curversion = 0
				while (@curversion <= @version)
				begin
					set @lineage = { fn UPDATELINEAGE (@lineage, @nickname, @oldmaxversion+1) }
					set @curversion = @curversion + 1
				end

				if (@colv1 IS NOT NULL)
					set @colv1 = { fn UPDATECOLVBM(@colv1, @nickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
				
				delete from ' + @tsview + ' where tablenick = @tablenick and rowguid in
					(select rowguidcol from inserted)
			end
		end

		if (@article_rows_inserted = 1)
		begin
			if not exists (select ct.rowguid from ' + @viewname + ' ct, inserted i where ct.tablenick = @tablenick and ct.rowguid = i.rowguidcol)
			begin
				insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, joinchangegen) select
					@tablenick, rowguidcol, @lineage, @colv1, A.gen_cur, A.gen_cur from inserted,
				(select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as A
			end
		end
		else
		begin
			insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, joinchangegen) select
				@tablenick, rowguidcol, @lineage, @colv1, A.gen_cur, A.gen_cur from inserted,
				(select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as A
				where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick)
		end
		if @@error <> 0 
			goto FAILURE
		return
	FAILURE:

				if @@trancount > 0
					rollback tran
				raiserror (20041, 16, -1)
				return
					'
	execute (@command)
	if @@ERROR <> 0 
		begin
			raiserror(21304, 16, -1, @source_table)
			return (1)
		end
	
    select @command3 = 'sp_MS_marksystemobject ''' + REPLACE(@owner, '''', '''''') + '.'  + @instrigname + ''''
	if @owner_is_admin = 1
		execute (@command3)	
	/* Call separate routine to add update trigger */
	exec @retcode=sp_MSaddupdatetrigger @source_table, @owner, @object, @artid, @column_tracking, @viewname
	if @retcode<>0 or @@ERROR<>0 return (1)

	/* Now make the delete trigger */
	-- NOTE: owner name removed

	/* Make sure trigger name is unique */
	exec @retcode = dbo.sp_MSuniqueobjectname @deltrigname, @deltrigname output
	if @retcode<>0 or @@ERROR<>0 return (1)

	set @command = 'create trigger ' + @deltrigname + ' on ' + @source_table +
	' FOR DELETE AS '

	if (@notforrepl_bit = 1)
		select @command = @command + @notforrepl_str

	select @command = @command + '
	/* Declare variables */
	declare @tablenick int, @retcode smallint, @reason nvarchar(255), @nickname int, @lineage varbinary(255), @oldmaxversion int
	
	set nocount on
	select @tablenick = ' + @tablenickchar + '
	select @oldmaxversion= maxversion_at_cleanup from sysmergearticles where nickname = @tablenick
	
	select @reason = ''user delete''
	execute dbo.sp_MSgetreplnick @nickname = @nickname output
	if (@@error <> 0)
		begin
		goto FAILURE
		end
	'
	set @command2 = '
	set @lineage = { fn UPDATELINEAGE(0x0, @nickname, @oldmaxversion) }

	insert into ' + @tsview + ' (rowguid, tablenick, type, lineage, generation, reason)
		select rowguidcol, @tablenick, 1, { fn UPDATELINEAGE(COALESCE(c.lineage, @lineage), @nickname, @oldmaxversion+1) }, a.gen_cur, @reason from 
			deleted d left outer join ' + @viewname + ' c on c.tablenick = @tablenick and c.rowguid = d.rowguidcol
			join (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as a on a.nickname = @tablenick
	if @@error <> 0
		GOTO FAILURE

	delete from ' + @viewname + ' where tablenick = @tablenick and rowguid in 
		(select rowguidcol from deleted) 
	if @@error <> 0
		GOTO FAILURE
	
	return
FAILURE:
				if @@trancount > 0
					rollback tran
				raiserror (20041, 16, -1)
				return
				'
	
	execute (@command + @inscommand + @command2)

	if @@ERROR <> 0 
		begin
			raiserror(21304, 16, -1, @source_table)
			return (1)
		end
    select @command3 = 'sp_MS_marksystemobject ''' + REPLACE(@owner, '''', '''''') + '.' + @deltrigname + ''''
	if @owner_is_admin = 1
		execute (@command3)	

	return (0)
GO

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

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

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

-- sp_showrowreplicainfo displays row and column version information about a specific row
-- parameters: 
-- 		@ownername: The table owner.
--		@tablename: Name of the table that contains the row.
--		@rowguid: Unique identifier of the row of interest.
--		@show: Determines whether to display row versions, colum versions, or both. Values are 'both', 'row', or 'columns'.
-- output columns for row version information:
--		server_name: Name of the server that made this entry
--		db_name: Name of the database that made this entry.
--		db_nickname: Nickname of the database that made this entry.
--		version: Version of the entry.
--		rowversion_table: Indicates whether lineage is in MSmerge_contents or MSmerge_tombstone.
--		comment: Records problems with this version entry.
-- output columns for column version information:
--		server_name, db_name, db_nickname, version, comment: As above.
--		colname: Name of the column the colv entry stands for.
create procedure sp_showrowreplicainfo
	(@ownername sysname = NULL, @tablename sysname = NULL, @rowguid uniqueidentifier, @show nvarchar(20) = 'both')
as 
	set nocount on

	-- some constants
	-- this stored proc is for debugging purposes, thus no need for localizing them
	declare @dbname sysname
	select @dbname= db_name()

	declare @missingcolname sysname
	set @missingcolname= '<Missing column>'

	declare @anonymousname sysname
	set @anonymousname= '<Anonymous subscriber>'

	declare @unknownname sysname
	set @unknownname= '<Unknown server name>'

	declare @mergename sysname
	set @mergename= '<Merge nickname>'

	declare @nondecreasingversion nvarchar(128)
	set @nondecreasingversion= 'Problem found: Non-decreasing version.'

	declare @toohighcolvversion nvarchar(128)
	set @toohighcolvversion= 'Problem found: Version is higher than highest version in lineage.'

	declare @naname sysname
	set @naname= '<n/a>'

	if @tablename is NULL
	begin
		set @tablename= (select top 1 object_name(objid) from sysmergearticles where 
							nickname = (select tablenick from MSmerge_contents where rowguid = @rowguid))
	end

	if @tablename is NULL
	begin
		set @tablename= (select top 1 object_name(objid) from sysmergearticles where 
							nickname = (select tablenick from MSmerge_tombstone where rowguid = @rowguid))
	end

	-- check whether given table exists
	if not exists (select * from sysobjects where xtype = 'U' and name = @tablename)
	begin
		raiserror (20507, 16, 1, @tablename, @dbname)
		return 1
	end
	else if @ownername is not null
	begin
		-- check whether table belongs to the given owner
		if not exists (select * from sysobjects where xtype = 'U' and name=@tablename and uid = (select uid from sysusers where name = @ownername))
		begin
			declare @qualifiedtablename nvarchar(257)
			select @qualifiedtablename= @ownername + '.' + @dbname
			raiserror (20507, 16, 1, @qualifiedtablename, @dbname)
			return 1
		end
	end

	-- get tableid and tablenick from tablename
	declare @tableid int
	declare @tablenick int
	set @tableid= object_id(@tablename)
	select @tablenick = (select top 1 nickname from sysmergearticles where objid = @tableid)
	if @tablenick is null
	begin
		raiserror (20027, 16, 1, @tablename)
		return 1
	end

	-- check whether there is an entry for this row in either MSmerge_contents or MSmerge_tombstone
	declare @incontents int
	declare @lineage varbinary(249)
	select @lineage= lineage from MSmerge_contents where rowguid = @rowguid
	if @lineage is not null
	begin
		set @incontents= 1
	end
	else
	begin
		select @lineage= lineage from MSmerge_tombstone where rowguid = @rowguid
		if @lineage is not null
		begin
			set @incontents= 0
		end
		else
		begin
			raiserror(21511,10,1)
			return 0
		end
	end

	-- create temporary table for information about lineage and colv entries
	create table #results (type nchar(7) null, rowversion_table nchar(17) null, server_name sysname null, 
							[db_name] sysname null,  db_nickname int not null, colid int null, colname sysname null, 
							version int not null, comment nvarchar(255) null, id int identity(1,1) not null) 
	
	if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'row')
	begin
		-- insert lineage information into temptable
		insert into #results (db_nickname, version) exec master..xp_showlineage @lineage
		update #results set type= 'lineage'
		if (@incontents = 1)
		begin
			update #results set rowversion_table = 'MSmerge_contents'
		end
		else
		begin
			update #results set rowversion_table = 'MSmerge_tombstone'
		end
	end

	if (@incontents = 1) and (lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'columns'))
	begin
		-- insert colv information into temptable
		declare @colv varbinary(2048)
		select @colv= colv1 from MSmerge_contents where rowguid=@rowguid
		if @colv is not null
		begin
			insert into #results (colid, db_nickname, version) exec master..xp_showcolv @colv
			update #results set type= 'colv' where type is null

			-- translate colids into column names
			if (select top 1 missing_col_count from sysmergearticles where nickname = @tablenick) = 0
			begin
				-- no missing cols: position of entries in colv correspond to colid in sysmergearticles
				update #results set colname= s.name from syscolumns s where #results.colid = s.colid and s.id = @tableid
			end
			else
			begin
				-- missing cols: colv has entries for columns that do not exist in this db
				declare @colname sysname
				declare @ismissing int
				declare @missingsofar int
				declare @colid int
				declare @missingcols varbinary(128)
				select @missingcols= (select top 1 missing_cols from sysmergearticles where nickname = @tablenick)
				set @missingsofar= 0
				select @colid= (select min(colid) from #results where colname is null and colid is not null)
				while @colid is not null
				begin
					-- is this column missing?
					exec @ismissing= sp_MStestbit @missingcols, @colid
					if @ismissing <> 0
					begin
						update #results set colname= @missingcolname, server_name= @naname, [db_name]= @naname
											 where colid = @colid
						set @missingsofar= @missingsofar + 1
					end
					else
					begin
						select @colname= (select name from syscolumns where id = @tableid and colid = (@colid - @missingsofar))
						update #results set colname= @colname where colid = @colid
					end
					
					select @colid= (select min(colid) from #results where colname is null and colid is not null)
				end
			end
		end
	end

	-- transform null comment to empty strings
	update #results set comment= ''

	-- translate nicknames in temptable into real db names; set server names, too
	declare @subid uniqueidentifier
	declare @servername sysname
	declare @srvid int
	declare @replnick int

	update #results set [db_name]= @mergename, server_name= @naname where db_nickname=1

	select @replnick= (select top 1 db_nickname from #results where [db_name] is null)
	while @replnick is not null
	begin
		select @subid= (select top 1 s.subid
							from sysmergesubscriptions s, MSmerge_replinfo r 
							where r.repid = s.subid and @replnick = r.replnickname)

		select @dbname= (select [db_name] from sysmergesubscriptions where subid = @subid)
		if @dbname is null
		begin
			set @dbname=@anonymousname
			set @servername= @unknownname
		end
		else
		begin
			select @servername= (select srv.srvname from master..sysservers srv, sysmergesubscriptions sub
							where srv.srvid = sub.srvid and sub.subid = @subid)
		end

		update #results set [db_name]= @dbname, server_name= @servername 
						where db_nickname = @replnick and [db_name] is null
		select @replnick= (select top 1 db_nickname from #results where [db_name] is null)
	end

	-- record increasing lineage versions
	update #results set comment= @nondecreasingversion 
			where type = 'lineage' and 
			exists (select * from #results r where r.version < #results.version and r.id < #results.id)

	-- record colv versions that are higher than highest lineage version
	update #results set comment= @toohighcolvversion 
			where type = 'colv' and 
			not exists (select version from #results r where type = 'lineage' and r.version >= #results.version)
	
	-- deliver results
	if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'row')
	begin
		select server_name, [db_name], db_nickname, version, rowversion_table, comment from #results where type = 'lineage' order by id
	end

	if lower(@show collate SQL_Latin1_General_CP1_CS_AS) in ('both', 'columns')
	begin
		select server_name, db_name, db_nickname, version, colname, comment from #results where type = 'colv' order by id
	end

	drop table #results
	return 0
go
exec dbo.sp_MS_marksystemobject sp_showrowreplicainfo
go
grant execute on dbo.sp_showrowreplicainfo to public
go

--------------------------------------------------------------------------------
--.	Merge Replication objects (rlrecon.sql)
--------------------------------------------------------------------------------

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

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

create procedure sp_MSdrop_rlrecon
as

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if object_id('sp_MSlocalizeinterruptedgenerations') is not null
		drop procedure sp_MSlocalizeinterruptedgenerations

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSgetchangecount')
		drop procedure sp_MSgetchangecount

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSuplineageversion')
		drop procedure sp_MSuplineageversion

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSvalidatearticle')
		drop procedure sp_MSvalidatearticle
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSgetviewcolumnlist')
		drop procedure sp_MSgetviewcolumnlist
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSsubscriptionvalidated')
		drop procedure sp_MSsubscriptionvalidated
		
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSdelsubrows')
		drop procedure sp_MSdelsubrows
		
	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSdelsubrowsbatch')
		drop procedure sp_MSdelsubrowsbatch

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MScontractsubsnb')
		drop procedure sp_MScontractsubsnb

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSexpandsubsnb')
		drop procedure sp_MSexpandsubsnb

	if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSmakeviewproc')
		drop procedure sp_MSmakeviewproc

	if exists (select * from sysobjects
			where type = 'P' and
				name = 'sp_MScreatebeforetable')
		drop procedure sp_MScreatebeforetable 

	if exists (select * from sysobjects
			where type = 'P' and
				name = 'sp_MShelpcreatebeforetable')
		drop procedure sp_MShelpcreatebeforetable 

	if exists (select * from sysobjects
			where type = 'P' and
				name = 'sp_MShelpalterbeforetable')
		drop procedure sp_MShelpalterbeforetable 

	if exists (select * from sysobjects
			where type = 'P' and
				name = 'sp_MSgetbeforetableinsert')
		drop procedure sp_MSgetbeforetableinsert 

	if exists (select * from sysobjects
		  where type = 'P '
				and name = 'sp_MSfixupbeforeimagetables')
		drop procedure sp_MSfixupbeforeimagetables

	if exists (select * from sysobjects
			where type = 'P' and
				name = 'sp_MSinserterrorlineage')
		drop procedure sp_MSinserterrorlineage 

	if exists (select * from sysobjects
				where type = 'P' and
				name = 'sp_MSevalsubscriberinfo')
		drop procedure sp_MSevalsubscriberinfo 

	if exists (select * from sysobjects
				where type = 'P' and
				name = 'sp_MSsetsubscriberinfo')
		drop procedure sp_MSsetsubscriberinfo 

	if exists (select * from sysobjects
				where type = 'P' and
				name = 'sp_MSgetsubscriberinfo')
		drop procedure sp_MSgetsubscriberinfo 

	if exists (select * from sysobjects
				where type = 'P '
				and name = 'sp_MSinsertgenerationschemachanges')
	drop procedure sp_MSinsertgenerationschemachanges

	if exists (select * from sysobjects
				where type = 'P '
				and name = 'sp_MSalreadyhavegeneration')
	drop procedure sp_MSalreadyhavegeneration

	if exists (select * from sysobjects
				where type = 'P '
				and name = 'sp_MSgettablecontents')
		drop procedure sp_MSgettablecontents

	if exists (select * from sysobjects
				where type = 'P '
				and name = 'sp_MSdelgenzero')
	drop procedure sp_MSdelgenzero

    if exists (select * from sysobjects
                where type = 'P '
                and name = 'sp_MSmakedynsnapshotvws')
    drop procedure sp_MSmakedynsnapshotvws

    if exists (select * from sysobjects
                where type = 'P '
                and name = 'sp_MSdropdynsnapshotvws')
    drop procedure sp_MSdropdynsnapshotvws

go
exec dbo.sp_MS_marksystemobject sp_MSdrop_rlrecon
go

--------------------------------------------------------------------------------
--. sp_MScleanuptask (obsolete sp - will be removed)
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MScleanuptask')
    drop procedure sp_MScleanuptask

go

--------------------------------------------------------------------------------
--. sp_MSupdatesysmergearticles
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSupdatesysmergearticles')
    drop procedure sp_MSupdatesysmergearticles

raiserror('Creating procedure sp_MSupdatesysmergearticles', 0,1)
GO

CREATE PROCEDURE sp_MSupdatesysmergearticles(
	@object					sysname, 				/* Name of the table */
	@artid					uniqueidentifier,		/* Article ID */
	@owner					sysname 			= NULL,
	@identity_support		int					= NULL,
	@next_seed				bigint				= NULL,
	@range					bigint				= NULL,
	@threshold				int					= NULL,
	@pubid					uniqueidentifier 	= NULL
	) AS
	declare @merge_pub_object_bit 	int
	declare @id						int
	declare @qualified_name			nvarchar(270)
	declare @colid					int
	declare @colname				sysname
	declare @mergepublish			int
    SET NOCOUNT ON
	
	declare @retcode int
	declare @objid int

	if @owner is NULL or @owner = ''
	begin
		if exists (select name from sysobjects where id = object_id(@object))
			select @owner = user_name(uid) from sysobjects where id = object_id(QUOTENAME(@object))
		else 
			begin
				raiserror(21078, 16, -1, @object)
				return (1)
			end
	end

	select @mergepublish = 0x4000
	
	select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object)
	select @objid = object_id(@qualified_name)
	
	/*
	** Check to see if current publication has permission
	*/
	/*
	** Check for subscribing permission
	*/
	exec @retcode=sp_MSreplcheck_subscribe
	if @retcode<>0 or @@ERROR<>0 return (1)
	
	select @merge_pub_object_bit 	= 128

	if (@artid is NULL)
    BEGIN
		RAISERROR (14057, 16, -1)
		RETURN (1)
	END
	begin tran
	save tran sp_MSupdatesysmergearticles
		if exists (select name from sysobjects where id = @objid)
		begin
			exec dbo.sp_replupdateschema @qualified_name
			if @@ERROR<>0 goto UNDO
			update sysobjects set replinfo = replinfo | @merge_pub_object_bit where id=@objid
			if @@ERROR<>0 goto UNDO
			update syscolumns set colstat=colstat | @mergepublish where id=@objid
			if @@ERROR<>0 goto UNDO
		/*
		** update sysmergearticles.objid for all articles sharing the same base table
		*/
		update sysmergearticles set objid = @objid where artid = @artid
			IF @@ERROR <> 0
			BEGIN
			RAISERROR (14057, 16, -1)
			goto UNDO
		END
        /*
        ** update sysmergearticles.sysnc_objid for only the article in this publication
        ** and for articles that no longer has a valid sync_objid (usually for the
        ** non-filtered case)
        */
        update sysmergearticles set sync_objid=@objid 
         where artid = @artid 
           and (pubid = @pubid or 
                (object_name(sync_objid) is null and isnull(view_type,0) = 0))
        IF @@ERROR <> 0
        BEGIN
            RAISERROR (14057, 16, -1)
            goto UNDO
        END
            
			
		/*
		** Set the next_seed, max value, and threshhold of identity table. New range and threshold are to be set
		** by sp_addmergearticle if the table is to be republished. Message based subscribers have to look up the
		** threshold and range info to see if they need to request a new range. Use max_identity for current_max for
		** now. The value of current_max can change by sp_addmergearticle if republished.
		*/
		if @identity_support = 1
		begin
			exec @retcode = sp_MSreseed @objid, @next_seed, @range
			if @@ERROR<>0 or @retcode<>0
				GOTO UNDO
			insert MSrepl_identity_range (objid, max_identity, next_seed, current_max, range, threshold) 
				values(@objid, @next_seed + @range, @next_seed, @next_seed + @range - 1, @range, @threshold)
			if @@ERROR<>0
			begin
				GOTO UNDO
			end
		end
		
		end
		else -- THIS IS FINE. This dynamic query is there to provide a good error message. No need to use SP.
			raiserror(21078, 16, -1, @object)
			exec dbo.sp_replupdateschema @qualified_name
			if @@error<>0 goto UNDO
	commit tran
	RETURN 0
UNDO:
	rollback tran sp_MSupdatesysmergearticles
	commit tran
	RETURN 1
go
exec dbo.sp_MS_marksystemobject sp_MSupdatesysmergearticles
go
grant exec on dbo.sp_MSupdatesysmergearticles to public
go

--------------------------------------------------------------------------------
--. sp_MSuplineageversion 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSuplineageversion')
    drop procedure sp_MSuplineageversion

go

raiserror('Creating procedure sp_MSuplineageversion', 0,1)
GO

CREATE PROCEDURE sp_MSuplineageversion
	(@tablenick int,
	 @rowguid uniqueidentifier,
	 @version int)
as
	declare @replnick int
	declare @curversion int
	declare @lineage varbinary(255)
	declare @retcode int
	declare @colv varbinary(2048)
	declare @col_tracking int
	declare @rowintombstone int
	
	/*
	** Check to see if current publication has permission
	*/
	if sessionproperty('replication_agent') = 0
	begin
		exec @retcode=sp_MSreplcheck_connection
			@tablenick = @tablenick
		if @retcode<>0 or @@ERROR<>0 return (1)
	end
	
	exec dbo.sp_MSgetreplnick @nickname = @replnick out
	if (@@error <> 0) or @replnick IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 
	if (@rowguid is null)
		begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (1)
		end
	if (@tablenick is null)
		begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
		end

	select @col_tracking = column_tracking
			 from sysmergearticles where nickname = @tablenick

	begin transaction
	save tran sp_MSuplineageversion

	-- get lineage, locking row in MSmerge_contents. If not found there, also try MSmerge_tombstone
	set @rowintombstone= 0
	select @lineage = lineage, @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
			rowguid = @rowguid
	if (@lineage is null)
	begin
		select @lineage = lineage from dbo.MSmerge_tombstone (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
			rowguid = @rowguid
		set @colv= NULL
		set @rowintombstone= 1
	end
	if (@lineage is null)
	begin
		RAISERROR(14043, 16, -1, '@lineage')
		goto Failure
	end

	set @curversion = 0
	while (@curversion < @version)
	begin
		set @lineage= { fn UPDATELINEAGE(@lineage, @replnick, 1) }
		set @curversion= { fn GETMAXVERSION(@lineage) }
		IF @@ERROR<>0 goto Failure
	end
	if (@col_tracking = 0 or @colv is NULL)
		set @colv = NULL
	else
		set @colv = { fn UPDATECOLVBM(@colv, @replnick, 0x01, 0x00, @curversion) }
		
	-- update lineage in MSmerge_contents or MSmerge_tombstone
	if (@rowintombstone = 0)
	begin
		update dbo.MSmerge_contents set lineage = @lineage, colv1 = @colv where 
			tablenick = @tablenick and rowguid = @rowguid
	end
	else
	begin
		update dbo.MSmerge_tombstone set lineage = @lineage where
			tablenick = @tablenick and rowguid = @rowguid
	end

	commit
	return (0)
Failure:
	rollback tran sp_MSuplineageversion
	commit tran
	return(1)
go
exec dbo.sp_MS_marksystemobject sp_MSuplineageversion
go
grant exec on dbo.sp_MSuplineageversion to public


--------------------------------------------------------------------------------
--. sp_MSdummyupdate 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSdummyupdate')
    drop procedure sp_MSdummyupdate

go

raiserror('Creating procedure sp_MSdummyupdate', 0,1)
GO

CREATE PROCEDURE sp_MSdummyupdate
	(@rowguid uniqueidentifier, @tablenick int, @metatype tinyint, @pubid uniqueidentifier = NULL, @uplineage tinyint = 1, @inlineage varbinary(255) = NULL, @incolv varbinary(2048) = NULL)
as
	declare @retcode	 int
	declare @lineage	 varbinary(255)
	declare	@conflict_lineage varbinary(255)
	declare @mynickname	 int
	declare @col_tracking int
	declare @colv varbinary(2048)
	declare @reason nvarchar(255)
	declare @oldmaxversion int

	/*
	** Check to see if current publication has permission
	*/
	if sessionproperty('replication_agent') = 0
	begin
		exec @retcode=sp_MSreplcheck_connection
			@tablenick = @tablenick
		if @retcode<>0 or @@ERROR<>0 return (1)
	end
	
	/* Parameter checks */
	if (@rowguid is null)
		begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (1)
		end
	if (@tablenick is null)
		begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
		end
	if (@metatype is null)
		begin
		RAISERROR(14043, 16, -1, '@metatype')
		return (1)
		end

	/* Check if we have a merge publication by whether system table is there */
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end

	exec dbo.sp_MSgetreplnick @nickname = @mynickname out
	if (@@error <> 0) or @mynickname IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

	-- Look for the "other" lineage in a conflict table
	select @conflict_lineage = max(lineage) from MSmerge_errorlineage where
		rowguid = @rowguid and tablenick = @tablenick

	set @oldmaxversion= (select top 1 maxversion_at_cleanup from sysmergearticles 
							where nickname = @tablenick)

	if (@metatype = 0)
	begin
		/* We don't have the row.  Putting in a system delete tombstone should cause a delete and
		** eventual convergence.  We are already logging the row as a conflict / error.
		*/
		if @conflict_lineage is not null
		begin
			set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
		end
		else
		begin
			set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
		end
		select @reason = formatmessage(20564) -- system delete
	
		insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason) 
			values (@rowguid, @tablenick, 6, @lineage, 0, @reason)
		
	end
	else if (@metatype = 1)
	begin
		if @inlineage is not null
		begin
			set @lineage = @inlineage
			set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
		end
		else
		begin
			select @lineage = lineage from dbo.MSmerge_tombstone (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
				rowguid = @rowguid
			if (@uplineage = 1)
			begin
				if @conflict_lineage is not null
				begin
					exec @retcode= master..xp_mergelineages @lineage, @conflict_lineage, @lineage output
					if @@error<>0 or @retcode<>0 return(1)
				end
				set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
			end
		end
			
		update dbo.MSmerge_tombstone set generation = 0, lineage = @lineage where
			tablenick = @tablenick and rowguid = @rowguid
	end
	else if (@metatype = 2)
	begin
		if @inlineage is not null
		begin
			set @lineage = @inlineage
			set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }

			if @incolv is not null
			begin
				set @colv = @incolv
			end
			else
			begin
				select @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where 
					tablenick = @tablenick and rowguid = @rowguid
				if @pubid is NULL
					select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick
				else
					select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick and pubid = @pubid
				if (@col_tracking = 0 or @colv is NULL)
					set @colv = NULL
				else
					set @colv = { fn UPDATECOLVBM(@colv, @mynickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
			end
		end
		else
			-- @inlineage is null -> @incolv is null, too
		begin
			select @lineage = lineage, @colv = colv1 from dbo.MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and
				rowguid = @rowguid
			if (@uplineage = 1)
			begin
				if @conflict_lineage is not null
				begin
					exec @retcode= master..xp_mergelineages @lineage, @conflict_lineage, @lineage output
					if @@error<>0 or @retcode<>0 return(1)
				end
				set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
				if @pubid is NULL
					select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick
				else
					select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick and pubid = @pubid
				if (@col_tracking = 0 or @colv is NULL)
					set @colv = NULL
				else
					set @colv = { fn UPDATECOLVBM(@colv, @mynickname, 0x01, 0x00, { fn GETMAXVERSION(@lineage) }) }
			end
		end

		update dbo.MSmerge_contents set generation = 0, lineage = @lineage, colv1 = @colv where
			tablenick = @tablenick and rowguid = @rowguid
	end
	else if (@metatype = 3)
	begin
		declare @ccols		 int
		declare @sync_objid	 int
		declare @missing_count int

		if @inlineage is not null
		begin
			set @lineage = @inlineage
			set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname, @oldmaxversion+1) }
		end
		else if @conflict_lineage is not null
		begin
			set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
		end
		else
		begin
			set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
		end

		if @incolv is not null
		begin
			set @colv = @incolv
		end
		else
		begin
			if @pubid is NULL
			begin
				select @sync_objid = sync_objid, @col_tracking = column_tracking, @missing_count = missing_col_count
				 from sysmergearticles where nickname = @tablenick
			end
			else
			begin
				select @sync_objid = sync_objid, @col_tracking = column_tracking, @missing_count = missing_col_count
				 from sysmergearticles where nickname = @tablenick and pubid = @pubid
			end

			if (@col_tracking = 0)
				set @colv = NULL
			else
			begin
				select @ccols= count(*) from syscolumns where id = @sync_objid
				set @ccols = @ccols + @missing_count
				set @colv = { fn INITCOLVS(@ccols, @mynickname ) }
			end
		end

		insert into dbo.MSmerge_contents (tablenick, rowguid, lineage, generation, colv1)
			values (@tablenick, @rowguid, @lineage, 0, @colv)
	end
	else if (@metatype = 6) -- e.g., used to cope with dup key / dup index
	begin
		if @conflict_lineage is not null
		begin
			set @lineage = { fn UPDATELINEAGE(@conflict_lineage, @mynickname, @oldmaxversion+1) }
		end
		else
		begin
	    	set @lineage = { fn UPDATELINEAGE(0x0, @mynickname, @oldmaxversion+1) }
		end
		select @reason = formatmessage(20564) -- system delete
	
		begin transaction
			if not exists (select * from MSmerge_tombstone where rowguid=@rowguid and tablenick=@tablenick)
			begin
				insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason) 
					values (@rowguid, @tablenick, @metatype, @lineage, 0, @reason)
			end
			delete from dbo.MSmerge_contents where rowguid=@rowguid and tablenick=@tablenick
		commit
	end
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSdummyupdate
go
grant exec on dbo.sp_MSdummyupdate to public
go

--------------------------------------------------------------------------------
--. sp_MSenumgenerations 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSenumgenerations')
    drop procedure sp_MSenumgenerations
go

raiserror('Creating procedure sp_MSenumgenerations', 0,1)
GO

CREATE PROCEDURE sp_MSenumgenerations
	(@genstart int, @pubid uniqueidentifier, @return_count_of_generations bit = 0)
as
	declare @retcode 	smallint
	declare @guidnull 	uniqueidentifier
	declare @generation_range TABLE (generation int NOT NULL, guidsrc uniqueidentifier NOT NULL, art_nick int NULL, guidlocal uniqueidentifier NOT NULL, pubid uniqueidentifier NULL, nicknames varbinary(1000) NOT NULL, okaytoskip bit NOT NULL)
	declare @status 	int
	declare @pubname 	sysname
	declare @rowcount	int
	set @guidnull = '00000000-0000-0000-0000-000000000000'
		
	/*
	** To public
	*/
	
	if (@genstart is null)
		begin
		RAISERROR(14043, 16, -1, '@genstart')
		return (1)
		end
	if (@pubid is null)
		begin
		RAISERROR(14043, 16, -1, '@pubid')
		return (1)
		end
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
		begin
		RAISERROR(20054 , 16, -1)
		return (1)
		end
    /*
    ** Check the publication status at the publisher - if it is inactive ( say because of a 
	** metadata cleanup event then return an error so the current merge will quit.
    */
    EXEC @retcode = dbo.sp_MScheckatpublisher @pubid
    IF @retcode = 0
        BEGIN

			select @pubname = name, @status = status from sysmergepublications where pubid = @pubid
			if @status = 0
				begin
					RAISERROR(21505, 16, -1, @pubname)
					return (1)
				end
        END

	insert into @generation_range (generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip)
	select DISTINCT generation, guidsrc, art_nick, guidlocal, pubid, nicknames, 0
	from dbo.MSmerge_genhistory 
	where generation >= @genstart 
	and (art_nick = 0 or art_nick is NULL or 
		art_nick in (select nickname from sysmergearticles 
		where pubid = @pubid)) 
	select @rowcount = @@rowcount

	if (@return_count_of_generations = 1)
		select @rowcount

	-- optimizations 
	-- 1. skip all rows that are for incomplete generations for articles that have no joins.
	-- 2. skip all rows for join articles if all the join article rows are incomplete generations.

	update @generation_range set okaytoskip = 1
	where art_nick is not null and art_nick <> 0
	and guidlocal = @guidnull 
	and 
	(
		(	
			-- 1. skip all rows that are for incomplete generations for articles that have no joins.
			not exists (select 1 from sysmergesubsetfilters where join_nickname = art_nick or art_nickname = art_nick)
		)
		or
		(	
			-- 2. skip all rows for join articles if all the rows for join and joined articles (i.e. the articles represented by join_nickname 
			--    and art_nickname in sysmergesubsetfilters) are incomplete generations.

			art_nick in (select join_nickname from sysmergesubsetfilters) 
			and not exists 
				(	
					select 1 from @generation_range b where b.guidlocal <> @guidnull 
					and exists (select 1 from sysmergesubsetfilters where join_nickname = b.art_nick or art_nickname = b.art_nick)
					and b.generation > @genstart
				) 
		)
	)
	
	select generation, guidsrc, art_nick, guidlocal, pubid, nicknames, okaytoskip from @generation_range
	ORDER BY generation ASC

	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumgenerations
go
grant exec on dbo.sp_MSenumgenerations to public
go


--------------------------------------------------------------------------------
--. sp_MSenumdeletesmetadata 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSenumdeletesmetadata')
    drop procedure sp_MSenumdeletesmetadata
go

raiserror('Creating procedure sp_MSenumdeletesmetadata', 0,1)
GO

CREATE PROCEDURE sp_MSenumdeletesmetadata(
	@pubid uniqueidentifier, 
	@maxrows int, 
	@genlist varchar(8000), 
	@tablenick int, 
	@rowguid 	uniqueidentifier,
	@filter_partialdeletes int = 0,
	@specified_article_only int = 0,
	@mingen	int = 0,
	@maxgen int = 0)
as
	declare @tnstring nvarchar(12)
	declare @rgstring nvarchar(38)
	declare @pubidstr nvarchar(38)
	declare @tablenick_qual nvarchar(100)
	declare @maxgenmingen_clause nvarchar(100)

	/*
	** To public.
	*/
	
	if (@genlist is null)
	begin
		RAISERROR(14043, 16, -1, '@genlist')
		return (1)
	end
	if (not exists(select * from sysobjects where name = 'MSmerge_contents'))
	begin
		RAISERROR(20054 , 16, -1)
		return (1)
	end
			
	set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''

	/* If the filter_partialdeletes is NOT set, include all types of tombstones, else filter the type = 5 ones */
	if (@filter_partialdeletes = 0)
		set @tablenick_qual = '	and ts.tablenick = sm.nickname '
	else
		set @tablenick_qual = '	and ts.tablenick = sm.nickname and ts.type <> 5'
	
	declare @selecttop nvarchar(20)
	if (@maxrows = 0)
		set @selecttop= 'select'
	else
		set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 
	
	declare @mingenstr nvarchar(13)
	declare @maxgenstr nvarchar(13)

	select @mingenstr = convert(nchar, @mingen)
	select @maxgenstr = convert(nchar, @maxgen)

	if (@maxgen = 0)
		select @maxgenmingen_clause = ' '
	else
		select @maxgenmingen_clause = ' generation >= ' + @mingenstr + ' and generation <= ' + @maxgenstr + ' and '

	if (@tablenick = 0)
	begin
		if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
		begin
			execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
				where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') 
				and sm.pubid = ' + @pubidstr + @tablenick_qual + '
				order by tablenick desc, rowguid asc' )

			IF @@ERROR <>0 
			begin
				return (1) 	
			end
		end
	end
	else
	begin
		set @tnstring = convert(nchar, @tablenick)
		set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''
		if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
		begin
			if (@specified_article_only = 1)
			begin
				execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
					where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
					tablenick = ' + @tnstring + ' and 
					rowguid > ' + @rgstring + ' 
					and sm.pubid = ' + @pubidstr + @tablenick_qual + ' 
					order by rowguid' )

				IF @@ERROR <>0 
				begin
					return (1) 	
				end
			end
			else
			begin
				execute (@selecttop + ' tablenick, rowguid, generation, lineage, ts.type from dbo.MSmerge_tombstone ts, sysmergearticles sm
					where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
					((tablenick = ' + @tnstring + ' and 
					rowguid > ' + @rgstring + ') or
					tablenick < ' + @tnstring + ') 
					and sm.pubid = ' + @pubidstr + @tablenick_qual + ' 
					order by tablenick desc, rowguid asc' )

				IF @@ERROR <>0 
				begin
					return (1) 	
				end

			end
		end
	end

	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumdeletesmetadata 
go
grant exec on dbo.sp_MSenumdeletesmetadata to public
go


--------------------------------------------------------------------------------
--. sp_MSenumchanges 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSenumchanges')
    drop procedure sp_MSenumchanges
go

raiserror('Creating procedure sp_MSenumchanges', 0,1)
GO
CREATE PROCEDURE sp_MSenumchanges
	(@maxrows int, @genlist varchar(8000), @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL,
		@oldmaxgen int=0, @mingen	int = 0, @maxgen int = 0)
as
	declare @tnstring	nvarchar(12)
	declare @oldmaxgenstr  nvarchar(12)
	declare @rgstring 	nvarchar(38)
	declare @retcode 	smallint
	declare @procname	nvarchar(270)
	declare @maxgenmingen_clause nvarchar(100)

	/*
	** To public.
	*/
	if (@tablenick is null)
	begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
	end
	if (@genlist is null)
	begin
		RAISERROR(14043, 16, -1, '@genlist')
		return (1)
	end

	create table #cont (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(249) NULL	, colv1 varbinary(2048) NULL)
	
	set @tnstring = convert(nchar, @tablenick)
	set @rgstring = '''' + convert(nchar(36), @rowguid) + ''''

	declare @selecttop nvarchar(20)
	if (@maxrows = 0)
		set @selecttop= 'select'
	else
		set @selecttop= 'select top ' + cast(@maxrows as nvarchar(9)) 

	declare @mingenstr nvarchar(13)
	declare @maxgenstr nvarchar(13)

	select @mingenstr = convert(nchar, @mingen)
	select @maxgenstr = convert(nchar, @maxgen)

	if (@maxgen = 0)
		select @maxgenmingen_clause = ' '
	else
		select @maxgenmingen_clause = ' generation >= ' + @mingenstr + ' and generation <= ' + @maxgenstr + ' and '

	if (@genlist is not null and rtrim(ltrim(@genlist)) <> '')
	begin
		if @oldmaxgen > 0
		begin
		set @oldmaxgenstr = convert(nchar, @oldmaxgen)
		execute ('insert into #cont ' +
					@selecttop + ' tablenick, rowguid, generation, lineage, colv1
	         				from dbo.MSmerge_contents where 
							(
								(
									' + @maxgenmingen_clause + ' generation in (' + @genlist + ')
								)
								or generation = 0 or generation > ' + @oldmaxgenstr + '
							) 
							and tablenick = ' + @tnstring + ' 
							and rowguid > ' + @rgstring + 	' 
							order by rowguid' )
		end
		else
		execute ('insert into #cont ' +
					@selecttop + ' tablenick, rowguid, generation, lineage, colv1
	         				from dbo.MSmerge_contents where ' + @maxgenmingen_clause + ' generation in (' + @genlist + ') and 
						tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring +
							' order by rowguid' )
		if @@ERROR <>0 
		begin
			return (1)
		end
	end

	select @procname = select_proc from sysmergearticles where nickname=@tablenick and pubid = @pubid
	exec @retcode = @procname @type=2
	IF @@ERROR<>0 or @retcode<>0
	begin
		RETURN (1)
	end

	drop table #cont
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSenumchanges
go
grant exec on dbo.sp_MSenumchanges to public
go

--------------------------------------------------------------------------------
--. sp_MSgetcolumnlist 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSgetcolumnlist')
    drop procedure sp_MSgetcolumnlist
go

raiserror('Creating procedure sp_MSgetcolumnlist', 0,1)
GO
create procedure sp_MSgetcolumnlist(
@pubid				uniqueidentifier,
@column_list 		nvarchar(4000) OUTPUT,
@source_objid		int,
@guid_alias			sysname=NULL
)
AS
/* 
** if it is not vertically partitioned, then get all columns 
** else get the column list as given in columns of sysmergearticles
*/
declare @bitset		int
declare @columns	varbinary(125)
declare @setcolcnt	int
declare @colcnt		int
declare @colname	nvarchar(140)
declare @colid		int
declare @unqual_sourcename	sysname
declare @qual_sourcename	nvarchar(140)
if @guid_alias is NULL
begin
	select @unqual_sourcename=object_name(@source_objid)
	select @qual_sourcename = QUOTENAME(@unqual_sourcename)
end
else
	select @qual_sourcename=@guid_alias	
select @columns = columns from sysmergearticles where objid = @source_objid and pubid=@pubid
select @column_list = ''
select @setcolcnt	= 0
select @colcnt = count(*) from syscolumns where id = @source_objid
declare collist CURSOR LOCAL FAST_FORWARD FOR 
   	select name, colid from syscolumns where id = @source_objid order by colid ASC
FOR READ ONLY
open collist
fetch collist into @colname, @colid
WHILE (@@fetch_status <> -1)
BEGIN
	exec @bitset = sp_MStestbit @columns, @colid
--	if @bitset<>0
	if @bitset<>0 or @columns is null or @columns = ''
	begin
		select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
		if @column_list=''					  --which can cause problems and is not necessary.
			select @column_list = @qual_sourcename + '.' + @colname
		else
			select @column_list = @column_list + ', ' + @qual_sourcename + '.' + @colname	
		select @setcolcnt = @setcolcnt + 1
	end					
fetch next from collist into @colname, @colid			
END
close collist
deallocate collist
if @setcolcnt = @colcnt
	select @column_list = ' * '
GO
exec dbo.sp_MS_marksystemobject sp_MSgetcolumnlist 
go
grant exec on dbo.sp_MSgetcolumnlist to public
go

--------------------------------------------------------------------------------
--. sp_MSpublicationview 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSpublicationview')
    drop procedure sp_MSpublicationview
go

raiserror('Creating procedure sp_MSpublicationview', 0,1)
GO
CREATE PROCEDURE sp_MSpublicationview(
    @publication sysname,
    @force_flag int = 0
    ) AS
    declare     @pubid              uniqueidentifier
    declare     @artid              uniqueidentifier
    declare     @join_articlename       nvarchar(270)
    declare     @join_viewname      nvarchar(270)
    declare     @join_before_view  	nvarchar(270)
    declare		@before_name		nvarchar(270)
    declare		@before_viewname	nvarchar(270)
    declare 	@unqual_sourcename	nvarchar(270)
    declare     @article            nvarchar(270)
    declare     @art_nick           int
    declare     @join_nick          int
    declare     @join_filterclause  nvarchar(4000)
    declare     @bool_filterclause  nvarchar(4000)
    declare     @view_rule          nvarchar(4000)
    declare		@before_view_rule	nvarchar(4000)
    declare		@before_objid		int
    declare     @article_level      int
    declare     @progress           int
    declare     @art                int
    declare     @viewname           nvarchar(270)
    declare     @procname           nvarchar(300)
    declare     @source_objid       int
    declare     @source_object      nvarchar(270)
    declare     @sync_objid         int
    declare 	@bitset				int
    declare     @permanent          int
    declare     @temporary          int
    declare     @filter_id          int
    declare     @filter_id_str      nvarchar(10)
	declare 	@guidstr nvarchar(40)
	declare 	@pubidstr nvarchar(40)
    declare     @rgcol              nvarchar(270)
    declare     @view_type          int
    declare     @belongsname        nvarchar(270)
    declare     @join_nickstr       nvarchar(10)
    declare     @unqual_jointable   nvarchar(270)  
    declare     @retcode            smallint
    declare     @hasguid            int
    declare 	@vertical_partition int
    declare     @join_unique_key    int
    declare     @simple_join_view   int
    declare     @join_filterid      int
    declare     @allhaveguids       int
    declare     @command            nvarchar(4000)
    declare     @objid              int
    declare     @owner              nvarchar(270)
    declare		@table				nvarchar(270)
    declare     @quoted_view        nvarchar(290)
    declare     @before_rowguidname	sysname
    declare     @quoted_pub         nvarchar(290)
    declare     @quoted_proc        nvarchar(290)
	declare 	@snapshot_ready		int
	declare 	@columns			varbinary(128)
	declare		@column_list		nvarchar(4000)
	declare		@prefixed_column_list		nvarchar(4000)
	declare 	@colname			nvarchar(270)
	declare 	@colid				int
    declare     @dynamic_filters    bit
    declare		@alias_for_sourceobject	sysname
    set @progress       = 1
    set @article_level  = 0
    set @permanent      = 1
    set @temporary      = 2
    set @allhaveguids   = 1
    set @before_rowguidname = NULL
    /*
    ** Only legal publisher can run this stored procedure
    */
    set nocount on
	/* make sure current database is enabled for merge replication */
    exec @retcode=dbo.sp_MSCheckmergereplication
    if @@ERROR<>0 or @retcode<>0
    	return (1)

    select @pubid = pubid, @snapshot_ready = snapshot_ready, @dynamic_filters = dynamic_filters FROM sysmergepublications 
        WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() 
    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

	select @table=object_name(objid) from sysmergearticles where pubid=@pubid and (columns is NULL or columns = 0x00)
	if @table is not NULL
		begin
			raiserror(21318, 16, -1, @table)
			return (1)
		end

    -- If snapshot is already ready, views are good.  Don't drop and recreate as someone
    -- might be using them.
    
	if @snapshot_ready = 1 and @force_flag = 0
		return (0)
		
	exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
	if @@ERROR <>0 OR @retcode <>0 return (1)

    create table #art(indexcol int identity NOT NULL, art_nick int NOT NULL, article_level int NOT NULL)
    if @@ERROR <> 0
        begin
        goto FAILURE
        end

    while @progress > 0
        BEGIN
        /*
        ** Select articles that have either a boolean_filter or at least one join filter 
        ** into a temp table in an optimized order.
        */
        insert into #art(art_nick, article_level) select nickname, @article_level from sysmergearticles 
            where pubid=@pubid and nickname not in (select art_nick from #art)
                and nickname not in 
                (select  art_nickname from sysmergesubsetfilters
                    where pubid=@pubid and join_nickname not in 
                        (select art_nick from #art))
        /*
        ** NOTENOTE: add error checking here.
        */

        set @progress = @@rowcount
        select @article_level = @article_level + 1
        END

    /* Drop the old views and reset sync_objid */
    select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and objid<>sync_objid
    while @art_nick is not null
        begin
        /* Drop the old view */
        select @viewname = OBJECT_NAME (sync_objid), @before_viewname = OBJECT_NAME(before_view_objid)
        	from sysmergearticles where
            pubid = @pubid and nickname = @art_nick
        if @viewname IS NOT NULL
        begin
            select @quoted_view = QUOTENAME(@viewname)
            exec ('drop view ' + @quoted_view)
        end
        if @before_viewname IS NOT NULL
        begin
            exec ('drop view ' + @before_viewname)
        end
        /* Update the row in sysmergearticles */
        update sysmergearticles set view_type = 0, sync_objid = objid where 
            pubid = @pubid and nickname = @art_nick
        if @@ERROR <> 0 goto FAILURE

        /* Find the next one */
        select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and objid<>sync_objid
        end
        
    set @art = 0
    select @art=min(indexcol) from #art where indexcol>@art

    while (@art is not null)
        begin
        select @art_nick=art_nick, @article_level = article_level from #art 
                where indexcol = @art
        select @article = name, @artid = artid, @columns = columns, @source_objid = objid,
        	@sync_objid = sync_objid, @procname = view_sel_proc, @before_objid = before_image_objid from sysmergearticles 
                where nickname=@art_nick and pubid = @pubid
                
        exec @retcode = sp_MSgetcolumnlist @pubid, @column_list OUTPUT, @source_objid
        
		set @before_name = OBJECT_NAME(@before_objid)
		if @before_name is not null
			begin
			select @before_rowguidname=name from syscolumns where id=@source_objid and columnproperty(@source_objid, name , 'isrowguidcol')=1
			exec @retcode = dbo.sp_MSguidtostr @pubid, @guidstr out
			set @before_viewname = @before_name + '_v_' + @guidstr
			end
		else
			set @before_viewname = NULL
        select @quoted_proc = QUOTENAME(@procname)
        
		exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out
		if @@ERROR <>0 OR @retcode <>0 return (1)

        select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects 
                where id = @source_objid 
        select @unqual_sourcename = QUOTENAME(OBJECT_NAME(@source_objid))
        
        select @bool_filterclause=subset_filterclause, @vertical_partition=vertical_partition 
        	from sysmergearticles where name = @article and pubid = @pubid

		-- verify the syntax of boolean filter, if added with vertical-partition to true
		-- in this case, the filter clause can contain columns that do not exist in the partition.
        if len(@bool_filterclause) > 0
        	begin
			/*
			-- let server return appropriate error message 
			exec ('select ' + @column_list + ' into #temptable_publicationview from ' + @source_object + 
				'declare @test int select @test=1 from #temptable_publicationview ' + @unqual_sourcename + ' where ' + @bool_filterclause)
			if @@ERROR<>0
			begin
				raiserror(21256, 16, -1, @bool_filterclause, @source_object)
				return (1)
			end
			*/
        	select @bool_filterclause = ' (' + @bool_filterclause + ') '
        	end
                
        set @rgcol = NULL
        select @rgcol = QUOTENAME(name) from syscolumns where id = @source_objid and
                ColumnProperty(id, name, 'isrowguidcol') = 1
        if @rgcol is not NULL
            set @hasguid = 1
        else 
            begin
            set @hasguid = 0
            set @allhaveguids = 0
            end

        /*
        ** Process non looping articles that have either a boolean or a join_filter.
        */
        if ( @article_level > 0 OR (len(@bool_filterclause) > 0) ) 
            begin
            /*
            ** If the article has a previously generated view, then drop the view before 
            ** creating the new one.
            */
            set @viewname = NULL
            select @viewname =  name from sysobjects where id = @sync_objid and
                ObjectProperty (id, 'IsView') = 1  and
                ObjectProperty (id, 'IsMSShipped') = 1 
            if @viewname IS NOT NULL
                begin
                    select @quoted_view = QUOTENAME(@viewname)
                    exec ('drop view ' + @quoted_view)
                    if @@ERROR<>0 return (1)
                end
                /*
                ** Any join filter(s)? If any, process join filter(s)
            	*/
            if (@article_level > 0) 
                begin
                declare pub1 CURSOR LOCAL FAST_FORWARD FOR select join_filterclause, join_nickname, join_articlename,
                    join_unique_key, join_filterid from sysmergesubsetfilters where pubid=@pubid and artid=@artid
                FOR READ ONLY
                open pub1                                       
                fetch pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
				select @join_filterclause=' ( ' + @join_filterclause + ') '
                select @unqual_jointable = QUOTENAME(name) from sysobjects 
                    where id = (select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) 
                
                select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid)
                	from sysmergearticles where nickname = @join_nick and pubid = @pubid
                select @join_viewname = QUOTENAME(@join_viewname)

                if (@join_unique_key = 1 and (@bool_filterclause is null or len(@bool_filterclause) = 0) and
                    not exists (select * from sysmergesubsetfilters where pubid=@pubid and artid=@artid and join_filterid <> @join_filterid))
                    begin
                    set @simple_join_view = 1
                    if @column_list = ' * '
                    	select @column_list = ' ' + @unqual_sourcename + '.* '
                    set @view_rule = 'select ' + @column_list + ' from ' + @source_object + ' ' + @unqual_sourcename + ' , ' +  @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause
                    /* add security check to the view if this is a dynamically filtered publication */
                    set @view_rule = @view_rule + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
                    end
                else
                    begin
                    set @simple_join_view = 0
					/* Alias the source object with the unqualified name and use that to select the rowguidcol */                   
                    set @view_rule = 'select ' + @unqual_sourcename + '.rowguidcol from ' + @source_object  + ' ' + @unqual_sourcename + ' , ' +  @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause
                    end
                if @before_name is not null
                	set @before_view_rule = 'select * from ' + @before_name + ' ' +  @unqual_sourcename + ' where exists (select * from ' +
                   	 	@join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from ' +
                   	 	@join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') '
                   	 	
                fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
                WHILE (@@fetch_status <> -1)
                    begin
					select @join_filterclause=' ( ' + @join_filterclause + ') '
                    select @unqual_jointable = name from sysobjects 
                        where id = ( select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) 
                
	                select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid)
                		from sysmergearticles where nickname = @join_nick and pubid = @pubid
                    select @join_viewname = QUOTENAME(@join_viewname)
                    set @view_rule = @view_rule + ' union select ' + @source_object + '.rowguidcol from ' + @source_object + ', ' +  @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause
                   	if @before_name is not null
                		set @before_view_rule = @before_view_rule + ' or exists (select * from ' +
                   	 	@join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from ' +
                   	 	@join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') '
                 
                    fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid
                    end 
                close pub1
                deallocate pub1
                        
                if len(@bool_filterclause) > 0
                	begin
                    set @view_rule = @view_rule + ' union select ' + @source_object + '.rowguidcol from '+ @source_object + ' where '+ @bool_filterclause
                   	if @before_name is not null
                		set @before_view_rule = @before_view_rule + ' or ' + @bool_filterclause
					
                    end
                -- Now do the actual view rule as a semi-join, if not a simple join on unique key
                if (@simple_join_view = 0)
                    begin
                    /* 
                    ** Generate a unique alias for the outer select to make sure that it does not generate an
                    ** ambiguous reference with table names used in the join_filter clause 
                    */
					set @alias_for_sourceobject = 'alias_' + @guidstr
					exec @retcode = sp_MSgetcolumnlist @pubid, @prefixed_column_list OUTPUT, @source_objid, @alias_for_sourceobject

                    set @view_rule = 'select ' + @prefixed_column_list + ' from ' + @source_object + ' ' + @alias_for_sourceobject + ' where rowguidcol in (' + @view_rule + ')'
					set @view_rule = @view_rule + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
                    end
                end
            else  /* boolean filter only */
            	begin
                select @view_rule = ' select ' + @column_list + ' from '+ @source_object + ' ' + @unqual_sourcename + ' where '+ @bool_filterclause
				if @before_name is not null
					set @before_view_rule = ' select * from ' + @before_name + ' ' + @unqual_sourcename + ' where ' + @bool_filterclause
                set @view_rule = @view_rule + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
				end
                           
            select @viewname = @publication + '_' + @article + '_VIEW'
            exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
            select @quoted_view = QUOTENAME(@viewname)
            
            if @retcode <> 0 or @@ERROR <> 0 return (1) 
            /* If we havent generated rowguidcol yet, use dummy rule that doesnt refer to it */
            if @hasguid = 0
                set @view_rule = ' select ' + @column_list + ' from '+ @source_object + ' ' + @unqual_sourcename
            exec ('create view '+ @quoted_view + ' as '+ @view_rule)
            if @@ERROR<>0
            	return (1)
            /* grant select permission on sync view to public - security check is performed inside the view */ 
			exec ('grant select on ' + @quoted_view + ' to public')
			if @@ERROR<>0
				return (1)
            /* Mark view as system object */                        
            execute sp_MS_marksystemobject @quoted_view
            if @@ERROR<>0
            	return (1)
            if @hasguid = 1
                begin
                select @procname=view_sel_proc from sysmergearticles where pubid=@pubid and artid=@artid
		        if object_id(@procname) is not NULL
                    begin
                    exec ('drop procedure ' + @quoted_proc)
                    update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid 
                    end
                else
                    begin
					set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
                    exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output
                    if @retcode <> 0 or @@ERROR <> 0
                            return (1)
                    end
                select @owner = user_name(uid) from sysobjects 
                    where name = @viewname 
                exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol, @source_objid
                if @retcode<>0 or @@ERROR<>0
                	return (1)
                update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid
                end
            select @quoted_view = QUOTENAME(@viewname)
            update sysmergearticles set sync_objid = OBJECT_ID (@quoted_view), view_type = @permanent
                where artid = @artid and pubid = @pubid 
			if @before_name is not null
				begin
				exec @retcode = sp_MScreatebeforetable @source_objid
				if @@ERROR <>0 OR @retcode <>0 return (1)
				if object_id(@before_viewname) is not NULL
					exec ('drop view ' + @before_viewname)				
				exec ('create view ' + @before_viewname + ' as ' + @before_view_rule)
				if @@ERROR<>0
					return (1)
				if @before_rowguidname is not NULL
					begin
						exec ('grant select (' + @before_rowguidname + ') on '+ @before_viewname + ' to public')
						if @@ERROR<>0
							return (1)
					end
				execute sp_MS_marksystemobject @before_viewname
	            if @@ERROR<>0
    	        	return (1)
	            update sysmergearticles set before_view_objid = OBJECT_ID (@before_viewname)
	            	where artid = @artid and pubid = @pubid
				end

            end /* end of view creation for this article */
        else 
        begin
            select @sync_objid = @source_objid
            if @vertical_partition=1 and @column_list<> ' * '
				begin
					select @viewname = @publication + '_' + @article + '_VIEW'
		            exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
					select @quoted_view = QUOTENAME(@viewname)
					set @view_rule = ' select ' + @column_list + ' from '+ @source_object + ' ' + @unqual_sourcename
                    set @view_rule = @view_rule + ' where ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'

	            	exec ('create view '+ @quoted_view + ' as '+ @view_rule)
	            	if @@ERROR<>0
	            		return (1)
	        	    execute sp_MS_marksystemobject @quoted_view
	            	if @@ERROR<>0
	            		return (1)

                    /* grant select permission on sync view to public - security check is performed inside the view */ 
					exec ('grant select on ' + @quoted_view + ' to public')
					if @@ERROR<>0
	                	return (1)
	            	select @sync_objid=object_id(@viewname)
				update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid
    	            where artid = @artid and pubid = @pubid 
				end
            else if @dynamic_filters = 1
                begin
                    /* This article doesn't have any vertical or horizontal filters but if the publication is enabled for dynamic filtering, 
                        we still want to generate a dummy view so that logins in the publication access list can generate a dynamic snapshot. */
                    select @viewname = @publication + '_' + @article + '_VIEW'
                    exec @retcode = dbo.sp_MSuniqueobjectname @viewname, @viewname output
                    select @quoted_view = QUOTENAME(@viewname)
                    set @view_rule = ' select  * from ' + @source_object  + ' where ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'     
	            	exec ('create view '+ @quoted_view + ' as '+ @view_rule)
	            	if @@ERROR<>0
	            		return (1)
	        	    execute sp_MS_marksystemobject @quoted_view
	            	if @@ERROR<>0
	            		return (1)
                    exec ('grant select on ' + @quoted_view + ' to public')
        	        if @@ERROR<>0
	                	return (1)
	            	select @sync_objid=object_id(@viewname)
    				update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid, view_type = @permanent
    	            where artid = @artid and pubid = @pubid 
                end

        	if @hasguid = 1
            begin
            /* still make the select proc, although it selects directly from table */
	        if object_id(@procname) is not NULL
				begin
					exec ('drop proc ' + @procname)
					update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid 
				end
			set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16)
            exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output
            if @retcode <> 0 or @@ERROR <> 0 return (1) 
            select @owner = user_name(uid), @viewname = name from sysobjects 
                where id = @source_objid
            exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol, @source_objid
			update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid
            end
        end
   select @art=min(indexcol) from #art where indexcol>@art
   end

    /* If there are looping articles, we must use a dynamic publication since no views on temp tables */
    update sysmergearticles set view_type = @temporary
        where pubid=@pubid and nickname not in (select art_nick from #art)
    if @@rowcount > 0
        begin
        if not exists (select * from sysmergepublications where dynamic_filters = 1 and pubid = @pubid)
            begin
            declare @repl_nick int
            /* treat these articles as if the publication were dynamic */
            execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output
            if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL 
		        begin
		        RAISERROR (14055, 11, -1)
		        RETURN(1)
		        end                 

            select @art_nick = min(nickname) from sysmergearticles where
                pubid = @pubid and view_type = @temporary
            while @art_nick is not null
                begin
                /* Loop over articles with circular filters.  Create dummy view and add rows to contents */
                select @article = name, @artid = artid, @source_objid = objid, @sync_objid = sync_objid, @procname = view_sel_proc from sysmergearticles 
                    where nickname=@art_nick and pubid = @pubid
                select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects 
                    where id = @source_objid 

                set @viewname = NULL
                select @viewname =  name from sysobjects where id = @sync_objid and
                    ObjectProperty (id, 'IsView') = 1  and
                    ObjectProperty (id, 'IsMSShipped') = 1 
                if @viewname IS NOT NULL
                    begin
                        select @quoted_view = QUOTENAME(@viewname)
                        exec ('drop view ' + @quoted_view)
                        if @@ERROR<>0 return (1)
                    end
                select @viewname = 'SYNC_' + @publication + '_' + @article 
                exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output
                if @retcode <> 0 or @@ERROR <> 0 return (1) 
                select @quoted_view = QUOTENAME(@viewname)
                exec ('create view ' + @quoted_view + ' as select * from ' + @source_object + ' 
                        where 1 = 0 ')
                if @@ERROR<>0 return (1)
                update sysmergearticles set sync_objid = OBJECT_ID (@viewname),
                    view_sel_proc = NULL where artid = @artid and pubid = @pubid 
                if @@ERROR<>0 return (1)

				select @owner = user_name(uid) from sysobjects where id = @source_objid
				set @table = OBJECT_NAME(@source_objid)
        		exec @retcode = dbo.sp_addtabletocontents @table, @owner
                IF @@ERROR <> 0 or @retcode <> 0 return (1)
                
                select @art_nick = min(nickname) from sysmergearticles where
                    pubid = @pubid and view_type = @temporary and nickname > @art_nick
                end
            end
        end
        
    drop table #art
    if @allhaveguids = 1
        begin
        declare @dbname sysname
        set @dbname = db_name()
        /* create the filter expand procs now */
        set @filter_id = 0
        select @filter_id = min(join_filterid) from sysmergesubsetfilters where
                pubid = @pubid and join_filterid > @filter_id
        while @filter_id is not null
            begin
            set @filter_id_str = convert(nvarchar(10), @filter_id)
            select @procname = expand_proc
                from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filter_id
            /* drop old proc, or generate a new procname */
            select @quoted_proc = QUOTENAME(@procname)
	        if object_id(@procname) is not NULL
                exec ('drop procedure ' + @quoted_proc)
            else
                begin
                set @procname = 'expand_' + @filter_id_str
                exec @retcode = dbo.sp_MSuniqueobjectname @procname, @procname output
                if @retcode <>0 return (1)
                update sysmergesubsetfilters set expand_proc = @procname where  pubid = @pubid and join_filterid = @filter_id
                end
            select @quoted_proc = QUOTENAME(@procname)
            select @quoted_pub = QUOTENAME(@publication)
            set @command = 'exec dbo.sp_MSmakeexpandproc ' + @quoted_pub + ' , ' + @filter_id_str + ', ' + @quoted_proc
            exec @retcode = master..xp_execresultset @command, @dbname
            if @retcode <> 0 return (1)
			exec dbo.sp_MS_marksystemobject @quoted_proc
            if @@ERROR<>0
            	return (1)
            exec ('grant execute on ' + @quoted_proc + ' to public ')
            select @filter_id = min(join_filterid) from sysmergesubsetfilters where
                pubid = @pubid and join_filterid > @filter_id
            end
        end

    return (0)

FAILURE: 
    return (1)
go

exec dbo.sp_MS_marksystemobject sp_MSpublicationview
go

grant execute on dbo.sp_MSpublicationview to public
go



--------------------------------------------------------------------------------
--. sp_MSgetrowmetadata 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSgetrowmetadata')
    drop procedure sp_MSgetrowmetadata
go


raiserror('Creating procedure sp_MSgetrowmetadata', 0,1)
GO

CREATE PROCEDURE sp_MSgetrowmetadata
	(@tablenick int,
	 @rowguid uniqueidentifier,
	 @generation int output,
	 @type  tinyint output,
	 @lineage varbinary(255) output,
	 @colv varbinary(2048) output,
	 @pubid uniqueidentifier = NULL)
as
	declare @retcode 		smallint
	declare @saverr 		int
	declare @rc 			int
	declare @procname 		nvarchar(270)
	
	/*
	** To public.
	*/
	
	
	if (@tablenick is null)
		begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
		end
	if (@rowguid is null)
		begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (1)
		end

	set @type= 4
	set @generation= 0
	set @lineage= NULL
	set @colv= NULL

	select @procname= select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid

	-- check for row in base table
	exec @retcode= @procname @type=@type output, @rowguid=@rowguid
	if @@error <>0 or @retcode <> 0 
	begin
		return (1)
	end

	begin tran
	if (@type = 3)
	begin
		-- row is in base table; check whether it is in contents, too
		--
		-- serializable makes sure row does not go from tombstone to contents between 
		-- querying contents and tombstone, which would falsely result in type = missing
		select @type= 2,  @generation= generation, @lineage= lineage, @colv= colv1 from dbo.MSmerge_contents
			with (serializable)
			where tablenick = @tablenick and rowguid = @rowguid
	end
	else
	begin
		-- row is not in base table; either it is in tombstone, or it is missing
		set @type= 0

		select @type= type, @generation= generation, @lineage= lineage from dbo.MSmerge_tombstone where
			tablenick = @tablenick and rowguid = @rowguid
	end
	commit tran
	
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetrowmetadata
go
grant exec on dbo.sp_MSgetrowmetadata to public
go


--------------------------------------------------------------------------------
--. sp_MSgetmetadatabatch 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSgetmetadatabatch')
    drop procedure sp_MSgetmetadatabatch
go

raiserror('Creating procedure sp_MSgetmetadatabatch', 0,1)
GO

CREATE PROCEDURE sp_MSgetmetadatabatch
	(@pubid uniqueidentifier,
	 @tablenickarray varbinary(2000),
	 @rowguidarray varbinary(8000)
	)
as
	declare @tablenick int
	declare @tablenicklast int
	declare @rowguid uniqueidentifier
	declare @generation int 
	declare @type  tinyint
	declare @lineage varbinary(255) 
	declare @colv varbinary(2048)
	declare @retcode 		smallint
	declare @saverr 		int
	declare @tnlength		int
	declare @tnoffset		int
	declare @guidoffset		int
	declare @procname 		nvarchar(270)

	-- create temp table for returning results
	declare  @meta_batch TABLE (idx int identity, generation int, type  tinyint,
	 		lineage varbinary(255), colv varbinary(2048))

	/*
	** To public.
	*/
	
	if (@tablenickarray is null)
		begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
		end
	if (@rowguidarray is null)
		begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (1)
		end
	
	set @tablenicklast = 0
	-- initialize offsets and length for walking through arrays
	set @tnoffset = 1
	set @guidoffset = 1
	set @tnlength = datalength(@tablenickarray)




	-- walk through arrays and populate temp table
	while (@tnoffset < @tnlength)
		begin
		set @tablenick = substring(@tablenickarray, @tnoffset, 4)
		set @rowguid = substring(@rowguidarray, @guidoffset, 16)

		-- instead of calling sp_MSgetrowmetadata, look it up ourselves might be faster
		
		--	exec @rc = sp_MSgetrowmetadata @tablenick, @rowguid,  @generation output,
	 	--	@type  output, @lineage output, @colv output, @pubid
		if @tablenick <> @tablenicklast
			begin
			select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid=@pubid
			set @tablenicklast = @tablenick
			end

		set @type= 4
		set @generation= 0
		set @lineage= NULL
		set @colv= NULL

		-- check for row in base table
		exec @retcode= @procname @type=@type output, @rowguid=@rowguid
		if @@error <>0 or @retcode <> 0 
		begin
			return (1)
		end

		begin tran
		if (@type = 3)
		begin
			-- row is in base table; check whether it is in contents, too
			--
			-- serializable makes sure row does not go from tombstone to contents between 
			-- querying contents and tombstone, which would falsely result in type = missing
			select @type= 2,  @generation= generation, @lineage= lineage, @colv= colv1 from dbo.MSmerge_contents
				with (serializable)
				where tablenick = @tablenick and rowguid = @rowguid
		end
		else
		begin
			-- row is not in base table; either it is in tombstone, or it is missing
			set @type= 0

			select @type= type, @generation= generation, @lineage= lineage from dbo.MSmerge_tombstone where
				tablenick = @tablenick and rowguid = @rowguid
		end
		commit tran




	 	-- insert values into temp table
	 	insert into @meta_batch (generation, type, lineage, colv) values
	 		(@generation, @type, @lineage, @colv) 

	 	-- bump up offsets for next time through loop
	 	set @tnoffset = @tnoffset + 4
	 	set @guidoffset = @guidoffset + 16
		end

	-- select out our result set
	select generation, type, lineage, colv from @meta_batch order by idx
	
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetmetadatabatch
go
grant exec on dbo.sp_MSgetmetadatabatch to public
go

--------------------------------------------------------------------------------
--. sp_MSupdategenhistory 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSupdategenhistory')
    drop procedure sp_MSupdategenhistory
go

raiserror('Creating procedure sp_MSupdategenhistory', 0,1)
GO

CREATE PROCEDURE sp_MSupdategenhistory
	(@guidsrc uniqueidentifier, @pubid uniqueidentifier, @gen int, @art_nick int = NULL)
as
	declare @guidlocal uniqueidentifier
	
	/*
	** Check to see if current publication has permission
	*/
	declare @retcode int

	if sessionproperty('replication_agent') = 0
	begin
		exec @retcode=sp_MSreplcheck_connection
			@pubid = @pubid
		if @retcode<>0 or @@ERROR<>0 return (1)
	end
	
	if (@guidsrc is null)
	begin
		RAISERROR(14043, 16, -1, '@guidsrc')
		return (1)
	end
		
	if @art_nick = 0 set @art_nick = NULL
	
	set @guidlocal = newid()
	begin tran
	save tran sp_MSupdategenhistory
	if exists (select * from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen)
	begin
		create table #gentable (generation int)

		insert into #gentable select generation from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen

		update mc set mc.generation= @gen from dbo.MSmerge_contents as mc inner join #gentable as g 
			on (mc.generation=g.generation) 
		if @@ERROR <> 0 goto FAILURE

		update mt set mt.generation= @gen from dbo.MSmerge_tombstone as mt inner join #gentable as g 
			on (mt.generation=g.generation) 
		if @@ERROR <> 0 goto FAILURE
		
		declare @cmd nvarchar(200)
		declare @bi_objid int
		set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @art_nick)
		if @bi_objid is not null
		begin
			set @cmd= 'update bi set bi.generation= @gen from dbo.' + object_name(@bi_objid) + ' as bi inner join #gentable as g
				on (bi.generation = g.generation)'
			exec dbo.sp_executesql @cmd, N'@gen int', @gen= @gen
			if @@ERROR <> 0 goto FAILURE
		end

		delete from dbo.MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen
		
		if @@ERROR <> 0 goto FAILURE
		drop table #gentable
	end
	if exists (select * from dbo.MSmerge_genhistory where guidsrc = @guidsrc)
		update dbo.MSmerge_genhistory set guidlocal= @guidlocal, coldate= getdate() where guidsrc = @guidsrc 
	else
	begin
		declare @mynickname int
		declare @nickbin varbinary(255)

		exec dbo.sp_MSgetreplnick @nickname = @mynickname out
		if @@ERROR<>0 goto FAILURE

		-- Append guard byte if it is needed
		if @mynickname % 256 = 0
			set @nickbin  = convert(binary(4), @mynickname) + 0x01
		else
			set @nickbin  = convert(binary(4), @mynickname)

		insert into dbo.MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values
			(@guidsrc, @guidlocal, @gen, @art_nick, @nickbin , getdate())

	end

	commit

	-- Now that we have closed a generation that was open, we might be ready to
	-- cleanup metadata or something like that.
	exec @retcode = sp_MSquiescecheck					
	
	return (0)
	
FAILURE:
	rollback tran sp_MSupdategenhistory
	commit tran
	return(1)
go
exec dbo.sp_MS_marksystemobject sp_MSupdategenhistory
go
grant exec on dbo.sp_MSupdategenhistory to public

--------------------------------------------------------------------------------
--. sp_MSinsertgenhistory 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSinsertgenhistory')
    drop procedure sp_MSinsertgenhistory
go

raiserror('Creating procedure sp_MSinsertgenhistory', 0,1)
GO

CREATE PROCEDURE sp_MSinsertgenhistory
	(@guidsrc uniqueidentifier,
	 @gen int output,
	 @pubid uniqueidentifier,
	 @pubid_ins uniqueidentifier = NULL,
	 @nicknames varbinary(1000) = 0x0,
	 @artnick int = NULL
	)
as
	/*
	** Check to see if current publication has permission
	*/
	declare @retcode int, @mynickname int, @newnicks varbinary(1000), @dt datetime
	
	if sessionproperty('replication_agent') = 0
	begin	
		exec @retcode=sp_MSreplcheck_connection
			@pubid = @pubid
		if @retcode<>0 or @@ERROR<>0 return (1)
	end
	
	if (@guidsrc is null)
	begin
		RAISERROR(14043, 16, -1, '@guidsrc')
		return (1)
	end
	
	-- having the login time in dbo.MSmerge_genhistory allows to associate the row with the merge process that inserted the row
	select @dt= login_time from master..sysprocesses where spid = @@spid

	-- Check for older in process generation

	select @gen = max(generation) from dbo.MSmerge_genhistory where guidsrc = @guidsrc
	if @gen is not null
	begin
		-- this generation was interrupted at a previous merge
		-- next statement makes sure that gen does no longer look interrupted to another process
		update dbo.MSmerge_genhistory set coldate= @dt where guidsrc = @guidsrc

		-- if @@rowcount = 0, another process removed the interrupted gen just before the previous update statement
		if @@rowcount > 0
		begin
			return (0)
		end
	end

	exec dbo.sp_MSgetreplnick @nickname = @mynickname out
	if @@ERROR<>0 return (1)

	-- Append guard byte if it is needed
	if @nicknames = 0x0 and (@mynickname % 256 = 0)
		set @newnicks = convert(binary(4), @mynickname) + 0x01
	else
		set @newnicks = convert(binary(4), @mynickname) + @nicknames
		
	begin tran
	save tran sp_MSinsertgenhistory
	
	select @gen = COALESCE(1 + max(generation), 1) from dbo.MSmerge_genhistory (updlock)

	if (@gen is NULL)
		select @gen = 1
	
	insert into dbo.MSmerge_genhistory (guidsrc, pubid, guidlocal, generation, art_nick, nicknames, coldate) 
		values (@guidsrc, @pubid_ins, '00000000-0000-0000-0000-000000000000', @gen, @artnick, @newnicks, @dt)

	if @@error<>0 goto Failure
		
	commit tran
	return (0)
Failure:
	rollback tran sp_MSinsertgenhistory
	commit tran
	RAISERROR(15001, 16, -1, 'MSmerge_genhistory')
	return (1)
go
exec dbo.sp_MS_marksystemobject sp_MSinsertgenhistory
go
grant exec on dbo.sp_MSinsertgenhistory to public

--------------------------------------------------------------------------------
--. sp_MSlocalizeinterruptedgenerations 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSlocalizeinterruptedgenerations')
    drop procedure sp_MSlocalizeinterruptedgenerations
go

raiserror('Creating procedure sp_MSlocalizeinterruptedgenerations', 0,1)
GO

CREATE PROCEDURE sp_MSlocalizeinterruptedgenerations
-- this proc loops over interrupted generations 
-- and transfers those changes that arrived before the interrupt to a new local generation
as

-- loop over interrupted generations
declare @guidnull uniqueidentifier, @guidsrc uniqueidentifier
declare @retcode int

set @guidnull= '00000000-0000-0000-0000-000000000000'
while (1=1) 
begin
	-- determine lowest incomplete generation
	select @guidsrc= null
	select @guidsrc= 
		(select top 1 guidsrc from dbo.MSmerge_genhistory h
			where	guidlocal=@guidnull  -- incomplete gen
					and generation not in (select gen_cur from sysmergearticles)  -- not a local incomplete gen
					and coldate not in (select login_time from master..sysprocesses)  -- not a gen that currently receives replica updates from another db
			order by generation asc
		)

	if (@guidsrc is null)
		break

	-- create a new generation
	declare @newguid uniqueidentifier
	declare @nicknames varbinary(255)
	declare @artnick integer, @oldgen integer

	set @newguid= newid()
	select @nicknames= nicknames, @artnick= art_nick, @oldgen= generation from dbo.MSmerge_genhistory where guidsrc=@guidsrc
	
	begin tran
	save tran sp_locintgens
	declare @newgen int
	select @newgen= max(generation) from dbo.MSmerge_genhistory (updlock)
	set @newgen= @newgen + 1

	insert into dbo.MSmerge_genhistory values (@newguid, @newguid, NULL, @newgen, @artnick, @nicknames, getdate())
	if @@ERROR <> 0
		goto ROLLBACK_T_INNER
	
	commit tran

	begin tran
	save tran sp_locintgens

	-- move rows of interrupted generation to the new generation
	update dbo.MSmerge_contents set generation= @newgen where generation=@oldgen
	if @@ERROR <> 0 goto ROLLBACK_T_INNER
	
	update dbo.MSmerge_tombstone set generation= @newgen where generation=@oldgen
	if @@ERROR <> 0 goto ROLLBACK_T_INNER

	declare @cmd nvarchar(200)
	declare @bi_objid int
	set @bi_objid= (select top 1 before_image_objid from sysmergearticles where nickname = @artnick)
	if @bi_objid is not null
	begin
		set @cmd= 'update dbo.' + object_name(@bi_objid) + ' set generation= @newgen where generation = @oldgen'
		exec dbo.sp_executesql @cmd, N'@newgen int, @oldgen int', @newgen= @newgen, @oldgen= @oldgen
		if @@ERROR <> 0 goto ROLLBACK_T_INNER
	end

	-- remove (now empty) interrupted generation
	delete from dbo.MSmerge_genhistory where 
				guidsrc=@guidsrc and
				guidlocal=@guidnull and
				coldate not in (select login_time from master..sysprocesses)
	if @@ERROR <> 0
		goto ROLLBACK_T_INNER

	commit tran

	-- Now that we have removed generations that were open, we might be ready to
	-- cleanup metadata or something like that.
	exec @retcode = sp_MSquiescecheck					

end

return 0

ROLLBACK_T_INNER:
rollback tran sp_locintgens -- the reconciler can still continue, but it will ignore interrupted generations
commit tran
return 1
go

exec dbo.sp_MS_marksystemobject sp_MSlocalizeinterruptedgenerations
go
grant exec on dbo.sp_MSlocalizeinterruptedgenerations to public


--------------------------------------------------------------------------------
--. sp_MSmakeconflictinsertproc 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSmakeconflictinsertproc')
    drop procedure sp_MSmakeconflictinsertproc
go

raiserror('Creating procedure sp_MSmakeconflictinsertproc', 0,1)
GO

create procedure sp_MSmakeconflictinsertproc 
	(@tablename sysname, @ownername sysname, @procname sysname, @basetableid int, @pubid uniqueidentifier=NULL)
as
declare @arglist	nvarchar(4000)
declare @header		nvarchar(4000)
declare @qualname   nvarchar(270)
declare @argname	nvarchar(270)
declare @noset		bit
declare @wherepc	nvarchar(255)
declare @id 		int
declare @sync_objid	int
declare @colname nvarchar(140)
declare @typename sysname
declare @colid smallint
declare @status tinyint
declare @len smallint
declare @prec smallint
declare @scale int
declare @retcode smallint
declare @sys_loop bit
declare @old_colname nvarchar(140)
declare @create_time_col nvarchar(8)
declare @p_number_for_conflict_type nvarchar(270)

set nocount on

select @sys_loop = 0
set @create_time_col = NULL

if (@ownername is null or @ownername = ' ')
	set @qualname = QUOTENAME(@tablename)
else
	set @qualname = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)

/*
** To check if specified object exists in current database
*/
set @id = object_id(@qualname)
	if @id is NULL return (1)

-- create temp table to select the command text out of
create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, 
cmdtext nvarchar(4000) collate database_default null)

select @header = 'Create procedure dbo.' + @procname + ' ( ' 
insert into #tempcmd (phase, cmdtext) values (0,  @header)

select @sync_objid = sync_objid from sysmergearticles where objid = @basetableid and (pubid = @pubid or @pubid is NULL)

select @colid = min(colid) from syscolumns where id = @id and iscomputed <>1 and 
	type_name(xtype) <> 'timestamp' and ((name not in (select name from syscolumns where id=@basetableid) 
		and @sys_loop =1) OR
	 (name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
	@prec = c.prec, @scale = c.scale
	from syscolumns c, systypes t
	where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype 

/*
** Get the column list from the conflict_table schema and filter it with 
table view for vertical partitioning
*/
Reverse_Order:
while (@colname is not null) 
begin
	set @noset = 0
	if exists (select * from syscolumns where name=@colname and id=@basetableid)
		and not exists (select * from syscolumns where name=@colname and id=@sync_objid)
		goto NEXT_COL 		
	if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
		select @len = @len/2
	exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
	if @@ERROR<>0 or @retcode<>0 return (1)
	select @argname = '@p' + rtrim(convert(nchar, @colid))
	
	if LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS)='conflict_type'
		select @p_number_for_conflict_type=@argname
		
	-- based on colid, add text to appropriate pieces
	if (COLUMNPROPERTY( @basetableid, @colname, 'IsRowGuidCol') = 1)  
		begin
			select @noset =1
			set @wherepc = ' where rowguidcol = ' + @argname
		end
	else if (@colname = 'origin_datasource')
		begin
			select @wherepc =@wherepc +  ' and origin_datasource = ' + @argname
			set @noset =1
		end
	set @old_colname = @colname
	set @colname = QUOTENAME(@colname)
	if @arglist is null
		begin
		set @arglist = @argname + ' ' + @typename
		--give default value of NULL to new merge columns for backward compatibility concern
		insert into #tempcmd (phase, cmdtext) values (3, @colname)
		select @header = ') values ('
		insert into #tempcmd (phase, cmdtext) values (4, @header)

		insert into #tempcmd (phase, cmdtext) values (4, @argname)
		if @noset=0
			insert into #tempcmd (phase, cmdtext) values (1, @colname + ' = ' + @argname)
		end
	else 
		begin
		if len(@arglist)>3700
			begin
				insert into #tempcmd (phase, cmdtext) values (0,  @arglist)			
				select @arglist = ' '
			end
		set @arglist = @arglist + ', ' + @argname + ' ' + @typename
		if @sys_loop = 1 and @old_colname not in ('origin_datasource','conflict_type','reason_code','reason_text', 'pubid') 
			begin
				select @arglist=@arglist + ' = NULL'		
				if @old_colname='MSrepl_create_time'
					select @create_time_col=@argname
			end

		insert into #tempcmd (phase, cmdtext) values (3, ',' + @colname)

		insert into #tempcmd (phase, cmdtext) values (4, ',' + @argname)

		if @noset =0
			begin
				if exists (select * from #tempcmd where phase=1)
					insert into #tempcmd (phase, cmdtext) values (1, ',' + @colname + ' = ' + @argname)
				else
					insert into #tempcmd (phase, cmdtext) values (1, @colname + ' = ' + @argname)
			end
		end
NEXT_COL:
	select @colid = min(colid) from syscolumns where id = @id and colid>@colid and iscomputed <>1 and 
		type_name(xtype) <> 'timestamp' and 
		((name not in (select name from syscolumns where id=@basetableid) and @sys_loop =1) OR
	 		(name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
	set @colname = NULL
	select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
		@prec = c.prec, @scale = c.scale
		from syscolumns c, systypes t
		where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype
end

if @sys_loop = 0
begin
	select @sys_loop = 1
	select @colid = min(colid) from syscolumns where id = @id  and iscomputed <>1 
		and type_name(xtype) <> 'timestamp' and 
		((name not in (select name from syscolumns where id=@basetableid) and @sys_loop =1) OR
	 	(name in (select name from syscolumns where id=@basetableid) and @sys_loop =0))
	select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length,
		@prec = c.prec, @scale = c.scale
		from syscolumns c, systypes t
			where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype 
	goto Reverse_Order
end

-- now create the procedure
select @procname = QUOTENAME(@procname)

insert into #tempcmd (phase, cmdtext) values (0,  @arglist)			

select @header =  ') as'
insert into #tempcmd (phase, cmdtext) values (0,  @header)

select @header = ' '
-- for ease of expansion here in case we add new merge columns in conflict tables.
if @create_time_col is not NULL
	select @header = @header + ' 
		select ' + @create_time_col + ' = getdate() '

select @header = @header + ' if exists (select * from ' + @qualname + ' ' + @wherepc + ')
	begin
	update ' + @qualname + ' set ' 
insert into #tempcmd (phase, cmdtext) values (0,  @header)

--see comment in sp_MSinsertdeleteconflict for this <5 or >4 checking.

select @header = @wherepc + ' and (conflict_type<5 or ' + @p_number_for_conflict_type + ' >4) 
	end
	else
	insert into ' + @qualname + ' ('
insert into #tempcmd (phase, cmdtext) values (2,  @header)

insert into #tempcmd (phase, cmdtext) values (4, ')')

-- Now we select out the command text pieces in proper order so that our caller,
-- xp_execresultset will execute the command that creates the stored procedure.

select cmdtext from #tempcmd order by phase, step
drop table #tempcmd
go
exec dbo.sp_MS_marksystemobject sp_MSmakeconflictinsertproc 
go
grant exec on dbo.sp_MSmakeconflictinsertproc to public
go

--------------------------------------------------------------------------------
--. sp_MSsetupworktables 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSsetupworktables')
    drop procedure sp_MSsetupworktables
go

raiserror('Creating procedure sp_MSsetupworktables', 0,1)
GO

-- Modify temp table. No security check needed.
create procedure sp_MSsetupworktables
	@pubid				uniqueidentifier,
	@genlist	 		varchar(8000),
	@articlesoption		int,	-- 0=process all articles, 1=process this specific article (whose nickname is passed in @tablenickname), 2=all articles involved in join filters, 3=process all articles involved in part filters, 4=process articles whose nicknames have been passed in @nicknamelist.
	@tablenickname		int,
	@nicknamelist		varchar(8000),
	@mingen				int = 0,
	@maxgen				int = 0,
	@skipgenlist		varchar(8000) = NULL,
	@contents_subset_rowcount int OUTPUT,
	@tombstone_subset_rowcount int OUTPUT
AS
	
	declare @lengenlist int
	declare @lenskipgenlist int

	-- put in a nickname with value 0 - This will match 
	-- gen history rows put in by downlevel subscribers 
	-- with art_nick = NULL 
	insert into #nicknames_to_process values (0)

	if (@articlesoption = 0)
	begin
		
		-- process all articles for this publication
		insert into #nicknames_to_process 
		select distinct nickname 
		from sysmergearticles a 
		where pubid = @pubid

	end
	else if (@articlesoption = 1)
	begin
		
		--process only the article whose nickname has been passed-in
		insert into #nicknames_to_process values (@tablenickname)
		
	end
	else if (@articlesoption = 2)
	begin
		--process all articles with join filters (article could be on any side - left or right - of any join filter)
		insert into #nicknames_to_process 
		select distinct nickname 
		from sysmergearticles a 
		where pubid = @pubid 
		and exists (select * from sysmergesubsetfilters s 
					where s.pubid = @pubid 
					and (s.art_nickname = a.nickname or s.join_nickname = a.nickname))
	end
	else if (@articlesoption = 3)
	begin
	
		--process all articles with part filters but that don't have a join filter.
		insert into #nicknames_to_process 
		select distinct nickname 
		from sysmergearticles a 
		where pubid = @pubid 
		and datalength(subset_filterclause) > 1
		and not exists (select * from sysmergesubsetfilters s 
					where s.pubid = @pubid 
					and (s.art_nickname = a.nickname or s.join_nickname = a.nickname))
	end
	else if (@articlesoption = 4)
	begin
		--process all articles whose nicknames have been passed into @nicknamelist
		if (@nicknamelist is not null and rtrim(ltrim(@nicknamelist)) <> '')
		begin
			exec ('insert into #nicknames_to_process select distinct nickname from sysmergearticles where nickname in (' + @nicknamelist + ')')
			if @@ERROR <>0 return (1)
		end
	end

	-- Create index on #nicknames_to_process now that it has been populated. Creating it after data insertion is better because
	-- that generates the stats for the index. That helps in the insert into #contents_subset query. The other option was to 
	-- create the index, insert the data, and then update statistics.
	create unique index #nicknames_ind on #nicknames_to_process (nickname)

	if (@maxgen <> 0)
	begin
			
		insert into #genlist select distinct generation 
			from dbo.MSmerge_genhistory gh 
			join #nicknames_to_process np
			on isnull(gh.art_nick,0) = np.nickname and 
			gh.generation >= @mingen
			and gh.generation <= @maxgen

		select @lengenlist = isnull(datalength(@genlist),0)
		select @lenskipgenlist = isnull(datalength(@skipgenlist),0)

		-- no need to do ltrim and rtrim on the @skipgenlist. sp_MSsetupbelongs already did that.
		if (@skipgenlist is not null and @skipgenlist <> '' and @lenskipgenlist <= @lengenlist)
		begin
			exec('delete from #genlist where generation in (' + @skipgenlist + ')')
		end
		else if (@genlist is not null and @genlist <> '')
		begin
			-- gen 0 won't be in @genlist, so will get deleted because of the NOT IN.
			exec('delete from #genlist where generation not in (' + @genlist + ')')
		end
	end
	else if (@genlist is not null and @genlist <> '')
	begin
		exec ('insert into #genlist select distinct generation from dbo.MSmerge_genhistory where
			(isnull(art_nick,0) in (select nickname from #nicknames_to_process)) and 
			generation in (' + @genlist + ') ')
		if @@ERROR <>0 return (1)
	end

	-- Create index on #genlist now that it has been populated. Creating it after data insertion is better because
	-- that generates the stats for the index. That helps in the insert into #contents_subset query. The other option was to 
	-- create the index, insert the data, and then update statistics.
	create unique index #genlist_ind on #genlist (generation)

	if @maxgen is null
		select @maxgen = 0

	if @mingen is null
		select @mingen = 0

	if (@maxgen = 0)
	begin
		-- SQL 7.0 pull merge agents do not pass in @maxgen and @mingen, so the default is 0. 
		-- For them need to compute min and max. Note that we could do the same for 8.0 agents as well
		-- but 8.0 agents pass the min and max because they are used in the INSERT INTO #genlist query above
		-- when we don't have the #genlist table and all we have is the comma-separated @genlist string.
		select @mingen = min(generation), @maxgen = max(generation) from #genlist
	end

	insert into #contents_subset (tablenick, rowguid, generation, partchangegen, joinchangegen) 
	select c.tablenick, c.rowguid, c.generation, c.partchangegen, c.joinchangegen
	from dbo.MSmerge_contents c 
	JOIN #nicknames_to_process a
	ON c.generation >= @mingen
	AND c.generation <= @maxgen
	AND c.tablenick = a.nickname
	JOIN #genlist g 
	ON c.generation = g.generation
	AND c.generation >= @mingen
	AND c.generation <= @maxgen

	UNION
	
	-- the rows retrieved below have a partition change that falls into the relevant generation range
	-- if we do not process them now, we would later on assume that the partition change has already been processed
	select c.tablenick, c.rowguid, c.generation, c.partchangegen, c.joinchangegen
	from dbo.MSmerge_contents c 
	JOIN #nicknames_to_process a
	ON c.partchangegen >= @mingen
	AND c.partchangegen <= @maxgen
	AND c.tablenick = a.nickname
	JOIN #genlist g 
	ON c.partchangegen = g.generation
	AND c.partchangegen >= @mingen
	AND c.partchangegen <= @maxgen
	
	select @contents_subset_rowcount = @@rowcount

	insert into #tombstone_subset (tablenick, rowguid, type, generation)
	select t.tablenick, t.rowguid, t.type, t.generation
	from dbo.MSmerge_tombstone t
	JOIN #nicknames_to_process a
	ON t.generation >= @mingen
	AND t.generation <= @maxgen
	AND t.tablenick = a.nickname
	JOIN #genlist g
	ON t.generation = g.generation
	AND t.generation >= @mingen
	AND t.generation <= @maxgen
		
	select @tombstone_subset_rowcount = @@rowcount

	create clustered index #ucind_contents_subset on #contents_subset (tablenick, rowguid) with FILLFACTOR = 100
	create clustered index #ucind_tombstone_subset on #tombstone_subset (tablenick, rowguid) with FILLFACTOR = 100

	delete #nicknames_to_process from #nicknames_to_process ntp
	where not exists (select tablenick from #contents_subset cs where cs.tablenick = ntp.nickname) 
	and not exists (select tablenick from #tombstone_subset ts where ts.tablenick = ntp.nickname) 

	-- remove the nickname with value 0 that we put in specially at the beginning of this proc.
	delete from #nicknames_to_process where nickname = 0
	return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSsetupworktables
go
grant exec on dbo.sp_MSsetupworktables to public
go
--------------------------------------------------------------------------------
--. sp_MSexclause 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
			where type = 'P'
				and name = 'sp_MSexclause')
		drop procedure sp_MSexclause
go
raiserror('Creating procedure sp_MSexclause', 0,1)
GO

create proc sp_MSexclause  @tablenick int, @pubid uniqueidentifier  as
set nocount on
declare @clause nvarchar(4000)
declare @filterid int
declare @joinnick int
declare @jointable nvarchar(270)
declare @table nvarchar(270)
declare @basetable nvarchar(270)
declare @filter_clause nvarchar(2000)
declare @retcode int

exec @retcode= sp_MStablenamefromnick @tablenick, @basetable out
if @@error<>0 or @retcode<>0 return(1)
select @table = QUOTENAME(name)  from sysobjects where id in (select 
			objid from sysmergearticles where nickname = @tablenick)

declare f_c CURSOR LOCAL FAST_FORWARD for  select art_nickname, join_filterclause 
	from sysmergesubsetfilters where join_nickname = @tablenick and pubid = @pubid
	FOR READ ONLY
open f_c
fetch next from f_c into @joinnick, @filter_clause
while (@@fetch_status <> -1)
	begin
	exec @retcode= sp_MStablenamefromnick @joinnick, @jointable out
	if @@error<>0 or @retcode<>0 goto Failure
	-- As helper proc for sp_MSmakeinsertproc, we can insert directly to the
	-- temp table as we build up more commands for the insert proc.
	-- Our commands are part of phase 8...
	set @clause = ' 
		if @has_rows = 0 
		begin
			if exists (select 1 from ' + @basetable + ' (NOLOCK) , ' + @jointable + ' (NOLOCK) where '

	insert into #tempcmd (phase, cmdtext) values (8, @clause)

	set @clause = @filter_clause
	
	insert into #tempcmd (phase, cmdtext) values (8, @clause)

	set @clause = 
			' and ' + @table + '.rowguidcol = @rowguid)	
				select @has_rows = 1
		end
'
	insert into #tempcmd (phase, cmdtext) values (8, @clause)

	fetch next from f_c into @joinnick, @filter_clause
	end

close f_c
deallocate f_c

return(0)

Failure:
	close f_c
	deallocate f_c
	return(1)
go
exec dbo.sp_MS_marksystemobject sp_MSexclause  
go
grant exec on dbo.sp_MSexclause to public
go
--------------------------------------------------------------------------------
--. sp_MSmakeinsertproc 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
				where type = 'P' and
				name = 'sp_MSmakeinsertproc')
		drop procedure sp_MSmakeinsertproc
go
raiserror('Creating procedure sp_MSmakeinsertproc', 0,1)
GO

-- This will be called by snapshot at publisher side and 
-- merge at the subscriber side, check for dbo permission
create procedure sp_MSmakeinsertproc 
	(@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier)
as
declare @argname			sysname
declare @id 				int
declare @sync_objid			int
declare @qualified_name		nvarchar(270)
declare @idstr				nvarchar(100)
declare @iscomputed			tinyint
declare @xtype				tinyint
declare @colstat 			int
declare @permissions		int
declare @permissions_str 	nvarchar(10)

if @ownername is NULL or @ownername=''
	select @qualified_name = QUOTENAME(@tablename)
else	
	select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
	
select @id = object_id(@qualified_name)
if @id is NULL return (1)

select @sync_objid = sync_objid, @permissions_str=convert(nvarchar(10),check_permissions), @permissions=check_permissions
	from sysmergearticles where objid=@id and pubid=@pubid

set @idstr = rtrim(convert(nchar, @id))	

declare @retcode int
declare @colname nvarchar(140)
declare @rgcolname nvarchar(140)
declare @typename nvarchar(140)
declare @colid smallint
declare @status tinyint
declare @len smallint
declare @prec int
declare @scale int
declare @tablenick int
declare @tablenickstr nvarchar(12)
declare @colordinal smallint
declare @cmdpiece nvarchar(4000)

set nocount on

-- Check for subscribing permission
exec @retcode=sp_MSreplcheck_subscribe
if @retcode<>0 or @@ERROR<>0 return (0)
	
execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output
IF @@ERROR <> 0 or @retcode <>0 return (0)
set @tablenickstr = rtrim(convert(nchar, @tablenick))

-- create temp table to select the command text out of
create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)

-- insert text pieces that don't repeat for each column

-- phase 0 : create procedure and fixed part of argument list
set @cmdpiece = 'create procedure dbo.'  + QUOTENAME(@procname) + ' (@rowguid uniqueidentifier, 
	@generation int, @lineage varbinary(255),  @colv varbinary(2048) '
insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece)

-- phase 1 is rest of argument list; goes in during loop over columns
-- phase 2 : paren to close argument list, and variable declarations
set @cmdpiece = ') as
	declare @tablenick int
	declare @errcode int
	declare @retcode int
	declare @has_rows int
	
	set @has_rows = 0
	set nocount on

	set @errcode= 0
	
	if sessionproperty(''replication_agent'') = 0
	begin
		exec @retcode = dbo.sp_MSreplcheck_connection @objid = ' + @idstr + '
		if @retcode<>0 or @@ERROR<>0 return (3)
	end
	'
	if @permissions>0
		begin
			select @cmdpiece = @cmdpiece + ' exec @retcode = dbo.sp_MSreplcheck_permission @objid = ' + @idstr + ', @type = 1, @permissions = ' + @permissions_str + '
				if @retcode<>0 or @@ERROR<>0 return (4)'
		end	
	select @cmdpiece = @cmdpiece + '
	select @tablenick = ' + @tablenickstr

insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)

-- phase 3 is optional set identity insert on, goes in during loop if needed
-- phase 4 is beginning a sub transaction, setting save point and starting insert statement
set @cmdpiece = '
	begin transaction
	save transaction sp_insproc
	if @metadata_type = 1 or @metadata_type = 5
	begin
		if not exists (select * from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid and
						lineage = @lineage_old)
		begin
			set @errcode= 2
			goto Failure
		end
	end
	exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage, @colv, 2, @tombstone_rows_deleted = @has_rows OUTPUT
	if @retcode<>0 or @@ERROR<>0
	begin
		set @errcode= 0
		goto Failure
	end
	insert into ' + @qualified_name + ' ('
insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece)

-- phase 5 is column list that we are inserting; done in loop

-- phase 6 is just the opening and closing parens and VALUES keyword
set @cmdpiece = ') values ('
insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece)

-- phase 7 is all of those arguments as the list of value expressions; done in loop
-- phase 8 finish insert, check status, etc.
-- if we have a permanent view, check for case where we inserted a row that doesn't
-- meet filters of subscriber we are getting the insert from
set @cmdpiece = ')
	if (@@rowcount <> 1)
	begin
		set @errcode= 3
		goto Failure
	end
'
insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)

-- only add the following code when creating proc at publisher
if exists (select 1 from sysmergepublications where  pubid=@pubid and LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())
begin
	-- Add in pieces that check for inserting a row that instantly means other rows need to be downloaded
	-- If we insert such a row, set the generation and partchangegen so that we will download everything
	-- that needs to go.

	exec sp_MSexclause @tablenick, @pubid
	if @@error<>0 return(1)

	if exists (select * from sysmergearticles where pubid = @pubid and objid = @id and view_type = 1)
	begin
		/* Get name of rowguidcol. Aliasing doesn't work through a view. */
		select @rgcolname = QUOTENAME(name) from syscolumns where id = @id and ColumnProperty(@id, name, 'isrowguidcol') = 1
		if @rgcolname is null
			set @rgcolname = 'rowguid'
		select @cmdpiece = ' 
			if @has_rows = 0
				begin
					if not exists (select 1 from ' + QUOTENAME(OBJECT_NAME(sync_objid))
			from sysmergearticles where pubid = @pubid and objid = @id
		set @cmdpiece = @cmdpiece + ' where ' + @rgcolname + ' = @rowguid) 
					begin
						select @has_rows = 1 '
		insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)

		exec sp_MSinsertbeforeimageclause @pubid, @id, @tablenickstr

		set @cmdpiece = ' 
					end	
				end '
		insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
	end
end
-- if we already have a tombstone for this row, (especially a remove from partial) then
-- make sure we will set the generation so that it goes on down to subscribers of republishers
-- for backward compatibility, for 7.0 subscribers we do not want @has_rows to be 1

set @cmdpiece = '
			if @has_rows > 0 	
				update dbo.MSmerge_contents set generation = 0, partchangegen = 0 
					where rowguid = @rowguid and tablenick = @tablenick'
insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)
 
set @cmdpiece = '

	commit tran
'
insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)

-- phase 9 is setting identity insert off if needed; done in loop
-- phase 10 is returning our success / failure status
set @cmdpiece = '
	return(1)
	
Failure:
	rollback tran sp_insproc
	commit tran	

	return(@errcode)
	'
insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece)
	
-- now loop over columns and insert missing command pieces

select @colid = min (colid) from syscolumns where id = @sync_objid and 
	name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
	
select @colname = QUOTENAME(name), @typename = type_name(xtype),
	@len = length, 	@prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
	from syscolumns 
	where id = @sync_objid and colid = @colid
select @status = status, @iscomputed=iscomputed, @xtype=xtype, @colstat=colstat from syscolumns 
	where id = @id and QUOTENAME(name) = @colname
if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
	select @len = @len/2
set @colordinal = 1

while (@colname is not null)
	begin
	if (@iscomputed=1 OR type_name(@xtype)='timestamp')
		goto Next_Column
	exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
	if @@error<>0 OR @retcode <>0 return (1)

	select @argname = '@p' + rtrim(convert(nchar, @colordinal))
	-- add to argument list (phase 1)
	set @cmdpiece = ', ' + @argname + ' ' + @typename
	insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)

	-- add to column list and value list
	if (@colordinal = 1)
		begin
		-- column list is phase 5
		set @cmdpiece = @colname
		insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)

		-- argname for values list is phase 7
		set @cmdpiece = @argname
		insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
		end
	else
		begin
		-- column list is phase 5; need preceding comma since not the first one.
		set @cmdpiece = ', ' + @colname
		insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)

		-- argname for values list is phase 7 need preceding comma since not the first one.
		set @cmdpiece = ', ' + @argname
		insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
		end
		
	-- is this an identity column without 'not for replication' marking?
	if (@status = 128) and (@colstat & 0x0008 =0)
		begin
		-- turning identity insert on is phase 3
		set @cmdpiece = '
	set identity_insert ' + @qualified_name + ' on'
		insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece)

		-- turning identity insert on is phase 9
		set @cmdpiece = '
	set identity_insert ' + @qualified_name + ' off'
		insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
		end

Next_Column:
	-- now set up to repeat the loop with the next column
	select @colid = min (colid) from syscolumns where id = @sync_objid and colid > @colid 
		
	set @colname = NULL
	if @colid is not null
		select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @len = length,
		@prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
		from syscolumns where id = @sync_objid and colid = @colid
	select @status = status, @iscomputed=iscomputed, @xtype=xtype,@colstat=colstat from syscolumns 
		where id = @id and QUOTENAME(name) = @colname
		
	if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
		select @len = @len/2
	set @colordinal = @colordinal + 1
	end

	select @cmdpiece = ',@metadata_type tinyint = NULL, @lineage_old varbinary(255) = NULL'
	insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)
	
-- Now we select out the command text pieces in proper order so that our caller,
-- xp_execresultset will execute the command that creates the stored procedure.

select cmdtext from #tempcmd order by phase, step
drop table #tempcmd
go

exec dbo.sp_MS_marksystemobject sp_MSmakeinsertproc 
go
grant exec on dbo.sp_MSmakeinsertproc to public
go
--------------------------------------------------------------------------------
--. sp_MSsetupbelongs 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSsetupbelongs')
    drop procedure sp_MSsetupbelongs
go

raiserror('Creating procedure sp_MSsetupbelongs', 0,1)
GO

-- Modify temp table. No security check needed.
create procedure sp_MSsetupbelongs
	@publisher			sysname,
	@publisher_db		sysname,
	@publication 		sysname,
	@genlist	 		varchar(8000),
	@commongen			int,
	@subissql			int,
	@articlesoption		int=0,	-- 0=process all articles, 1=process this specific article (whose nickname is passed in @tablenickname), 2=all articles involved in join filters, 3=process all articles involved in part filters, 4=process articles whose nicknames have been passed in @nicknamelist.
	@tablenickname		int=0,
	@handle_null_tables bit=0, 	-- 0=caller cannot handle NULL ##belongs and ##notbelongs tables, 1=caller handles NULL ##belongs and ##notbelongs tables (post 8.0 Beta 2 version)
	@nicknamelist		varchar(8000) = NULL,
	@mingen				int = 0,
	@maxgen				int = 0,
	@skipgenlist		varchar(8000) = NULL

AS
	declare @pubid uniqueidentifier
	declare @retval int
	declare @tablenick int
	declare @rowguid uniqueidentifier
	declare @rowguidstr nvarchar(40)
	declare @belongsname sysname
	declare @notbelongsname sysname
	declare @artnick	int
	declare @before_view_objid int
	declare @before_table_objid int
	declare @procname sysname
	declare @artbaseobjid int
	declare @rgcol sysname
	declare @maxfilterid int
	declare @retcode smallint
	declare @dynamic_join_cnt int
	declare @contents_subset_rowcount int
	declare @tombstone_subset_rowcount int
	declare @belongsempty bit
	declare @notbelongsempty bit

	-- trim spaces from the generation lists so that we don't have to use functions ltrim 
	-- and rtrim again and again later on.
	select @genlist = ltrim(rtrim(@genlist))
	select @skipgenlist = ltrim(rtrim(@skipgenlist))
	
	select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db	
	
	set @rowguid = newid()
	
	select @rowguidstr = replace( convert( nvarchar(36), @rowguid ), '-', '' )

	set @belongsname = '##belong' + @rowguidstr
	set @notbelongsname = '##notbelong' + @rowguidstr
	-- since the belongsname and notbelongsname names have guids appended to them generated using newid(), we can safely assume
	-- that the names are unique.

	create table #genlist (generation int)

	create table #temp_cont (temp_id int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
			partchangegen int null, joinchangegen int null)

	create table #contents_subset(tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NOT NULL,
			partchangegen int NULL, joinchangegen int NULL)
	
	create table #tombstone_subset(tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, type tinyint NOT NULL, 
			generation int NOT NULL)

	create table #belong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL,
		partchangegen int null, joinchangegen int null, skipexpand bit NOT NULL)

	create table #notbelong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
		flag int NOT NULL, partchangegen int null, joinchangegen int null, type tinyint default 5)
	create table #nicknames_to_process (nickname int)
	create index #indbelong on #belong (rowguid, tablenick)
	create index #indnbelong on #notbelong (tablenick, rowguid)

	exec ('create table ' + @belongsname + ' (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
		generation int NULL, lineage varbinary(255) NULL, colv varbinary(2048) NULL)')
	if @@ERROR <>0 return (1)
		
	exec ('create table ' + @notbelongsname + ' (bookmark int identity unique NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL,
		generation int NULL, lineage varbinary(255) NULL, type tinyint NOT NULL)')

	if @@ERROR <>0 return (1)

	-- Fully qualifying the proc avoids recompiles
	exec @retcode = dbo.sp_MSsetupworktables @pubid, @genlist, @articlesoption, @tablenickname, @nicknamelist,
										@mingen, @maxgen, @skipgenlist,
										@contents_subset_rowcount OUTPUT, @tombstone_subset_rowcount OUTPUT

	IF @@ERROR<>0 OR @retcode<>0 return (1)	

	if (@contents_subset_rowcount = 0 and @tombstone_subset_rowcount = 0)
		goto EXITPROC

	if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4)
	begin
		select @dynamic_join_cnt = count(*) from 
			(select join_filterclause_spaces_stripped = 
			REPLACE(REPLACE(REPLACE(REPLACE(UPPER(join_filterclause collate SQL_Latin1_General_CP1_CS_AS), char(0x20),''), char(0x09),''), char(0x0D),''), char(0x0A),'')
			from sysmergesubsetfilters 
			where pubid = @pubid) 
			as sysmergesubsetfilters_temp
		where 
		sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%USER[_]%NAME()%' or
		sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%USER[_]%ID()%' or
		sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%SESSION[_]USER%' or
		sysmergesubsetfilters_temp.join_filterclause_spaces_stripped like '%SYSTEM[_]USER%'
	end
	
	/* step 2 setup pass through dbo.MSmerge_contents */
	/* article with permanent views can be handled with bulk inserts */
	set @artnick = NULL
	set rowcount 0
	
	/* Get first article, go into loop */
	select @artnick = min(nickname) from #nicknames_to_process 
	
	while (@artnick is not null)
	begin
		select	@artbaseobjid = objid, @procname = view_sel_proc, @before_view_objid = before_view_objid,
				@before_table_objid = before_image_objid 
				from sysmergearticles 
				where pubid = @pubid 
				and nickname = @artnick
		/* Get name of rowguidcol. Aliasing doesn't work through a view. */
		select @rgcol = name from syscolumns where id = @artbaseobjid and ColumnProperty(@artbaseobjid, name, 'isrowguidcol') = 1

		if (@procname is not null)
		begin
			-- Fully qualifying the proc avoids recompiles
			select @procname = 'dbo.' + @procname
			exec @retcode = @procname @artnick
			if @@ERROR <>0 or @retcode <> 0
				begin
				return (1)
				end
		end
		else
		begin
			-- Fully qualifying the proc avoids recompiles
			exec @retcode = dbo.sp_MSsetupbelongs_withoutviewproc @publisher, @publisher_db, @publication, @artnick		
			if @@ERROR <>0 or @retcode <> 0
				return (1)
		end

		-- Fully qualifying the proc avoids recompiles
		exec @retcode = dbo.sp_MSsetupnotbelongs @artnick, @before_view_objid, @before_table_objid, @rgcol, @commongen
		if @@ERROR <>0 or @retcode <> 0
				return (1)

		/* Move on to next article, repeat while loop */
		select @artnick = min(nickname) from #nicknames_to_process where nickname > @artnick 
	end

	if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4)
	begin
		/* Optimization: If joinchangegen and partchange are both null or < common gen,
		** it is not necessary to expand #belong for that particular row.
		*/
		
		select @maxfilterid = max(join_filterid) from sysmergesubsetfilters

		if @maxfilterid is not null
		begin
			update #belong set flag = @maxfilterid, skipexpand = 1 where isnull(joinchangegen,0) <= @commongen and
				isnull(partchangegen,0) <= @commongen 

			/* Expand the #belong temptable */
			exec @retcode = dbo.sp_MSexpandbelongs @pubid

			if @@ERROR<>0 OR @retcode<>0
				begin
				return (1)
				end
		end
	end

	/* If subscriber is sql server, we don't have to expand belongs */
	if (@articlesoption <> 1 and @articlesoption <> 3 and @articlesoption <> 4) and (@subissql = 0 or @dynamic_join_cnt > 0)
	begin
		/* Expand the #notbelong temptable */
		exec dbo.sp_MSexpandnotbelongs @pubid
		if @@error<>0 return(1)
	end

EXITPROC:
		
	/* transfer rows from local temp to global temp */

	-- Could have used if not exists instead of the following but want to use the KEEP PLAN option which is not supported in the IF EXISTS 
	select @belongsempty = 0
	select @belongsempty = 1 where not exists (select * from #belong) OPTION(KEEP PLAN)
	
	select @notbelongsempty = 0
	select @notbelongsempty = 1 where not exists (select * from #notbelong) OPTION(KEEP PLAN)

	/* If there are no rows in #belong, then drop the global ##belongs so that we do not call sp_MSenumpartialchanges */
	if (@belongsempty = 1)
	begin
		/* Post SQL 8.0 Beta 2 agents pass this flag with value 1 since they can handle NULL belongs table name */
		if @handle_null_tables = 1
			begin
				exec ('drop table ' + @belongsname)
				select @belongsname = NULL
			end
	end
	else
	begin
		exec ('insert into ' + @belongsname + ' (tablenick, rowguid, generation, lineage, colv) 
				select distinct b.tablenick, b.rowguid, c.generation, c.lineage, c.colv1 from
				#belong b left outer join dbo.MSmerge_contents c  
				on  c.tablenick = b.tablenick and c.rowguid = b.rowguid ')

		if @@ERROR <>0	
		begin
			return (1)
		end

		-- this index will be useful in sp_MSenumpartialchanges
		exec ('create index nc1belongstable on ' + @belongsname + ' (tablenick, rowguid) with FILLFACTOR = 100')
		if @@ERROR <>0	
			return (1)
	end
			
	/* If there are no rows in #notbelong, then drop the global ##notbelongs so that we do not call sp_MSenumpartialchanges */
	if (@notbelongsempty = 1)
	begin
		/* Post SQL 8.0 Beta 2 agents pass this flag with value 1 since they can handle NULL notbelongs table name */
		if @handle_null_tables = 1
			begin
				exec ('drop table ' + @notbelongsname)
				select @notbelongsname = NULL
			end
	end
	else
	begin
		/* transfer rows from local temp to global temp */
		exec ('insert into ' + @notbelongsname + ' (tablenick, rowguid, generation, lineage, type) 
				select distinct b.tablenick, b.rowguid, coalesce (c.generation, t.generation), coalesce(c.lineage, t.lineage), b.type from
				#notbelong b left outer join dbo.MSmerge_contents c  
				 on  c.tablenick = b.tablenick and c.rowguid = b.rowguid
				left outer join dbo.MSmerge_tombstone t on t.tablenick = b.tablenick and t.rowguid = b.rowguid order by b.tablenick DESC, b.rowguid ASC ')
		if @@ERROR <>0	
		begin
			return (1)
		end

		-- this index will be useful in sp_MSenumpartialdeletes
		exec ('create index nc1notbelongstable on ' + @notbelongsname + ' (tablenick DESC, rowguid) with FILLFACTOR = 100')
		if @@ERROR <>0	
			return (1)
		
	end
	
	if (@belongsempty = 1)
		select @belongsname, @notbelongsname, -1
	else
	begin
		if (@articlesoption = 1)
		begin
			select @belongsname, @notbelongsname, @tablenickname
		end
		else
		begin
			select distinct @belongsname, @notbelongsname, tablenick from #belong 
		end
	end

	drop table #notbelong
	drop table #belong
	drop table #contents_subset
	drop table #tombstone_subset
	drop table #temp_cont 
	drop table #nicknames_to_process
	
	return (0)
go

exec dbo.sp_MS_marksystemobject sp_MSsetupbelongs
go
grant exec on dbo.sp_MSsetupbelongs to public
go

--------------------------------------------------------------------------------
--. sp_MSmakeupdateproc 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSmakeupdateproc')
    drop procedure sp_MSmakeupdateproc
go

raiserror('Creating procedure sp_MSmakeupdateproc', 0,1)
GO

-- This will be called by snapshot at publisher side and 
-- merge at the subscriber side, check for dbo permission
create procedure sp_MSmakeupdateproc 
	(@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier)
as
declare @retcode 			int
declare @argname			nvarchar(10)
declare @varname			nvarchar(10)
declare @cmdpiece			nvarchar(4000)
declare @qualified_name		nvarchar(270)
declare @littlecomp			nvarchar(300)
declare @id					int
declare @sync_objid			int
declare @idstr				nvarchar(100) 
declare @fast_multicol_updateproc_bit bit
declare @permissions_str	nvarchar(10)
declare @permissions		int

set nocount on

if @ownername is NULL or @ownername=''
	select @qualified_name = QUOTENAME(@tablename)
else	
	select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)

select @id = object_id(@qualified_name)
	if @id is NULL return (1)

select @sync_objid = sync_objid, @fast_multicol_updateproc_bit = fast_multicol_updateproc, @permissions=check_permissions,
		@permissions_str=convert(nvarchar(10), check_permissions) from sysmergearticles 
		where objid=@id and pubid = @pubid
	
set @idstr = rtrim(convert(nchar, @id))	

declare @colname nvarchar(140)
declare @typename nvarchar(140)
declare @colid smallint
declare @colordinal smallint
declare @colordstr nvarchar(4)
declare @xtype		tinyint
declare @iscomputed tinyint
declare @isrowguidcol tinyint
declare @separate_update_needed tinyint
declare @update_stmt_started tinyint
declare @status tinyint
declare @len smallint
declare @blen smallint
declare @prec int
declare @scale int
declare @tablenick int
declare @tablenickstr nvarchar(12)
declare @bytestr      nvarchar(10)
declare @byteordinal  smallint
declare @numbytes	  smallint
declare @bitstr       nvarchar(10)
declare @colpat		  nvarchar(130)
declare @has_updateable_columns_in_select_list bit
select @separate_update_needed = 0
select @update_stmt_started = 0
select @has_updateable_columns_in_select_list = 0
	/*
	** Check for dbo permission
	*/
	exec @retcode=sp_MSreplcheck_subscribe
	if @retcode<>0 or @@ERROR<>0 return (1)
	
execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output
if @@ERROR <>0 OR @retcode <>0 return (1)
set @tablenickstr = rtrim(convert(nchar, @tablenick))

-- create temp table to select the command text out of
create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)

-- insert text pieces that don't repeat for each column

-- phase 0 : create procedure and fixed part of argument list
set @cmdpiece = 'Create procedure dbo.' + @procname + ' (@rowguid uniqueidentifier, @setbm varbinary(125) = NULL,
	@metadata_type tinyint, @lineage_old varbinary(255), @generation int,
	@lineage_new varbinary(255), @colv varbinary(2048) '
insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece)

-- phase 1 is rest of argument list; goes in during loop over columns
-- phase 2 paren to close argument list and fixed variable declarations
set @cmdpiece = ') as
	declare @tablenick int
	declare @errcode int
	declare @fset int
	declare @match int
	declare @retcode smallint
	set nocount on

	if sessionproperty(''replication_agent'') = 0
	begin
		exec @retcode = dbo.sp_MSreplcheck_connection @objid = ' + @idstr + '
		if @retcode<>0 or @@ERROR<>0 return (3)
	end
	'
	if @permissions>0
		begin
		select @cmdpiece=@cmdpiece + '
			exec @retcode = dbo.sp_MSreplcheck_permission @objid = ' + @idstr + ', @type=2, @permissions = ' + @permissions_str + '
			if @retcode<>0 or @@ERROR<>0 return (4)'
		end

	select @cmdpiece = @cmdpiece + '
	select @tablenick = ' + @tablenickstr

insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)

-- phase 3 is rest of variable declarations; goes in during loop over columns
-- phase 4 begin a transaction, set savepoint in case we roll back, begin select to get current values
set @cmdpiece = '	begin transaction sub
	save transaction sub
	select '
insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece)

-- phase 5 is middle part of select assigning column values to local variables -- goes in loop
-- phase 6 -- finish the select, check that metadata matches
set @cmdpiece = '	from ' + @qualified_name + ' (updlock) where rowguidcol = @rowguid
	exec @retcode= dbo.sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
	if @retcode<>0 or @@ERROR<>0
	begin
		set @errcode= 3
		goto Failure
	end
	if (@match = 1)
	begin
'
insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece)

-- phase 7 is a bunch of if's that compare old values with new values ; goes in during loop
-- phase 8 finish the stored procedure
set @cmdpiece = '		exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, @colv, 2
		if @retcode<>0 or @@ERROR<>0
		begin
			set @errcode= 3
			goto Failure
		end
	end
	else
	begin
		set @errcode= 2
		goto Failure
	end

	commit transaction





	return(1)

Failure:
	rollback transaction sub
	commit transaction




	return @errcode'
insert into #tempcmd (phase, cmdtext) values (11, @cmdpiece)

-- now do the loop over all columns and insert the missing pieces

-- don't script out computed columns or timestamp columns
select @colid = min (colid) from syscolumns where id = @sync_objid and 
	name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
select @colname = NULL
select @colname = name, @typename = type_name(xtype), @blen = length,
	@prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
	from syscolumns 
	where id = @sync_objid and colid = @colid
select @status = status, @iscomputed=iscomputed, @xtype=xtype,
	@isrowguidcol = COLUMNPROPERTY(id, name, 'IsRowGuidCol')
	from syscolumns 
	where id = @id and name = @colname

-- get col count to determine what size our bitmask is going to be
declare @colcount int
select @colcount = count(*) from syscolumns where id = @sync_objid and 
	name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))	

set @cmdpiece = '		
	declare @colbitmask binary(' + convert(nvarchar,1+(@colcount-1) / 8) + ') 
	select @colbitmask = 0
	'

select @numbytes = 1+(@colcount-1) / 8
insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece)

if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
	set @len = @blen/2
else
	set @len = @blen
set @colordinal = 1

declare @firstCol tinyint
set @firstCol= 1

while (@colname is not null)
begin
	
	set @colordstr = convert(nvarchar(4), @colordinal)
	exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
	if @@ERROR <>0 OR @retcode <>0 return (1)

	if (@fast_multicol_updateproc_bit = 1)
	begin
		
		-- check if separate update statement is needed only if article supports fast multi-column updates.

		-- reset @separate_update_needed
		set @separate_update_needed = 0
	
		--check if this column is part of the filter or join filter clause.
		-- if so, use a separater update statement for it rather than setting bitmask for the one cumulative update statement.
		set @colpat = '%' + @colname + '%'
		-- does updating this column change membership in a partial replica? 
		if exists (select * from sysmergearticles where objid = @id and subset_filterclause like @colpat)
			set @separate_update_needed = 1
		else if exists (select * from sysmergesubsetfilters where art_nickname = @tablenick and join_filterclause like @colpat)
			set @separate_update_needed = 1
		else if exists (select * from sysmergesubsetfilters where join_nickname = @tablenick and join_filterclause like @colpat)
			set @separate_update_needed = 1
		else if (@typename = 'ntext' or @typename = 'text' or @typename = 'image')
			set @separate_update_needed = 1
	end
	else
	begin
		set @separate_update_needed = 1			-- separate update statement for each column.
	end
	
	if @status = 128 OR @iscomputed=1 OR type_name(@xtype)='timestamp'
		goto Next_Column

	set @colname = QUOTENAME(@colname)

	-- put in argument list element (phase 1)
	set @argname = '@p' + rtrim(@colordstr)

	set @cmdpiece = ',
		' + @argname + ' ' + @typename + ' = NULL '

	insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece)

	if (@isrowguidcol = 1)
		goto Next_Column

	if (@separate_update_needed = 0)
	begin
		
		select @bytestr = convert( nvarchar, 1 + (@colordinal-1) / 8 )
		select @byteordinal = 1 + (@colordinal-1) / 8
		select @bitstr =  convert( nvarchar, power(2, (@colordinal-1) % 8 ) )

		if (@update_stmt_started = 0)
		begin
			select @update_stmt_started = 1
			select @cmdpiece = 'update ' + @qualified_name + ' set '
			insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece)		-- goes after phase 7
			select @cmdpiece = ' where rowguidcol = @rowguid 
				if (@@rowcount <> 1)
				begin
					set @errcode= 3
					goto Failure
				end'
			insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece)	-- goes after phase 9 which would be the SET clause for different columns
		end
		else
		begin
			select @cmdpiece = ','
			insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
		end

		select @cmdpiece = @colname + ' = case substring(@colbitmask,' + @bytestr + ',1) & ' + @bitstr + ' when ' + @bitstr + ' then ' + @argname + ' else ' + @colname + ' end '
		insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece)
	end

	-- put in declaration for variable (phase 3) -- text and image get no variable
	if (@typename <> 'ntext' and @typename <> 'text' and @typename <> 'image')
	begin
		set @varname = '@l' + rtrim(@colordstr)

		set @cmdpiece = 'declare ' + @varname + ' ' + @typename + '
'
		insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece)

		-- put in set piece to initialize variable to old value in select statement (phase 5)
		if @firstCol=1
		begin
			set @cmdpiece= ''
			set @firstCol= 0
		end
		else
			set @cmdpiece= ', '

		set @cmdpiece = @cmdpiece + @varname + ' = ' + @colname
		insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece)

		-- put in if piece that compares old value with new, checks bit if argument is null
		if (@typename like '%char%')
		begin
			-- Compare binaries instead of variables so that case changes are caught as different
			set @littlecomp = 'convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @argname + ')
				= convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @varname + ')'
		end
		else
		begin
			set @littlecomp = @argname + ' = ' + @varname
		end

		set @cmdpiece = '			if ' + @littlecomp + '
				set @fset = 0
			else if ( ' + @varname + ' is null and ' + @argname + ' is null) 
				set @fset = 0
			else if ' + @argname + ' is not null
				set @fset = 1
			else if @setbm = 0x0
				set @fset = 0
			else
				exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + '
			if @fset <> 0
				begin
				'
		insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)

		if (@separate_update_needed = 0)
		begin
			if (@numbytes = 1)
			begin
				-- no bytes on left or right of the byte being bitwise OR-ed.
				set @cmdpiece = '
					select @colbitmask = convert(varbinary(1), substring(@colbitmask, ' + @bytestr + ' , 1) | ' + @bitstr + ')
					end
					'
			end
			else 
			begin
				-- there could be byte(s) on left and/or right of byte being bitwise OR-ed.
				set @cmdpiece = '
				select @colbitmask = 
					convert
					(
					varbinary(' + convert(nvarchar, @numbytes) + '), '
					+ case when (@byteordinal = 1) then '' else ' convert(varbinary(' + convert(nvarchar, @byteordinal-1) + '), substring(@colbitmask, 1, ' + convert(nvarchar, @byteordinal-1) + ')) +' end +
					' convert(varbinary(1), substring(@colbitmask, ' + @bytestr + ' , 1) | ' + @bitstr + ') '
					+ case when (@byteordinal = @numbytes) then '' else ' + convert(varbinary(' + convert(nvarchar, @numbytes - @byteordinal) + '), substring(@colbitmask, ' + convert(nvarchar, @byteordinal+1) + ', ' + convert(nvarchar, @numbytes - @byteordinal) + ')) ' end + '
					)
				end 
				'
			end
		end
		else
		begin
			set @cmdpiece = '
					update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid 
					if (@@rowcount <> 1)
					begin
						set @errcode= 3
						goto Failure
					end
				end 
				'
		end
		insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)
        select @has_updateable_columns_in_select_list = 1
	end
	else
	begin
		-- for text and image, we just test if argument is null and whether bit is set
		-- build conditional update (phase 7)
		set @cmdpiece =  '			if ' + @argname + ' is not null
				set @fset = 1
			else if @setbm = 0x0
				set @fset = 0
			else 
				exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + '
			if @fset <> 0
				begin
					update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid 
					if (@@rowcount <> 1)
					begin
						set @errcode= 3
						goto Failure
					end
				end 
			'
		-- Now insert the command to temp table
		insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece)	
	end
	
Next_Column:		
	-- Advance loop to next column and repeat!
	select @colid = min (colid) from syscolumns where id = @sync_objid and colid > @colid and
		name not in (select name from syscolumns where id=@id and (iscomputed=1 OR type_name(xtype)='timestamp'))
	set @colname = NULL
	if (@colid is not null)
	begin
		select @colname = name, @typename = type_name(xtype), @blen = length,
			@prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale
			from syscolumns 
			where id = @sync_objid and colid = @colid
		select @status = status, @iscomputed=iscomputed, @xtype=xtype,
			@isrowguidcol = COLUMNPROPERTY(id, name, 'IsRowGuidCol') 
			from syscolumns 
			where id = @id and name = @colname
		
		if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
			set @len = @blen/2
		else
			set @len = @blen
		set @colordinal = @colordinal + 1
	end
end

-- Add dummy column list to select statement if there is no user updateable 
-- column.
if @has_updateable_columns_in_select_list = 0
begin
    insert into #tempcmd (phase, cmdtext) values (3, N'declare @l int')
    insert into #tempcmd (phase, cmdtext) values (5, N'@l = 1')
end

-- Now we select out the command text pieces in proper order so that our caller,
-- xp_execresultset will execute the command that creates the stored procedure.

select cmdtext from #tempcmd order by phase, step
drop table #tempcmd
go

exec dbo.sp_MS_marksystemobject sp_MSmakeupdateproc 
go
grant exec on dbo.sp_MSmakeupdateproc to public
go

--------------------------------------------------------------------------------
--. sp_MSproxiedmetadata 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSproxiedmetadata')
    drop procedure sp_MSproxiedmetadata
go

raiserror('Creating procedure sp_MSproxiedmetadata', 0, 1)
GO

create procedure sp_MSproxiedmetadata
	@tablenick	int,
	@rowguid	uniqueidentifier,
	@lineage	varbinary(256),
	@colv		varbinary(2048)
as
	declare @old_lin varbinary(256)
	declare @old_colv varbinary(2048)
	declare @retcode int
	
	select @old_lin = lineage, @old_colv = colv1 from dbo.MSmerge_contents where
		tablenick = @tablenick and rowguid = @rowguid

	if (@old_lin IS NOT NULL)
	begin
		exec @retcode= master..xp_proxiedmetadata @lineage out, @colv out, @old_lin, @old_colv
		if @@error<>0 or @retcode<>0
		begin


			return(1)
		end
		update dbo.MSmerge_contents set lineage = @lineage, colv1 = @colv
			where tablenick = @tablenick and rowguid = @rowguid


	end
	else
	begin
		select @old_lin = lineage from dbo.MSmerge_tombstone where
			tablenick = @tablenick and rowguid = @rowguid
		if (@old_lin IS NULL)
			return (0)

		exec @retcode= master..xp_proxiedmetadata @lineage out, @colv, @old_lin, NULL
		if @@error<>0 or @retcode<>0
		begin


			return(1)
		end
		update dbo.MSmerge_tombstone set lineage = @lineage
			where tablenick = @tablenick and rowguid = @rowguid


	end

	return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSproxiedmetadata
grant exec on dbo.sp_MSproxiedmetadata to public
go


--------------------------------------------------------------------------------
--. sp_MSmakeviewproc 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSmakeviewproc')
    drop procedure sp_MSmakeviewproc
go

raiserror('Creating procedure sp_MSmakeviewproc', 0,1)
GO

create procedure sp_MSmakeviewproc 
	(@viewname sysname, 
	@ownername sysname, 
	@procname nvarchar(290), 
	@rgcol sysname,
	@objid	int = NULL --for possible backward comp. issue
	)
as
declare @retcode 			smallint
declare @colname			nvarchar(140)
declare @view_id			int
declare @iscomputed			tinyint
declare @xtype 				sysname
declare @varname			nvarchar(10)
declare @cmdpiece			nvarchar(4000)
declare @column_list		nvarchar(4000)  -- basically we have two column_list, one is for vertical partitioning,
											-- which is a subset of all columns; the other is for transferring data
											-- for dynamic publications, which is a subset of the former, excluding
											-- computed columns and timestamp columns
set nocount on

--prefixed with a v, cause it will be used to construct query: see below
select @column_list = 'v.*'

if @objid is not NULL and exists (select * from syscolumns where id = @objid 
	and (iscomputed=1 or type_name(xtype)='timestamp'))
begin
	select @view_id = object_id(@viewname)
	declare collist CURSOR LOCAL FAST_FORWARD FOR 
   		select name from syscolumns where id = @view_id order by colid ASC
			FOR READ ONLY
	open collist
	fetch collist into @colname
	WHILE (@@fetch_status <> -1)
	BEGIN
		--since views does not preserve computed/timestamp property, we have to rely on base table
		select @iscomputed=iscomputed, @xtype=xtype from syscolumns where id=@objid and name=@colname
		if @iscomputed=0 and type_name(@xtype) <> 'timestamp'
		begin
			select @colname = QUOTENAME(@colname) --previously we use rowguidcol to replace 'rowguid'
			if @column_list='v.*'					  --which can cause problems and is not necessary.
				select @column_list = 'v.' + @colname
			else
				select @column_list = @column_list + ', v.' + @colname	
		end
		fetch next from collist into @colname			
	END					
end

select @procname=QUOTENAME(@procname)

set @cmdpiece = 'create procedure dbo.' + @procname + ' (@tablenick int, @max_rows int = NULL,
	@guidlast uniqueidentifier = NULL) 
	AS

	set nocount on
	set rowcount 0
	if  @max_rows is not null
	begin
		-- used to select data for initial pop. of subscriber for dynamic filtered publication
		set rowcount @max_rows
		declare @lin varbinary (255)
		declare @cv varbinary (2048)
		declare @replnick int
		declare @objid int
		declare @ccols int

		select @objid = objid from sysmergearticles where nickname = @tablenick
		select @ccols = max(colid) from syscolumns where id = @objid
		
		exec dbo.sp_MSgetreplnick @nickname = @replnick out
		if (@@error <> 0) or @replnick IS NULL 
		begin
			RAISERROR (14055, 11, -1)
			RETURN(1)
		end 				
		set @lin = { fn UPDATELINEAGE(0x0, @replnick, 1) }
		set @cv = { fn INITCOLVS(@ccols, @replnick) }

		select @tablenick, v.' + @rgcol + ', coalesce (c.generation,1), 
			coalesce (c.lineage, @lin), coalesce (c.colv1, @cv), ' + @column_list  + ' from ' +
				 QUOTENAME(@ownername) + '.' +
					QUOTENAME(@viewname) + ' v left outer join  dbo.MSmerge_contents c on
					  v.' + @rgcol + ' = c.rowguid  and c.tablenick = @tablenick where v.' + @rgcol + ' > @guidlast 
					 order by v.' + @rgcol + '
		return (1)		
	end

	insert into #belong (tablenick, rowguid, flag, skipexpand, partchangegen, joinchangegen)
		select ct.tablenick, ct.rowguid, 0, 0, ct.partchangegen, ct.joinchangegen
					from  #contents_subset ct, ' + QUOTENAME(@ownername) + '.' +
					QUOTENAME(@viewname) + ' v where ct.tablenick = @tablenick
					and ct.rowguid = v.' + @rgcol + '  
	if @@ERROR <> 0
		begin
		RAISERROR(''Error selecting from view'' , 16, -1)
		return (1)	
		end'

			
exec (@cmdpiece)
if @@error<>0 return(1)
exec dbo.sp_MS_marksystemobject @procname
if @@error<>0 return(1)
exec ('grant exec on ' + @procname + ' to public')
if @@error<>0 return(1)
return(0)
go
			
exec dbo.sp_MS_marksystemobject sp_MSmakeviewproc 
go


--------------------------------------------------------------------------------
--. sp_MScreatebeforetable 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MScreatebeforetable')
    drop procedure sp_MScreatebeforetable

go

raiserror('Creating procedure sp_MScreatebeforetable', 0,1)
GO

--------------------------------------------------------------------------------
--. sp_MScreatebeforetable 
--------------------------------------------------------------------------------
create procedure sp_MScreatebeforetable
	@objid int
AS
    declare     @command            nvarchar(4000)
	declare 	@objidstr			nvarchar(12)
    declare 	@dbname 			sysname
    declare		@oldname			sysname
	declare 	@newname 			sysname
	declare 	@nameguid 			uniqueidentifier
	declare 	@before_rowguidname sysname
	declare 	@retcode 			int
 	declare 	@tablenick 				int
    set nocount on

    set @before_rowguidname = NULL

-- If no publication including this table needs before images, just return
	if not exists (select * from sysmergepublications p, sysmergearticles a where
			a.objid = @objid and p.pubid = a.pubid and p.keep_before_values = 1)
		return (0)
	select @tablenick = max(nickname) from sysmergearticles where objid = @objid
	if @tablenick is null return (1)

-- If a before image table already exists for this table, we need to drop it and create a new one
	select @oldname = max(o.name) from sysobjects o, sysmergearticles a where
		a.objid = @objid and o.id = a.before_image_objid
	if @oldname is not null
		begin
   		exec @retcode = sp_MShelpalterbeforetable @objid, @oldname
   		if @@error<>0 or @retcode<>0 return (1)
   		return(0)
		end
-- If this table is not involved with any filters or join filters, don't bother
	if not exists (select * from sysmergesubsetfilters where art_nickname = @tablenick
		or join_nickname = @tablenick) and
		not exists (select * from sysmergearticles where nickname = @tablenick and
			datalength (subset_filterclause) > 1)
		return(0)
	
-- Generate a unique name for our new table
	set @nameguid = newid()
	exec @retcode = dbo.sp_MSguidtostr @nameguid, @newname out
	if @@ERROR <>0 OR @retcode <>0 return (1)
	set @newname = 'MS_bi' + @newname

-- Call xp_execresultset with helper function command
    set @objidstr = convert(nvarchar(12), @objid)
    set @dbname = db_name()

   	set @command = 'exec dbo.sp_MShelpcreatebeforetable '  + @objidstr + ', ''' + @newname + '''' 
   	exec @retcode = master..xp_execresultset @command, @dbname
   	if @@error<>0 or @retcode<>0 return (1)

	select @before_rowguidname=name from syscolumns where id=@objid and columnproperty(@objid, name , 'isrowguidcol')=1

	if @before_rowguidname is not NULL
		begin
		   	exec ('grant select (' + @before_rowguidname + ') on ' + @newname + ' to public')
		   	if @@ERROR<>0 return (1)
		end

	/* grant select to system_delete column */
   	exec ('grant select (system_delete, generation), update(generation), delete on ' + @newname + ' to public')
   	if @@ERROR<>0 return (1)

   	exec dbo.sp_MS_marksystemobject @newname
	if @@ERROR<>0 return (1)

	update sysmergearticles set before_image_objid = object_id( @newname )
		where objid = @objid

	return(0)
go
exec dbo.sp_MS_marksystemobject sp_MScreatebeforetable 
go

--------------------------------------------------------------------------------
--. sp_MShelpalterbeforetable 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MShelpalterbeforetable')
    drop procedure sp_MShelpalterbeforetable
go

raiserror('Creating procedure sp_MShelpalterbeforetable', 0,1)
GO

create procedure sp_MShelpalterbeforetable
	@objid int,
	@biname sysname
AS
	declare @command nvarchar(4000)
	declare @retcode int
	declare @include int
	declare @tablenick int
	declare @colpat nvarchar(130)
	declare @colname nvarchar(130)
	declare @typename sysname
	declare @colid smallint
	declare @colidstr nvarchar(3)
	declare @status tinyint
	declare @len smallint
	declare @prec smallint
	declare @scale int
	declare @isnullable tinyint
	declare @bi_objid int
	set nocount on
	declare @cMaxIndexLength int

	set @cMaxIndexLength= 900  -- max index column size in SQL 2000

	select @tablenick = max(nickname) from sysmergearticles where objid = @objid
	if @tablenick is null 
		return (1)

	select @bi_objid = OBJECT_ID(@biname)		
	
	-- Loop over the columns and see which ones we include
	declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, status, type_name(xtype), length,
		 prec, scale, isnullable, colid from syscolumns
	where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
	FOR READ ONLY
	
	open col_cursor
	fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
	while (@@fetch_status <> -1)
		begin
		set @include = 0
		set @colpat = '%' + @colname + '%'

		if not exists (select * from syscolumns where id = @bi_objid and QUOTENAME(name) = QUOTENAME('system_delete'))
			begin
				set @command = 'alter table ' + @biname + ' ADD system_delete bit default(0) '
				execute ( @command )
				if @@ERROR<>0 
					goto errlabel

				/* grant select to system_delete column */
			   	exec ('grant select (system_delete) on ' + @biname + ' to public')
			   	if @@ERROR<>0 
					goto errlabel

					
			end

			exec ('grant select (generation), update(generation), delete on ' + @biname + ' to public')
			   	if @@ERROR<>0 
					goto errlabel

		-- Is this column already in the before image table?
		if exists (select * from syscolumns where id = @bi_objid and name = @colname)
			begin
			goto fetchnext
			end

		-- does updating this column change membership in a partial replica? 
		if exists (select * from sysmergearticles 
			where objid = @objid and subset_filterclause like @colpat)
			set @include = 1
		else if exists (select * from sysmergesubsetfilters
			where art_nickname = @tablenick and join_filterclause like @colpat)
			set @include = 1
		else if exists (select * from sysmergesubsetfilters
			where join_nickname = @tablenick and join_filterclause like @colpat)
			set @include = 1

		-- If we want this column, map its type and insert a row to temp table
		if @include <> 1
			begin
			goto fetchnext
			end
		if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
			set @len = @len/2
		exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
		if @@ERROR<>0 or @retcode<>0 
			goto errlabel
		if @typename not in ('text', 'ntext','image')
		begin
			set @colname = QUOTENAME(@colname)
	
			-- Always make columns nullable when we add them because we might have
			-- existing rows in the before image table.

			set @command = 'alter table ' + @biname + ' ADD ' + @colname + ' ' + @typename + ' NULL '
		
			execute ( @command )
			if @@ERROR<>0 goto errlabel

			-- Insert a create index command if column is not too long
			if (@len <= @cMaxIndexLength)
			begin
				set @colidstr =convert(nvarchar(3), @colid)
	 			set @command = 'create index ' + @biname + '_' + @colidstr + ' on ' + @biname + ' (' + @colname + ')'
				execute ( @command )
				if @@ERROR<>0 goto errlabel
			end
		end
							
fetchnext:
		/* Repeat the loop with next column */
		fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
		end
	close col_cursor
	deallocate col_cursor	
	return 0
errlabel:
	close col_cursor
	deallocate col_cursor	
	return 1

go

exec dbo.sp_MS_marksystemobject sp_MShelpalterbeforetable 
go


--------------------------------------------------------------------------------
--. sp_MShelpcreatebeforetable 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MShelpcreatebeforetable')
    drop procedure sp_MShelpcreatebeforetable
go

raiserror('Creating procedure sp_MShelpcreatebeforetable', 0,1)
GO

create procedure sp_MShelpcreatebeforetable
	@objid int,
	@newname sysname
AS
	declare @command nvarchar(1000)
	declare @retcode int
	declare @include int
	declare @tablenick int
	declare @colpat nvarchar(130)
	declare @colname nvarchar(140)
	declare @typename nvarchar(140)
	declare @colid smallint
	declare @colidstr nvarchar(3)
	declare @status tinyint
	declare @len smallint
	declare @prec smallint
	declare @scale int
	declare @isnullable tinyint
	declare @cMaxIndexLength int

	set @cMaxIndexLength= 900  -- max index column size in SQL 2000

	set nocount on

	select @tablenick = max(nickname) from sysmergearticles where objid = @objid
	if @tablenick is null 
	begin
		select 'a' = 'raiserror (''Error creating before image table'' , 16, -1)'
		return (1)
	end
		
	-- create temp table to select the command text out of
	create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)

	set @command = 'create table ' + @newname + '('
	insert into #tempcmd (phase, cmdtext) values (1, @command)
	
	-- Loop over the columns and see which ones we include
	declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, status, type_name(xtype), length,
		 prec, scale, isnullable, colid from syscolumns
	where id = @objid and iscomputed <> 1 and type_name(xtype) <> 'timestamp' order by colid
	FOR READ ONLY
	
	open col_cursor
	fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
	while (@@fetch_status <> -1)
	begin
		set @include = 0
		set @colpat = '%' + @colname + '%'
		if columnproperty( @objid, @colname , 'isrowguidcol')=1
		begin
			set @include = 1
		end
		else
		begin
			-- does updating this column change membership in a partial replica? 
			if exists (select * from sysmergearticles 
				where objid = @objid and subset_filterclause like @colpat)
				set @include = 1
			else if exists (select * from sysmergesubsetfilters
				where art_nickname = @tablenick and join_filterclause like @colpat)
				set @include = 1
			else if exists (select * from sysmergesubsetfilters
		 		where join_nickname = @tablenick and join_filterclause like @colpat)
				set @include = 1
		end
		-- If we want this column, map its type and insert a row to temp table
		if @include = 1
		begin
			if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes
				set @len = @len/2
			exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale			
			if @@ERROR<>0 or @retcode<>0 goto Failure
			if @typename not in ('text', 'ntext','image')
			begin
				select @colname = N'[' + replace(@colname, N']', N']]') + N']'
	
				if @isnullable = 1
					set @command = @colname + ' ' + @typename + ' NULL, '
				else
					set @command = @colname + ' ' + @typename + ' NOT NULL, '
				
				-- Insert the part of create table command for this column
				insert into #tempcmd (phase, cmdtext) values (1, @command)

				-- Insert a create index command if column is not too long
				if (@len <= @cMaxIndexLength)
				begin
					set @colidstr =convert(nvarchar(3), @colid)
					set @command = 'create index ' + @newname + '_' + @colidstr + ' on ' + @newname + ' (' + @colname + ') '
					insert into #tempcmd (phase, cmdtext) values (2, @command)
				end
			end
		end
		/* Repeat the loop with next column */
		fetch next from col_cursor into @colname, @status, @typename, @len, @prec, @scale, @isnullable, @colid
	end

	close col_cursor
	deallocate col_cursor

	-- Insert last column, generation
	set @command = 'generation int NOT NULL, system_delete bit default(0))
		'
	insert into #tempcmd (phase, cmdtext) values (1, @command)
	set @command = 'create clustered index ' + @newname + '_gen on ' + @newname + '(generation) 
		'
	insert into #tempcmd (phase, cmdtext) values (2, @command)
		
	select cmdtext from #tempcmd order by phase, step
	drop table #tempcmd

	return(0)
Failure:
	close col_cursor
	deallocate col_cursor
	return(1)
go
exec dbo.sp_MS_marksystemobject sp_MShelpcreatebeforetable 
go


--------------------------------------------------------------------------------
--. sp_MSgettablecontents 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSgettablecontents')
    drop procedure sp_MSgettablecontents
go

raiserror('Creating procedure sp_MSgettablecontents', 0,1)
GO


CREATE PROCEDURE sp_MSgettablecontents 
	@pubid uniqueidentifier
as 
	declare @tablenick 			int
	declare @new_active			int
	declare @new_inactive		int
	declare @artname			sysname
	declare @view_name			nvarchar(60)
	declare @rowguidcolname		sysname
	declare @sync_viewname		sysname
	declare @quoted_sync_viewname nvarchar(144)
	declare @quoted_view_name	nvarchar(144)
	declare @nickname			int
	declare @objid 				int
	
	declare @tablenickstr nvarchar(12)
	
	select @new_inactive = 5 --special article status for adding article after snapshot
	select @new_active = 6 	 --special article status for adding article after snapshot
	
	select Top 1 @tablenick = nickname, @sync_viewname=object_name(sync_objid), @objid=objid, @artname=name
		from sysmergearticles where pubid = @pubid and (status=@new_inactive or status=@new_active)
								order by nickname ASC
	while @objid is not null
		begin
			set @tablenickstr = convert(nchar(12), @tablenick)
			select @rowguidcolname = name from syscolumns where id = @objid and columnproperty(id, name, 'isrowguidcol')=1
			select @view_name='MSmerge_contents_' + @artname
			select @quoted_view_name=QUOTENAME(@view_name)
			--Must drop the view (if exists) and recreate
			if exists (select * from sysobjects where name=@view_name and xtype = 'V')
			begin				
				exec ('drop view ' + @quoted_view_name)
			end
			select @quoted_sync_viewname=QUOTENAME(@sync_viewname)
			exec('create view ' + @quoted_view_name + 
				' as select * from dbo.MSmerge_contents where (tablenick = ' + @tablenickstr + ' and rowguid in
						(select ' + @rowguidcolname + ' from ' + @quoted_sync_viewname + '))')

			select @objid = NULL
			select Top 1 @tablenick = nickname,@sync_viewname=object_name(sync_objid), @objid=objid, @artname=name from sysmergearticles 
				where pubid = @pubid and nickname>@tablenick and (status=@new_inactive or status=@new_active) 
					order by nickname ASC
			insert #temp_table_for_systable_view(contentsview) values(@view_name)		
		end	
go

exec dbo.sp_MS_marksystemobject sp_MSgettablecontents
go
grant exec on dbo.sp_MSgettablecontents to public
GO

--------------------------------------------------------------------------------
--. sp_MSfixupbeforeimagetables 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSfixupbeforeimagetables')
    drop procedure sp_MSfixupbeforeimagetables
go

raiserror('Creating procedure sp_MSgettablecontents', 0,1)
GO

create procedure sp_MSfixupbeforeimagetables(@pubid uniqueidentifier)
AS
begin
	-- This procedure updates the generations in the existing rows in the before-image
	-- tables of all articles in the specified publication to the current gen_cur value for 
	-- the respective article.
	-- This is done after the subscription has been reinitialized (at a republisher). The reason
	-- is that the genhistory rows at the subscriber no longer correspond to the values before 
	-- the reinit. They are simply bcp-ed in from the bcp generated at the publisher. 
	-- Setting the existing before image rows to gen_cur has the effect of avoiding the retention-
	-- based cleanup of these rows based on invalid coldate values (since they are in context of
	-- the publisher). The cleanup thus gets delayed to when the current gen_cur value expires retention.
	declare @before_image_tablename sysname, @gencur int, @gencur_str nvarchar(20), @cmd nvarchar(256)

	if @pubid is null
		return 0

	declare beforeimagetables_cursor CURSOR LOCAL FAST_FORWARD for 
	select distinct object_name(before_image_objid), gen_cur 
	from sysmergearticles 
	where artid in 
		(select artid from sysmergearticles where pubid = @pubid)
	and before_image_objid is not null
	FOR READ ONLY

	open beforeimagetables_cursor
	fetch next from beforeimagetables_cursor into @before_image_tablename, @gencur

	while (@@fetch_status <> -1)
	begin
		
		if @before_image_tablename is not null
		begin
			select @gencur_str = convert(nvarchar(20), @gencur)
			select @cmd = 'update ' + @before_image_tablename + ' set generation = ' + @gencur_str
			exec (@cmd)
		end
		
		fetch next from beforeimagetables_cursor into @before_image_tablename, @gencur
	end

	close beforeimagetables_cursor
	deallocate beforeimagetables_cursor

	return 0

end

go
exec dbo.sp_MS_marksystemobject sp_MSfixupbeforeimagetables 
go
grant exec on dbo.sp_MSfixupbeforeimagetables to public
go
if exists (select * from sysobjects
    where type = 'P'
            and name = 'sp_MSrepl_backup_start')
    drop procedure sp_MSrepl_backup_start
go

print ''
print 'Creating procedure sp_MSrepl_backup_start'
go
create procedure sp_MSrepl_backup_start
as
	declare @sync_bit int
	declare @dist_bit int

	set nocount on
	
	set @sync_bit = 32
	set @dist_bit = 16

	-- If this is a distribution database and it is marked by 'sync with backup'
	if exists (select * from master.dbo.sysdatabases where
		name = db_name() collate database_default and
		category & (@sync_bit | @dist_bit) = @sync_bit | @dist_bit)
	begin
		update MSrepl_backup_lsns set next_xact_id = t2.xact_id, next_xact_seqno = m.xact_seqno from 
			(select tm.publisher_database_id, max(tm.xact_seqno) from 
				-- max seqno of xacts not involved in partial tran processing
				(select t.publisher_database_id, max(substring(t.xact_seqno, 1, 10)) from 
					MSrepl_transactions t where
					not t.xact_id = 0x0 
					group by t.publisher_database_id, substring(t.xact_seqno, 1, 10)
					having count(t.xact_seqno) < 2
				union
				-- max seqno of xacts involved in and completed partial tran processing
				select t.publisher_database_id, max(substring(xact_seqno, 1, 10)) from
					MSrepl_transactions t where
					not t.xact_id = 0x0 
					and t.xact_id = substring(t.xact_seqno, 1, 10)
					group by t.publisher_database_id
				)as tm(publisher_database_id, xact_seqno) -- derived table containing up to 2 rows per publication_database_id
			group by tm.publisher_database_id -- derived table containing up to 1 row per publication_database_id
			)as m(publisher_database_id, xact_seqno), 
			MSrepl_transactions t2				
		where m.publisher_database_id = MSrepl_backup_lsns.publisher_database_id and
				t2.publisher_database_id = MSrepl_backup_lsns.publisher_database_id and
				t2.xact_seqno	= m.xact_seqno
		if @@error <> 0
			return 1
	end

	return 0
go
EXEC dbo.sp_MS_marksystemobject sp_MSrepl_backup_start
GO

--------------------------------------------------------------------------------
--. sp_MSdelrow 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSdelrow')
    drop procedure sp_MSdelrow
go

raiserror('Creating procedure sp_MSdelrow', 0,1)
GO

create PROCEDURE sp_MSdelrow 
	(@rowguid 		uniqueidentifier,
	@tablenick 	int,
	@metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred, 6 - system delete */
	@lineage_old varbinary(255),
	@generation int,
	@lineage_new varbinary(255),
	@pubid uniqueidentifier = NULL,
	@check_permission int = 0)

as
	set nocount on
	declare @match 			int
	declare @new_metatype	tinyint
	declare @retcode 		smallint
	declare @errcode		int
	declare @reason 		nvarchar(255)
	declare @procname 		sysname
	declare @objid			int
	declare @permissions	int
	
	/*
	** Check to see if current publication has permission
	*/
	if sessionproperty('replication_agent') = 0
	begin
		exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
		if @retcode<>0 or @@ERROR<>0 return (0)
	end
			
	/* Parameter validation */
	if (@rowguid is null)
	begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (0)
	end
	if (@tablenick is null)
	begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (0)
	end
	if (@lineage_new is null)
	begin
		RAISERROR(14043, 16, -1, '@lineage_new')
		return (0)
	end

	if @check_permission =1
	begin
		select @objid=objid, @permissions= check_permissions from sysmergearticles 
			where nickname=@tablenick and (pubid is NULL or pubid=@pubid)
		if @objid is NULL
			return (0)

		exec @retcode = dbo.sp_MSreplcheck_permission @objid = @objid, @type = 3, @permissions = @permissions
		if @retcode<>0 or @@ERROR<>0 return (4)
	end

	-- Are we just changing the type of a tombstone?
	-- This routine is only called for Upload; won't be type 5 (remove from partial) unless
	-- subscriber has a user delete and found an existing metadata type of 5 here.
	-- In that case, set delete type to 1 and update generation, reason text too.
	if (@metadata_type = 5)
	begin
		if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
		begin
			set @reason = formatmessage (20562) -- User delete
			update dbo.MSmerge_tombstone set type = 1, reason = @reason, generation = @generation, lineage = @lineage_new where
				rowguid = @rowguid and tablenick = @tablenick
			return 1
		end
	end
	-- Are we just changing the type of a tombstone?
	else if (@metadata_type = 6)
	begin
		if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
		begin
			set @reason = formatmessage (20564) -- System deleted
			update dbo.MSmerge_tombstone set type = @metadata_type, reason = @reason,
				generation = @generation, lineage = @lineage_new where
				rowguid = @rowguid and tablenick = @tablenick
			return 1
		end
	end

	-- begin transaction and lock row that we plan to delete
	begin transaction
	save tran sp_MSdelrow

	select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
	exec @retcode = @procname @type =8, @rowguid=@rowguid
	IF @@ERROR<>0 or @retcode<>0
	begin
		set @errcode= 0
		goto Failure
	end

	if @metadata_type = 5
	begin
		set @match = 1
		set @new_metatype = 5
	end
	else if @metadata_type = 6
	begin
		set @match = 1
		set @new_metatype = 6
	end
	else
	begin
		exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
		IF @@ERROR<>0 or @retcode<>0
		begin
			set @errcode= 0
			goto Failure
		end
		
		set @new_metatype = 1
	end
	
	if (@match = 1)
	begin
		-- select_proc makes a delete with @type = 5, despite its name. 
		declare @rowcount int, @error int
		exec @retcode = @procname @type =5, @rowguid=@rowguid
		select @error=@@error, @rowcount=@@rowcount
		if @error<>0 or @retcode<>0
		begin
			set @errcode= 0
			goto Failure
		end
		
		if (@rowcount = 1)
		begin
			exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype
			IF @@ERROR<>0 or @retcode<>0
			begin
				set @errcode= 0
				goto Failure
			end
		end
		else
		begin
			set @errcode= 3
			goto Failure
		end
	end
	else
	begin
		set @errcode= 2
		goto Failure
	end

	commit tran
	return(1)-- in sp_MSdelrow, 1=okay

Failure:
	rollback tran sp_MSdelrow
	commit tran
	return(@errcode)
go
exec dbo.sp_MS_marksystemobject sp_MSdelrow 
go
grant exec on dbo.sp_MSdelrow to public
go

--------------------------------------------------------------------------------
--. sp_MSdelsubrows 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSdelsubrows')
    drop procedure sp_MSdelsubrows
go

raiserror('Creating procedure sp_MSdelsubrows', 0,1)
GO

create PROCEDURE sp_MSdelsubrows 
	(@rowguid 		uniqueidentifier,
	@tablenick 	int,
	@metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred, 6 - system delete */
	@lineage_old varbinary(255),
	@generation int,
	@lineage_new varbinary(255),
	@pubid uniqueidentifier = NULL,
	@rowsdeleted INT = NULL OUTPUT)

as
	declare @match 			int
	declare @errcode		int
	declare @new_metatype	tinyint
	declare @retcode 		smallint
	declare @reason 		nvarchar(255)
	declare @procname 		sysname
	declare @tnstr			nvarchar(11)
	declare @error int, @rowcount int
	
	/* By default this sp should delete exactly one row */
	set	@rowsdeleted = 1
	
	/*
	** Check to see if current publication has permission
	*/
	if sessionproperty('replication_agent') = 0
	begin
		exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
		if @retcode<>0 or @@ERROR<>0 return (0)
	end
		
	/* Parameter validation */
	if (@rowguid is null)
	begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (0)
	end
	if (@tablenick is null)
	begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (0)
	end
	if (@lineage_new is null)
	begin
		RAISERROR(14043, 16, -1, '@lineage_new')
		return (0)
	end

	-- Are we just changing the type of a tombstone?
	if (@metadata_type = 5 or @metadata_type = 1)
	begin
		if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
		begin
			
			if (@metadata_type = 5)
				set @reason = formatmessage (20563) -- Remove from partial
			else if (@metadata_type = 1)
				set @reason = formatmessage (20562) -- User delete

			update dbo.MSmerge_tombstone 
				set type = @metadata_type, reason = @reason, generation = @generation, lineage = @lineage_new 
				where rowguid = @rowguid and tablenick = @tablenick
		return 1
		end
	end
	
	-- Are we just changing the type of a tombstone?
	else if (@metadata_type = 6)
	begin
		if exists (select * from dbo.MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)
		begin
			set @reason = formatmessage (20564) -- System deleted
			update dbo.MSmerge_tombstone set type = @metadata_type, reason = @reason 
				where rowguid = @rowguid and tablenick = @tablenick
			return 1
		end
	end

	-- begin transaction and lock row that we plan to delete
	begin transaction
	save tran sp_MSdelsubrows

	select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid = @pubid
	exec @retcode = @procname @type =8, @rowguid=@rowguid
	IF @@ERROR<>0 or @retcode<>0
	begin
		set @errcode= 0
		goto Failure
	end
		
	if @metadata_type = 5
	begin
		set @match = 1
		set @new_metatype = 5
	end
	else if @metadata_type = 6
	begin
		set @match = 1
		set @new_metatype = 6
	end
	else if @metadata_type = 7
	begin
		set @match = 1
		set @new_metatype = 7
	end
	else
	begin
		exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output
		IF @@ERROR<>0 or @retcode<>0
		begin
			set @errcode= 0
			goto Failure
		end

		set @new_metatype = 1
	end

	if (@match = 1)
	begin
		
		/* If there are any joinfilters with this as the join table, try to expand to deleting
		** a set of related rows.
		*/
		if (exists (select * from sysmergesubsetfilters where pubid = @pubid and join_nickname = @tablenick))
		begin
			declare @tn int
			declare @table_name nvarchar(270)
			
			select @rowsdeleted = 0

			set @reason = formatmessage (20563) -- Moved out of partial range
			/* create temp and put in our tablenick, rowguid */
			create table #notbelong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL)
			create index #indnbelong on #notbelong (tablenick, rowguid)
			insert into #notbelong (tablenick, rowguid, flag) values
					(@tablenick, @rowguid, 0)
			
			/* call expand proc */
			exec @retcode = dbo.sp_MSexpandsubsnb @pubid
			IF @@ERROR<>0 or @retcode<>0
			begin
				set @errcode= 0
				goto Failure
			end
		
			select @tn = max(tablenick) from #notbelong where flag > -1
			while @tn is not null
			begin
				select @tnstr = convert(nvarchar(11), @tn)

				exec @retcode = dbo.sp_MStablenamefromnick @tn, @table_name out, @pubid
				-- delete all rows indicated by the temp table
				IF @@ERROR<>0 or @retcode<>0
				begin
					set @errcode= 0
					goto Failure
				end
				exec ('delete from ' + @table_name + ' where RowGuidCol in 
					(select rowguid from #notbelong where tablenick = ' + @tnstr + ')' )
				select @error=@@error, @rowcount=@@rowcount
				IF @error<>0
				begin
					set @errcode= 0
					goto Failure
				end

				select @rowsdeleted = @rowsdeleted + @rowcount
			
				-- move on to next nickname - decreasing makes delete order correct
				update #notbelong set flag = -1 where tablenick = @tn
				select @tn = max(tablenick) from #notbelong where flag > -1
			end

			-- change tombstone type for those rows
			update dbo.MSmerge_tombstone 
			set type = 5, reason = @reason 
			from #notbelong nb, dbo.MSmerge_tombstone ts
			where ts.tablenick = nb.tablenick and
			ts.rowguid = nb.rowguid

			drop table #notbelong
			exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype
			IF @@ERROR<>0 or @retcode<>0
			begin
				set @errcode= 0
				goto Failure
			end
		end
		else
		begin
			
			-- select_proc makes a delete with @type = 5, despite its name. 
			exec @retcode = @procname @type =5, @rowguid=@rowguid
			select @error= @@error, @rowcount= @@rowcount
			IF @error<>0 or @retcode<>0
			begin
				set @errcode= 0
				goto Failure
			end
		
			if (@rowcount = 1)
			begin
				exec @retcode= dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype
				IF @@ERROR<>0 or @retcode<>0
				begin
					set @errcode= 0
					goto Failure
				end
			end
			else
				goto Failure
		end
	end
	else
	begin
		set @errcode= 2
		goto Failure
	end

	commit tran
	return 1 -- in sp_MSdelsubrows, 1=okay

Failure:
	rollback tran sp_MSdelsubrows
	commit tran
	return(@errcode) -- in sp_MSdelsubrows, 0=error

go
exec dbo.sp_MS_marksystemobject sp_MSdelsubrows 
go
grant exec on dbo.sp_MSdelsubrows to public
go

--------------------------------------------------------------------------------
--. sp_MSaddguidcolumn 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSaddguidcolumn')
    drop procedure sp_MSaddguidcolumn
go

raiserror('Creating procedure sp_MSaddguidcolumn', 0,1)
GO

SET ANSI_NULLS ON 
SET QUOTED_IDENTIFIER ON
go
create procedure sp_MSaddguidcolumn
	@source_owner	sysname,
	@source_table 	sysname 		/* table name */
as
	declare @rowguidcol 		sysname
	declare @id					int
	declare @qualified_name		nvarchar(270)
	declare @columns			varbinary(128)
	declare @retcode			int
	declare @colid				int
	declare @pubid				uniqueidentifier

	set nocount on
		
	select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table)
	select @id = object_id(@qualified_name)
	
	/* Alter the source table to add a rowguid column */
	begin tran
	save tran sp_MSaddguidcolumn
	exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner
	if @@ERROR <>0 goto UNDO

	if not exists (select * from syscolumns
		where ObjectProperty(object_id(@qualified_name), 'tablehasrowguidcol')=1)
	begin
		exec dbo.sp_MSuniquecolname @qualified_name, 'rowguid', @rowguidcol output
		exec ('alter table ' + @qualified_name + ' add ' + @rowguidcol + ' uniqueidentifier ROWGUIDCOL default newid() not null')
		if @@ERROR<>0 goto UNDO
	end
	exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner, 1
	if @@ERROR<>0 goto UNDO
	
	commit tran
	return (0)
UNDO:
	rollback tran sp_MSaddguidcolumn
	commit tran
	return (1)	
go

exec dbo.sp_MS_marksystemobject sp_MSaddguidcolumn 
go
grant exec on dbo.sp_MSaddguidcolumn to public
go
--------------------------------------------------------------------------------
--. sp_MSsetrowmetadata 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSsetrowmetadata')
    drop procedure sp_MSsetrowmetadata
go

CREATE PROCEDURE sp_MSsetrowmetadata
	(@tablenick int, @rowguid uniqueidentifier, @generation int,
	 @lineage varbinary(255), @colv varbinary(2048), @type tinyint,
	 @tombstone_rows_deleted int = NULL OUTPUT)
as
	declare @reason nvarchar(255), @retcode int
	
	/*
	** Check to see if current publication has permission
	*/
	if sessionproperty('replication_agent') = 0	
	begin
		exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick
		if @retcode<>0 or @@ERROR<>0 return (1)
	end
		
	if (@tablenick is null)
	begin
		RAISERROR(14043, 16, -1, '@tablenick')
		return (1)
	end
	if (@rowguid is null)
	begin
		RAISERROR(14043, 16, -1, '@rowguid')
		return (1)
	end
	if (@generation is null)
	begin
		RAISERROR(14043, 16, -1, '@generation')
		return (1)
	end
	if (@lineage is null)
	begin
		RAISERROR(14043, 16, -1, '@lineage')
		return (1)
	end

	if (@type=1 or @type=5 or @type=6)
	begin
		if @type = 5
		begin
			set @reason = formatmessage(20563) -- Out of partial range
			set @lineage = 0x00
		end
		else if @type = 6
		begin
			set @reason = formatmessage(20564) -- Deleted by system (e.g., to cope with dup key)
		end
		else
		begin
			set @reason = formatmessage(20562) -- Deleted by user
		end
		-- update or insert dbo.MSmerge_tombstone
		update dbo.MSmerge_tombstone set generation = @generation, lineage = @lineage, type = @type, reason = @reason
			where tablenick = @tablenick and rowguid = @rowguid

		if (@@rowcount = 0)
		begin
			insert into dbo.MSmerge_tombstone (rowguid, tablenick, type, generation, lineage, reason)
				values (@rowguid, @tablenick, @type, @generation, @lineage, @reason)

			delete from dbo.MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid
		end
	end
	else
	begin

		if not exists (select rowguid from dbo.MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid)
		begin
			insert into dbo.MSmerge_contents (rowguid, tablenick, generation, lineage, colv1)
				values (@rowguid, @tablenick, @generation, @lineage, @colv)
			delete from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid
			select @tombstone_rows_deleted = @@rowcount
		end
		else
		begin
			-- update or insert to MSmerge_contents
			-- The following updates the generation to passed in value only if the 
			-- filter columns have not changed.

			-- If filter values have changed, update the generation to gen_cur for article - 
			-- This will allow a subsequent download to cleanup rows that don't belong at subscriber
			
			update dbo.MSmerge_contents 
			set generation = case when (isnull(partchangegen, -1) <> sma.gen_cur and isnull(joinchangegen, -1) <> sma.gen_cur) then @generation else sma.gen_cur end, 
				lineage = @lineage, 
				colv1 = case when datalength(@colv) < datalength(colv1) then colv1 else @colv end
			from dbo.MSmerge_contents mc, (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as sma
			where tablenick = @tablenick 
			and rowguid = @rowguid
			and mc.tablenick = sma.nickname

			if (@@rowcount = 0)
			begin
				insert into dbo.MSmerge_contents (rowguid, tablenick, generation, lineage, colv1)
					values (@rowguid, @tablenick, @generation, @lineage, @colv)
				delete from dbo.MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid
				select @tombstone_rows_deleted = @@rowcount
			end
		end
	end

	IF @@ERROR<>0 return (1) 
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSsetrowmetadata
go
grant exec on dbo.sp_MSsetrowmetadata to public
go
--------------------------------------------------------------------------------
--. sp_MSgetbeforetableinsert 
--------------------------------------------------------------------------------
if exists (select * from sysobjects
    where type = 'P '
            and name = 'sp_MSgetbeforetableinsert')
    drop procedure sp_MSgetbeforetableinsert
go
create procedure sp_MSgetbeforetableinsert
	@objid int,
	@inscommand nvarchar(2000) output
AS
	declare @before_objid int
	declare @before_name sysname
	declare @collist nvarchar(1000)
	declare @colname sysname

	-- Do we have a before table?
	select @before_objid = max(before_image_objid) from  sysmergearticles where objid = @objid and
			before_image_objid is not null
	select @before_name = OBJECT_NAME(@before_objid)

	if @before_name is null
		begin
		set @inscommand = ''
		return 0
		end

	set @collist = ''
	-- Loop over columns to make the column list for the insert / select command
	declare col_cursor CURSOR LOCAL FAST_FORWARD for select name from syscolumns
	where id = @before_objid and name <> 'generation' and name <> 'system_delete' order by colid
	FOR READ ONLY

	open col_cursor

	fetch next from col_cursor into @colname
	while (@@fetch_status <> -1)
		begin
		set @collist = @collist + QUOTENAME(@colname) + ', '
		fetch next from col_cursor into @colname
		end
	close col_cursor
	deallocate col_cursor

	-- Our list has all of the columns except generation since that gets set to a local variable
	-- Make the insert command
	set @inscommand = 'insert into ' + QUOTENAME(@before_name) + ' ( ' + @collist +
		' generation) select ' + @collist + ' a.gen_cur from deleted, (select top 1 nickname, gen_cur = isnull(gen_cur, 0) from sysmergearticles where nickname = @tablenick) as a '

	return 0
	
go
exec dbo.sp_MS_marksystemobject sp_MSgetbeforetableinsert 
go

SET ANSI_NULLS OFF
GO

-------------------------------------------------------------------------------
-- END OF FILE: Turn off marking of system objects.
--	DO NOT ADD ANYTHING AFTER THIS POINT
-------------------------------------------------------------------------------
exec sp_MS_upd_sysobj_category 2
go

exec sp_configure 'allow updates',0
go

reconfigure with override
go




