				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
 
/*
** Create replication stored procedures.
** Part 1:  create codependent procedures.
*/

EXEC dbo.sp_MS_marksystemobject sp_addarticle
GO

print ''
print 'Creating procedure sp_MSgettranconflictname'
go
CREATE PROCEDURE sp_MSgettranconflictname (
@publication sysname,
@source_object nvarchar(540),
@str_prefix nvarchar(30) = NULL,
@conflict_table sysname = NULL OUTPUT)
AS
begin
	declare @objid 				int
	declare @retcode			int
	declare @object_name		sysname
	declare @name_out			sysname
	declare @pubid				int
	declare @article			sysname
	declare @artid				int
	declare @prefixlen			int

	if (@str_prefix is NULL)
		select @str_prefix = 'conflict_'

	select @prefixlen = len(@str_prefix)

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

	select @objid = object_id(@source_object)
	select @artid = artid, @article=name from sysarticles 
		where objid = @objid and pubid=@pubid

	if len(@publication) + len(@article) > 128 - @prefixlen -1	 -- SYSNAME minus prefix len
	begin
		select @object_name = @str_prefix + 
			convert(nvarchar(59), @publication) + 
			'_' + convert(nvarchar(59), @article)
	end
	else
	begin
		select @object_name = @str_prefix + @publication + '_' + @article
	end
	select @conflict_table = @object_name
	exec @retcode = dbo.sp_MSuniqueobjectname @object_name, @conflict_table OUTPUT
end
GO
EXEC dbo.sp_MS_marksystemobject sp_MSgettranconflictname
GO

raiserror('Creating procedure sp_MSmaketrancftproc', 0,1)
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(540)
		,@destqualname   nvarchar(540)
		,@destowner sysname
		,@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, @destowner = a.dest_owner 
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
--
select @qualname = case when (@owner is null or @owner = ' ') then QUOTENAME(@conflict_table)
					else QUOTENAME(@owner) + N'.' + QUOTENAME(@conflict_table) end
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

--
-- prepare destination table name (required for decentralized conflict processing)
--
select @destqualname = case when (@destowner is null or @destowner = ' ') 
					then QUOTENAME(@conflict_table)
					else QUOTENAME(@destowner) + N'.' + QUOTENAME(@conflict_table) 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','decimal','numeric'))
		select @compinsterm = N' '' + CAST(' + @valterm + N' as nvarchar) '
	else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
		select @compinsterm = N' '' + CONVERT(nvarchar(60),' + @valterm + N', 2) '
	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', 112) + N'' ''  + CONVERT(nvarchar(40), ' + @valterm + N', 114) + '''''''' '
	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(@destqualname) 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

print ''
print 'Creating procedure sp_changesubstatus'
go
CREATE PROCEDURE sp_changesubstatus (
    @publication sysname = '%',    /* publication name */
    @article sysname = '%',        /* article name */
    @subscriber sysname = '%',      /* subscriber name */
    @status sysname,                /* subscription status */
    @previous_status sysname=NULL,  /* previous subscription status */
    @destination_db sysname = '%',   /* destination database name */

    @frequency_type int = NULL,
    @frequency_interval int = NULL,
    @frequency_relative_interval int = NULL,
    @frequency_recurrence_factor int = NULL,
    @frequency_subday int = NULL,
    @frequency_subday_interval int = NULL,
    @active_start_time_of_day int = NULL,
    @active_end_time_of_day int = NULL,
    @active_start_date int = NULL,
    @active_end_date int = NULL,
    @optional_command_line nvarchar(4000) = NULL,
    @distribution_jobid binary(16) = NULL OUTPUT,
    @from_auto_sync bit = 0,
    @ignore_distributor bit = 0,
    -- Agent offload
    @offloadagent bit = 0,
    @offloadserver sysname = NULL,
	@dts_package_name sysname = NULL,
	@dts_package_password nvarchar(524) = NULL,
	@dts_package_location int = 0,
    @schemastabilityonly int = 0,
	@distribution_job_name sysname = NULL

) AS

    SET NOCOUNT ON
    DECLARE @inactive tinyint
    DECLARE @subscribed tinyint
    DECLARE @active tinyint
	DECLARE @initiated tinyint
    DECLARE @public tinyint
    DECLARE @replicate_bit smallint
    DECLARE @msg nvarchar(255)
    DECLARE @prevstatid tinyint
    DECLARE @artid int
    DECLARE @tabid int
    DECLARE @srvid smallint
    DECLARE @statusid tinyint
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @pub_db sysname
    DECLARE @dest_db sysname
    DECLARE @sub_name sysname
    DECLARE @sub_status tinyint
    DECLARE @sub_ts varbinary (16)
    DECLARE @non_sql_flag bit
    DECLARE @qcmd nvarchar (4000)
    DECLARE @cmd1 nvarchar (255)
    DECLARE @cmd2 nvarchar (255)
    DECLARE @cmd3 nvarchar (255)
    DECLARE @retcode int
    DECLARE @repl_freq tinyint
    DECLARE @art_type tinyint
    DECLARE @proccmd  nvarchar(255)
    DECLARE @procnum  smallint
    DECLARE @finished_real bit
    DECLARE @finished_virtual bit
    DECLARE @virtual_id smallint
    DECLARE @immediate_sync bit
    DECLARE @enabled_for_internet bit
    DECLARE @allow_anonymous bit
    DECLARE @subscription_type int
    DECLARE @xact_seqno binary(10)
    DECLARE @sync_type tinyint
    DECLARE @automatic tinyint
    DECLARE @bcp_char tinyint	
    DECLARE @concurrent_char tinyint	

    DECLARE @art_change bit
    declare @login_name sysname

	DECLARE @pubid int
	DECLARE @syncinit_lsn binary(10)

	DECLARE @f_syncstat_posted bit

    -- synctran
    DECLARE @update_mode tinyint
    DECLARE @art_name sysname
    declare @synctran tinyint
    declare @no_distproc bit
    declare @loopback_detection bit
	
    /*
    ** Initializations.
    */
    select @synctran = 1
			
    SELECT @automatic = 1
    SELECT @inactive = 0        /* Const: subscription status 'inactive' */
    SELECT @subscribed = 1      /* Const: subscription status 'subscribed' */
    SELECT @active = 2          /* Const: subscription status 'active' */
	SELECT @initiated = 3        /* Const: subscription status 'initiated' */
    SELECT @public = 0          /* Const: publication status 'public' */
    SELECT @pub_db = DB_NAME()
    SELECT @virtual_id = -1
    SELECT @art_change = 0
    select @bcp_char = 1
    select @concurrent_char = 4	

	SELECT @f_syncstat_posted = 0

    SELECT @replicate_bit = 2

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

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

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

    IF @publication <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @publication
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END

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

    /*
    ** Parameter Check:  @article
    ** Check to make sure that the article exists, that it's not null,
    ** and that it conforms to the rules for identifiers.
    */

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

    /*
    IF @article <> '%'
        BEGIN
            EXECUTE @retcode = dbo.sp_validname @article
            IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)
        END
    */

    IF NOT EXISTS (SELECT *
                     FROM sysextendedarticlesview a,
                          syspublications b
                WHERE a.name LIKE @article
                      AND a.pubid = b.pubid
                      AND b.name LIKE @publication)

        BEGIN
        IF @article = '%'
                RAISERROR (14009, 11, -1, @publication)
        ELSE
                RAISERROR (20027, 11, -1, @article)
        RETURN (1)
        END

    /*
    ** Parameter Check:  @subscriber
    ** Check to make sure that the subscriber exists, that it is not NULL,
    ** and that it conforms to the rules for identifiers.
    ** Null subscriber represents virtual subscriptions
    */

    IF @subscriber IS NOT NULL AND @subscriber <> '%'
    BEGIN    
        EXECUTE @retcode = dbo.sp_validname @subscriber
        IF @@ERROR <> 0 OR @retcode <> 0
        RETURN (1)

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

            BEGIN
                RAISERROR (14063, 11, -1)
                RETURN (1)
            END
    END

    /*
    ** Parameter Check: @status.
    ** Set the @statusid according to the @status value.  Values can be
    ** any of the following:
    **
    **      status      statusid
    **      =========   ========
    **      inactive           0
    **      subscribed         1
    **      active             2
	**		initiated          3
    */

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

	IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
		SELECT @statusid = @initiated
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
        SELECT @statusid = @active
    ELSE IF LOWER(@status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
        SELECT @statusid = @subscribed
    ELSE
        SELECT @statusid = @inactive

    /*
    ** Parameter Check: @previous_status.
    ** Set the @prevstatid according to the @previous_status value.
    ** Values can be any of the following:
    **
    **      previous_status      prevstatid
    **      ===============      ==========
    **      inactive                      0
    **      subscribed                    1
    **      active                        2
	**		initiated					  3
    */

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

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

		IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('initiated')
			SELECT @prevstatid = @initiated
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('active')
            SELECT @prevstatid = @active
        ELSE IF LOWER(@previous_status collate SQL_Latin1_General_CP1_CS_AS) IN ('subscribed')
            SELECT @prevstatid = @subscribed
        ELSE
           SELECT @prevstatid = @inactive
    END

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

    IF @destination_db <> '%' 
    BEGIN
		EXECUTE @retcode = dbo.sp_validname @destination_db
		IF @retcode <> 0
		RETURN (1)
    END

    /*
    ** Get distribution server information for remote RPC
    ** subscription calls.
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 1 
        select @no_distproc = 1
    else
        select @no_distproc = 0

    IF @no_distproc = 0 --and @from_auto_sync = 0 
    BEGIN
        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distribdb OUTPUT

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

        IF @retcode <> 0 OR @distribdb IS NULL OR @distributor IS NULL
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END
    END


    create table #sysextendedarticlesview
    (
    artid               int                 NULL,
    columns             varbinary(32)       NULL,
    creation_script     nvarchar(255)       collate database_default null,
    del_cmd             nvarchar(255)       collate database_default null,
    description         nvarchar(255)       collate database_default null,
    dest_table          sysname             collate database_default null,
    filter              int                 NULL,
    filter_clause       ntext               NULL,
    ins_cmd             nvarchar(255)       collate database_default null,
    name                sysname             collate database_default null,
    objid               int                 NULL,
    pubid               int                 NULL,
    pre_creation_cmd    tinyint             NULL,
    status              tinyint             NULL,
    sync_objid          int                 NULL,
    type                tinyint             NULL,
    upd_cmd             nvarchar(255)       collate database_default null,
    schema_option       binary(8)           NULL,
    dest_owner          sysname             collate database_default null
    )

    insert into #sysextendedarticlesview select * from sysextendedarticlesview

    begin tran
    save TRANSACTION changesubstatus

        SELECT @finished_virtual = 0
        SELECT @finished_real = 0

        /* 
        ** If @subscriber is null, don't process real subscriptions
        ** If @subscriber is not null and '%', don't process virtual subscriptions
        */
        IF @subscriber IS NULL SELECT @finished_real = 1
        ELSE IF @subscriber <> '%'  SELECT @finished_virtual = 1

        WHILE (@finished_real = 0 OR @finished_virtual = 0)
        BEGIN
            /*
            ** Declare cursor containing subscriptions to be updated.
            */
            IF @finished_real = 0
            BEGIN
                IF @previous_status IS NOT NULL
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND sub.status = @prevstatid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db collate database_default))
                END
                ELSE
                BEGIN
                    DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                        SELECT sub.artid,
                               art.objid,
                               sub.srvid,
                               ss.srvname,
                               sub.dest_db,
                               sub.status,
                           case when ss.srvproduct = 'MSREPL-NONSQL' or
								pub.allow_dts = 1
								then 1
                           else 0 end,
                           pub.repl_freq,
                               art.type,
                           pub.immediate_sync,
                           pub.enabled_for_internet,
                           pub.allow_anonymous,
                           sub.subscription_type,
                           sub.sync_type,
                           sub.update_mode,
                           art.name,
                           sub.login_name,
                           sub.loopback_detection,
						   pub.pubid
                          FROM syssubscriptions sub,
                               #sysextendedarticlesview art,
                               syspublications pub,
                               master..sysservers ss
                         WHERE pub.name LIKE @publication collate database_default
                           AND art.name LIKE @article collate database_default
                           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default))
                           AND sub.srvid = ss.srvid
                           AND sub.artid = art.artid
                           AND art.pubid = pub.pubid
                           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db))
                END		   
                SELECT @finished_real = 1
            END

            ELSE IF @finished_virtual = 0  
            BEGIN
                DECLARE @sub_bit smallint
                DECLARE @null_name sysname

                SELECT @sub_bit = 4
                SELECT @null_name = NULL

                /*
                ** Treat anonymous virtual subscription as DSN subscriber.
                ** This will cause sp_MSarticlecol being called in sp_changesubstatus
                */
                DECLARE hCsubstatus CURSOR LOCAL SCROLL_LOCKS FOR
                    SELECT sub.artid,
                           art.objid,
                           sub.srvid,
                           @null_name,              /* subscriber name. NULL for virtual */
                           sub.dest_db,
                           sub.status,
                      case when (pub.allow_anonymous = 1 and (pub.sync_method = @bcp_char or pub.sync_method = @concurrent_char)) or
							pub.allow_dts = 1 then 1
                       else 0 end, /*indicate dsn or not */ 
                       pub.repl_freq,
                       art.type,
                       pub.immediate_sync,
                       pub.enabled_for_internet,
                       pub.allow_anonymous,
                       sub.subscription_type,
                       sub.sync_type,
                       sub.update_mode,
                       art.name,
                       login_name,
                       sub.loopback_detection,
					   pub.pubid

                      FROM syssubscriptions sub,
                           #sysextendedarticlesview art,
                           syspublications pub
                     WHERE pub.name LIKE @publication
                       AND art.name LIKE @article
                       AND sub.srvid = -1
                       AND sub.artid = art.artid
                       AND art.pubid = pub.pubid
                SELECT @finished_virtual = 1
            END

            OPEN hCsubstatus
            FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
                @sub_status, @non_sql_flag, @repl_freq, @art_type,
                @immediate_sync, @enabled_for_internet,
                @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection,@pubid


            WHILE (@@fetch_status <> -1)
            BEGIN

                IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
                    AND is_member ('db_owner') <> 1
                BEGIN
                    CLOSE hCsubstatus
                    DEALLOCATE hCsubstatus
                    if @@trancount > 0
                    begin
                        ROLLBACK TRANSACTION changesubstatus
                        commit tran
                    end
                    RAISERROR (14126, 11, -1)
                    RETURN (1)
                END
                /*
				** condition 1:
                ** If current status is same as new status, and status is not 'initiated' do nothing.
				** If both old and new status = 'initiated', this indicates that the 
				** snapshot agent previously bombed out between the initiation and activation stages and
				** is now again trying to sync the publication.
				**
				** condition 2:
                ** @auto_sync_only is used by snapshot for immediate_sync
                ** publications.
				**
				** condition 3:
				** Because sp_MSactivate_auto_sub (and thus the snapshot agent)
				** calls this procedure for all subscriptions, we need to ignore
				** the real subscriptions that are already active so that they won't be
				** transitioned to the initiated state.  If we don't do this, those
				** subscriptions will be resynced using the new snapshot.
				** 
				** however, we DO want a new snapshot to be generated for virtual
				** subscriptions to active publications.
				**
                */
                IF  (@sub_status = @statusid AND @sub_status <> @initiated ) OR
                    (@from_auto_sync = 1 AND @sync_type <> @automatic) OR
					(@sub_status = @active AND @statusid = @initiated AND @srvid <> -1 AND @from_auto_sync = 1)
                BEGIN
                    FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name,
                       @dest_db, @sub_status, @non_sql_flag, @repl_freq, @art_type, 
                       @immediate_sync, @enabled_for_internet,
                       @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                       @art_name, @login_name, @loopback_detection, @pubid

                    CONTINUE
                END

				-- If changing a virtual subscription to 'subscribed' status
				-- change the immediate_sync_ready bit
				if @statusid = @subscribed and @sub_name is NULL
				begin
					UPDATE syspublications SET immediate_sync_ready = 0 WHERE 
						pubid = @pubid and
						immediate_sync_ready <> 0
                    IF @@ERROR <> 0
                    BEGIN
                      CLOSE hCsubstatus
                      DEALLOCATE hCsubstatus
                      if @@trancount > 0
                        begin
                            ROLLBACK TRANSACTION changesubstatus
                            commit tran
                        end
                      RETURN (1)
                    END
				end


				-- acquire schema lock, mark rollback point in order to allow
				-- for 'unflush' of proc cache

                declare @qualified_name nvarchar(512)

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

                /*
                ** Update syssubscription status
                */
                UPDATE syssubscriptions
                       SET status = @statusid
                       FROM syssubscriptions sub,
                           sysextendedarticlesview art,
                           syspublications pub
                       WHERE pub.name LIKE @publication
                            AND art.artid = @artid
                            AND sub.srvid = @srvid
                            AND sub.artid = @artid
                            AND art.pubid = pub.pubid
                            AND sub.dest_db = @dest_db
                if @@ERROR <> 0
                               BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                                   RETURN (1)
                               END

				--
				-- Subscription reinitialization processing for Immediate 
				-- and Queued publications
				--
				if (@update_mode in (1,2,3,4,5))
				begin
					select @retcode = 0
					IF ((@statusid != @active) AND (@sub_status = @active))
					begin
						--
						-- If we are going from active state to subscribed
						-- set the reinit column so that no more updates from
						-- subscriber are applied until (re)activation
						--
						update dbo.syssubscriptions
						set queued_reinit = 1
						where 
							artid = @artid 
							and srvid = @srvid
							and dest_db = @dest_db
					end
					ELSE IF ((@statusid = @active) AND (@sub_status != @active ))
					begin
						--
						-- If we are going from subscribed state to active state
						--
						if (@update_mode = 1)
						begin
							--
							-- Sync tran case : reset the reinit column
							--
							update dbo.syssubscriptions
							set queued_reinit = 0
							where 
								artid = @artid 
								and srvid = @srvid
								and dest_db = @dest_db
						end
						--
						-- For queued case : we do not need to send compensating
						-- command anymore, sp_addqueued_artinfo will do the 
						-- queue reinitialization for all types of queued
						-- subscriptions
						--
					end					

					--
					-- Check for error
					--
					if (@@error != 0 or @retcode != 0)
					begin
						CLOSE hCsubstatus
						DEALLOCATE hCsubstatus
						if @@trancount > 0
						begin
							ROLLBACK TRANSACTION changesubstatus
							commit tran
						end
						RAISERROR (14053, 16, -1)
						RETURN (1)
					end
				end

                /*
                ** Get timestamp of subscription.
                */
                EXEC @retcode = dbo.sp_replincrementlsn_internal @xact_seqno OUTPUT
                IF @@ERROR <> 0 or @retcode <> 0
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                               RETURN (1)
                            END
                select @sub_ts = @xact_seqno


                IF @sub_ts IS NULL
                            BEGIN
                               CLOSE hCsubstatus
                               DEALLOCATE hCsubstatus
                               if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14053, 16, -1)
                               RETURN (1)
                            END
				
				-------------------------------------------------------------------
				-- If initiating the subscription, toss a SYNCINIT token into the 
				-- log for the article and return LSN as a results set
				--
				-- Note:  This should come after the subscription LSN is obtained.
				-- in order to assure proper application of SYNSTAT tokens in the
				-- distribution database
				-------------------------------------------------------------------

				IF @statusid = @initiated --and @sub_status <> @initiated
				BEGIN
					-- set filtered status.  Must log old text information during initiated state
					-- in order to support update splitting

					exec sp_MSsetfilteredstatus @tabid

					-- set nonsqlsub status.  must prevent UPDATETEXT operations during
					-- initiated state

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'add'
					exec sp_replpostsyncstatus @pubid, @artid, 1, @syncinit_lsn output
					if @f_syncstat_posted = 0
					begin
						select @pubid, @artid, @syncinit_lsn
						select @f_syncstat_posted = 1
					end
				END

				-------------------------------------------------------------------
				-- If changing the state FROM initiated, post a SYNCDONE token to the 
				-- log for the article. 
				-------------------------------------------------------------------
				IF @sub_status = @initiated and @statusid <> @initiated
				BEGIN
					-- reset filtered status to normal value

					exec sp_MSsetfilteredstatus @tabid

					-- clear nonsqlsub status for this article.

                    exec sp_MSarticlecol @artid, NULL,N'nonsqlsub', N'drop'

					--if @f_syncstat_posted = 0
					--begin
						exec sp_replpostsyncstatus @pubid, @artid, 0, @syncinit_lsn output
					--	select @f_syncstat_posted = 1
					--end
				END

                /*
                ** If activating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */
                IF @statusid in ( @active, @initiated )
                BEGIN
                    
                    /*
                    ** Update status of article to show it has been activated.
                    */
                    IF @repl_freq = 0 and EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                        AND status & 1 <> 1)
                    BEGIN
                        -- At most one row will be updated in the following two updates as the artid is unique
                        -- among both sysarticles and sysschemaarticles
                        UPDATE sysarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        UPDATE sysschemaarticles SET status = status | 1 WHERE artid = @artid
                        IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                        SELECT @art_change = 1
                    END

                        /*
                        ** Turn the replication flag on for this object in the
                        ** sysobjects table (make it logbased).
                        */

                    if @repl_freq = 0
                      BEGIN
                        UPDATE sysobjects SET replinfo = replinfo | @replicate_bit
                        WHERE id = ( SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )
                      END

                      IF @@ERROR <> 0
                      BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                      END

                END

                /*
                ** Update status of all columns if subscriber is non-SQL Server.
                */
                IF @non_sql_flag <> 0 AND ( @art_type & 1 ) = 1
                BEGIN
                    IF @statusid = @subscribed OR @statusid = @active
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'add'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RAISERROR (14068, 16, -1)
                            RETURN (1)
                        END


                    END
                    ELSE IF @statusid = @inactive
                    BEGIN

                        EXEC @retcode = dbo.sp_MSarticlecol @artid, NULL,
                                                          'nonsqlsub', 'drop'
                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                          CLOSE hCsubstatus
                          DEALLOCATE hCsubstatus
                          if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                          RAISERROR (14068, 16, -1)
                          RETURN (1)
                        END
                    END
                END

				
                /*
                ** If deactivating subscription, update sysextendedarticlesview, sysobjects and
                ** MSrepl_subscriptions.
                */

                IF @statusid NOT IN( @active, @initiated ) AND @sub_status IN ( @active, @initiated )
                BEGIN
                    /*
                    ** Set the article status to 'inactive' if there are
                    ** no other active subscriptions on it.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                       artid = @artid AND status = @active)
                    BEGIN
                        IF EXISTS (SELECT * FROM sysextendedarticlesview WHERE artid = @artid
                            AND status & 1 = 1)
                        BEGIN
                            -- At most one row will be updated in the following two updates as the artid is unique
                            -- among both sysarticles and sysschemaarticles
                            UPDATE sysarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END
                            UPDATE sysschemaarticles SET status = status & ~1 WHERE
                                artid = @artid
                            IF @@ERROR <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RAISERROR (14069, 16, -1)
                                RETURN (1)
                            END

                            SELECT @art_change = 1
                        END
                    END

                    /*
                    ** Set the object replication bits  to 'inactive' if
                    ** there are no other active subscriptions on the
                    ** table.
                    */
                    IF NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                        artid IN (SELECT sa.artid FROM sysextendedarticlesview sa, syspublications sp WHERE
                        sa.objid = @tabid and sa.pubid = sp.pubid and sp.repl_freq = 0) AND status = @active)
                    BEGIN
                        UPDATE sysobjects SET replinfo =  replinfo & ~@replicate_bit
                        WHERE id = (SELECT objid FROM sysextendedarticlesview WHERE artid = @artid )

                        IF @@ERROR <> 0
                        BEGIN
                           CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14068, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                END

				-- Note:  Not only do we need to have the replupdateschema already executed
				-- so we can handle rollbacks, we also need to
                -- acquire the schema lock before RPC to the distributor to avoid livelock
                -- with snapshot agents. Snapshot agents acquire lock on user table before
                -- updating the distribution db.

                if @no_distproc = 0
                begin
                    /*
                    ** Add the active subscription to the distributor's
                    ** subscriptions table if changing status from @inactive
                    */
                    IF @sub_status = @inactive 
                    -- From inactive to subscribed or active
                    BEGIN

                        DECLARE @null_char sysname
                        SELECT @null_char = NULL

                        DECLARE @zero_bit bit
                        SELECT @zero_bit = 0

                        SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadd_subscription'
                        EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, 
                            @artid, @dest_db, @statusid, @sub_ts,
                            @publication, 
                            @null_char, /* Pass null to @article, we already gave @artid */
                            @subscription_type,
                            --@immediate_sync, 
                            @sync_type, 
                            @zero_bit,
                            @frequency_type,
                            @frequency_interval,
                            @frequency_relative_interval,
                            @frequency_recurrence_factor,
                            @frequency_subday,
                            @frequency_subday_interval,
                            @active_start_time_of_day,
                            @active_end_time_of_day,
                            @active_start_date,
                            @active_end_date,
                            @optional_command_line = @optional_command_line,
                            -- synctran
                            @update_mode = @update_mode,
                            @loopback_detection = @loopback_detection,
                            @distribution_jobid = @distribution_jobid OUTPUT,
                            @offloadagent = @offloadagent,
                            @offloadserver = @offloadserver,
							@dts_package_name = @dts_package_name,
							@dts_package_password = @dts_package_password,
							@dts_package_location = @dts_package_location,
							@distribution_job_name = @distribution_job_name

                        IF @@ERROR <> 0 OR @retcode <> 0
                        BEGIN
                            CLOSE hCsubstatus
                            DEALLOCATE hCsubstatus
                            RAISERROR (14070, 16, -1)
                            if @@trancount > 0
                            begin
                                ROLLBACK TRANSACTION changesubstatus
                                commit tran
                            end
                            RETURN (1)
                        END
                    END
                    ELSE
                    -- From subscribed or active to others
                    BEGIN
                        /*
                        ** Drop the deactivated subscription from the distributor's
                        ** subscriptions table.
                        */
                        IF @statusid = @inactive
                        -- From subscribed to inactive or from active to inactive
                        BEGIN
                            SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_subscription'
                            EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name,  @artid, @dest_db, @publication
                            IF @@ERROR <> 0 OR @retcode <> 0
                            BEGIN
                                CLOSE hCsubstatus
                                DEALLOCATE hCsubstatus
                                RAISERROR (14070, 16, -1)
                                if @@trancount > 0
                                begin
                                    ROLLBACK TRANSACTION changesubstatus
                                    commit tran
                                end
                                RETURN (1)
                            END
                        END
                        ELSE 
                        -- From subscribed to initiated to active or from active to subscribed.
                        BEGIN
                            -- Don't do it if activating the subscription for snapshot agent.
                            --IF NOT (@from_auto_sync = 1 AND @statusid in(@active, @initiated) )
                            IF NOT (@from_auto_sync = 1 AND @statusid in(@active) )
                            BEGIN
                                SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSupdate_subscription'
                                EXEC @retcode = @distproc @@SERVERNAME, @pub_db, @sub_name, @artid, @statusid, @sub_ts, @dest_db
                                IF @@ERROR <> 0 OR @retcode <> 0
                                BEGIN
                                    CLOSE hCsubstatus
                                    DEALLOCATE hCsubstatus
                                    RAISERROR (14070, 16, -1)
                                    if @@trancount > 0
                                    begin
                                        ROLLBACK TRANSACTION changesubstatus
                                        commit tran
                                    end
                                    RETURN (1)
                                END
                            END
                        END
                    END
                end

                /*
                ** Set internal object replication bit  to 'inactive' if
                ** there are no other active subscriptions on the
                ** table.
                */

                IF @statusid = @inactive AND @sub_status IN (@active,@initiated) AND
                    NOT EXISTS (SELECT * FROM syssubscriptions WHERE
                    artid IN (SELECT artid FROM sysextendedarticlesview WHERE
                    objid = @tabid) AND status IN (@active,@initiated) )
                BEGIN
                       /*
                       ** If it's a procedure execution article, clear proc status bits
                       */
                       IF (@art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo & ~24 WHERE id = @tabid
                       END
                END


                /* Turn on object replication */

                ELSE IF @statusid = @active
                BEGIN
                       IF (@art_type & 24 ) = 24
                       BEGIN

                           UPDATE sysobjects SET replinfo = replinfo | 24 WHERE id = @tabid
                       END
                       ELSE IF( @art_type & 8 ) = 8
                       BEGIN
                           UPDATE sysobjects SET replinfo = replinfo | 8 WHERE id = @tabid
                       END
                END


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

               /*
               ** Get next row.
               */
               FETCH hCsubstatus INTO @artid, @tabid, @srvid, @sub_name, @dest_db,
               @sub_status, @non_sql_flag, @repl_freq, @art_type ,  
               @immediate_sync, @enabled_for_internet,
               @allow_anonymous, @subscription_type, @sync_type, @update_mode,
                @art_name, @login_name, @loopback_detection, @pubid

          
                                    
           END  -- end while for cursor

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

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

    COMMIT TRANSACTION
    drop table #sysextendedarticlesview
    RETURN(0)
go
 
EXEC dbo.sp_MS_marksystemobject sp_changesubstatus
GO

print ''
print 'Creating procedure sp_addsubscription'
go
CREATE PROCEDURE sp_addsubscription (
    @publication sysname,                            /* publication name */
    @article sysname = 'all',                        /* article name */
    @subscriber sysname = NULL,                        /* subscriber name */
    @destination_db sysname = NULL,                /* destination database */
    @sync_type nvarchar (15) = 'automatic',                /* subscription sync type */
    @status sysname = NULL,                            /* subscription status */
    @subscription_type nvarchar(4) = 'push',                /* subscription type:
                                                        ** 'push' or 'pull' */
    -- SyncTran
    @update_mode           nvarchar(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

print ''
print 'Creating procedure 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

print ''
print 'Creating procedure sp_changearticle'
GO
CREATE PROCEDURE sp_changearticle (
    @publication sysname = NULL,        /* Publication name */
    @article sysname = NULL,            /* Article name */
    @property nvarchar(20) = NULL,      /* The property to change */
    @value nvarchar(255) = NULL,        /* The new property value */
	@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

print ''
print 'Creating procedure sp_droparticle'
go

CREATE PROCEDURE sp_droparticle(
	@publication sysname,     /* The publication name */
	@article sysname,          /* The article name */
	@ignore_distributor bit = 0,	
	@force_invalidate_snapshot bit = 0	/* Force invalidate existing snapshot */

) 
AS
BEGIN
    /*
    ** Declarations.
    */

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

    SET NOCOUNT ON

    /*
    ** Initializations.
    */

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


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

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

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

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


    /*
    ** Get the @pubid.
    */

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

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

    IF LOWER(@article) = 'all'
        BEGIN
			-- If drop all articles, set force flag to true
			select @force_invalidate_snapshot = 1
            DECLARE hC  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT  name FROM sysextendedarticlesview 
                    WHERE pubid = @pubid
            OPEN hC
            FETCH hC INTO @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_droparticle 
                        @publication = @publication, 
                        @article = @article,
                        @ignore_distributor = @ignore_distributor,
						@force_invalidate_snapshot = @force_invalidate_snapshot

                    FETCH hC INTO @article
                END
            CLOSE hC
            DEALLOCATE hC
            RETURN (0)
        END

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

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

    /*
    EXECUTE @retcode = dbo.sp_validname @article

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

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

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

    /*
    ** Check to make sure that there are no 'real' subscriptions on the article.
    */

    IF EXISTS (SELECT *
                 FROM syssubscriptions, sysextendedarticlesview
                WHERE sysextendedarticlesview.name = @article
                  AND sysextendedarticlesview.pubid = @pubid
                  AND sysextendedarticlesview.artid = syssubscriptions.artid
                  AND syssubscriptions.srvid <> @virtual_id)
        BEGIN
            RAISERROR (14046, 16, -1)
            RETURN (1)
        END

    -- 
    -- If SyncTran/QueuedTran enabled
    -- retrieve info from sysarticle updates
    --
    if (@allow_sync_tran_id = 1 or @allow_queued_tran_id = 1)
    begin
        select @artid = artid from sysarticles where name = @article and pubid = @pubid
        select @insproc_id = sync_ins_proc, @updproc_id = sync_upd_proc, @delproc_id = sync_del_proc,
			@updtrig_id = sync_upd_trig,
			@tran_conflict_tabid = conflict_tableid,
			@tran_conflict_procid = ins_conflict_proc
        from sysarticleupdates
        where artid = @artid and pubid = @pubid 
    end
    -- end SyncTran

    /*
    ** Retrieve the object id of the underlying object,
    ** article id, and article type. Note that the 
    ** subsequent code relies on the values of the variables in
    ** the select list. Please do not remove any variable from 
    ** the seletc list unless you make sure that all the subsequent
    ** references to the variable are accounted for.  
    */
 
    SELECT @artid = artid, @objid = objid, @type = type
      FROM sysextendedarticlesview
     WHERE name = @article
       AND pubid = @pubid

    begin tran
    save TRAN droparticle

		-- @ignore_distributor is set to 1 when removing replication forcefully. In that
		-- case, no need to check or reinit
		if @ignore_distributor = 0
		begin
			-- Have to call this stored procedure to invalidate existing snapshot
			-- if there are any. immediate_sync_ready bit would be changed or error will be railsed.
			EXECUTE @retcode  = dbo.sp_MSreinit_article
				@publication = @publication, 
				@need_new_snapshot = 1,
				@force_invalidate_snapshot = @force_invalidate_snapshot
			IF @@ERROR <> 0 OR @retcode <> 0
				GOTO UNDO
		end

        /* Drop virtual subscription first for @immediate_sync publications
         */
        if EXISTS (SELECT * FROM syspublications WHERE
            name = @publication    AND
            immediate_sync = 1)
        BEGIN
            EXECUTE @retcode  = dbo.sp_dropsubscription 
                @publication = @publication, 
                @article = @article,
                @subscriber = NULL,
                @ignore_distributor = @ignore_distributor,
                @reserved = 'internal'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                if @@trancount > 0
                begin
                    ROLLBACK TRAN droparticle
                    commit tran
                end
                RETURN (1)
            END
        END

        /* Drop article at the distributor side */
        /*
        ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
        */
        if @ignore_distributor = 0
        begin

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

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

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

        IF @type IN (0x20, 0x40, 0x80)
        BEGIN
            -- Handle the schema only articles a little bit differently from 
            -- other articles as they are simpler objects. 

            -- Note that we have already obtained the article id earlier 
            -- so we can use that to delete the corresponding record
            -- in sysschemaarticles
            
            DELETE sysschemaarticles WHERE artid = @artid and pubid = @pubid

            -- If the object is no longer published as an schema only
            -- article, unmark its published for schema only bit (512) in 
            -- sysobjects/replinfo so that it can be dropped by the user.
            -- Note that we need to check sysmergeschemaarticles too.


            -- Note that we have obtained the object id for the undelying 
            -- object of this article already.

            IF NOT EXISTS (SELECT * 
                             FROM sysschemaarticles 
                            WHERE objid = @objid)
            BEGIN
                SELECT @publish_bit = 512
                IF NOT EXISTS (SELECT * 
                                 FROM sysobjects 
                                WHERE name = 'sysmergeschemaarticles')
                BEGIN
                    UPDATE sysobjects 
                       SET replinfo = replinfo & ~@publish_bit
                    WHERE id = @objid 
                END
                ELSE IF NOT EXISTS (SELECT * 
                                      FROM sysmergeschemaarticles
                                     WHERE objid = @objid)
                BEGIN
                    UPDATE sysobjects 
                       SET replinfo = replinfo & ~@publish_bit
                    WHERE id = @objid 
                END
            END  
        END
        ELSE
        BEGIN
        
            /*
            **  Delete article from sysarticles and clear publish bit in
            **  sysobjects.
            */


            /*
            ** If this article is the only one that references this object,
            ** then we can safely turn off the publish bit in sysobjects.
            */

            IF NOT EXISTS (SELECT *
                             FROM sysarticles
                            WHERE objid = @objid
                              AND NOT (name = @article AND pubid = @pubid))
                BEGIN

                UPDATE sysobjects SET replinfo = replinfo & ~ @publish_bit 
                    WHERE id = (SELECT objid FROM sysarticles WHERE name = @article 
                        AND pubid =  @pubid) 

			    /*
                EXEC (@cmd)

                IF @@ERROR <> 0
                    BEGIN
                        if @@trancount > 0
                            ROLLBACK TRAN
                        RAISERROR (14047, 16, -1, @article)
                        RETURN (1)
                    END
			    */

                END

            /*
            ** Drop article view if not logbased manualview (type = 5)
            */
            IF (@type & 5) = 1
            BEGIN    
                SELECT @view_id = sysobjects.id
                  FROM sysarticles, sysobjects
                 WHERE sysarticles.name = @article
                   AND pubid = @pubid
                   AND sync_objid = sysobjects.id
                   AND sysobjects.type = 'V'
                exec sp_MSget_qualified_name @view_id, @view_name OUTPUT

            END

            /*
            ** Drop article filter if not logbased manualfilter (type = 3)
            */
            IF (@type & 3) = 1
            BEGIN    
                SELECT @filter_id = sysobjects.id
                  FROM sysarticles, sysobjects
                 WHERE sysarticles.name = @article
                   AND pubid = @pubid
                   AND filter = sysobjects.id
                   AND sysobjects.type = 'RF'

                exec sp_MSget_qualified_name @filter_id, @filter_name OUTPUT
       
            END


            IF( @type & 3 ) = 3
            BEGIN
                select @filter_id =  filter from sysarticles
                where name = @article and pubid = @pubid

                exec sp_MSget_qualified_name @filter_id, @filter_name OUTPUT

                if @filter_name is not null
                    EXEC dbo.sp_MSsetfilterparent @filter_name, 0
            
                -- Clear base table dependency on the filter
                EXEC dbo.sp_MSsetfilteredstatus @objid

                -- This is a manual filter, we should not drop it automatically
                -- since it is not created by us.
                -- Set @filter_id to null so the object will not be dropped later.
                select @filter_name = null
 
            END


            /*
            ** If this is a table based article, Drop all article columns.
            ** This is done to force all Text\Image column status to be updated.
            */

            IF (@type & 8) != 8
            BEGIN

	            -- propagate @ignore_distributor to sp_articlecolumn to allow forced cleanup
                EXECUTE @retcode  = dbo.sp_articlecolumn @publication, @article,
                @operation = 'drop', @ignore_distributor = @ignore_distributor
                -- synctran
                , @refresh_synctran_procs = 0
				, @force_invalidate_snapshot = @force_invalidate_snapshot
                IF @@ERROR <> 0 OR @retcode <> 0
                BEGIN
                    if @@trancount > 0
                    begin
                        ROLLBACK TRAN droparticle
                        commit tran
                    end
                    RETURN (1)
                END
            END


            /*
            ** Remove the row from sysarticles.
            */
            DELETE
              FROM sysarticles
             WHERE name = @article
               AND pubid = @pubid

            IF @@ERROR <> 0
            BEGIN
                if @@trancount > 0
                    ROLLBACK TRAN 
                RAISERROR (14047, 16, -1, @article)
                RETURN (1)
            END

            -- SyncTran
            /*
            ** Drop associated sync tran procs and entries in sysarticle updates
            */
            if (@allow_sync_tran_id = 1 or @allow_queued_tran_id = 1)
            begin
                exec @retcode = dbo.sp_MSdrop_object 
                    @object_id = @insproc_id
                if @retcode <> 0 or @@error <> 0
                    goto UNDO

                exec @retcode = dbo.sp_MSdrop_object 
                    @object_id = @updproc_id
                if @retcode <> 0 or @@error <> 0
                    goto UNDO

                exec @retcode = dbo.sp_MSdrop_object 
                    @object_id = @delproc_id
                if @retcode <> 0 or @@error <> 0
                    goto UNDO
            
			    if @updtrig_id is not null
			    begin
				    exec @retcode = dbo.sp_MSdrop_object 
					    @object_id = @updtrig_id
				    if @retcode <> 0 or @@error <> 0
					    goto UNDO
                end

			    -- drop conflict tables as necessary
			    if @tran_conflict_tabid is not null
			    begin
				    exec @retcode = dbo.sp_MSdrop_object 
					    @object_id = @tran_conflict_tabid
				    if @retcode <> 0 or @@error <> 0
					    goto UNDO
                end

			    if @tran_conflict_procid is not null
			    begin
				    exec @retcode = dbo.sp_MSdrop_object 
					    @object_id = @tran_conflict_procid
				    if @retcode <> 0 or @@error <> 0
					    goto UNDO
                end

                delete from sysarticleupdates where artid = @artid and pubid = @pubid
                if @@ERROR <> 0 
                begin
                    if @@trancount > 0
                        ROLLBACK TRAN
                    RETURN (1)

                end

			    -- Cleanup MSpub_identity_range if needed.
			    if not exists (select * from sysarticles where objid = @objid)
			    begin
					if exists (select * from MSpub_identity_range where objid = @objid)
					begin
						-- Drop the identity range constraits.
						-- RESEED and change constraint
						exec @retcode = dbo.sp_MSreseed
							@objid =  @objid,
							-- next_seed and range 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 MSpub_identity_range where objid = @objid
						if @@ERROR <> 0 
							GOTO UNDO
				    end
			    end
            -- end SyncTran
            end
	end
    COMMIT TRAN

    IF @view_name IS NOT NULL
	BEGIN
        -- @view_name is already quoted.
		SELECT @cmd = 'drop view ' + @view_name
		exec (@cmd)
	END

    IF @filter_name IS NOT NULL
	BEGIN
        -- @filter_name is already quoted.
		SELECT @cmd = 'drop proc ' + @filter_name
		exec (@cmd)
	END
    /*
    ** Force the article cache to be refreshed; only if needed
    */
	if ( @ignore_distributor = 0 )
		EXECUTE dbo.sp_replflush

    return (0)

UNDO:

	if @@trancount > 0
    begin
        ROLLBACK TRANSACTION droparticle
        commit tran
    end
    RETURN (1)
END
go
 
EXEC dbo.sp_MS_marksystemobject sp_droparticle
GO

print ''
print 'Creating procedure sp_droppublication'
go

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

    /*
    ** Declarations.
    */

    DECLARE @article sysname
    DECLARE @cmd nvarchar(255)
    DECLARE @retcode int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    DECLARE @distproc nvarchar (255)
    DECLARE @agentname nvarchar (40)
    DECLARE @dbname sysname
    DECLARE @virtual_id smallint
	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

print ''
print 'Creating procedure sp_dropsubscription'
go
CREATE PROCEDURE sp_dropsubscription (
    @publication sysname = NULL,   /* The publication name */
    @article sysname = NULL,       /* The article name */
    @subscriber sysname,           /* The subscriber name */
    @destination_db sysname =NULL,                /* Name of the destination database */
                                        /* If null, all the subscriptions from that
                                            subscriber will be dropped */
    @ignore_distributor bit = 0,

    @reserved nvarchar(10) = NULL            /* reserved, used when calling from other system */
                                            /* stored procedures, it will be set to 'internal'.*/
                                            /* It should never be used directly */
    ) AS

    /*
    ** Declarations.
    */

    DECLARE @subscriber_bit smallint
    DECLARE @cmd nvarchar(255)
    DECLARE @srvid smallint
    DECLARE @artid int
    DECLARE @retcode int
    DECLARE @active tinyint
    DECLARE @internal nvarchar(10)
    DECLARE @expand_article nvarchar(10)
    DECLARE @push tinyint
    DECLARE @virtual_id smallint
    DECLARE @login_name sysname
    DECLARE @immediate_sync bit
    DECLARE @subscription_type int
    DECLARE @qualified_subscription_name nvarchar(512)
	DECLARE @sync_method tinyint
	DECLARE @concurrent tinyint
	DECLARE @concurrent_char tinyint

    /*
    ** Initializations.
    */
    SET NOCOUNT ON
    SELECT @subscriber_bit = 4  /* Const: subscription server status */
    SELECT @active = 2          /* Const: subscription status 'active' */
    SELECT @push = 0        /* Const: push publication type */
    SELECT @virtual_id = -1 /* Const: virtual subscriber id */
    SELECT @internal = 'internal' /* Const: Flag of calling internally from system */
                                  /* stored procedures     */
    SELECT @expand_article = 'expand_art' 
        /* Const: Flag of calling after expand 'all' for @article  */
    SELECT @concurrent = 3
    SELECT @concurrent_char = 4

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

    -- Test distributor RPC connection before open the cursor

    /*
    ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC.
    */
    if @ignore_distributor = 0
    begin
        declare @distributor sysname
        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT
        if @@ERROR <> 0 or @retcode <> 0
            return(1)
    end

    /*
    ** If the @subscriber is 'all', the user wants to cancel all subscriptions
    ** to the specified article(s).
    */

    IF LOWER(@subscriber) = 'all'
        BEGIN
            DECLARE hCdrop_subscription1  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT srvname 
                    FROM master..sysservers a, syssubscriptions b 
                    WHERE srvstatus & @subscriber_bit <> 0 
                    AND a.srvid = b.srvid

    -- With ANSI Defaults ON, the cursor will automatically
    -- be closed on commit.   Since this proc gets called recursively, 
    -- this can happen.  So check before opening. 
    IF CURSOR_STATUS('local','hCdrop_subscription1') = -1
            OPEN hCdrop_subscription1

			-- must owner qual proc invoke to exec inside server on restore/attach cleanup
            FETCH hCdrop_subscription1 INTO @subscriber
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber  = @subscriber,
                        @destination_db = 'all',
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved

        IF CURSOR_STATUS('local','hCdrop_subscription1') = -1
                OPEN hCdrop_subscription1
                FETCH hCdrop_subscription1 INTO @subscriber
                END
            CLOSE hCdrop_subscription1
            DEALLOCATE hCdrop_subscription1
            RETURN (0)
        END

    
    
    /*
    ** Parameter Check: @subscriber.
    **
    ** Check if the server exists and that it is a subscription server.
    **
    */
    IF @subscriber IS NULL
        BEGIN
            SELECT @srvid = @virtual_id 
        END
    ELSE
        BEGIN
            /* validate name and get subscriber ID  and server status  */
            EXECUTE @retcode = dbo.sp_validname @subscriber
            IF @retcode <> 0
            RETURN (1)

            SELECT @srvid = srvid
              FROM master..sysservers
             WHERE UPPER(srvname) = UPPER(@subscriber) collate database_default
               AND (srvstatus & @subscriber_bit) <> 0

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

	-- Have to check @destination_db before expanding publications and articles
	-- Otherwise, the error will not be caught because the cursor will return zero row.
	if @destination_db is not null and LOWER(@destination_db) <> 'all' 
	begin
		if not exists (select * from syssubscriptions where
			srvid = @srvid and
			dest_db = @destination_db)
		begin
            RAISERROR (14055, 11, -1)
            RETURN (1)
		end
	end

    /*
    ** If the @publication is 'all', the user wants to cancel all subscriptions
    ** for all publications associated with the specified @subscriber.
    */

    IF LOWER(@publication) = 'all'
        BEGIN
            DECLARE hCdrop_subscription2  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT a.name 
                    FROM syspublications a, sysextendedarticlesview b,  syssubscriptions c 
                    WHERE c.srvid = @srvid
					-- @destination_db will not be expanded before @publication is expanded.
					AND (c.dest_db = @destination_db 
					or @destination_db is null
					or LOWER(@destination_db) = 'all')
                    AND a.pubid = b.pubid 
                    AND b.artid = c.artid 
                    
            OPEN hCdrop_subscription2
            FETCH hCdrop_subscription2 INTO @publication
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription @publication = @publication,
                                                @article     = 'all',
                                                @subscriber  = @subscriber,
                                                @destination_db = @destination_db,
                                                @ignore_distributor = @ignore_distributor,
                                                @reserved = @reserved

                    FETCH hCdrop_subscription2 INTO @publication
                END
            CLOSE hCdrop_subscription2
            DEALLOCATE hCdrop_subscription2
            RETURN (0)
        END

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

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

    EXECUTE @retcode = dbo.sp_validname @publication

    IF @retcode <> 0
    RETURN (1)

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

    /* Get subscription type of the publication */
    SELECT @immediate_sync = immediate_sync, @sync_method = sync_method
        FROM syspublications WHERE name = @publication

    /*
    ** Parameter Check:  @article
    */

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


	/* 
	** If publication is of concurrent sync, then all articles must
	** be unsubscribed to
	*/
	/*IF @sync_method in (@concurrent, @concurrent_char) AND
	   LOWER(@article) != 'all' AND
	   @reserved NOT IN( @expand_article, @internal )
	BEGIN
		RAISERROR( 14102, 16, -1 )
		RETURN (1)
	END*/

    /** For immediate_sync publication, @article has to be 'all'     */
    -- Relax this constraint since users will need to do this before dropping
    -- an article
    /*
    IF @reserved <> @internal AND @reserved <> @expand_article
        AND @immediate_sync = 1
        AND NOT LOWER(@article) = 'all'
        BEGIN
            RAISERROR (14122, 16, -1)
            RETURN (1)
        END
    */

    /*
    ** If the @article is 'all', the user wants to cancel all
    ** subscriptions on this publisher associated with the given @subscriber
    ** and @publication.
    */

    IF LOWER(@article) = 'all'
        BEGIN

            /* Make the operation automic for immediate_sync publications */
            BEGIN TRAN

            IF @reserved IS NULL
                SELECT @reserved = @expand_article

            DECLARE hCdrop_subscription3  CURSOR LOCAL FAST_FORWARD FOR
                SELECT DISTINCT art.name 
                    FROM sysextendedarticlesview art, syssubscriptions sub, syspublications pub 
                    WHERE sub.srvid = @srvid
					-- @destination_db will not be expanded before @article is expanded.
					AND (sub.dest_db = @destination_db 
					or @destination_db is null
					or LOWER(@destination_db) = 'all')
                    AND sub.artid = art.artid
                    AND art.pubid = pub.pubid
                    AND pub.name = @publication 
                    
            OPEN hCdrop_subscription3
            FETCH hCdrop_subscription3 INTO @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE @retcode = dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber = @subscriber,
                        @destination_db = @destination_db,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved
                    IF @@error<>0 OR @retcode <> 0
                    BEGIN
                        CLOSE hCdrop_subscription3
                        DEALLOCATE hCdrop_subscription3
                        GOTO UNDO                        
                    END
                    FETCH hCdrop_subscription3 INTO @article
                END
            CLOSE hCdrop_subscription3
            DEALLOCATE hCdrop_subscription3

            COMMIT TRAN
            RETURN (0)
        END

    /*
    ** Parameter Check: @article
    ** Check if the article exists.
    */

    /*
    EXECUTE @retcode = dbo.sp_validname @article

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

    SELECT @artid = artid
      FROM sysextendedarticlesview art, syspublications pub
     WHERE pub.name = @publication
       AND art.name = @article
       AND art.pubid = pub.pubid

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


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

    IF @destination_db IS NULL
    BEGIN
        /*
        ** Check if the subscription exists.
        */

        IF NOT EXISTS (SELECT *
                         FROM syssubscriptions
                        WHERE srvid = @srvid
                          AND artid = @artid)
        BEGIN    
                RAISERROR (14055, 11, -1)
                RETURN (1)
        END
        ELSE

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

    IF LOWER(@destination_db) = 'all' 
        BEGIN
            DECLARE hCdropsub4  CURSOR LOCAL FAST_FORWARD FOR 
                SELECT DISTINCT dest_db
                    FROM syssubscriptions 
                    WHERE srvid = @srvid
                    AND artid = @artid
            OPEN hCdropsub4
            FETCH hCdropsub4 INTO @destination_db
            WHILE (@@fetch_status <> -1)
                BEGIN
                    EXECUTE dbo.sp_dropsubscription 
                        @publication = @publication,
                        @article = @article,
                        @subscriber = @subscriber,
                        @destination_db = @destination_db,
                        @ignore_distributor = @ignore_distributor,
                        @reserved = @reserved
                    FETCH hCdropsub4 INTO @destination_db
                END
            CLOSE hCdropsub4
            DEALLOCATE hCdropsub4
            RETURN (0)
        END

    /*
    ** Dropping virtual subscriptions is not allowed
    ** in following case:
    ** 1. non sa or dbo user
    ** 2. the stored procedure is not in internal usage mode 
    **        (called by system stored procedures)
    **
    ** Note: Only immediate_sync publications have virtual subscriptions
    ** 
    */

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

    /*
    ** Check if the subscription exists.
    */

    IF NOT EXISTS (SELECT *
                     FROM syssubscriptions
                    WHERE srvid = @srvid
                      AND artid = @artid
                      AND dest_db = @destination_db)
    BEGIN
            RAISERROR (14055, 11, -1)
            RETURN (1)
    END


    /* Check the current login id. It is valid only when
    ** 1. sa or dbo
    ** 2. same as the one who add the subscription.
    */
    SELECT @login_name = login_name 
         FROM syssubscriptions
        WHERE srvid = @srvid
          AND artid = @artid
          AND dest_db = @destination_db

    IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
        AND is_member ('db_owner') <> 1
    BEGIN
            SELECT @qualified_subscription_name = @subscriber + N':' + @destination_db
            RAISERROR(21120, 11, -1, @qualified_subscription_name, @publication)
            RETURN (1)
    END


    begin tran
    save TRANSACTION dropsubscription

        /* If dropping virtual subscriptions, reset immediate_sync_ready bit */
        IF @srvid = @virtual_id
        BEGIN
            UPDATE syspublications SET immediate_sync_ready = 0
                WHERE
                    name = @publication and
                    immediate_sync = 1 and
                    immediate_sync_ready = 1
            IF @@ERROR <> 0
                goto UNDO
        END

        /*
        ** Change the status of the subscription to 'inactive'.
        */

        EXECUTE @retcode = dbo.sp_changesubstatus @publication = @publication,
                                              @article = @article,
                                              @subscriber = @subscriber,
                                              @status = 'inactive',
                                              @destination_db = @destination_db,
                                              @ignore_distributor = @ignore_distributor
        IF @@ERROR <> 0 OR @retcode <> 0
        BEGIN
            if @@trancount > 0
            begin
                ROLLBACK TRANSACTION dropsubscription
                commit tran
            end
            RETURN (1)
        END

    /* Read the subscription_type befor removing the syssubscriptions row */
    select @subscription_type = subscription_type from syssubscriptions
        WHERE artid = @artid
        AND srvid = @srvid
        AND dest_db = @destination_db
    /*
    ** Remove subscription from syssubscriptions.
    */
    DELETE syssubscriptions
     WHERE artid = @artid
       AND srvid = @srvid
       AND dest_db = @destination_db

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

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

            IF @retcode<>0 or @@ERROR<>0
                GOTO UNDO
        end             
  
    COMMIT TRANSACTION
    RETURN (0)

UNDO:
    IF @@TRANCOUNT = 1
        ROLLBACK TRAN
    ELSE
        COMMIT TRAN
    RETURN(1)
go
 
EXEC dbo.sp_MS_marksystemobject sp_dropsubscription
GO

print ''
print 'Creating procedure sp_subscribe'
go
CREATE PROCEDURE sp_subscribe (
    @publication sysname,          /* publication name */
    @article sysname = 'all',          /* article name */
    @destination_db sysname = NULL,  /* subscriber database */
    @sync_type nvarchar (15) = 'automatic' /* subscription sync type */
    ) AS

    -- New 7.0 sp_addsubscription parameters
    DECLARE @subscriber                  sysname
    DECLARE @status                      sysname
    DECLARE @subscription_type           nvarchar(4)
    DECLARE @update_mode                 nvarchar(15)
    DECLARE @loopback_detection          nvarchar(5)
    DECLARE @enabled_for_syncmgr         nvarchar(5)
    DECLARE @retcode                     int

    SET NOCOUNT ON

    -- sp_subscribe has to be called from a remote subscriber 
    -- If not, we state that it is unsupported
    SELECT @subscriber = @@REMSERVER
    IF @subscriber IS NULL
    BEGIN
      RAISERROR (21023, 16, -1,'sp_subscribe')
      RETURN(1)
    END
    
    SELECT @status = NULL
    SELECT @subscription_type = 'push'
    SELECT @update_mode = 'read only'
    SELECT @loopback_detection = 'false'
    SELECT @enabled_for_syncmgr = 'false'

    -- Call sp_addsubscription to do the actual work
    EXEC @retcode = dbo.sp_addsubscription @publication = @publication,
                                           @article = @article,
                                           @destination_db = @destination_db,
                                           @sync_type = @sync_type,
                                           @subscriber = @subscriber,
                                           @status = @status,
                                           @subscription_type = @subscription_type,
                                           @update_mode = @update_mode,
                                           @loopback_detection = @loopback_detection,
                                           @enabled_for_syncmgr = @enabled_for_syncmgr
                                        
    RETURN @retcode   
go
 
EXEC dbo.sp_MS_marksystemobject sp_subscribe
GO

print ''
print 'Creating procedure sp_unsubscribe'
go
CREATE PROCEDURE sp_unsubscribe (
    @publication sysname = NULL,       /* publication name */
    @article sysname = NULL            /* article name */
    ) AS

    -- New 7.0 sp_dropsubscription parameters
    DECLARE @subscriber     sysname
    DECLARE @destination_db sysname    
    DECLARE @retcode        int 

    SET NOCOUNT ON
    
    -- sp_unsubscribe has to be callled from a remote subscriber
    -- If not, we state that it is unsupported
    SELECT @subscriber = @@REMSERVER
    IF @subscriber IS NULL
    BEGIN
        RAISERROR (21023, 16, -1,'sp_unsubscribe')
        RETURN(1)
    END

    -- 6.5 didn't support having multiple databases on the same subscriber
    -- subscribing to the same publication so here, all subscriptions to the
    -- same publication will be dropped 
    SELECT @destination_db = NULL
    
    -- Call sp_dropsubscription to do the real work
    EXEC @retcode = sp_dropsubscription @publication = @publication,
                                        @article = @article,
                                        @subscriber = @subscriber,
                                        @destination_db = @destination_db
    RETURN @retcode
    
go
 
EXEC dbo.sp_MS_marksystemobject sp_unsubscribe
GO

print ''
print 'Creating procedure sp_refreshsubscriptions'
go

CREATE PROCEDURE sp_refreshsubscriptions (
    @publication sysname       /* Publication name */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @article  sysname 
    DECLARE @subscriber sysname
    DECLARE @dest_db sysname
    DECLARE @retcode int
    DECLARE @pubid int
    DECLARE @immediate_sync bit 
    DECLARE @no_sync tinyint
    DECLARE @subscription_type_id int
    DECLARE @subscription_type nvarchar(4)
    DECLARE @virtual smallint
    DECLARE @srvid smallint
    DECLARE @sync_typeid int
    DECLARE @automatic tinyint
    DECLARE @sync_type nvarchar(9)

    SELECT @no_sync = 2
    SELECT @virtual = -1
    SELECT @automatic = 1
    /*
    ** Security Check
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

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

    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = DB_NAME() 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
        FROM syspublications WHERE name = @publication

    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END
    
    
    /* Add real subscription to the new articles  */
    /* Open a cursor on all the pending subscriptions, that is */
    /* All the subscriptions on the publication that */
    /* are not on an article in the publication. */
    /* not including virtual subscriptions */

    DECLARE hCrefreshsubscriptions CURSOR LOCAL FAST_FORWARD FOR
        SELECT DISTINCT art1.name, subs1.dest_db, subs1.srvid
            FROM syssubscriptions subs1, sysextendedarticlesview art1
            WHERE art1.pubid = @pubid AND
                  subs1.srvid <> @virtual AND
                  EXISTS (SELECT * FROM syssubscriptions subs2, sysextendedarticlesview art2
                    WHERE subs2.srvid = subs1.srvid AND
                          subs2.dest_db = subs1.dest_db AND
                          subs2.artid = art2.artid AND
                          art2.pubid = @pubid) AND
                  NOT EXISTS ( SELECT * FROM syssubscriptions subs3 
                    WHERE  subs3.artid = art1.artid AND
                           subs3.srvid = subs1.srvid AND
                           subs3.dest_db = subs1.dest_db)
    FOR READ ONLY
    OPEN hCrefreshsubscriptions
    FETCH hCrefreshsubscriptions INTO @article,  @dest_db, @srvid
            
    
    WHILE (@@fetch_status <> -1)
    BEGIN

        /* 
        ** Get subscription type on the publication
        */ 
        SELECT @subscription_type_id = subs.subscription_type,
            @sync_typeid = subs.sync_type
         from 
            sysextendedarticlesview art, syssubscriptions subs where 
            art.pubid = @pubid AND
            subs.srvid = @srvid AND
            subs.dest_db = @dest_db AND
            subs.artid = art.artid

        /* 
        ** only do it if the subscription all have the same subscription type
        ** and sync_type
        */
        IF NOT EXISTS (SELECT * from 
            sysextendedarticlesview art, syssubscriptions subs where 
            art.pubid = @pubid AND
            subs.srvid = @srvid AND
            subs.dest_db = @dest_db AND
            subs.artid = art.artid AND
            (subscription_type <> @subscription_type_id OR
            sync_type <> @sync_typeid))
        BEGIN
            IF @subscription_type_id = 0
                SELECT @subscription_type = 'push'
            ELSE
                SELECT @subscription_type = 'pull'

            if @sync_typeid = @automatic
                SELECT @sync_type = 'automatic'
            else
                SELECT @sync_type = 'none'

            /* 
            ** Get the server name
            */
            SELECT @subscriber = srvname FROM master.dbo.sysservers 
                WHERE srvid = @srvid

            EXECUTE @retcode  = dbo.sp_addsubscription 
                        @publication = @publication, 
                        @article = @article, 
                        @subscriber = @subscriber, 
                        @destination_db = @dest_db, 
                        @sync_type = @sync_type, 
                        @status = NULL, 
                        @subscription_type = @subscription_type,
                        @reserved = 'internal'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCrefreshsubscriptions
                DEALLOCATE hCrefreshsubscriptions
                RETURN (1)
            END
        END
        FETCH hCrefreshsubscriptions INTO @article, @dest_db, @srvid
    END
    
    CLOSE hCrefreshsubscriptions
    DEALLOCATE hCrefreshsubscriptions

GO
 
EXEC dbo.sp_MS_marksystemobject sp_refreshsubscriptions
GO

print ''
print 'Creating procedure sp_MSpublishdb'
go

CREATE PROCEDURE sp_MSpublishdb(
      @value     sysname,
      @ignore_distributor bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @quoted_db      sysname
    declare @db_name        sysname
    declare @command        nvarchar(255)
    declare @description    nvarchar(500)
    declare @category_name  nvarchar(100)
    DECLARE @agentname      nvarchar(300)
    DECLARE @dbname         sysname 
    DECLARE @retcode        int
    DECLARE @distributor    sysname
    DECLARE @distribdb      sysname
    DECLARE @distproc       nvarchar (255)
    /*
    ** 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

print ''
print 'Creating procedure 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

raiserror('Creating procedure sp_MSget_synctran_commands', 0,1)
GO
CREATE PROCEDURE sp_MSget_synctran_commands(
    @publication sysname    /* publication name */,
    @article sysname = 'all',
    @command_only bit = 0   /* 0 if called by snapshot agent, 1 if called by sp_script_..., */
) AS
BEGIN
    SET NOCOUNT ON
    DECLARE @artid int
			,@tabid int
			,@retcode int
			,@art_type tinyint        
			,@filter_id int
			,@filter_clause nvarchar(4000)
			,@columns binary(32)
			,@distributor sysname
			,@pubid int
			,@art_name sysname 
			,@posted_synctran_artid int
			,@dest_table sysname 
			,@dest_owner sysname
			,@proc_owner sysname

			,@ts_col sysname
			,@replcmd nvarchar(4000)
			,@insproc sysname
			,@updproc sysname
			,@delproc sysname
			,@cftproc sysname
			,@cft_table sysname
			,@is_synctran bit
			,@is_queued bit
			,@identity_col sysname
			,@identity_prop tinyint
			,@identity_support bit


    /*
    ** Initializations.
    */
    select @posted_synctran_artid = 0 
	select @identity_support = 0

    /* 
    ** Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    ** Do a relaxed security check here.
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

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

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

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

	declare @independent_agent bit
	SELECT @pubid = pubid,
			@independent_agent = independent_agent,
			@is_synctran = allow_sync_tran,
			@is_queued = allow_queued_tran
	FROM syspublications 
	WHERE name = @publication

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

    -- If the publication does not allow sync tran or queued tran return nothing
    IF (@is_synctran = 0 AND @is_queued = 0)
        RETURN(0)

	--
	-- get the distributor details for this publisher
	--
	exec @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT
	if (@@ERROR != 0 OR @retcode != 0 or @distributor IS NULL)
	begin
		raiserror('sp_MSget_synctran_commands(debug): could not get distributor info', 16, 1)
		RETURN (1)
	end

    CREATE TABLE #art_commands (artid int NOT NULL, commands nvarchar(4000) collate database_default null, id int identity NOT NULL)
    
    declare @all_article bit 

    if lower(@article) = 'all'
        select @all_article = 1
    else
        select @all_article = 0

	-- Construct ver check cmd
	declare @ver_check_cmd nvarchar(4000)
	-- Construct message.
	select @ver_check_cmd = formatmessage(21273)
	select @ver_check_cmd = '''' + replace(@ver_check_cmd, '''', '''''') + ''''
	select @ver_check_cmd = 'if @@microsoftversion<0x07320000 raiserror(' + 
		@ver_check_cmd + ',16, -1)'

    DECLARE hCsynctran_arts CURSOR LOCAL FAST_FORWARD FOR
        SELECT art.artid,
               art.objid,
               
               art.dest_table,
			   art.dest_owner,
			   art.name,
			   art.type,
			   art.filter,
			   art.columns
          FROM sysarticles art,
               syspublications pub
         WHERE pub.pubid = @pubid and
               pub.pubid = art.pubid and
               (art.type & 0x1) = 1 and
               (art.name = @article or
               @all_article = 1)
    FOR READ ONLY

    OPEN hCsynctran_arts

	FETCH hCsynctran_arts INTO @artid, @tabid, @dest_table, @dest_owner, @art_name, 
		@art_type, @filter_id, @columns
	
    WHILE (@@fetch_status <> -1)
    BEGIN

    /*
    ** Determine conflict detection method 
    */
        -- Determine if table has timestamp property
        select @ts_col = NULL
        if ObjectProperty(@tabid, 'TableHasTimestamp') = 1 
        begin
            exec dbo.sp_MSis_col_replicated @publication, @art_name, 
                'timestamp', @ts_col OUTPUT
        end

        select @posted_synctran_artid = @artid

        select @insproc = null, @updproc = null, @delproc = null

        -- Get sproc names and owner name of the sprocs
        -- Note artid is unique
        select @insproc = o.name, @proc_owner = u.name from sysobjects o, sysarticleupdates a, sysusers u
        where a.artid = @artid and a.sync_ins_proc = o.id and
            u.uid = o.uid

        select @updproc = o.name from sysobjects o, sysarticleupdates a
        where a.artid = @artid and a.sync_upd_proc = o.id
    
        select @delproc = o.name from sysobjects o, sysarticleupdates a
        where a.artid = @artid and a.sync_del_proc = o.id 

        select @cftproc = o.name from sysobjects o, sysarticleupdates a
        where a.artid = @artid and a.ins_conflict_proc = o.id 
        
        if @insproc IS NULL
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@insproc')
            RETURN (1)
        end

        if @updproc IS NULL 
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@updproc')
            RETURN (1)
        end

        if @delproc IS NULL
        begin
            CLOSE hCsynctran_arts
            DEALLOCATE hCsynctran_arts
            RAISERROR (14043, 11, -1, '@delproc')
            RETURN (1)
        end

        if (@cftproc IS NULL)
        begin
            if (@is_queued = 1)
            begin
                CLOSE hCsynctran_arts
                DEALLOCATE hCsynctran_arts
                RAISERROR (14043, 11, -1, '@cftproc')
                RETURN (1)
            end        	
        end

        -- Determine if published table has identity  col
        select @identity_col = NULL
        select @identity_support = 0
        if ObjectProperty(@tabid, 'TableHasIdentity') = 1 
            exec @retcode = dbo.sp_MSis_col_replicated @publication, @art_name, 'identity', @identity_col OUTPUT
		if @identity_col is not null
			select @identity_support = identity_support from sysarticleupdates where artid = @artid
                
        -- Horizontal partition
        select @filter_clause = 'null'
        if @filter_id <> 0
        begin
            -- We don't handle manual filters;  allow all updates
            if ((@art_type & 0x3) <> 0x3) 
                select @filter_clause = RTRIM(LTRIM(CONVERT(nvarchar(4000), filter_clause)))
                     from sysarticles where artid = @artid
        end
	
        declare @fullname nvarchar(512)
        declare @indkey       int
        declare @indid        int
        declare @key          sysname
        declare @col          sysname
        declare @this_col	  int
        declare @src_cols	  int
        declare @primary_key_bitmap varbinary(4000)
        declare @byte varbinary(1)
        declare @i_byte			int
        declare @num_bytes		int
        declare @i_bit			tinyint	
        declare @bitmap_str	varchar(8000)
        declare @bitmap			varbinary(4000)


        -- Get qualified name
        exec dbo.sp_MSget_qualified_name @tabid, @fullname output

        -- Get number of columns in the partition.
        exec dbo.sp_MSget_col_position @tabid, @columns, @key, @col output, 
        	@this_col output, 
        	1, -- Get num of columns in the partition.
        	@src_cols output
        select @num_bytes = @src_cols / 8 + 1
	
        -- Set varbinary length
        set @byte = 0
        set @primary_key_bitmap = @byte
        set @i_byte = 1
        while @i_byte < @num_bytes
        begin
        	set @primary_key_bitmap = @primary_key_bitmap + @byte
        	set @i_byte = @i_byte + 1
        end
	
        -- get index id
        exec @indid = dbo.sp_MStable_has_unique_index @tabid
        set @indkey = 1
        while @indkey < 16 and index_col(@fullname, @indid, @indkey) is not null
        begin
            set @key = index_col(@fullname, @indid, @indkey)
            exec dbo.sp_MSget_col_position @tabid, @columns, @key, @col output, @this_col output
			set @i_byte = 1 + (@this_col-1) / 8
			set @i_bit  = power(2, (@this_col-1) % 8 )
		    set @primary_key_bitmap 
                = substring(@primary_key_bitmap, 1, @i_byte - 1)
                + convert(binary(1), substring(@primary_key_bitmap, @i_byte, 1) | @i_bit)
                + substring(@primary_key_bitmap, @i_byte + 1, @num_bytes - @i_byte)
			select @indkey = @indkey + 1
        end
        exec @retcode = master..xp_varbintohexstr @primary_key_bitmap, @bitmap_str output
        if @retcode <> 0 or @@error <> 0
        	return 1
        if @dest_owner is null 
        begin
        	select @dest_owner = N'null'
        end
        --
        -- If we are processing queued publications, insert a command
        -- to populate MSsubsciption_articles for this article
        --
        if (@is_queued = 1)
        begin
        	select @cft_table = OBJECT_NAME(conflict_tableid) 
        	from sysarticleupdates
        	where artid = @artid and pubid = @pubid

        	if (@cft_table IS NULL)
        	begin
        		CLOSE hCsynctran_arts
        		DEALLOCATE hCsynctran_arts
        		raiserror('Debug: article %s in publication % should have valid conflict table', 
        			16, 1, @art_name, @publication)
        		return 1				
        	end

        	--
        	-- add another command
        	--
        	select @replcmd = '{call sp_addqueued_artinfo (' + 
        		cast(@artid as nvarchar(10)) collate database_default + ', N' +
        		quotename(@art_name,'''') collate database_default + ', N' + 				
        		quotename(@@SERVERNAME,'''') collate database_default + ', N' +   
        		quotename(db_name(),'''') collate database_default + ', N' + 
        		quotename(@publication,'''') collate database_default + ', N' +  
        		quotename(@dest_table,'''') collate database_default + ', N' + 
        		quotename(@dest_owner,'''') collate database_default + ', N' +   
        		quotename(@cft_table,'''') collate database_default + ', ' +
        		master.dbo.fn_varbintohexstr(@columns) collate database_default + ' )}'
        	
        	-- Must add ver check cmd for each article since user can subscribe
        	-- to just one article.	
        	insert into #art_commands values (@artid, @ver_check_cmd)						
        	insert into #art_commands values (@artid, @replcmd)						
        end
        --
        -- insert the command to generate the triggers
        -- for Sp3 or later subscribers
        --
        select @replcmd = 'if (@@microsoftversion >= 0x080002C0) begin ' + 
              'exec sp_addsynctriggers N' + 
        	quotename(@dest_table,'''') + ', N' + 
        	quotename(@dest_owner,'''') + ', N' +  
        	quotename(@@SERVERNAME,'''') + ', N' +   
        	quotename(db_name(),'''') + ', N' + 
        	quotename(@publication,'''') + ', N' +  
        	quotename(@insproc,'''') + ', N' +   
        	quotename(@updproc,'''') + ', N' +   
        	quotename(@delproc,'''') + ', N' + 
        	ISNULL(quotename(@cftproc,''''), '''null''')  + ', N' + 
        	quotename(@proc_owner,'''') + ', N' + 
        	ISNULL(quotename(@identity_col,''''),'''null''') + ', N' + 
        	ISNULL(quotename(@ts_col,''''), '''null''') + ', N''' + 
        	replace(@filter_clause,'''', '''''')  + ''', ' + 
        	@bitmap_str   + ', ' + 
        	convert(nvarchar(2), @identity_support)  + ',' +
        	convert(nvarchar(2), @independent_agent) + ',N' +
        	quotename(@distributor,'''') +  ', ' +
        	'2 ' + 
        	'end '
        -- Must add ver check cmd for each article since user can subscribe
        -- to just one article.	
        insert into #art_commands values (@artid, @ver_check_cmd) 
        insert into #art_commands values (@artid, @replcmd)
        --
        -- insert the command to generate the triggers
        -- for pre Sp3 subscribers
        --
        select @replcmd = 'if (@@microsoftversion < 0x080002C0) begin ' + 
              'exec sp_addsynctriggers N' + 
        	quotename(@dest_table,'''') + ', N' + 
        	quotename(@dest_owner,'''') + ', N' +  
        	quotename(@@SERVERNAME,'''') + ', N' +   
        	quotename(db_name(),'''') + ', N' + 
        	quotename(@publication,'''') + ', N' +  
        	quotename(@insproc,'''') + ', N' +   
        	quotename(@updproc,'''') + ', N' +   
        	quotename(@delproc,'''') + ', N' + 
        	ISNULL(quotename(@cftproc,''''), '''null''')  + ', N' + 
        	quotename(@proc_owner,'''') + ', N' + 
        	ISNULL(quotename(@identity_col,''''),'''null''') + ', N' + 
        	ISNULL(quotename(@ts_col,''''), '''null''') + ', N''' + 
        	replace(@filter_clause,'''', '''''')  + ''', ' + 
        	@bitmap_str   + ', ' + 
        	convert(nvarchar(2), @identity_support)  + ',' +
        	convert(nvarchar(2), @independent_agent) + ',N' +
        	quotename(@distributor,'''')  +
        	' end '
        -- Must add ver check cmd for each article since user can subscribe
        -- to just one article.	
        insert into #art_commands values (@artid, @ver_check_cmd) 
        insert into #art_commands values (@artid, @replcmd)

        FETCH hCsynctran_arts INTO @artid, @tabid, @dest_table, @dest_owner, @art_name, 
        	@art_type, @filter_id, @columns
    end

    -- end SyncTran
    if @command_only = 0 
        select * from #art_commands order by id
    else
        select commands from #art_commands order by id

    CLOSE hCsynctran_arts
    DEALLOCATE hCsynctran_arts

    return 0
END
go
 
EXEC dbo.sp_MS_marksystemobject sp_MSget_synctran_commands
GO

--
-- Name: sp_script_synctran_commands
--
-- Description: This SP is used by customers to generate the synctran commands 
-- to be executed on subscriber for manual initialization updating subscriptions. 
-- This is needed for the case when the subscription synchronization is not automatic.
-- Invoked on the publisher
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does publisher security check. 
--
raiserror('Creating procedure sp_script_synctran_commands', 0,1)
GO
CREATE PROCEDURE sp_script_synctran_commands(
    @publication sysname,    /* publication name */
    @article sysname = 'all'    /* article name, all means all article */
) 
AS
begin
    declare @retcode int

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    --
    -- Generate the scripts by calling internal SP
    --
    exec @retcode = dbo.sp_MSget_synctran_commands 
        @publication = @publication,
        @article = @article,
        @command_only = 1
    if @retcode <> 0 or @@error <> 0
        return (1)
end
go
EXEC dbo.sp_MS_marksystemobject sp_script_synctran_commands
GO

print ''
print 'Creating procedure sp_MSaddpub_snapshot'
go
CREATE PROCEDURE sp_MSaddpub_snapshot (
    @publication sysname,    
    @freqtype  int = 4 ,                  /* 4== Daily */
    @freqinterval int  = 1,             /* Every day */
    @freqsubtype int =  4,                 /* Sub interval = Minute */
    @freqsubinterval int = 5,              /* Every five minutes */
    @freqrelativeinterval int = 1, 
    @freqrecurrencefactor int = 0, 
    @activestartdate int = 0,             /* 12:00 am - 11:59 pm */
    @activeenddate int =99991231 ,         /* No start date */    
    @activestarttimeofday int = 0,         
    @activeendtimeofday int = 235959,     /* No end time */       
    @newagentid int = 0 OUTPUT,
    @snapshot_job_name nvarchar(100) = null
) AS


    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @retcode            int
    DECLARE @distributor        sysname
    DECLARE @distribdb          sysname
    DECLARE @distproc           nvarchar (255)
    DECLARE @agentname          nvarchar(100)
    DECLARE @database           sysname
    DECLARE @newid              int
    DECLARE @mergepublish_bit   smallint
    DECLARE @centralpublish_bit int
    DECLARE @fFoundPublication  int
    DECLARE @agent_args         nvarchar(4000)
    DECLARE @snapshot_jobid     binary(16)
    DECLARE @dist_rpcname       sysname
    DECLARE @publication_type   int
    DECLARE @job_existing       bit

    /*
    ** Initializations
    */
    select @mergepublish_bit    = 4
    select @centralpublish_bit  = 1
    select @fFoundPublication   = 0
    if (@snapshot_job_name is null) or (@snapshot_job_name = N'')
    begin
        select @job_existing = 0
    end 
    else
    begin
        select @job_existing = 1
    end

    EXEC @retcode = dbo.sp_helppublication @publication, @fFoundPublication output

    IF @@ERROR <> 0 OR @retcode <> 0
    BEGIN
        RETURN (1)
    END
        
    IF @fFoundPublication = 0 
    BEGIN
        SELECT @newagentid = 0
        RETURN (0)
    END

        
    /* 
    ** Make sure the publication does not already have a agent.
    */
    IF EXISTS (SELECT * FROM syspublications WHERE name = @publication and snapshot_jobid <> NULL)
    BEGIN
        RAISERROR (14101, 11, -1, @publication)
        RETURN(1)
    END

    /* Get publication_type */
    SELECT @publication_type = repl_freq from syspublications WHERe name = @publication
    
    /*
    ** Get distributor information
    */
    EXEC @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT, 
        @distribdb = @distribdb OUTPUT,
        @rpcsrvname = @dist_rpcname OUTPUT
    IF @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL
    BEGIN
        RAISERROR (14071, 16, -1)
        RETURN (1)
    END

    SELECT @database = DB_NAME()

    SELECT @distproc = RTRIM(@dist_rpcname) + '.' + @distribdb + '.dbo.sp_MSadd_snapshot_agent'
    
    SELECT @agent_args = '-Publisher ' + QUOTENAME(@@SERVERNAME)
    SELECT @agent_args = @agent_args + ' -PublisherDB ' + QUOTENAME(@database)
    SELECT @agent_args = @agent_args + ' -Distributor ' + QUOTENAME(@distributor)
    SELECT @agent_args = @agent_args + ' -Publication ' + QUOTENAME(@publication)

    BEGIN TRAN

    EXECUTE @retcode = @distproc 
        @name = @snapshot_job_name,
        @publisher = @@SERVERNAME,
        @publisher_db = @database,
        @publication = @publication,  
        @publication_type = @publication_type,
        @local_job = 1,  

        @freqtype = @freqtype, 
        @freqinterval = @freqinterval, 
        @freqsubtype = @freqsubtype, 
        @freqsubinterval = @freqsubinterval, 
        @freqrelativeinterval = @freqrelativeinterval, 
        @freqrecurrencefactor = @freqrecurrencefactor, 
        @activestartdate = @activestartdate, 
        @activeenddate = @activeenddate, 
        @activestarttimeofday = @activestarttimeofday, 
        @activeendtimeofday =  @activeendtimeofday,
        @command = @agent_args,
        @snapshot_jobid = @snapshot_jobid OUTPUT,
        @job_existing = @job_existing
  
   IF @@ERROR <> 0 or @retcode <> 0
        GOTO UNDO

    -- Legacy, use non zero taskid to indicate agent already created at the distributor.
    UPDATE syspublications set snapshot_jobid =  @snapshot_jobid
        WHERE name =  @publication 

    IF @@ERROR <> 0 
        GOTO UNDO

    -- This is the output parameter to indicate agent created.
    SELECT  @newagentid = 1
 
    COMMIT TRAN

    return (0)  
    
UNDO:
    if @@TRANCOUNT = 1
        ROLLBACK TRAN
    else
        COMMIT TRAN
    return(1)
GO
 
EXEC dbo.sp_MS_marksystemobject sp_MSaddpub_snapshot
GO

dump tran master with no_log
GO

/*
** SyncTran support procs
*/

print ''
print 'Creating procedure sp_MSis_pk_col'
go
create proc sp_MSis_pk_col @source_table sysname, @colname sysname, @indid int
as
begin

    declare @indkey int
    select @indkey = 1

    while @indkey < 16 and index_col(@source_table, @indid, @indkey) is not null
    begin
        if index_col(@source_table, @indid, @indkey) = @colname
            return (1)

        select @indkey = @indkey + 1
    end

    return (0)
end
GO
EXEC dbo.sp_MS_marksystemobject sp_MSis_pk_col
GO

print ''
print 'Creating procedure sp_MSmark_proc_norepl'
go

create procedure sp_MSmark_proc_norepl
    @procname nvarchar(517)
as
    set nocount on

    -- CHECK PERMISSIONS (MUST BE DBO) --
    if not (is_member('db_owner')=1 or is_srvrolemember('sysadmin') = 1) 
    begin
        raiserror(20521,0,1)
        return 1
    end

    -- CHECK THE OBJECT NAME --
    if object_id(@procname, 'local') is null
    begin
        raiserror(20522,0,1,@procname)
        return 1
    end

    -- DO THE UPDATE --
    begin tran
    exec dbo.sp_replupdateschema @procname
    update sysobjects set replinfo = replinfo | 0x40
                        where id = object_id(@procname, 'local')
    exec dbo.sp_replupdateschema @procname
    commit tran
    return @@error 
go

EXEC dbo.sp_MS_marksystemobject sp_MSmark_proc_norepl
GO

create procedure sp_MSdrop_expired_subscription
AS
/*
** This stored procedure is to periodically check the status of all the subscriptions 
** of every merge publication. If any of them is out-of-date, i.e., has lost contact
** with publisher for a certain length of time, we can declare the death of that replica
** and cleanup their traces at the publisher side
*/
declare @independent_agent  bit
declare @article            sysname
declare @publication        sysname
declare @pubid              int
declare @artid              int
declare @publisher          sysname
declare @subscriber         sysname
declare @subscriber_id      smallint
declare @subscriber_db      sysname
declare @publisher_db       sysname
declare @out_of_date        int
declare @distributor        sysname
declare @distribdb          sysname
declare @retention          int  -- in days         
declare @retcode            smallint
declare @distproc           nvarchar(255)
declare @localproc          nvarchar(255)
declare @msg                nvarchar(255)
declare @open_cursor        nvarchar(400)

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

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

    
SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MShelp_subscription_status '
select @publisher = @@SERVERNAME
select @publisher_db = db_name()

declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT name, pubid, independent_agent, retention from syspublications p
    open PC
    fetch PC into @publication, @pubid, @independent_agent, @retention
    WHILE (@@fetch_status <> -1)
        BEGIN
            -- Don't do anything if the retention is zero, this means
            -- subscriptions to the publication will never expire
            IF @retention = 0
            BEGIN
                GOTO ZERO_RETENTION
            END
            declare SC CURSOR LOCAL FAST_FORWARD for select s.srvid, s.dest_db, a.name from syssubscriptions s, sysextendedarticlesview a 
                where a.pubid= @pubid and s.artid = a.artid and s.srvid<>-1 
                for read only
            open SC
            fetch SC into @subscriber_id, @subscriber_db, @article
            WHILE (@@fetch_status <> -1)
                BEGIN
                    select @subscriber=srvname from master..sysservers where srvid=@subscriber_id
                    exec @retcode = @distproc @publisher = @publisher, 
                                    @publisher_db = @publisher_db, 
                                    @publication = @publication, 
                                    @subscriber = @subscriber, 
                                    @subscriber_db = @subscriber_db,
                                    @retention = @retention,
                                    @out_of_date = @out_of_date OUTPUT,
                                    @independent_agent = @independent_agent
                    if @retcode<>0 or @@ERROR<>0 
                        begin
                            close SC
                            deallocate SC
                            close PC
                            deallocate PC
                            return (1)
                        end
                    IF (@out_of_date = 1)
                        begin
                            exec @retcode = dbo.sp_dropsubscription   -- publisher_db.dbo.sp_dropsubscription
                                @publication = @publication,
                                @article = @article,
                                @subscriber = @subscriber,
                                @destination_db = @subscriber_db,
                                @reserved = 'internal'
                            if @retcode <>0 or @@ERROR<>0
                                begin
                                    close SC
                                    deallocate SC
                                    close PC
                                    deallocate PC
                                    return (1)
                                end
                            raiserror(14157, 10, -1, @subscriber, @publication) 
                        end
                    fetch SC into @subscriber_id, @subscriber_db, @article
                END
            CLOSE SC
            DEALLOCATE SC
    ZERO_RETENTION:
            fetch PC into @publication, @pubid, @independent_agent, @retention
        END
    CLOSE PC
    DEALLOCATE PC

GO
EXEC dbo.sp_MS_marksystemobject sp_MSdrop_expired_subscription
go


-- synctran supporting procs
raiserror('Creating procedure sp_MSscript_validate_subscription', 0,1)
go
create procedure sp_MSscript_validate_subscription (
    @publication sysname,
	@article sysname)
as
BEGIN
    declare @cmd          nvarchar(4000)
	declare @pubid int
	declare @artid int
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid from sysarticles where pubid = @pubid and name = @article

	select @cmd = N'
	' + N'--
	' + N'-- Check for subscription validation
	' + N'--
	exec @retcode = dbo.sp_MSvalidate_subscription @orig_server, @orig_db, '
			+ convert(nvarchar(10), @artid) + N'
	if (@retcode != 0 or @@error != 0)
		return -1'

    insert into #proctext(procedure_text) values(@cmd)
	return 0		
END                    
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_validate_subscription
GO


-- synctran supporting procs
raiserror('Creating procedure sp_MSvalidate_subscription', 0,1)
go
create procedure sp_MSvalidate_subscription
    @subscriber sysname,
	@subscriber_db sysname,
	@artid int
as
 
	declare @srvid smallint
	select @srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
	if not exists (select * from syssubscriptions where artid = @artid and 
		srvid = @srvid and dest_db = @subscriber_db)
	begin
		--  The subscription has been dropped from the publisher. Please run sp_subscription_cleanup to cleanup the triggers.
		exec sp_MSreplraiserror 21161
		return -1
	end                    
go
EXEC dbo.sp_MS_marksystemobject sp_MSvalidate_subscription
GO


raiserror('Creating procedure sp_MSscript_insert_statement', 0,1)
go
create procedure sp_MSscript_insert_statement(
    @objid int,
    @columns binary(32),
	@identity_insert bit = 0,
	@queued_pub bit = 0
	)
as
BEGIN
	declare @cmd          nvarchar(4000)
	declare @qualname     nvarchar(512)
	declare @colname      sysname
	declare @ccoltype     sysname
	declare @this_col     int
	declare @rc           int
	declare @num_col	  int
	declare @column_string nvarchar(4000)
			,@var_string nvarchar(4000)
	
    
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- detection/conflict resolution stage
	' + N'--'
	
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
	if (@execution_mode = @QPubWins)
		save tran cftpass'
	end
	insert into #proctext(procedure_text) values( @cmd) 
    
	--
	-- set indentity_insert on
	--
	if @identity_insert = 1
	begin
		-- Only to call set if identity is not marked for 'not for repl'
		-- This is to avoid security failure of 'SET' for PAL users
		if not exists (select * from syscolumns where id = @objid and
			ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
		begin
			select @cmd = N'
	set identity_insert ' + @qualname + ' on'
			insert into #proctext(procedure_text) values( @cmd )
		end
	end

	--
	-- prepare the insert statement now
	--
	select @cmd = N'
	insert into ' + @qualname + N'( '
	insert into #proctext(procedure_text) values( @cmd )
	-- Generate strings for col names and variables
	select @num_col = 0
	select @cmd = N''

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
            if rtrim(@ccoltype) not like N'timestamp' and 
				not (ColumnProperty(@objid, @colname, 'IsIdentity') = 1 and 
					@identity_insert = 0)
            begin
				select @num_col = @num_col + 1
				if @num_col > 1
					select @cmd = @cmd + N', '
				select @cmd = @cmd + QUOTENAME(@colname)			
				exec dbo.sp_MSflush_command @cmd output, 1
			end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid

	-- Script end of colmn names
	select @cmd = N' )'
	insert into #proctext(procedure_text) values( @cmd )

	
	-- Script column value string
	if @num_col > 0
	begin
		select @cmd = N'
	values ( '
		insert into #proctext(procedure_text) values( @cmd )
		-- Script column value string
		select @num_col = 0
		select @cmd = N''

		OPEN hCColid

		FETCH hCColid INTO @this_col

		WHILE (@@fetch_status != -1)
		begin
			exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
			if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
			begin
				if rtrim(@ccoltype) not like N'timestamp' and 
					not (ColumnProperty(@objid, @colname, 'IsIdentity') = 1 and 
						@identity_insert = 0)
				begin
					select @num_col = @num_col + 1
					if @num_col > 1
						select @cmd = @cmd + N', '
					select @cmd = @cmd + N'@c' + cast(@this_col as nvarchar(4))				
					exec dbo.sp_MSflush_command @cmd output, 1
				end
			end
			FETCH hCColid INTO @this_col
		end
		CLOSE hCColid
		
		-- Script end of column value string
		select @cmd = N' )
	'
		insert into #proctext(procedure_text) values( @cmd )
	end
	else
	begin
		-- This is to set @@rowcount.
		insert into #proctext(procedure_text) values( N' 
	select @retcode = @retcode')
	end
	
	--
	-- set the rowcount and error
	--
	select @cmd = N'
	select @rowcount = @@ROWCOUNT, @error = @@ERROR 
	'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- set indentity_insert off
	--
	if @identity_insert = 1
	begin
		-- Only to call set if identity is not marked for 'not for repl'
		-- This is to avoid security failure of 'SET' for PAL users
		if not exists (select * from syscolumns where id = @objid and
			ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
		begin
			select @cmd = N'
	set identity_insert ' + @qualname + ' off'
			insert into #proctext(procedure_text) values( @cmd )
		end
	end


	if (@queued_pub = 1)
	begin
		select @cmd = N'
	if (@execution_mode = @QPubWins)
		rollback tran cftpass'
		insert into #proctext(procedure_text) values( @cmd )
	end
	
	--
	-- all done 
	-- 
	return 0
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_insert_statement
GO

--
-- sp_script_insertforcftresolution
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the insert command 
-- to resolve conflicts in a subscriber wins resolution. It is used by
-- sp_script_insert_subwins, sp_script_update_subwins
-- Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_script_insertforcftresolution', 0,1)
go
create procedure sp_script_insertforcftresolution 
(
	@objid int				-- object id
	,@columns binary(32)		-- columns replicated
	,@identity_insert bit		-- enable identity insert
	,@prefix nvarchar(10)=N'@c' -- prefix
	,@suffix nvarchar(10)=NULL  -- suffix
)
as
begin
	declare @cmd nvarchar(4000)
			,@qualname nvarchar(512)
			,@column_string nvarchar(4000)
			,@var_string nvarchar(4000)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
	declare @worktab  table( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	declare @worktab2 table( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

	--
	-- initialize
	--
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	-- prepare the assignments and column list for 
	-- insert statement  
	--
	select @num_col = 0
	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col
	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) not like N'timestamp' 
			begin
				select @num_col = @num_col + 1
					,@column_string = quotename(@colname)
					,@var_string = @prefix + cast(@this_col as nvarchar(4))
				if (@suffix is not null)
					select @var_string = @var_string + @suffix
				
				if (@num_col > 1)
				begin
					select @column_string = N', ' + @column_string
						,@var_string = N', ' +@var_string 
				end
				insert into @worktab(procedure_text) values( @column_string )				
				insert into @worktab2(procedure_text) values( @var_string )				
			end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	if (@num_col > 0)
	begin
		if (@identity_insert = 1)
		begin
			-- Only to call set if identity is not marked for 'not for repl'
			-- This is to avoid security failure of 'SET' for PAL users
			if not exists (select * from syscolumns where id = @objid and
				ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
			begin
				select @cmd = N'
			set identity_insert ' + @qualname + N' on '
				insert into #proctext(procedure_text) values( @cmd )
			end
		end

		select @cmd = N'
			insert into ' + @qualname + N'( '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @worktab order by c1 asc
		select @cmd = N' )
			values ( '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @worktab2 order by c1 asc
		select @cmd = N' )'
		insert into #proctext(procedure_text) values( @cmd )

		if (@identity_insert = 1)
		begin
			-- Only to call set if identity is not marked for 'not for repl'
			-- This is to avoid security failure of 'SET' for PAL users
			if not exists (select * from syscolumns where id = @objid and
				ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
			begin
				select @cmd = N'
			set identity_insert ' + @qualname + N' off '
				insert into #proctext(procedure_text) values( @cmd )
			end
		end
	end
	--
	-- all done
	-- 
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_script_insertforcftresolution
go

--
-- sp_MSscript_insert_subwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a subscriber wins resolution 
-- policy for INSERT commands. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_insert_subwins', 0,1)
go
create procedure sp_MSscript_insert_subwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
	,@identity_insert bit		-- enable identity insert
)
as
begin
	declare @cmd nvarchar(4000)
			,@qualname nvarchar(512)
			,@rc           int
			,@fhasnonpkuniquekeys int

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	if (@execution_mode = @QSubWins)
	begin
		'+N'--
		'+N'-- Subscriber wins resolution
		'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script this block if the article has non PK unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
		if (@cftcase = 22)
		begin
			'+N'--
			'+N'-- delete rows with values of non PK keys
			'+N'-- '
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script delete rows with values for non PK keys
		--
		select @cmd = N'
			delete ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 7
		--
		-- continue scripting
		--
		select @cmd = N'
		end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		if (@cftcase = 21)
		begin
			'+N'--
			'+N'-- delete rows with values of all keys
			'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script delete rows with values of all keys 
	--
	select @cmd = N'
			delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = NULL
				,@mode = 6
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		if (@cftcase in (21,22))
		begin
			'+N'--
			'+N'-- insert row
			'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script insert row  
	--
	exec @rc = sp_script_insertforcftresolution 
			@objid = @objid
			,@columns = @columns
			,@identity_insert = @identity_insert
			,@prefix = N'@c'
			,@suffix = NULL
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- all done for conflict resolution for Subscriber Wins policy
		'+N'-- --------------------------------------------------------------------
		'+N'--
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_insert_subwins
go

--
-- proc to test if we need to turn on identity insert
--
raiserror('Creating procedure sp_MSis_identity_insert', 0,1)
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

--
-- proc that scripts the sending of a compensating command
-- used by the compensating code generation SPs
--
raiserror('Creating procedure sp_MSscript_compensating_send', 0,1)
go
create procedure sp_MSscript_compensating_send (
	@pubid int,
	@artid int,
	@cmdstate int = 0,
	@setprefix bit = 1)
AS
BEGIN
	declare @cmd nvarchar(4000)
	
	select @cmd = N'
			' + N'--
			' + N'-- sending of compensating command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			exec @retcode = dbo.sp_MSadd_compensating_cmd
				@orig_srv = @orig_server
				,@orig_db = @orig_db
				,@command = @cmd
				,@article_id = ' + CAST(@artid as nvarchar(4)) + N'
				,@publication_id = ' + CAST(@pubid as nvarchar(4)) + N'
				,@cmdstate = ' + CAST(@cmdstate as nvarchar(4)) + N'
				,@mode = 0
				,@setprefix = ' + CAST(@setprefix as nvarchar(4))
	insert into #proctext(procedure_text) values( @cmd )

	select @cmd = N'
			if (@@error != 0 or @retcode != 0)
				return -1'
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	return 0	
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_compensating_send
GO

--
-- sp_MSscriptinsertconflictfinder
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran procedures
-- and scripts the code that is a state machine and finds the exact nature of conflict
-- for INSERT operations and then assigns it a unique conflict identity.  
-- Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscriptinsertconflictfinder', 0,1)
go
create procedure sp_MSscriptinsertconflictfinder 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare 
			@rc int
			,@cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid 
	from syspublications 
	where name = @publication
	select @artid = artid
	from sysarticles 
	where name = @article 
		and pubid = @pubid
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	
	'+N'--
	'+N'-- --------------------------------------------------------------------
	'+N'-- This is the crux of the proc for conflict resolution 
	'+N'-- This code block is essentially a state machine
	'+N'-- where we ascertain the state of resolution
	'+N'-- The actions of this resolution varies for the policy
	'+N'-- The comments for each state outline the policy
	'+N'-- specific actions 
	'+N'-- --------------------------------------------------------------------
	'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin
		'+N'--
		'+N'-- initialize the conflict case
		'+N'--
		select @cftcase = 0

		if (@rowcount = 0)
		begin
			'+N'--
			'+N'-- we had conflict for this command
			'+N'--
			if (@error in (547, 2601, 2627))
			begin'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
				'+N'--
				'+N'-- Conflict due to unique key/constraint
				'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script row check with PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0
	insert into #proctext(procedure_text) values( N' )')
	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					'+N'--
					'+N'-- case 21: A row with same PK already exists
					'+N'-- PubWins -----------------------------------------------------------
					'+N'-- generate delete compensating action for row with PK
					'+N'-- generate delete + insert compensating action with values for all unique keys 
					'+N'-- SubWins -----------------------------------------------------------
					'+N'-- delete rows with values of all keys
					'+N'-- insert row with values
					'+N'--
					select @cftcase = 21 
				end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script this block if the article has non PK unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
				else
				begin
					'+N'--
					'+N'-- case 22: A row with same nonPK key(s) already exists
					'+N'-- PubWins -----------------------------------------------------------
					'+N'-- generate delete compensating action for row with PK
					'+N'-- generate delete + insert compensating action with values for non PK keys 
					'+N'-- SubWins -----------------------------------------------------------
					'+N'-- delete rows with values of non PK keys
					'+N'-- insert row with values
					'+N'--
					select @cftcase = 22 
				end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
			end
		end
		else if (@execution_mode = @QPubWins)
		begin
			'+N'--
			'+N'-- we had no conflict for this command
			'+N'-- We need to process this block only in the Publisher Wins cases
			'+N'--

			'+N'--
			'+N'-- case 23: No conflict
			'+N'-- PubWins -----------------------------------------------------------
			'+N'-- generate delete compensating action with PK
			'+N'-- 
			select @cftcase = 23
		end	
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'

	'+N'--
	'+N'-- --------------------------------------------------------------------
	'+N'-- Now the generation phase
	'+N'-- Use the conflict case value to decide what to do
	'+N'-- --------------------------------------------------------------------
	'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscriptinsertconflictfinder
go

--
-- sp_MSscript_insert_pubwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a publisher wins resolution 
-- policy for INSERT commands. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_insert_pubwins', 0,1)
go
create procedure sp_MSscript_insert_pubwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@rc           int
			,@qualname nvarchar(512)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	if (@execution_mode = @QPubWins)
	begin
		'+N'--
		'+N'-- Publisher wins resolution
		'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- declare fetch variables for cursor
	--
	exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
	--
	-- continue scripting
	--
	select @cmd = N'

		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- Perform single row delete generations first
		'+N'-- --------------------------------------------------------------------
		'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'

		'+N'--
		'+N'-- Generate DELETE for PK
		'+N'--
		if (@cftcase in (21,22,23))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- Generate the delete compensating code
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
	--
	-- generate the send command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- Perform refresh(delete+insert) generations next
		'+N'-- --------------------------------------------------------------------
		'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script this block if the article has non PK unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'

		'+N'--
		'+N'-- Generate delete+insert for values of non PK keys
		'+N'--
		if (@cftcase = 22)
		begin'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- generate delete compensating command for values of non PK unique keys
		--
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
					+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 5
		--
		-- script the sending command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- script the refresh commands for values of non PK unique keys
		--
		exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 3, 0
		if (@rc != 0 or @@error != 0)
			return 1
		--
		-- continue scripting
		--
		select @cmd = N'
		end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		'+N'--
		'+N'-- Generate delete+insert for values of all keys
		'+N'--
		if (@cftcase = 21)
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate delete compensating command for values of all unique keys
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = NULL
				,@mode = 4
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- script the refresh commands for values of all unique keys
	--
	exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 5, 0
	if (@rc != 0 or @@error != 0)
		return 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- all done for conflict resolution for Publisher Wins policy
		'+N'-- --------------------------------------------------------------------
		'+N'--
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_insert_pubwins
go

raiserror('Creating procedure sp_MSscript_update_statement', 0,1)
go
create procedure sp_MSscript_update_statement (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@queued_pub bit = 0
)
as
BEGIN
	declare @cmd			nvarchar(4000)
			,@cmd2			nvarchar(4000)
			,@qualname		nvarchar(512)
			,@colname		sysname
			,@typestring	nvarchar(4000)
			,@spacer		nvarchar(1)
			,@ccoltype		sysname
			,@this_col		int
			,@rc			int
			,@column		nvarchar(4000)
			,@num_col		int
			,@bitstr nvarchar(20)
			,@bytestr nvarchar(20)
			,@art_col		int -- position in the article partition.
			,@isset			int
			,@timestamp_subscribed bit
			,@pubid			int

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

	if exists (select * from sysarticles where pubid = @pubid and
		name = @article and
		status & 32 <> 0)
		select @timestamp_subscribed = 1
	else
		select @timestamp_subscribed = 0
	
	--
	-- Start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- detection/conflict resolution stage
	' + N'--'
	
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
	if (@execution_mode = @QPubWins)
		save tran cftpass
	'
	end
	insert into #proctext(procedure_text) values(@cmd)
	
	--
	-- Generate the update statement
	--
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	select @cmd2 = N'
	update ' + @qualname + N' set
	'

	select @spacer = N' 
		'
	select @cmd = N''
	exec dbo.sp_MSpad_command @cmd output, 8
	
	select @num_col = 0
	select @art_col = 0

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col
	WHILE (@@fetch_status <> -1)
	begin
		-- Get the ordinal of the article partition or not.
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
		if @isset = 0
		begin
			-- Special handling of a timestamp col in a queued tran publication
			-- See sp_helparticlecolumns : xtype 189 is timestamp
			if ((@timestamp_subscribed = 1) and 
					exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
				select @art_col = @art_col + 1
		end
		else
			select @art_col = @art_col + 1

		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
		if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) not like N'timestamp' and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
			begin
				if @cmd2 is not null
				begin
					exec dbo.sp_MSflush_command @cmd2 output, 1, 8
					select @cmd2 = null
				end

				select @num_col = @num_col + 1
				-- Optimization:
				-- Get null or actual column name
				-- Note: the output is quoted.
				exec dbo.sp_MSget_synctran_column 
					@ts_col = null,
					@op_type = null , -- 'ins, 'upd', 'del'
					@is_new = null,
					@primary_key_bitmap = null,
					@colname = @colname,
					@this_col = @this_col,
					@column = @column output,
					@from_proc = 1,
					@art_col = @art_col -- position in the partition.

				select @cmd = @cmd + @spacer + QUOTENAME(@colname) + N' = ' + @column 			    
				select @spacer = N','

				--
				-- flush command if necessary
				--
				exec dbo.sp_MSflush_command @cmd output, 1, 8
			end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid

	-- save off cmd fragment
	if @num_col > 0
	begin
		--
		-- Add the where clause based on the update mode
		--
		select @colname = 'msrepl_tran_version'
		exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', @colname, 4
	end 
	else
	-- set the @@rowcount
		insert into #proctext(procedure_text) values( N' select @retcode = @retcode
	')

	--
	-- continue with rest of scripting
	--
	select @cmd = N'
	select @rowcount = @@ROWCOUNT, @error = @@ERROR
	'

	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
	if (@execution_mode = @QPubWins)
		rollback tran cftpass'
	end
	insert into #proctext(procedure_text) values(@cmd)
	--
	-- Queued specific case
	--
	if (@queued_pub = 1)
	begin
		--
		-- script the assignment of new values based on bitmask
		--
		select @num_col = 0
				,@art_col = 0
				,@cmd = N'
	' + N'--
	' + N'-- for conflict resolution - assign the NEW values based on bitmap
	' + N'--
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin 	
		select '
		insert into #proctext(procedure_text) values(@cmd)	

		DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
			select colid from dbo.syscolumns where id = @objid order by colid asc

		OPEN hCColid
		FETCH hCColid INTO @this_col
		WHILE (@@fetch_status != -1)
		begin
			-- Get the ordinal of the article partition or not.
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
			if @isset = 0
			begin
				if ((@timestamp_subscribed = 1) and 
						exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
					select @art_col = @art_col + 1
			end
			else
				select @art_col = @art_col + 1

			exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
			if ((@rc = 0) 
				and EXISTS (select name from dbo.syscolumns where id=@objid and colid=@this_col and iscomputed != 1) 
				and (rtrim(@ccoltype) != N'timestamp'))
			begin
				select @num_col = @num_col + 1
						,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar)
						,@bitstr =  cast( power(2, (@art_col-1) % 8 ) as nvarchar)

				select @cmd = N'@c' + cast(@this_col as nvarchar(10)) + N' = case substring(@bitmap,' + 
					@bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + 
					N' then @c' + cast(@this_col as nvarchar(4)) + 
					N' else @c' + cast(@this_col as nvarchar(4)) + N'_old end '

				if (@num_col = 1)
				begin
					select @cmd = N'
				' + @cmd
				end
				else
				begin
					select @cmd = N'
				, ' + @cmd
				end
				insert into #proctext(procedure_text) values(@cmd)	
			end
			--
			-- fetch next row
			--
			FETCH hCColid INTO @this_col
		end
		CLOSE hCColid
		DEALLOCATE hCColid
		--
		-- continue with scripting
		--
		select @cmd = N'
	end' 	
		insert into #proctext(procedure_text) values(@cmd)	
	end
	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_update_statement
GO

--
-- sp_scriptpubwinsrefreshcursorvars
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates variable declarations
-- used for compensating refresh curors in a publisher wins cases. 
-- Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_scriptpubwinsrefreshcursorvars', 0,1)
go
create procedure sp_scriptpubwinsrefreshcursorvars 
(
	@objid int				-- object id
)
as
begin
	declare
			@rc           int
			,@cmd nvarchar(4000)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@typestring nvarchar(100)
 			,@spacer nvarchar(5)
			,@isset int
			,@pkcolumns varbinary(32)

	select @cmd = N'
		declare '
		,@spacer = N''
	exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
	declare #hccolid cursor local fast_forward for 
		select colid from syscolumns where id = @objid order by colid asc
	open #hccolid
	fetch #hccolid into @this_col
	while (@@fetch_status != -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
		if @isset != 0 and exists ( select name from syscolumns where id=@objid and colid=@this_col and iscomputed !=1 ) 
		begin
			exec dbo.sp_gettypestring @objid, @this_col, @typestring output
			select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @this_col ) + N' ' + @typestring 
					,@spacer = N','

			if len( @cmd ) > 3000
			begin
				insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		fetch #hccolid into @this_col
	end
	close #hccolid
	deallocate #hccolid
	if len(@cmd) > 0
		insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_scriptpubwinsrefreshcursorvars
go

--
--
-- sp_MSscript_update_subwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a subscriber wins resolution 
-- policy. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_update_subwins', 0,1)
go
create procedure sp_MSscript_update_subwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
	,@identity_insert bit
)
AS
BEGIN
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@rc           int
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	if (@execution_mode = @QSubWins)
	begin
		' + N'--
		' + N'-- Subscriber wins resolution
		' + N'-- 
		if (@cftcase in (10,11,14,15,18,20,21,22))
		begin
			'+N'--
			'+N'-- delete the row with OLD_PK
			'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script delete with PK=OLD_PK
	--
	select @cmd = N'
			delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	--
	-- continue scripting
	--
	select @cmd = N'
		end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- if the table has non PK unique keys
	-- generate the commands for non PK keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
		if (@cftcase in (17,20,22,23))
		begin
			'+N'--
			'+N'-- delete with NEW values of non PK keys
			'+N'--'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script delete with NEW values of non PK keys
		--
		select @cmd = N'
			delete ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 7
		--
		-- continue scripting
		--
		select @cmd = N'
		end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		if (@cftcase in (15,16))
		begin
			'+N'--
			'+N'-- delete with NEW values of all keys
			'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script delete with NEW values of all keys
	--
	select @cmd = N'
			delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = NULL
				,@mode = 6
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		if (@cftcase in (10,11,12,13,14,15,16,17,18,20,21,22,23,24))
		begin
			'+N'--
			'+N'-- insert with NEW values of all keys
			'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	--  
	-- generate insert statement with NEW values 
	--
	exec @rc = sp_script_insertforcftresolution 
			@objid = @objid
			,@columns = @columns
			,@identity_insert = @identity_insert
			,@prefix = N'@c'
			,@suffix = NULL
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		' + N'--
		' + N'-- --------------------------------------------------------------------
		' + N'-- all done for conflict resolution for Subscriber Wins policy
		' + N'-- --------------------------------------------------------------------
		' + N'--
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_update_subwins
go

--
-- sp_MSscriptupdateconflictfinder
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran procedures
-- and scripts the code that is a state machine and finds the exact nature of conflict
-- for UPDATE operations and then assigns it a unique conflict identity.  
-- Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscriptupdateconflictfinder', 0,1)
go
create procedure sp_MSscriptupdateconflictfinder 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare 
			@rc int
			,@cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid 
	from syspublications 
	where name = @publication
	select @artid = artid
	from sysarticles 
	where name = @article 
		and pubid = @pubid
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- --------------------------------------------------------------------
	' + N'-- This is the crux of the proc for conflict resolution 
	' + N'-- This code block is essentially a state machine
	' + N'-- where we ascertain the state of resolution
	' + N'-- The actions of this resolution varies for the policy
	' + N'-- The comments for each state outline the policy
	' + N'-- specific actions (I have only outlined Pub Wins for
	' + N'-- now)
	' + N'-- --------------------------------------------------------------------
	' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin 
		declare @fpkeyupdated int'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- non PK unique keys specific scripting
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
		declare @fnpukeyupdated int'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		' + N'--
		' + N'-- initialize the conflict case
		' + N'--
		select @cftcase = 0 '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script the PK update check
	--
	select @cmd = N'
		exec @fpkeyupdated = dbo.sp_MSispkupdateinconflict ' + 
		cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
		if (@fpkeyupdated = -1)
			return -1'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script non PK unique key update check
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
		exec @fnpukeyupdated = dbo.sp_MSisnonpkukupdateinconflict ' + 
		cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
		if (@fnpukeyupdated = -1)
			return -1'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
		if (@rowcount = 0)
		begin
			' + N'--
			' + N'-- we had conflict for this command
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	if (@fhasnonpkuniquekeys = 1)
	begin
		select @cmd = N'
			if (@error in (547, 2601, 2627) or (@fpkeyupdated = 1) or (@fnpukeyupdated = 1)) '
	end
	else
	begin
		select @cmd = N'
			if (@error in (547, 2601, 2627) or (@fpkeyupdated = 1)) '
	end
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'
			begin
				' + N'--
				' + N'-- Conflict due to unique key/constraint
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
				if (@fpkeyupdated = 1)
				begin
					' + N'--
					' + N'-- PK is being updated 
					' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script check for rows with all keys with OLD values
	--
	--if (row exists with pk = OLD_PK or non PK unique keys = OLD values)
	select @cmd = N'
					if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = N'_old'
				,@mode = 6
	insert into #proctext(procedure_text) values( N' )')
	--
	-- continue scripting
	--
	select @cmd = N'
					begin
						' + N'--
						' + N'-- case 14: row(s) with OLD key values exist(s) 
						' + N'-- (and rows with NEW key values do not exist)
						' + N'-- PubWins -----------------------------------------------------------
						' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
						' + N'-- generate delete compensating action for row with PK = NEW_PK 
						' + N'-- SubWins -----------------------------------------------------------
						' + N'-- delete row with PK=OLD_PK
						' + N'-- insert row with NEW values (use bitmap)
						' + N'--
						select @cftcase = 14
					end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script check for rows with all keys with NEW values (use bitmap)
	--
	--if (row exists with pk = NEW_PK or non PK unique keys = NEW values)
	select @cmd = N'
					if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = NULL
				,@mode = 6
	insert into #proctext(procedure_text) values( N' )')
	--
	-- continue scripting
	--
	select @cmd = N'
					begin
						' + N'--
						' + N'-- row with NEW key values exist(s)
						' + N'--
						if (@cftcase = 14)
						begin
							' + N'--
							' + N'-- case 15: rows exist with NEW key values and OLD key values
							' + N'-- PubWins -----------------------------------------------------------
							' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
							' + N'-- generate delete + insert compensating action with NEW values for all unique keys 
							' + N'-- SubWins -----------------------------------------------------------
							' + N'-- delete row with PK=OLD_PK
							' + N'-- delete rows with NEW values of all keys
							' + N'-- insert row with NEW values (use bitmap)
							' + N'--
							select @cftcase = 15 
						end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
						else
						begin
							' + N'--
							' + N'-- case 16: rows exist with NEW key values and 
							' + N'-- row does not exist for OLD values
							' + N'-- PubWins -----------------------------------------------------------
							' + N'-- generate delete compensating action for row with PK = OLD_PK 
							' + N'-- generate delete + insert compensating action with NEW values for all unique keys 
							' + N'-- SubWins -----------------------------------------------------------
							' + N'-- delete rows with NEW values of all keys
							' + N'-- insert row with NEW values (use bitmap)
							' + N'--
							select @cftcase = 16 
						end
					end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
					else
					begin
						' + N'--
						' + N'-- row with NEW key values does not exist
						' + N'--
						if (@cftcase = 0)
						begin
							' + N'--
							' + N'-- case 12 : no existing rows with OLD key values or NEW or new key values
							' + N'-- PubWins -----------------------------------------------------------
							' + N'-- generate delete compensating action with PK = OLD_PK
							' + N'-- generate delete compensating action with PK = NEW_PK
							' + N'-- SubWins -----------------------------------------------------------
							' + N'-- insert row with NEW values (use bitmap)
							' + N'--
							select @cftcase = 12 
						end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
						else
						begin
							' + N'--
							' + N'-- case 14: row(s) with OLD key values exist(s) 
							' + N'-- (and rows with NEW key values do not exist)
							' + N'-- PubWins -----------------------------------------------------------
							' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
							' + N'-- generate delete compensating action for row with PK = NEW_PK 
							' + N'-- SubWins -----------------------------------------------------------
							' + N'-- delete row with PK=OLD_PK
							' + N'-- insert row with NEW values (use bitmap)
							' + N'--
							select @cftcase = 14
						end
					end
				end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script this block if the article has non PK unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		--
		-- continue scripting
		--
		select @cmd = N'
				else if (@fnpukeyupdated = 1)
				begin
					'+N'-- 
					'+N'-- non PK unique keys are being updated but PK is not updated
					'+N'-- OLD_PK == NEW_PK in these cases
					'+N'--'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script the pkrowexists assignment
		--
		select @cmd = N'
					declare @pkrowexist bit
					
					if exists (select * from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
		select @cmd =  N' )
						select @pkrowexist = 1 '
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script check for rows with non PK keys with OLD values
		--
		-- if (rows exist with OLD values of non PK unique keys values)
		select @cmd = N'
					if exists (select * from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = N'_old'
					,@mode = 7
		insert into #proctext(procedure_text) values( N' )')
		--
		-- continue scripting
		--
		select @cmd = N'
					begin
						if (@pkrowexist = 1)
						begin
							'+N'--
							'+N'-- case 10: rows exist with OLD non PK key values
							'+N'-- (and rows with NEW non PK key values do not exist)
							'+N'-- and row with OLD_PK exists
							'+N'-- PubWins -----------------------------------------------------------
							'+N'-- generate delete + insert compensation action with OLD values for all keys 
							'+N'-- generate delete compensating action with NEW values for non PK keys
							'+N'-- SubWins -----------------------------------------------------------
							'+N'-- delete row with PK=OLD_PK
							'+N'-- insert row with NEW values (use bitmap)
							'+N'--
							select @cftcase = 10
						end'
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
						else
						begin
							'+N'--
							'+N'-- case 21: rows exist with OLD non PK key values
							'+N'-- (and rows with NEW non PK key values do not exist)
							'+N'-- and row with OLD_PK does not exist
							'+N'-- PubWins -----------------------------------------------------------
							'+N'-- generate delete with PK = OLD_PK
							'+N'-- generate delete + insert compensation action with OLD values for non PK keys 
							'+N'-- generate delete compensating action with NEW values for non PK keys
							'+N'-- SubWins -----------------------------------------------------------
							'+N'-- delete row with PK=OLD_PK
							'+N'-- insert row with NEW values (use bitmap)
							'+N'--
							select @cftcase = 21
						end
					end '
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script check for rows with non PK keys with NEW values (use bitmap)
		--
		-- if (rows exist with NEW values of non PK unique keys values)
		select @cmd = N'
					if exists (select * from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 7
		insert into #proctext(procedure_text) values( N' )')
		--
		-- continue scripting
		--
		select @cmd = N'
					begin
						'+N'--
						'+N'-- find the type of conflict
						'+N'--
						if (@cftcase in (10,21))
						begin
							if (@pkrowexist = 1)
							begin
								'+N'--
								'+N'-- case 20: rows exist with OLD and NEW values of non PK keys
								'+N'-- and row with OLD_PK exists
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- generate delete + insert compensation action with OLD values for all keys 
								'+N'-- generate delete + insert compensation action with NEW values for non PK keys 
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- delete row with PK=OLD_PK
								'+N'-- delete row with NEW values for non PK keys
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 20 
							end '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
							else
							begin
								'+N'--
								'+N'-- case 22: rows exist with OLD and NEW values of non PK keys
								'+N'-- and row with OLD_PK does not exist
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- generate delete with PK = OLD_PK
								'+N'-- generate delete + insert compensation action with OLD values for non PK keys 
								'+N'-- generate delete + insert compensation action with NEW values for non PK keys 
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- delete row with PK=OLD_PK
								'+N'-- delete row with NEW values for non PK keys
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 22 
							end
						end '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
						else
						begin
							if (@pkrowexist = 1)
							begin
								'+N'--
								'+N'-- case 17: rows exist with NEW values of non PK keys  
								'+N'-- and row does not exist with OLD values of non PK keys
								'+N'-- and row with OLD_PK exists
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- generate delete compensating action with OLD values for non PK keys 
								'+N'-- generate delete + insert compensation action with NEW values for all keys 
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- delete row with NEW values for non PK keys
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 17 
							end '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
							else
							begin
								'+N'--
								'+N'-- case 23: rows exist with NEW values of non PK keys  
								'+N'-- and row does not exist with OLD values of non PK keys
								'+N'-- and row with OLD_PK does not exist
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- delete row with PK=OLD_PK
								'+N'-- generate delete compensating action with OLD values for non PK keys 
								'+N'-- generate delete + insert compensation action with NEW values for non PK keys 
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- delete row with NEW values for non PK keys
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 23 
							end
						end
					end '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
					else
					begin
						'+N'--
						'+N'-- row does not exist with NEW values of non PK keys
						'+N'--
						if (@cftcase = 0)
						begin
							if (@pkrowexist = 1)
							begin
								'+N'--
								'+N'-- case 18 : no existing rows with OLD or NEW values of non PK keys
								'+N'-- and row with OLD_PK exists
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- delete row with PK=OLD_PK
								'+N'-- generate delete compensating action with OLD values for non PK keys 
								'+N'-- generate delete compensating action with NEW values for non PK keys 
								'+N'-- generate insert with PK = OLD_PK
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 18 
							end '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
							else
							begin
								'+N'--
								'+N'-- case 24 : no existing rows with OLD or NEW values of non PK keys
								'+N'-- and row with OLD_PK does not exist
								'+N'-- PubWins -----------------------------------------------------------
								'+N'-- delete row with PK=OLD_PK
								'+N'-- generate delete compensating action with OLD values for non PK keys 
								'+N'-- generate delete compensating action with NEW values for non PK keys 
								'+N'-- SubWins -----------------------------------------------------------
								'+N'-- insert row with NEW values (use bitmap)
								'+N'--
								select @cftcase = 24 
							end
						end
					end
				end '
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'
			end
			else
			begin
				' + N'--
				' + N'-- Conflict due non key column change or row deleted
				' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script check for rows with pk = OLD_PK
	--
	select @cmd = N'
				if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N' )')
	--
	-- continue scripting
	--
	select @cmd = N'
				begin
					' + N'--
					' + N'-- case 11: row exists
					' + N'-- PubWins -----------------------------------------------------------
					' + N'-- generate delete + insert compensating action with PK = OLD_PK
					' + N'-- SubWins -----------------------------------------------------------
					' + N'-- delete row with PK=OLD_PK
					' + N'-- insert row with NEW values (use bitmap)
					' + N'--
					select @cftcase = 11
				end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
				else
				begin
					' + N'--
					' + N'-- case 13: row does not exist
					' + N'-- PubWins -----------------------------------------------------------
					' + N'-- generate delete compensating action with PK = OLD_PK
					' + N'-- SubWins -----------------------------------------------------------
					' + N'-- insert row with NEW values (use bitmap)
					' + N'--
					select @cftcase = 13
				end
			end
		end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
		else if (@execution_mode = @QPubWins)
		begin
			' + N'--
			' + N'-- we had no conflict for this command
			' + N'-- We need to process this block only in the Publisher Wins cases
			' + N'--'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
			if (@fpkeyupdated = 1)
			begin
				' + N'--
				' + N'-- PK is being updated
				' + N'-- PubWins -----------------------------------------------------------
				' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
				' + N'-- generate delete compensating action with PK=NEW_PK
				' + N'-- 
				select @cftcase = 1
			end'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
			else
			begin
				' + N'--
				' + N'-- non PK column updated
				' + N'-- PubWins -----------------------------------------------------------
				' + N'-- generate delete + insert compensating action with OLD values for all unique keys
				' + N'--
				select @cftcase = 3
			end
		end
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0	
end
go
exec dbo.sp_MS_marksystemobject sp_MSscriptupdateconflictfinder
go

--
-- sp_MSscript_update_pubwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a publisher wins resolution 
-- policy for UPDATE commands. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_update_pubwins', 0,1)
go
create procedure sp_MSscript_update_pubwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@rc           int
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	
	' + N'-- 
	' + N'--  --------------------------------------------------------------------
	' + N'--  Now the generation phase
	' + N'--  Use the conflict case value to decide what to do
	' + N'--  --------------------------------------------------------------------
	' + N'--
	'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
	
	if (@execution_mode = @QPubWins)
	begin
		' + N'-- 
		' + N'--  Publisher wins resolution
		' + N'--  
		'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- declare fetch variables for cursor
	--
	exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
	--
	-- continue scripting
	--
	select @cmd = N'
		' + N'-- 
		' + N'--  --------------------------------------------------------------------
		' + N'--  Perform single row delete generations first
		' + N'--  --------------------------------------------------------------------
		' + N'-- 
		'
	insert into #proctext(procedure_text) values( @cmd )
	select @cmd = N'
		' + N'-- 
		' + N'--  Generate DELETE for PK = OLD_PK
		' + N'-- 
		if (@cftcase in (11,12,13,16,18,21,22,23,24))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate delete compensating cmd with OLD_PK
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'del'
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		' + N'-- 
		' + N'--  Generate DELETE for PK = NEW_PK 
		' + N'-- 
		if (@cftcase in (1,12,14))
		begin'
	insert into #proctext(procedure_text) values( @cmd )		
	--
	-- generate delete compensating cmd with NEW_PK
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- this scripting is specific to non PK unique keys
	--
	if (@fhasnonpkuniquekeys = 1)
	begin
		--
		-- continue scripting
		--
		select @cmd = N'

		'+N'--
		'+N'-- Generate delete for OLD values of non PK keys
		'+N'--
		if (@cftcase in (17,18,23,24))
		begin'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- generate delete compensating command for OLD values of non PK unique keys
		--
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
					+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = N'_old'
				,@mode = 5
		--
		-- script the sending command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- continue scripting
		--
		select @cmd = N'
		end

		'+N'--
		'+N'-- Generate delete for NEW values of non PK keys
		'+N'--
		if (@cftcase in (10,18,21,24))
		begin'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- generate delete compensating command for NEW values of non PK unique keys
		--
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
					+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 5
		--
		-- script the sending command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- continue scripting
		--
		select @cmd = N'
		end

		' + N'-- 
		' + N'--  --------------------------------------------------------------------
		' + N'--  Perform refresh(delete+insert) generations next
		' + N'--  --------------------------------------------------------------------
		' + N'-- 
		
		' + N'-- 
		' + N'--  Generate delete+insert for OLD values of non PK keys
		' + N'-- 
		if (@cftcase in (21,22))
		begin'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- generate delete compensating command for OLD values of non PK unique keys
		--
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
					+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = N'_old'
				,@mode = 5
		--
		-- script the sending command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- script the refresh commands for OLD values of non PK unique keys
		--
		exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 2, 0
		if (@rc != 0 or @@error != 0)
			return 1
		--
		-- continue scripting
		--
		select @cmd = N'
		end
		' + N'-- 
		' + N'--  Generate delete+insert for NEW values of non PK keys
		' + N'-- 
		if (@cftcase in (20,22,23))
		begin'
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- generate delete compensating command for NEW values of non PK unique keys
		--
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
					+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = NULL
					,@mode = 5
		--
		-- script the sending command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- script the refresh commands for NEW values of non PK unique keys
		--
		exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 3, 0
		if (@rc != 0 or @@error != 0)
			return 1
		--
		-- continue scripting
		--
		select @cmd = N'
		end'
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- continue scripting
	--
	select @cmd = N'

		' + N'-- 
		' + N'--  Generate delete+insert for OLD values of all keys
		' + N'-- 
		if (@cftcase in (1,3,10,14,15,20))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate delete compensating command for OLD values of all unique keys
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = N'_old'
				,@mode = 4
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- script the refresh commands for OLD values of all unique keys
	--
	exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 4, 0
	if (@rc != 0 or @@error != 0)
		return 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		' + N'-- 
		' + N'--  Generate delete+insert for NEW values of all keys
		' + N'-- 
		if (@cftcase in (15,16,17))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate delete compensating command for NEW values of all unique keys
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = NULL
				,@mode = 4
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- script the refresh commands for NEW values of all unique keys
	--
	exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 5, 0
	if (@rc != 0 or @@error != 0)
		return 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		' + N'-- 
		' + N'--  --------------------------------------------------------------------
		' + N'--  Perform single row insert generations next
		' + N'--  --------------------------------------------------------------------
		' + N'-- 

		' + N'-- 
		' + N'--  Generate INSERT for PK = OLD_PK
		' + N'-- 
		if (@cftcase in (11,18))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script compensating insert with OLD_PK
	--
	exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 1, 0
	--
	-- continue scripting
	--
	select @cmd = N'
		end

		' + N'-- 
		' + N'--  --------------------------------------------------------------------
		' + N'--  all done for conflict resolution for Publisher Wins policy
		' + N'--  --------------------------------------------------------------------
		' + N'-- 
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0	
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_update_pubwins
go

raiserror('Creating procedure sp_MSscript_delete_statement', 0,1)
go
create procedure sp_MSscript_delete_statement (
	@publication sysname,
	@article     sysname, 
	@objid int,
	@columns binary(32),
	@queued_pub bit = 0
)
as
BEGIN
	declare @cmd          nvarchar(4000)
	declare @qualname     nvarchar(512)

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- detection/conflict resolution stage
	' + N'--'
	
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
	if (@execution_mode = @QPubWins)
		save tran cftpass
	'
	end
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- delete statement
	--
	select @cmd = N'
	delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', 'msrepl_tran_version', 4

	--
	-- continue with scripting
	--
	select @cmd = N'
	select @rowcount = @@ROWCOUNT, @error = @@ERROR
	'

	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N'
	if (@execution_mode = @QPubWins)
		rollback tran cftpass
	'
	end
	insert into #proctext(procedure_text) values( @cmd )

	--
	-- all done
	--
	return 0
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_delete_statement
GO

--
-- sp_MSscript_delete_subwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a subscriber wins resolution 
-- policy for DELETE commands. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_delete_subwins', 0,1)
go
create procedure sp_MSscript_delete_subwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare @cmd nvarchar(4000)
			,@qualname nvarchar(512)

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	-- start scripting
	--
	select @cmd = N'
	if (@execution_mode = @QSubWins)
	begin
		'+N'--
		'+N'-- Subscriber wins resolution
		'+N'-- 
		if (@cftcase = 31)
		begin
			'+N'--
			'+N'-- delete row with PK
			'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate the delete statement
	--
	select @cmd = N'
			delete ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	--
	-- continue with scripting
	--
	select @cmd = N'			
		end

		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- all done for conflict resolution for Subscriber Wins policy
		'+N'-- --------------------------------------------------------------------
		'+N'--
	end'
	insert into #proctext(procedure_text) values( @cmd )	
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_delete_subwins
go

--
-- sp_MSscriptdelconflictfinder
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran procedures
-- and scripts the code that is a state machine and finds the exact nature of conflict
-- for DELETE operations and then assigns it a unique conflict identity.  
-- Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscriptdelconflictfinder', 0,1)
go
create procedure sp_MSscriptdelconflictfinder 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare 
			@rc int
			,@cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@qualname nvarchar(512)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid 
	from syspublications 
	where name = @publication
	select @artid = artid
	from sysarticles 
	where name = @article 
		and pubid = @pubid
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	--  check if this article has non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- start scripting
	--
	select @cmd = N'
	'+N'--
	'+N'-- --------------------------------------------------------------------
	'+N'-- This is the crux of the proc for conflict resolution 
	'+N'-- This code block is essentially a state machine
	'+N'-- where we ascertain the state of resolution
	'+N'-- The actions of this resolution varies for the policy
	'+N'-- The comments for each state outline the policy
	'+N'-- specific actions 
	'+N'-- --------------------------------------------------------------------
	'+N'--
	'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin
		'+N'--
		'+N'-- initialize the conflict case
		'+N'--
		select @cftcase = 0

		if (@rowcount = 0)
		begin
			'+N'--
			'+N'-- row was deleted or updated
			'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- script row exists with OLD_PK
	--
	select @cmd = N'
			if exists (select * from ' + @qualname 
	insert into #proctext(procedure_text) values( @cmd )
	exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
	insert into #proctext(procedure_text) values( N'			)')
	--
	-- continue scripting
	--
	select @cmd = N'
			begin
				'+N'--
				'+N'-- Case 31: Conflict as row was updated
				'+N'-- PubWins -----------------------------------------------------------
				'+N'-- generate delete + insert compensating action with values for all unique keys 
				'+N'-- SubWins -----------------------------------------------------------
				'+N'-- delete row with PK
				'+N'--
				select @cftcase = 31
			end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'
			else
			begin
				'+N'--
				'+N'-- Case 33: Conflict as row does not exist
				'+N'-- PubWins -----------------------------------------------------------
				'+N'-- do nothing
				'+N'-- SubWins -----------------------------------------------------------
				'+N'-- do nothing
				'+N'--
				select @cftcase = 33
			end
		end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'
		else if (@execution_mode = @QPubWins)
		begin
			'+N'--
			'+N'-- we had no conflict for this command
			'+N'-- We need to process this block only in the Publisher Wins cases
			'+N'--

			'+N'--
			'+N'-- case 30: No conflict - we have to undo the delete
			'+N'-- PubWins -----------------------------------------------------------
			'+N'-- generate delete + insert compensating action with values for all unique keys 
			'+N'-- 
			select @cftcase = 30
		end	
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- continue scripting
	--
	select @cmd = N'

	'+N'--
	'+N'-- --------------------------------------------------------------------
	'+N'-- Now the generation phase
	'+N'-- Use the conflict case value to decide what to do
	'+N'-- --------------------------------------------------------------------
	'+N'--'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscriptdelconflictfinder
go

--
--
-- sp_MSscript_compensating_insert
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code for insert compensating command
-- and refresh (delete+insert for selected rowset) compensating 
-- command to resolve conflicts in a publisher wins resolution 
-- policy. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_compensating_insert', 0,1)
go
create procedure sp_MSscript_compensating_insert 
(
	@publication sysname 	-- publication name
	,@article sysname 		-- article name
	,@objid int			-- table object id
	,@columns binary(32)	-- columns replicated
	,@proctype tinyint		-- what are we scripting 		
	-- 0 = use new_pk
	-- 1 = use old_pk
	-- 2 = use old nonpkkeys
	-- 3 = use new nonpkkeys
	-- 4 = use oldallkeys
	-- 5 = use newallkeys
	,@fdodeclare bit = 1	-- 0 = do not script declares for non PK unique key processing
)
as
begin
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@colname      sysname
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@num_col	  int
			,@qualname nvarchar(540)
			,@cast_str nvarchar(4000)
			,@column_string nvarchar(4000)
			,@ins_cmd nvarchar(255)
			,@startoffset int
			,@setprefix bit
			,@commandlen int
			,@fragmentlen int
			,@collen int
			,@first_time bit
			,@fullcastlen int
			,@splitlen int
			,@pkcolumns varbinary(32)
			,@fhasnonpkuniquekeys int
	declare @pkfetch table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
	--
	-- constants
	--
	declare @typeusenew_pk tinyint
			,@typeuseold_pk tinyint
			,@typeuseoldnonpkkeys tinyint
			,@typeusenewnonpkkeys tinyint
			,@typeuseoldallkeys tinyint
			,@typeusenewallkeys tinyint
	--
	-- initialize constants
	--
	select @typeusenew_pk = 0
			,@typeuseold_pk = 1
			,@typeuseoldnonpkkeys = 2
			,@typeusenewnonpkkeys = 3
			,@typeuseoldallkeys = 4
			,@typeusenewallkeys = 5

	--
	-- validate @proctype
	--
	if (@proctype not in (@typeusenew_pk,@typeuseold_pk,@typeuseoldnonpkkeys,
		@typeusenewnonpkkeys,@typeuseoldallkeys,@typeusenewallkeys))
	begin
		-- raiserror invalid proctype
		return 1
	end
	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, 
		@dest_owner = dest_owner, @ins_cmd = ins_cmd from sysarticles 
	where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
			,@fhasnonpkuniquekeys = 0
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	-- Do we have non PK unique keys
	--
	exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
	--
	-- If we are generating refreshing commands
	-- we will be using cursors
	--
	if (@proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys
						,@typeuseoldallkeys,@typeusenewallkeys))
	begin
		--
		-- generate cursor to collect PK for selected rowset
		-- and then perform delete compensation followed by
		-- insert compensation
		--
 		declare @cmd2 nvarchar(4000)
			,@cmd3 nvarchar(4000)
			,@spacer nvarchar(5)
			,@typestring sysname
			,@isset int
			,@wheremode tinyint
			,@suffix nvarchar(10)
		declare @pkvars table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
		declare @pkcols table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)

		--
		-- if the article has no non PK unique keys
		-- we should not be processing for @typeuseoldnonpkkeys,@typeusenewnonpkkeys
		--
		if (@fhasnonpkuniquekeys = 0 and 
			@proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys))
		begin
			-- error we should not generate these cases if there are no non PK unique keys
			return 1
		end
		--
		-- build some strings for PK columns and PK variables (@pkc1..)
		--
		exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
		select @cmd = N''
			,@cmd2 = N''
			,@cmd3 = N''
			,@spacer = N''
		declare #hccolid cursor local fast_forward for 
			select colid, name from syscolumns where id = @objid order by colid asc
		open #hccolid
		fetch #hccolid into @this_col, @colname
		while (@@fetch_status != -1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset != 0 and (@colname is not null)
			begin
				exec dbo.sp_gettypestring @objid, @this_col, @typestring output
				select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @this_col ) + N' ' + @typestring 
						,@cmd2 = @cmd2 + @spacer + quotename(@colname)
						,@cmd3 = @cmd3 + @spacer + N'@pkc' + convert( nvarchar, @this_col )
				select @spacer = N','

				if len( @cmd ) > 3000
				begin
					insert into @pkvars(procedure_text) values( @cmd )
					select @cmd = N''
				end
				if len( @cmd2 ) > 3000
				begin
					insert into @pkcols(procedure_text) values( @cmd2 )
					select @cmd2 = N''
				end
				if len( @cmd3 ) > 3000
				begin
					insert into @pkfetch(procedure_text) values( @cmd3 )
					select @cmd3 = N''
				end
			end
			fetch #hccolid into @this_col, @colname
		end
		close #hccolid
		deallocate #hccolid
		if len(@cmd) > 0
			insert into @pkvars(procedure_text) values( @cmd )
		if len(@cmd2) > 0
			insert into @pkcols(procedure_text) values( @cmd2 )
		if len(@cmd3) > 0
			insert into @pkfetch(procedure_text) values( @cmd3 )
		--
		-- script the PK variable declare now
		--
		if (@fdodeclare = 1)
		begin
			select @cmd = N'
			declare '
			insert into #proctext(procedure_text) values( @cmd )
			insert into #proctext(procedure_text) 
				select procedure_text from @pkvars order by c1 asc
		end
		--
		-- script the cursor declare now
		--
		select @cmd = N'
			declare #hccompins cursor local fast_forward for 
				select distinct '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkcols order by c1 asc
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script the where clause for the cursor
		-- based on @proctype
		--
		if (@proctype = @typeuseoldnonpkkeys) 
		begin
			select @wheremode = 7
				,@suffix = N'_old'
		end
  		else if (@proctype = @typeusenewnonpkkeys) 
  		begin
			select @wheremode = 7
				,@suffix = NULL
  		end
  		else if (@proctype = @typeuseoldallkeys) 
  		begin
			select @wheremode = 6
				,@suffix = N'_old'
  		end
  		else if (@proctype = @typeusenewallkeys) 
  		begin
			select @wheremode = 6
				,@suffix = NULL
		end
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@c' 
					,@suffix = @suffix
					,@mode = @wheremode
		--
		-- script the cursor open and fetch
		--
		select @cmd = N'
			open #hccompins
			fetch #hccompins into '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkfetch order by c1 asc
		select @cmd = N'
			while (@@fetch_status != -1)
			begin '
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- we are processing a refresh process
		-- issue a compensating delete for the row
		-- select in the cursor
		--
		select @cmd = N'
			' + '--
			' + '-- Issue a delete command for row selected in cursor
			' + '-- '
		insert into #proctext(procedure_text) values( @cmd )
		select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
			+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
		insert into #proctext(procedure_text) values( @cmd )
		exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
					,@columns = @columns
					,@prefix = N'@pkc' 
					,@suffix = NULL
					,@mode = 8
		--
		-- script the send for this command
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
		--
		-- continue scripting
		--
		select @cmd = N'
			' + '--
			' + '-- Issue a compensating insert for row selected in cursor
			' + '-- '
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- The compensating command will be split into one or more
	-- fragment commands if the length exceeds 3450 characters in length 
	-- (to accomodate compensating server/db names)
	-- For correctly estimating the length of the compensating command
	-- we have to take the max column length of the data into consideration along
	-- with the scripting command length
	--

	--
	-- use the insert command if available
	--
	select @commandlen = 0
			,@setprefix = 1

	if (@ins_cmd = N'SQL')
	begin
		select @cmd = N'
			select @cmd = ''INSERT INTO ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
						+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N''' + 
						'' SELECT '' + '
	end
	else
	begin
		select @cmd = N'
			select @cmd = ''EXEC ' + substring(@ins_cmd, 5, len(@ins_cmd) - 4) + N' '' + '
	end
	insert into #proctext(procedure_text) values( @cmd )
 	select @commandlen = @commandlen + len(@cmd)
	
	select @num_col = 0
	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid, length from syscolumns where id = @objid order by colid asc

	OPEN hCColid
	FETCH hCColid INTO @this_col, @collen
	WHILE (@@fetch_status != -1)
	begin
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
		begin
			if rtrim(@ccoltype) not like N'timestamp' 
			begin
				select @num_col = @num_col + 1
				--
				-- Compute the command fragment length needed for this column
				-- based on the coltype
				--				
				if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('ntext','text','image'))
				begin
					--
					-- For compensating commands we have to include the text and image data
					-- as the custom procs used by Distribution process expects them - as it
					-- done for regular transactional replication - but we will only send NULLs
					-- as it is not possible to ascertain the size of the data during the generation
					--		
					select @cast_str = N' ''null'' '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
				begin
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
						select @collen = (@collen / 2)
	
					select @cast_str = case 
							when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
								then N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
								else N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
							end
	   
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
				begin
					--
					-- each byte has 2 nibbles - we need a char to represent each nibble
					--
					select @collen = @collen * 2
					select @cast_str = N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' + quotename(@colname) + N',1,0) collate database_default, ''null'') '
					select @fullcastlen = len(@cast_str)
					select @fragmentlen = @fullcastlen + 4 + @collen + 2
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','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 ('float','real'))
				begin
					select @collen = 60
					select @cast_str = N' ISNULL(CONVERT(nvarchar(60),' + quotename(@colname) + N',2), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CONVERT(nvarchar(40),' + quotename(@colname) + N',2), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CAST(' + quotename(@colname) + N' as nvarchar(40)) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
				begin
					select @collen = 40
					select @cast_str = N' ISNULL('''''''' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 112) + N'' '' +  CONVERT(nvarchar(40), ' + quotename(@colname) + N', 114) + '''''''', ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
				begin
					--
					-- need to revisit this later
					--
					select @cast_str = N' ISNULL(master.dbo.fn_sqlvarbasetostr(' + quotename(@colname) + N' ) collate database_default, ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end					
				else
				begin
					select @collen = 40
					select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
					select @fragmentlen = len(@cast_str) + @collen
				end
				--
				-- for fixed datatypes - we will not split the data at all we will
				-- flush the command script and continue
				-- for varying/large datatypes, we will have to split data if necessary
				--
				if ((lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar','binary','varbinary')) 
						and (@fragmentlen + @commandlen > 3450))
				begin
			 		--
			 		-- the column length is too big, we have to break the data string
			 		-- initialize
			 		--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' 
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' 
					end
					--
					-- use substring to break the string value in the
					-- compensating command
					--
					select @first_time = 1
							,@startoffset = 1
					while (@collen > 0)
					begin
				 		select @splitlen = case when ((@first_time = 1) or (@collen > 3450))
				 								then (3450 - @commandlen - 30 - @fullcastlen)
				 								else @collen end
				 		if (@splitlen < 1)
				 		begin
				 			--
				 			-- we have overcompensated the splitlen
				 			-- set to half of the column length
				 			--
				 			select @splitlen = @collen / 2
				 		end
						--
						-- Do we need to put quotes (many datatypes need it)
						--
					 	if (@first_time = 1)
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
								select @column_string = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
										then @column_string + N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr( '
										else @column_string + N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr( '
									end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' 
						end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
						 		select @column_string = N' + ISNULL(master.dbo.fn_MSgensqescstr( '
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @column_string = @column_string + N' + ISNULL(master.dbo.fn_varbintohexsubstring(0,' 
					 	end
						--
						-- prepare the substring script
						--
						if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							select @cast_str = N'SUBSTRING(' + quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast(@splitlen as nvarchar) + N')'
						else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
							select @cast_str = quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast((@splitlen/2) as nvarchar)

						if (@first_time = 1)
					 	begin
							select @cast_str = @cast_str + N') collate database_default, ''null'') '
									,@first_time = 0
					 	end
					 	else
					 	begin
							if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
							begin
								--
								-- for strings the last fragment needs the single
								-- quote to be added for the string
								--
								select @cast_str = @cast_str + N') collate database_default '
								select @cast_str = case 
									when (@collen - @splitlen < 1)
										then @cast_str + N'+ '''''''', '''') '											
										else @cast_str + N', '''') ' 
									end
							end
							else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
								select @cast_str = @cast_str + N') collate database_default, '''') '
						end
						 		
						select @column_string = @column_string + @cast_str
						insert into #proctext(procedure_text) values( @column_string )

						if (@fragmentlen + @commandlen > 3450)
						begin
							select @cmd = N'
			from ' + @qualname 
							insert into #proctext(procedure_text) values( @cmd )
							--
							-- script the where clause
							--
							if (@proctype in (@typeusenew_pk,@typeuseold_pk))
							begin
								--
								-- only PK unique key
								--
								if (@proctype = @typeuseold_pk)
									exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
								else
									exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
							end
							else
							begin
								--
								-- we are in the cursor for qualifying row
								-- 
								exec dbo.sp_scriptpkwhereclause @src_objid = @objid
											,@pkcolumns = @pkcolumns
											,@prefix = N'@pkc'
											,@artcolumns = @columns
											,@mode = 2
							end
							--
							-- Script the compensating send
							--
							exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
							if (@setprefix = 1)
								select @setprefix = 0

							select @cmd = N'
			select @cmd = N''''' 
							insert into #proctext(procedure_text) values( @cmd )
							select @commandlen = 0
						end
						else
							select @commandlen = @commandlen + len(@column_string)
						--
						-- update vars for next round
						--
						select @collen = @collen - @splitlen
								,@column_string = N''
								,@startoffset = case 
									when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) 
										then (@splitlen/2) + @startoffset 
										else @splitlen + @startoffset 
									end
						select @fragmentlen = @fullcastlen + 4 + @collen
					end							
					--
					-- we done with this column now
					-- skip processing further and continue
					--						
					select @commandlen = @commandlen + len(@column_string)
			 	end
			 	else
			 	begin
					--
					-- Handling general fixed type column cases
					--
					if (@num_col = 1)
					begin
						select @column_string = N'
				' + @cast_str
					end
					else
					begin
						select @column_string = N'
				+ '','' + ' + @cast_str
					end
					--
					-- check if we need to flush the command first
					--
					if (@fragmentlen + len(@column_string) + @commandlen > 3450)
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )
						--
						-- script the where clause
						--
						if (@proctype in (@typeusenew_pk,@typeuseold_pk))
						begin
							--
							-- only PK unique key
							--
							if (@proctype = @typeuseold_pk)
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
							else
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
						end
						else
						begin
							--
							-- we are in the cursor for qualifying row
							-- 
							exec dbo.sp_scriptpkwhereclause @src_objid = @objid
										,@pkcolumns = @pkcolumns
										,@prefix = N'@pkc'
										,@artcolumns = @columns
										,@mode = 2
						end
						--
						-- Script the compensating send
						--
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end
					--
					-- script out the column string
					--
					insert into #proctext(procedure_text) values( @column_string )
					--
					-- if we are processing sql_variants, flush the command again
					--
					if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
					begin
						--
						-- send this compensating command first
						--
						select @cmd = N'
			from ' + @qualname 
						insert into #proctext(procedure_text) values( @cmd )
						--
						-- script the where clause
						--
						if (@proctype in (@typeusenew_pk,@typeuseold_pk))
						begin
							--
							-- only PK unique key
							--
							if (@proctype = @typeuseold_pk)
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
							else
								exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
						end
						else
						begin
							--
							-- we are in the cursor for qualifying row
							-- 
							exec dbo.sp_scriptpkwhereclause @src_objid = @objid
										,@pkcolumns = @pkcolumns
										,@prefix = N'@pkc'
										,@artcolumns = @columns
										,@mode = 2
						end
						--
						-- Script the compensating send
						--
						exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
						if (@setprefix = 1)
							select @setprefix = 0

						select @cmd = N'
			select @cmd = N'' ''' 
						insert into #proctext(procedure_text) values( @cmd )
						select @commandlen = 0					
					end
					else
						select @commandlen = @commandlen + @fragmentlen + len(@column_string)
				end
			end
		end
		--
		-- process the next column
		--
		FETCH hCColid INTO @this_col, @collen
	end
	CLOSE hCColid
	DEALLOCATE hCColid
	--
	-- Check if we need to flush the command one more time (final)
	--
	if (@commandlen > 0)
	begin
		--
		-- send the last fragment of the command
		--
		select @cmd = N'
			from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd )
		--
		-- script the where clause
		--
		if (@proctype in (@typeusenew_pk,@typeuseold_pk))
		begin
			--
			-- only PK unique key
			--
			if (@proctype = @typeuseold_pk)
				exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
			else
				exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
		end
		else
		begin
			--
			-- we are in the cursor for qualifying row
			-- 
			exec dbo.sp_scriptpkwhereclause @src_objid = @objid
						,@pkcolumns = @pkcolumns
						,@prefix = N'@pkc'
						,@artcolumns = @columns
						,@mode = 2
		end
		--
		-- Script the compensating send
		--
		exec sp_MSscript_compensating_send @pubid, @artid, 0, @setprefix
	end
	--
	-- More scripting for refresh command processing modes
	--
	if (@proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys
					,@typeuseoldallkeys,@typeusenewallkeys))
	begin
		--
		-- script the cursor fetch
		--
		select @cmd = N'
			fetch #hccompins into '
		insert into #proctext(procedure_text) values( @cmd )
		insert into #proctext(procedure_text) 
			select procedure_text from @pkfetch order by c1 asc
		--
		-- script the cursor close and deallocate
		--
		select @cmd = N'
			end
			close #hccompins
			deallocate #hccompins '
		insert into #proctext(procedure_text) values( @cmd )
	end
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_compensating_insert
go

--
-- sp_MSscript_delete_pubwins
--
-- Owner: KaushikC
--
-- Description: this stored procedure is used for scripting of synctran 
-- procedures and scripts the code that generates the compensating 
-- commands to resolve all the conflicts in a publisher wins resolution 
-- policy for DELETE commands. Executed on publisher database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	SQL script specific to the article
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_MSscript_delete_pubwins', 0,1)
go
create procedure sp_MSscript_delete_pubwins 
(
	@publication sysname		-- publication name
	,@article sysname			-- article name
	,@objid int				-- object id
	,@columns binary(32)		-- columns replicated
)
as
begin
	declare @cmd nvarchar(4000)
			,@artid int
			,@pubid int
			,@dest_table sysname
			,@dest_owner nvarchar(260)
			,@rc           int
			,@qualname nvarchar(512)
			,@fhasnonpkuniquekeys int

	--
	-- initialize the vars we will use
	--
	select @pubid = pubid from syspublications where name = @publication
	select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
	from sysarticles where name = @article and pubid = @pubid
	select @dest_owner = case when (@dest_owner IS NULL) then N''
				else quotename(@dest_owner) + N'.' end
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	--
	-- start scripting
	--
	select @cmd = N'
	if (@execution_mode = @QPubWins)
	begin
		'+N'--
		'+N'-- Publisher wins resolution
		'+N'-- '
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- declare fetch variables for cursor
	--
	exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
	--
	-- continue scripting
	--
	select @cmd = N'

		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- Perform refresh(delete+insert) generations next
		'+N'-- --------------------------------------------------------------------
		'+N'--
		
		'+N'--
		'+N'-- Generate delete+insert for values of all keys
		'+N'--
		if (@cftcase in (30,31))
		begin'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- generate delete compensating command for OLD values of all unique keys
	--
	select @cmd = N'
			select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
		+ quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
	insert into #proctext(procedure_text) values( @cmd )
	exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
				,@columns = @columns
				,@prefix = N'@c' 
				,@suffix = N'_old'
				,@mode = 4
	--
	-- script the sending command
	--
	exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
	--
	-- script the refresh commands for OLD values of all unique keys
	--
	exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 4, 0
	if (@rc != 0 or @@error != 0)
		return 1
	--
	-- continue scripting
	--
	select @cmd = N'
		end
		'+N'--
		'+N'-- --------------------------------------------------------------------
		'+N'-- all done for conflict resolution for Publisher Wins policy
		'+N'-- --------------------------------------------------------------------
		'+N'--
	end'
	insert into #proctext(procedure_text) values( @cmd )
	--
	-- all done
	--
	return 0		
end
go
exec dbo.sp_MS_marksystemobject sp_MSscript_delete_pubwins
go

raiserror('Creating procedure sp_MSscript_beginproc', 0,1)
go
create procedure sp_MSscript_beginproc (
    @publication  sysname, 
    @article      sysname, 
    @procname     sysname,
    @source_objid int        output,
    @columns      binary(32) output)
as
BEGIN
    declare @cmd nvarchar(4000)
    declare @source_table sysname
    declare @owner sysname

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

    -- Get the object owner name
    select @owner = u.name from sysusers u, sysobjects o where 
        o.id = @source_objid and
        o.uid = u.uid
            
    if @source_table IS NULL
    begin
        raiserror (20506, 16, 1,  @source_table, 'sp_MSscript_beginproc')
        return 0
    end

    -- Construct proc name
    -- Create proc under the table owner account to preserve the ownership chain
    select @cmd = N'create procedure '+QUOTENAME(@owner)+ N'.'+ QUOTENAME(@procname) + N' (
	@orig_server sysname, @orig_db sysname,'
    exec dbo.sp_MSflush_command @cmd output, 1

    return 1
END
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_beginproc
GO

raiserror('Creating procedure sp_MSscript_security', 0,1)
go
create procedure sp_MSscript_security (
    @publication sysname)
as
BEGIN
    declare @cmd nvarchar(4000)
	
	select @cmd = N'
	' + N'--
	' + N'-- Check for security
	' + N'--
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = '+ quotename(@publication) + N'
	if (@retcode != 0 or @@error != 0)
		return -1
	'
    insert into #proctext(procedure_text) values(@cmd)
END                    
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_security
GO

raiserror('Creating procedure sp_MSscript_endproc', 0,1)
go
create procedure sp_MSscript_endproc (
	@objid int, 
	@op_type varchar(3) = 'ins', -- 'ins', 'upd', 'del'
	@columns binary(32),
	@outvars nvarchar(4000),
	@queued_pub bit = 0
)
as
BEGIN
	declare @cmd nvarchar(4000)
	declare @qualname nvarchar(512)

	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	--
	-- start scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- decide the return code
	' + N'--
	if (@execution_mode = @immediate)
	begin
		if @error != 0
      		return -1
		-- Return special code to indicate the subscriber row needs to be
		-- refreshed.
		if @rowcount = 0
      		return 5
	end'
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- operation specific stuff
	--
	if (@queued_pub = 1)
	begin
		if (@op_type = 'ins')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (547, 2601, 2627))
				return 2 -- insert conflict
			else
				return -1 -- error
		end
	end'
		end
		else if (@op_type = 'upd')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (0, 547, 2601, 2627))
				return 1 -- update conflict
			else
				return -1 -- error
		end
	end'
		end
		else if (@op_type = 'del')
		begin
			select @cmd = N'
	if (@execution_mode = @QFirstPass)
	begin
		if (@rowcount = 0)
		begin
			if (@error in (0, 547))
				return 3 -- delete conflict
			else
				return -1 -- error
		end
	end'
		end
		insert into #proctext(procedure_text) values(@cmd)
		
		--
		-- continue with scripting
		--
		select @cmd = N'
	
	if (@execution_mode in (@QPubWins, @QSubWins))
	begin		
		if (@@error != 0 or @retcode != 0)
			return -1 -- error
	end
    '
		insert into #proctext(procedure_text) values(@cmd)
	end

	--
	-- if we have output vars to assign do it now
	--
	if (@outvars is not null)
	begin   
		if @op_type = 'upd'
		begin
			--
			-- Script out pk var assigment that used in sp_MSscript_where_clause
			--
			exec dbo.sp_MSscript_pkvar_assignment @objid, @columns, 1, null, null, null, @queued_pub
			insert into #proctext(procedure_text) values(N'
	')
		end

		select @cmd = N'
	select ' + @outvars + N'
	from ' + @qualname 
		insert into #proctext(procedure_text) values( @cmd)
		insert into #proctext(procedure_text) values( N'
	')
	
		if (@op_type = 'ins')
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'new pk', null, 4
		else if (@op_type = 'upd')
			exec dbo.sp_MSscript_where_clause @objid, @columns, 'old pk', null, 4
	end

	--
	-- Final part of the proc
	--
    select @cmd = N'
    
	' + N'--
	' + N'-- past all checks
	' + N'--
	return 0
END
'
	insert into #proctext(procedure_text) values(@cmd)
	
	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSscript_endproc
go

raiserror('Creating procedure sp_MStable_not_modifiable', 0,1)
go
create proc sp_MStable_not_modifiable
    @objid   int,
    @columns binary(32)
as
    declare @colname      sysname
    declare @typestring   nvarchar(4000)
    declare @this_col     int
    declare @art_col      int
    declare @isset        int
    declare @found int, @repl_columns int

    select @art_col = 1
    select @found = 0, @repl_columns = 0

	DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
	select colid from syscolumns where id = @objid order by colid asc

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns

        if @isset != 0 and EXISTS (select name from syscolumns where id=@objid and @this_col=colid and iscomputed<>1)
        begin
            select @repl_columns = @repl_columns + 1
            exec dbo.sp_MSget_type @objid, @this_col, @colname output, @typestring OUTPUT

            if @typestring = N'timestamp' or ColumnProperty(@objid, @colname, 'IsIdentity') = 1
                select @found = 1

        end
		FETCH hCColid INTO @this_col
    end
	CLOSE hCColid
	DEALLOCATE hCColid

    if @found = 1 and @repl_columns = 1
        return 1
    else
        return 0
go


EXEC dbo.sp_MS_marksystemobject sp_MStable_not_modifiable
GO

--
-- proc to script the various checks done for queued and
-- synctran execution prior to actual detection/resolution
-- For queued execution, we also check for Reinitialization
-- phase
--
raiserror('Creating procedure sp_MSscript_ExecutionMode_stmt', 0,1)
go
create procedure sp_MSscript_ExecutionMode_stmt (
	@publication sysname, 
	@article     sysname,
	@proctype	int = 0)		-- 0 insert, 1 delete, 2 update
as
begin
	declare @cmd		nvarchar(4000)
			,@artid		int
			,@pubid		int
			,@queued_pub bit

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

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

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

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

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

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

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

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

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

--
