-- Name: sp_MSscript_sync_ins_proc
--
-- Description: This procedure is used during the scripting of publisher 
-- synctran procedures. This SP generates script for the INSERT synctran 
-- procedure. Invoked on publisher during the article creation.
--
-- 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_MSscript_sync_ins_proc', 0,1)
go
create procedure sp_MSscript_sync_ins_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
			,@colname sysname
			,@indid int
			,@cmd          nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@error_cmd	tinyint
			,@identity_insert bit
			,@queued_pub bit

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

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

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

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

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

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

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

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

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

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

--
-- Name: sp_MSscript_sync_upd_proc
--
-- Description: This procedure is used during the scripting of publisher 
-- synctran procedures. This SP generates script for the UPDATE 
-- synctran procedure. Invoked on publisher during the article creation.
--
-- 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_MSscript_sync_upd_proc', 0,1)
go
create procedure sp_MSscript_sync_upd_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
			,@colname sysname
			,@indid int
			,@cmd          nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@error_cmd	tinyint
			,@identity_insert bit
			,@queued_pub bit

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

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

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

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

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

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

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

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

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

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

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

--
-- Name: sp_MSscript_sync_del_proc
--
-- Description: This procedure is used during the scripting of publisher 
-- synctran procedures. This SP generates script for the DELETE 
-- synctran procedure. Invoked on publisher during the article creation.
--
-- 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_MSscript_sync_del_proc', 0,1)
go
create procedure sp_MSscript_sync_del_proc (
    @publication sysname, 
    @article     sysname,
    @procname    sysname)
as
BEGIN
	declare @source_objid int
	declare @colname sysname
	declare @indid int
	declare @cmd          nvarchar(4000)
	declare @columns      binary(32)
	declare @outvars      nvarchar(4000)
	declare @rc           int
	declare @error_cmd	tinyint
	declare @queued_pub bit

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

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

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

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

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

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

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

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

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

		--
		-- script queued specific stuff
		--
		if (@queued_pub = 1)
		begin
			--
			-- script the conflict resolution logic common to all resolution policies
			--
			exec sp_MSscriptdelconflictfinder @publication, @article, @source_objid, @columns
			--
			-- script Conflict resolution block for Publisher Wins case
			--
			exec dbo.sp_MSscript_delete_pubwins @publication, @article, @source_objid, @columns
			--
			-- script Conflict resolution block for Subscriber Wins case
			--
			exec dbo.sp_MSscript_delete_subwins @publication, @article, @source_objid, @columns
		end
		
		--
		-- script closing 
		--
		exec dbo.sp_MSscript_endproc @source_objid, 'del', @columns, @outvars, @queued_pub
	end
	else
	begin
		--
		-- Generate error command and finish
		--
		insert into #proctext(procedure_text) values( N'
	exec sp_MSreplraiserror 20516
END
')
	end
	              
	--
	-- send fragments to client
	--
	select procedure_text from #proctext order by c1 asc

END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_del_proc
GO

--
-- Name: sp_MSscript_pub_upd_trig
--
-- Description: This proc is used during the scripting of publisher synctran trigger 
-- used by updating subscribers to force row version change implicitly. This SP 
-- generates a script for UPDATE trigger.It is executed on publisher during 
-- the article creation phase.
--
-- 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_MSscript_pub_upd_trig', 0,1)
go
create procedure sp_MSscript_pub_upd_trig
(
    @publication sysname, 
    @article     sysname,
    @procname    sysname
)
as
begin
    declare @cmd       nvarchar(4000)
    declare @qualname  nvarchar(512)
    declare @objid	   int
    declare @columns   binary(32)
                ,@retcode int

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

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


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

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

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

    exec dbo.sp_MSflush_command @cmd output, 1

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

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

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

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

raiserror('Creating procedure sp_MSmakeconflicttable', 0,1)
go
create procedure sp_MSmakeconflicttable (
	@article sysname, 
	@publication sysname,
	@creation_mode bit = 0, 	-- 0 = for publisher, 1 = for subscriber (snapshot)
	@is_debug bit = 0)	
as
begin
	--
	-- variables
	--
	declare @retcode	int
			,@cmd		nvarchar(4000)
			,@qualname	nvarchar(540)
			,@basetablename nvarchar(540)
			,@id 		int
			,@colid		int
			,@colname	sysname
			,@col		sysname
			,@coltype	sysname
			,@iscolnullable	bit
			,@dbname		sysname
			,@ownername	sysname
			,@tablename	sysname
			,@basetableid int
			,@columns	varbinary(32)
			,@isset		int
			,@tabid		int
			,@artid		int
			,@pubid		int
			,@indid		int
			,@indkey		int
			,@key		sysname
			,@indexname	sysname
			,@mode_publisher bit
			,@mode_subscriber bit
			,@is_queued bit

	set nocount on
	select @dbname = db_name()
	select @mode_publisher = 0, @mode_subscriber = 1

	--
	-- Check and make sure the base table exists
	--
	select	@artid = a.artid, @basetableid = a.objid, 
			@basetablename = object_name(a.objid), @columns = a.columns, 
			@pubid = a.pubid, @is_queued = NULLIF(p.allow_queued_tran, 0)
	from sysarticles a, syspublications p
	where	a.name = @article and
			p.name = @publication and
			a.pubid = p.pubid
	if (@basetableid is null or @basetableid = 0)
	begin
		raiserror('sp_MSmakeconflicttable(debug): bad basetableid = %d', 16, 1, @basetableid)
		return (1)
	end

	--
	-- If the publication does not allowed queued tran, return
	--
	if (@is_queued != 1)
		return 0

	--
	-- get the article owner
	--
    select @ownername = user_name(o.uid) 
	from sysobjects o , sysarticles a 
	where	o.id=a.objid and 
			a.name=@article

	--
	-- base table should be owner qualified
	--
	select @basetablename = QUOTENAME(@ownername) + N'.' + QUOTENAME(@basetablename)
	
	--
	-- Prepare the name for the Conflict table, index
	--
	if (@creation_mode = @mode_publisher)
	begin
		--
		-- creating on publisher - get unique names for table, index
		--
		exec @retcode = sp_MSgettranconflictname @publication=@publication, 
							@source_object=@basetablename, 
							@str_prefix='conflict_', 
							@conflict_table=@tablename OUTPUT
		if (@retcode != 0 or @@error != 0)
		begin
			raiserror('sp_MSmakeconflicttable(debug): sp_MSgettranconflictname failed for cft name', 16, 1)
			return (1)
		end

		exec @retcode = sp_MSgettranconflictname @publication=@publication, 
							@source_object=@basetablename, 
							@str_prefix='cftind_', 
							@conflict_table=@indexname OUTPUT
		if (@retcode != 0 or @@error != 0)
		begin
			raiserror('sp_MSmakeconflicttable(debug): sp_MSgettranconflictname failed for cft index', 16, 1)
			return (1)
		end
	end
	else
	begin
		--
		-- Get the destination owner
		--
		select	@ownername = dest_owner
		from sysarticles 
		where artid = @artid and pubid = @pubid
		
		--
		-- creating for subscriber, get the names from existing
		-- table on publisher
		--
		select @id = conflict_tableid, @tablename = OBJECT_NAME(conflict_tableid) 
		from sysarticleupdates
		where artid = @artid and pubid = @pubid

		exec @indid = dbo.sp_MStable_has_unique_index @id
		if (@indid = 0)
		begin
			raiserror('sp_MSmakeconflicttable(debug): no unique index for cft table', 16, 1)
			return (1)
		end
			
		select @indexname = name
		from sysindexes 
		where indid = @indid and id = @id
	end
	
	--
	-- Qualify the Conflict tablename
	--
	select @qualname = case 
		when (@ownername is null or @ownername = ' ') then QUOTENAME(@tablename)
				else QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename) end

	--
	-- To check if specified object exists in current database drop it if it exists
	-- Do this only if we are creating for Publisher
	--
	if (@creation_mode = @mode_publisher)
	begin
		select @id = object_id(@qualname)
		if @id is not NULL
		begin
			execute( N'drop table ' + @qualname )
			if (@@error != 0)
			begin
				raiserror('sp_MSmakeconflicttable(debug): could not drop cft table', 16, 1)
				return (1)
			end
		end
	end

	--
	-- begin tran
	--
	begin tran sp_MSmakeconflicttable

	--
	-- create 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 (step int identity NOT NULL, cmdtext nvarchar(4000) NULL)

	if (@creation_mode = @mode_subscriber)
	begin
		select @cmd = N'DROP TABLE ' + @qualname + N'
'
		insert into dbo.tempcmd(cmdtext) values(@cmd)
		insert into dbo.tempcmd(cmdtext) values(N'GO
')		
	end
	
	select @cmd = N'CREATE TABLE ' + @qualname + N'('
	insert into dbo.tempcmd(cmdtext) values(@cmd)

	--
	-- Declare the cursor to get info on each column of base table
	--
	declare #hcurColumnInfo cursor local FAST_FORWARD FOR
		select colid,
		isnullable
		from syscolumns
		where iscomputed = 0 and id=@basetableid 
		order by colid
	FOR READ ONLY

	select @cmd = NULL
	open #hcurColumnInfo
	fetch #hcurColumnInfo into @colid, @iscolnullable
	while (@@FETCH_STATUS = 0)
	begin
		-- Check if this column is included for replication
		if (@columns is null)
			select @isset = 1
		else
			exec @isset = dbo.sp_isarticlecolbitset @colid, @columns

		-- Get the typestring for this column
		-- Skip this column if it is NULL
		if ( @isset != 0 )
		begin		
			exec @retcode = dbo.sp_MSget_type @basetableid, @colid, @colname output, @coltype OUTPUT
			if (@@ERROR!= 0 or @retcode != 0)
			begin
				raiserror('sp_MSmakeconflicttable(debug): sp_MSget_type failed', 16, 1)
				rollback tran sp_MSmakeconflicttable
				return (1)
			end

			if (@coltype IS NULL)
				select @isset = 0
		end
			
		-- process the column ?
		if ( @isset != 0 )
		begin		
			-- Initialize
			if (@cmd is NULL)
				select @cmd = N'	'
			else
				select @cmd = N'	,'

			-- Create the column info
			select @cmd = @cmd + quotename(@colname) + N' ' 
			select @cmd = @cmd + @coltype
			
			-- Apply nullability
			if (@iscolnullable = 1)
				select @cmd = @cmd + N' NULL'
			else
				select @cmd = @cmd + N' NOT NULL'

			-- insert into the temptable
			insert into dbo.tempcmd(cmdtext) values(@cmd)
		end

		-- do the next fetch
		fetch #hcurColumnInfo into @colid, @iscolnullable
	end

	close #hcurColumnInfo
	deallocate #hcurColumnInfo

	--
	-- Now add the conflict related columns
	--
	insert into dbo.tempcmd(cmdtext) values(N'	,origin_datasource nvarchar(255) NULL
	,conflict_type int NULL
	,reason_code int NULL
	,reason_text nvarchar(720) NULL
	,pubid int NULL
	,tranid nvarchar(40) NULL
	,insertdate datetime NOT NULL
	,qcfttabrowid uniqueidentifier DEFAULT NEWID() NOT NULL)
	')

	--
	-- Create an unique index - we add some more fields to the index of base table
	--
	exec @indid = dbo.sp_MStable_has_unique_index @basetableid
	if (@indid = 0)
	begin
		raiserror('sp_MSmakeconflicttable(debug): no unique index for base table', 16, 1)
		rollback tran sp_MSmakeconflicttable
		return (1)
	end

	if (@creation_mode = @mode_subscriber)
	begin
		insert into dbo.tempcmd(cmdtext) values(N'GO
')		
	end

	insert into dbo.tempcmd(cmdtext) values(N'
	CREATE UNIQUE INDEX ' + quotename(@indexname) + ' ON ' +  @qualname  + N'(')

	select @cmd = NULL
	select @indkey = 1
	while (@indkey <= 16)
	begin	
		select @key = index_col(@basetablename, @indid, @indkey)
		if (@key is not null)
		begin
			-- make sure we are replicating this column
			if (@columns is null)
				select @isset = 1
			else
			begin
				-- map the index to the right column in base table
				exec dbo.sp_MSget_col_position @basetableid, @columns, @key, @col output, @colid output
				exec @isset = dbo.sp_isarticlecolbitset @colid, @columns
			end
				
			if (@isset = 1)
			begin
				if (@cmd is NULL)
					select @cmd = quotename(@key)
				else
					select @cmd = @cmd + N', ' + quotename(@key)
			end
		end
		select @indkey = @indkey + 1
	end
	
	--
	-- Add two more fields in the index
	--
	if (@cmd is NULL)
		select @cmd = N'tranid, qcfttabrowid'
	else
		select @cmd = @cmd + N', tranid, qcfttabrowid'
	insert into dbo.tempcmd(cmdtext) values(@cmd + N')')

	--
	-- If we are creating on publisher
	-- create the table now and update sysarticleupdates now
	--
	if (@creation_mode = @mode_publisher)
	begin
		if (@is_debug = 0)
		begin
			--
			-- create the table now
			--
			select @cmd = 'select cmdtext from dbo.tempcmd order by step'
			exec @retcode = master..xp_execresultset @cmd, @dbname
			if (@@error != 0 or @retcode != 0)
			begin
				raiserror('sp_MSmakeconflicttable(debug): xp_execresultset failed', 16, 1)
				rollback tran sp_MSmakeconflicttable
				return (1)
			end

			--
			-- update sysarticleupdates
			--
			select @tabid = id from sysobjects where name = @tablename
			if (@tabid = 0 or @tabid is NULL)
			begin
				raiserror('sp_MSmakeconflicttable(debug): cft table not created after xp_execresultset', 16, 1)
				rollback tran sp_MSmakeconflicttable
				return (1)
			end
			else
			begin
				update dbo.sysarticleupdates set conflict_tableid = @tabid
					where artid = @artid and pubid = @pubid

				-- mark the table as system object
				if (@ownername in ('dbo','INFORMATION_SCHEMA'))
				begin
					exec @retcode = dbo.sp_MS_marksystemobject @tablename
					if (@@error != 0 or @retcode != 0)
					begin
						-- roll back the tran
						raiserror('sp_MSmakeconflicttable(debug): sp_MS_marksystemobject exec failed for cft table', 16, 1)
						rollback tran sp_MSmakeconflicttable
						return (1)
					end
				end
			end
		end
		else
			select cmdtext from dbo.tempcmd order by step
	end

	--
	-- commit the tran
	--
	commit tran	

	--
	-- If we are creating for subscriber then
	-- just to a select on the temp table
	--
	if (@creation_mode = @mode_subscriber)
	begin
		select cmdtext from dbo.tempcmd order by step
	end

	-- drop the table we created
	drop table dbo.tempcmd
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSmakeconflicttable 
go

dump tran master with no_log
go

--
-- sp_scriptsubconflicttable
--
-- This proc is used when the user is creating a nosync queued subscription.
-- It generates the script for creating conflict table on subscriber for a 
-- given queued subscription article. The SP is executed on the publisher.publisher_db 
-- and it generates the script which is executed on the subscriber.subscriber_db
-- See the docs for more information on creation of nosync queued subscription.
-- 
-- Parameters:
--    @publication    sysname - name of publication we are subscribing to
--    @article    sysname - name of the subscribed article
--
-- Return :
--    0 if successfull, 1 otherwise
--
-- Rowset
--    Return script to create the conflict table for the given article
--
print ''
print 'Creating procedure sp_scriptsubconflicttable'
go
create proc sp_scriptsubconflicttable (
	@publication sysname
	,@article sysname
	)
as
begin
	declare @retcode int

    --
    -- Security Check.
    --
	exec @retcode = dbo.sp_MSreplcheck_publish
	if (@@error != 0 or @retcode != 0)
		return (1)

	--
	-- Parameter Check: @publication.
	-- The @publication cannot be NULL and must conform to the rules
	-- for identifiers.
	--
	if (@publication IS NULL)
	begin
		raiserror (14043, 16, 2, '@publication')
		return (1)
	end
	exec @retcode = dbo.sp_validname @publication
	if (@retcode != 0)
		return (1)

	--
	-- Parameter Check: @article.
	-- The @article cannot be NULL and must conform to the rules
	-- for identifiers.
	--	
	if @article IS NULL
	begin
		raiserror (14043, 16, 3, '@article')
		return (1)
	end
	exec @retcode = dbo.sp_MSreplcheck_name @article
	if (@@error != 0 or @retcode != 0)
		return (1)

	if LOWER(@article) = 'all'
	begin
		raiserror (14032, 16, 2, '@article')
		return (1)
	end

	--
	-- now call the SP to generate the script
	--
	exec @retcode = dbo.sp_MSmakeconflicttable @article, @publication, 1
	return @retcode
end
go

EXEC dbo.sp_MS_marksystemobject sp_scriptsubconflicttable
GO

print ''
print 'Creating procedure sp_MSgen_sync_tran_procs'
go
create procedure sp_MSgen_sync_tran_procs (
	@publication    sysname,        -- table name 
	@article        sysname,
	@ins_proc       sysname,
	@upd_proc       sysname,
	@del_proc       sysname,
	@upd_trig		sysname
)
as
begin
    set nocount on

	declare @cmd nvarchar(4000)
			,@procname nvarchar(517)
			,@dbname sysname
			,@owner sysname
			,@retcode int

    select @owner = user_name(o.uid) from sysobjects o , sysarticles a where o.id=a.objid and a.name=@article

    -- We are now going to create procs, so start a transaction
    begin tran gen_procs
		
		-- Call out to individual create proc routines      
		select @dbname = db_name()
		select @cmd = N'sp_MSscript_sync_ins_proc ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@article) collate database_default  + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@ins_proc) collate database_default + N''''
		exec @retcode = master.dbo.xp_execresultset @cmd, @dbname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end

		select @cmd = N'sp_MSscript_sync_upd_proc ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@article) collate database_default + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@upd_proc) collate database_default + N''''
		exec @retcode = master.dbo.xp_execresultset @cmd, @dbname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end

		select @cmd = N'sp_MSscript_sync_del_proc ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@article) collate database_default  + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@del_proc) collate database_default + N''''
		exec @retcode = master.dbo.xp_execresultset @cmd, @dbname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end

		select @cmd = N'sp_MSscript_pub_upd_trig ''' + master.dbo.fn_MSgensqescstr(@publication) collate database_default + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@article) collate database_default  + 
				N''', ''' + master.dbo.fn_MSgensqescstr(@upd_trig) collate database_default + N''''
		exec @retcode = master.dbo.xp_execresultset @cmd, @dbname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end

		-- Grant permissions
		select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@ins_proc) + ' to public'
		exec (@cmd)
		if (@@error != 0)
		begin
			rollback tran gen_procs
			return 1
		end
		select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@upd_proc) + ' to public'
		exec (@cmd)
		if (@@error != 0)
		begin
			rollback tran gen_procs
			return 1
		end
		select @cmd = 'grant exec on ' + quotename(@owner) + '.' + quotename(@del_proc) + ' to public'
		exec (@cmd)
		if (@@error != 0)
		begin
			rollback tran gen_procs
			return 1
		end

		-- Mark procedures as system procs so they don't show up in the UI
		if @owner in ('dbo','INFORMATION_SCHEMA')
		begin
			select @procname = @owner + '.' + @ins_proc
			exec @retcode = dbo.sp_MS_marksystemobject @procname
			if (@@error != 0 or @retcode != 0)
			begin
				rollback tran gen_procs
				return 1
			end
			select @procname = @owner + '.' + @upd_proc
			exec @retcode = dbo.sp_MS_marksystemobject @procname
			if (@@error != 0 or @retcode != 0)
			begin
				rollback tran gen_procs
				return 1
			end
			select @procname = @owner + '.' + @del_proc
			exec @retcode = dbo.sp_MS_marksystemobject @procname
			if (@@error != 0 or @retcode != 0)
			begin
				rollback tran gen_procs
				return 1
			end
			select @procname = @owner + '.' + @upd_trig
			exec @retcode = dbo.sp_MS_marksystemobject @procname
			if (@@error != 0 or @retcode != 0)
			begin
				rollback tran gen_procs
				return 1
			end
		end

		-- Mark procedures to set 'NOT FOR REPL' bit
		select @procname = @owner + '.' + @ins_proc
		exec @retcode = dbo.sp_MSmark_proc_norepl @procname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end
		select @procname = @owner + '.' + @upd_proc
		exec @retcode = dbo.sp_MSmark_proc_norepl @procname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end
		select @procname = @owner + '.' + @del_proc
		exec @retcode = dbo.sp_MSmark_proc_norepl @procname
		if (@@error != 0 or @retcode != 0)
		begin
			rollback tran gen_procs
			return 1
		end

    -- Commit tran
    commit tran
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSgen_sync_tran_procs
GO

print ''
print 'Creating procedure sp_articlesynctranprocs'
go

CREATE PROCEDURE sp_articlesynctranprocs
    @publication sysname,         -- publication name 
    @article sysname,              -- article name 
    @ins_proc sysname,       -- name of sproc supporting Sync Tran inserts associated with this article
    @upd_proc sysname,       -- name of sproc supporting Sync Tran updates associated with this article
    @del_proc sysname,       -- name of sproc supporting Sync Tran deletes associated with this article
    @autogen       nvarchar(5) = 'true', -- indicates wether or not to auto generate sprocs
    @upd_trig sysname
AS
    SET NOCOUNT ON

    -- Declarations.
    DECLARE @pubid int
    DECLARE @artid int
    DECLARE @retcode int
    DECLARE @autogen_id bit
    DECLARE @ins_proc_id int
    DECLARE @upd_proc_id int
    DECLARE @del_proc_id int
    DECLARE @upd_trig_id int
    
    /* 
    ** Security Check.
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)
    
    -- Parameter Check: @article. The @article name cannot be NULL and must conform 
    -- to the rules for identifiers.
    IF @article IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@article')
            RETURN (1)
        END

    EXECUTE @retcode = dbo.sp_validname @article
    IF @retcode <> 0
        RETURN(1)
    
    -- Parameter Check: @publication.
    -- The @publication name cannot be NULL and must conform to the rules
    -- for identifiers.
    IF @publication IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publication')
            RETURN (1)
        END

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

    -- Parameter Check: @ins_proc, @upd_proc, @del_proc, @upd_trig
    -- The sproc names cannot be NULL and must conform to the rules
    -- for identifiers

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

    EXECUTE @retcode = dbo.sp_validname @ins_proc
    IF @retcode <> 0
        RETURN (1)

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

    EXECUTE @retcode = dbo.sp_validname @upd_proc
    IF @retcode <> 0
        RETURN (1)

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

    EXECUTE @retcode = dbo.sp_validname @del_proc
    IF @retcode <> 0
        RETURN (1)

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

    EXECUTE @retcode = dbo.sp_validname @upd_trig
    IF @retcode <> 0
        RETURN (1)

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

    IF LOWER(@autogen collate SQL_Latin1_General_CP1_CS_AS) = 'true' 
        SELECT @autogen_id = 1
    ELSE 
        SELECT @autogen_id = 0

    -- Retrieve pubid & artid
    SELECT @pubid = a.pubid, @artid = a.artid 
    FROM sysarticles a, syspublications p
    WHERE p.name = @publication AND a.name = @article AND
        a.pubid = p.pubid
    IF @pubid IS NULL OR @artid IS NULL
    BEGIN
        if @pubid IS NULL RAISERROR (20026, 16, 1, @publication)
        if @artid IS NULL RAISERROR (20026, 16, 1, @publication)
        RETURN (1)
    END

       BEGIN TRAN sp_articlesynctranprocs

        -- if @autogen is true, generate the sprocs
        IF @autogen_id = 1
        BEGIN
            EXECUTE @retcode =  dbo.sp_MSgen_sync_tran_procs @publication, @article, 
                @ins_proc, @upd_proc, @del_proc, @upd_trig
            IF @retcode <> 0
            BEGIN
                IF @@TRANCOUNT <> 0
                    ROLLBACK tran sp_articlesynctranprocs
                RETURN (1)
            END
        END

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

        IF (@ins_proc_id IS NULL) OR (@upd_proc_id IS NULL) OR (@del_proc_id IS NULL) OR
            (@upd_trig_id IS NULL)             
        BEGIN
            if @ins_proc_id IS NULL RAISERROR (20500, 16, 1, @ins_proc)
            if @upd_proc_id IS NULL RAISERROR (20500, 16, 1, @upd_proc)
            if @del_proc_id IS NULL RAISERROR (20500, 16, 1, @del_proc)
            if @upd_trig_id IS NULL RAISERROR (20500, 16, 1, @upd_trig)
            IF @@TRANCOUNT <> 0
                ROLLBACK tran sp_articlesynctranprocs
            RETURN (1)
        END

        -- perform insert into sysarticleupdates
        -- need to mark this as a system table, so this sproc can live in master db
        INSERT sysarticleupdates(pubid, artid, sync_ins_proc, sync_upd_proc, sync_del_proc, autogen, sync_upd_trig)
            VALUES (@pubid, @artid, @ins_proc_id, @upd_proc_id, @del_proc_id, @autogen_id, @upd_trig_id)

        IF @@ERROR <> 0
            BEGIN
                IF @@TRANCOUNT <> 0
                    ROLLBACK tran sp_articlesynctranprocs
                RETURN (1)
            END

    COMMIT TRAN
go

EXEC dbo.sp_MS_marksystemobject sp_articlesynctranprocs
GO

print ''
print 'Creating procedure sp_reinitsubscription'
go

CREATE PROCEDURE sp_reinitsubscription (
    @publication sysname = 'all',    /* publication name */
    @article sysname = 'all',        /* article name */
    -- Force user to specify the subscriber name
    @subscriber sysname,             /* subscriber name */
    @destination_db sysname = 'all'   /* destination database name */
	,@for_schema_change bit = 0
) AS

    DECLARE @retcode int
    DECLARE @distributor sysname
    DECLARE @distribdb sysname
    declare @active tinyint
    declare @subscribed tinyint
    declare @automatic tinyint
    DECLARE @artid int
    DECLARE @distproc nvarchar (255)
    DECLARE @dbname sysname
    DECLARE @sub_ts binary(10) -- must be binary(10) type.
    DECLARE @sync_type tinyint
    DECLARE @immediate_sync bit
    DECLARE @subscription_type int
    DECLARE @push int
    DECLARE @pub sysname
    DECLARE @dest_db sysname
    DECLARE @sub_name sysname
    DECLARE @art_name sysname
    DECLARE @none tinyint
    declare @login_name sysname


  
    -- Initialization
    select @active = 2
    select @subscribed = 1
    select @dbname = DB_NAME()
    SELECT @none = 2            /* Const: synchronization type 'none' */
    SELECT @automatic = 1       /* Const: synchronization type 'automatic' */
    select @push = 0

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

    /* Validate names */

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

    /* article name can be a quoted name
    EXECUTE @retcode = dbo.sp_validname @article
    IF @@ERROR <> 0 OR @retcode <> 0
        RETURN (1)
    */

    -- Subscriber can be NULL
    IF @subscriber IS NOT NULL
    BEGIN
        EXECUTE @retcode = dbo.sp_validname @subscriber
        IF @@ERROR <> 0 OR @retcode <> 0
            RETURN (1)

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

    -- Replace 'all' with '%'
    if LOWER(@publication) = 'all'
        SELECT @publication = '%'

    if LOWER(@article) = 'all'
        SELECT @article = '%'

    if LOWER(@subscriber) = 'all'
        SELECT @subscriber = '%'

    if LOWER(@destination_db) = 'all'
        SELECT @destination_db = '%'

    /*
    ** Parameter Check:  @publication
    ** Check to make sure that the publication exists, that it's not NULL,
    ** and that it conforms to the rules for identifiers.
    */
    IF NOT EXISTS (SELECT * FROM syspublications WHERE name LIKE @publication)
        BEGIN
        IF @publication = '%'
                RAISERROR (14008, 11, -1)
        ELSE
                RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
        END

    /*
    ** Parameter Check:  @article
    ** Check to make sure that the article exists, that it's not null,
    ** and that it conforms to the rules for identifiers.
    */
    IF NOT EXISTS (SELECT *
                     FROM 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

    -- Don't check subscriber and dest_db for virtual subscriptions
    IF @subscriber IS NOT NULL and @subscriber <> N'%'
    BEGIN    
        /*
        ** Parameter Check:  @subscriber
        ** Check to make sure that the subscriber exists
        */
        select @subscriber = UPPER(@subscriber)
        
        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

    -- Wrong dest_db will be caught by the following query

    -- Check to make sure the subscription exists 
    IF  @publication <> '%' AND
        @subscriber <> '%' AND

        NOT EXISTS (SELECT *
          FROM syssubscriptions sub,
               sysextendedarticlesview art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication collate database_default
           AND art.name LIKE @article collate database_default
           AND ((UPPER(ss.srvname) = UPPER(@subscriber) collate database_default
           AND sub.srvid = ss.srvid)
           OR (@subscriber is NULL 
           AND pub.allow_anonymous = 1))
           AND sub.artid = art.artid
           AND art.pubid = pub.pubid
           AND ((@destination_db = N'%') OR (sub.dest_db = @destination_db collate database_default)))
    BEGIN
        RAISERROR (14055, 16, -1)
        RETURN (1)
    END

    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                       @distribdb = @distribdb OUTPUT
    IF @retcode <> 0 OR @@ERROR <> 0
        RETURN (1)

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

    DECLARE hCresyncsub CURSOR LOCAL FAST_FORWARD FOR
        -- non immediate_sync pubs
        SELECT pub.name,
               pub.immediate_sync,
               art.name,
               ss.srvname,
               sub.dest_db,
               sub.sync_type,
               sub.subscription_type,
               sub.login_name
          FROM syssubscriptions sub,
               sysextendedarticlesview art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication
           AND art.name LIKE @article
           AND ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) 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 collate database_default))
           AND sub.status = @active
           AND pub.immediate_sync = 0
        
        UNION
        -- Immediate_sync pubs
        SELECT DISTINCT
               pub.name,
               immediate_sync,
			   -- If @article is '%', do publication level operation.
			   -- otherwise, do article level
               case @article 
					when '%' then '%'
					else art.name
					end, 
               ss.srvname,
               sub.dest_db,
               sub.sync_type,
               sub.subscription_type,
               sub.login_name
          FROM syssubscriptions sub,
               sysextendedarticlesview art,
               syspublications pub,
               master..sysservers ss
         WHERE pub.name LIKE @publication collate database_default -- Ignore @article
           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 collate database_default))
           AND sub.status = @active
           AND pub.immediate_sync = 1
                 
        UNION
        -- For anonymous subscribers or attached subscriptions.
        SELECT DISTINCT pub.name,
               immediate_sync,
			   -- If @article is '%', do publication level operation.
			   -- otherwise, do article level
               case @article 
					when '%' then '%'
					else art.name
					end, -- art.name is '%' from immediate_sync pub
               CONVERT(sysname, NULL), -- subscriber name (null represent virtual)
               'virtual', -- destination_db for virtual subscription is hardcoded in 
                         -- sp_MSadd_subscription.
               @automatic, -- sub.sync_type is auto tor anonymous subscriber
               @push,      -- virtual subscription is push type,
               'sa'
          FROM syspublications pub,
               sysarticles art
         WHERE pub.name LIKE @publication -- Ignore @article
           AND art.name LIKE @article
           AND art.pubid = pub.pubid
           AND pub.immediate_sync = 1
           AND (@subscriber = '%' OR @subscriber IS NULL) 
                 
    FOR READ ONLY

    OPEN hCresyncsub 

    -- Note: Don't overwrite the variables used in the cursor.
    FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
        @dest_db, @sync_type, @subscription_type, @login_name

    WHILE (@@fetch_status <> -1)
    BEGIN
        -- Security Check
        IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
            AND is_member ('db_owner') <> 1
        BEGIN
                RAISERROR (14126, 11, -1)
                RETURN (1)
        END

        if @sync_type = @none
        begin
		raiserror(21071, 10, -1, @art_name, @sub_name, @dest_db, @pub)
		FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
			@dest_db, @sync_type, @subscription_type, @login_name
		continue
        end

        begin tran
        save TRAN sp_reinitsubscription

        -- Reset subscription status to subscribed.
		-- It will be reactivated later as following:
		-- 1. Well known on non immediate_sync: it need to be reactivated by snapshot agent
		-- 2. Well known on immediate_sync: it will be reactivated laster in 
		-- this stored procedure to the state of virtual subscription. The status will be 
		-- active if the virtual subscription is active.
		-- 3. Anonymous (on immediate_sync by design): Only reset the status to subscribed
		-- if a single article is reinited or there's a schema change on the article. 
		-- (refer to sp_MSreinit_article.) In this case, the status will be reactivated by
		-- snapshot agent. If the whole publication is reinited and it is not for a schema 
		-- change, we don't need to do this 
		-- since the anonymous agent will automatically pick up latest snapshots after
		-- we reset the subscription guid later.

		-- If @sub_name is null, we are resetting anonymous subscriptions.
		-- Don't do this when reiniting anonymous subscription on whole publication.
        IF not (@sub_name IS NULL and @article = '%') or @for_schema_change = 1
        BEGIN
            EXEC @retcode = dbo.sp_changesubstatus
                @publication = @pub,
                @article = @art_name,
                @subscriber = @sub_name,
                @destination_db = @dest_db,
                @status = 'subscribed'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCresyncsub
                DEALLOCATE hCresyncsub
                RAISERROR (14070, 16, -1)
                GOTO UNDO
            END
        END

		-- Don't do this when reiniting a single article.
        -- Reset the subscription guid at the distributor for immediate_sync publication.
     	-- Reset subscription creation datetime for all types of publication
		-- used by retention cleanup.
		if @article = '%'
		begin
			SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSreset_subscription'
			EXEC @retcode = @distproc 
				@publisher = @@SERVERNAME, 
				@publisher_db = @dbname, 
				@publication = @pub,
				@subscriber = @sub_name, 
				@subscriber_db = @dest_db,
				@subscription_type = @subscription_type

			IF @@ERROR <> 0 OR @retcode <> 0
			BEGIN
				CLOSE hCresyncsub
				DEALLOCATE hCresyncsub
				GOTO UNDO
			END
		end

        -- Activate the subscription again if the publication is immediate_sync and
		-- the whole publication is reinitted.
        -- Otherwise, the snapshot agent will activate the subscription
		
		-- If this is for schema change, commands generated by the LR will be invalid
		-- until the new snapshot is generated and applied so DON'T reactivate. 
		-- Let the snapshot agent do it.

        --IF (@for_schema_change = 0 AND @immediate_sync = 1 AND @subscriber IS NOT NULL)
        IF (@for_schema_change = 0 and 
				@immediate_sync = 1 AND 
				@subscriber IS NOT NULL and 
				@article = '%')
        BEGIN
            -- Set subscription status back to active again.
            EXEC @retcode = dbo.sp_changesubstatus
                @publication = @pub,
                @article = @art_name,
                @subscriber = @sub_name,
                @destination_db = @dest_db,
                @status = 'active'
            IF @@ERROR <> 0 OR @retcode <> 0
            BEGIN
                CLOSE hCresyncsub
                DEALLOCATE hCresyncsub
                RAISERROR (14070, 16, -1)
                GOTO UNDO
            END
        END
		
		-- If article level reinit, reinit dependent articles in the publication as well	
		if @article <> '%'
		begin
			-- Reinit articles on which the current article depends on.
			declare @objid int, @pubid int, @srvid smallint,
				@pre_creation_cmd tinyint
			select @pubid = pubid from syspublications where name = @pub
			select @objid = objid,
					@pre_creation_cmd = pre_creation_cmd from sysarticles where 
				pubid = @pubid and 
				name = @art_name
			-- @sub_name is from sysservers, no need to upper it.
			select @srvid = srvid from master..sysservers where srvname = @sub_name collate database_default
			-- set virtual id if needed
			if @srvid is null
				select @srvid = -1

			-- Have to use temp cursor name otherwise we will get a 'cursor already exists' error
			-- in recursive calls.
			DECLARE #hCdep CURSOR LOCAL FAST_FORWARD FOR
				SELECT distinct art.name from sysextendedarticlesview art, syssubscriptions s where
					art.pubid = @pubid and
					s.artid = art.artid and
					s.srvid = @srvid and
					s.dest_db = @dest_db and
					s.status = @active and
					-- Has dri on referencing table or not
					(convert(int, substring(art.schema_option, len(art.schema_option) - 2 + 1, 2)) & 0x00000200 <> 0 and
					  -- If the article schema option includes DRI, reinit articles that have 
					  -- forein key relationship on this table, have to do this
					  -- otherwise dist will fail because we cannot drop or delete base table.
					  exists ( select * from  sysreferences r where
							r.rkeyid = @objid and
							art.objid = r.fkeyid) or
					  -- If there's a schema bound view on this table, reinit that view etc.
					  -- We have to do this for schema bound view other wise, we cannot drop the table
					 -- Only do it if precreation command is 'drop table'
					 (@pre_creation_cmd = 1 and
					  exists ( select * from sysdepends d where
							d.depid = @objid and
							art.objid = d.id and
							objectproperty(art.objid, 'IsSchemaBound') = 1)))
			FOR READ ONLY

			OPEN #hCdep

			-- Note: @art_name is changed
			FETCH #hCdep INTO @art_name

			WHILE (@@fetch_status <> -1)
			BEGIN
				EXEC @retcode = dbo.sp_reinitsubscription
					@publication = @pub,
					@article = @art_name,
					@subscriber = @sub_name,
					@destination_db = @dest_db,
					@for_schema_change = @for_schema_change
				IF @@ERROR <> 0 OR @retcode <> 0
					GOTO UNDO
				FETCH #hCdep INTO @art_name
			END
			
			CLOSE #hCdep
			DEALLOCATE #hCdep
		end
	
        COMMIT TRAN 

        FETCH hCresyncsub INTO @pub, @immediate_sync, @art_name, @sub_name, 
            @dest_db, @sync_type, @subscription_type, @login_name
    END

    CLOSE hCresyncsub
    DEALLOCATE hCresyncsub

    RETURN(0)

UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_reinitsubscription
        COMMIT TRAN
    end
    return 1
go

EXEC dbo.sp_MS_marksystemobject sp_reinitsubscription
GO

dump tran master with no_log
GO



--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_MSareallcolumnscomputed'
go
create procedure sp_MSareallcolumnscomputed @tabid int, @colbitmap binary(32)
as
declare @isset int
declare @retcode int
declare @this_col int

select @retcode = 1

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
BEGIN
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @colbitmap
    if @isset != 0 and EXISTS (select name from syscolumns where id=@tabid and @this_col=colid and iscomputed<>1)
	BEGIN 
		select @retcode = 0
		break
	END
	FETCH hCColid INTO @this_col
END
CLOSE hCColid
DEALLOCATE hCColid

return @retcode
GO

EXEC dbo.sp_MS_marksystemobject sp_MSareallcolumnscomputed
GO
-----------------------------------------------------------
-----------------------------------------------------------

print ''
print 'Creating procedure sp_MSgettypestringudt'
go

create procedure sp_MSgettypestringudt @tabid int, @colid int, @typestring nvarchar(255) output
as
declare @coltypename sysname
declare @coltype  tinyint
declare @colusertype smallint
declare @collen   smallint
declare @colprec  tinyint
declare @colscale tinyint

select @coltypename = type_name( sc.xusertype ), @colusertype = sc.xusertype, @coltype = sc.xtype,
       @collen = sc.length, @colprec = sc.xprec, @colscale = sc.xscale
from syscolumns sc 
where sc.id = @tabid
and sc.colid = @colid
--and st.xtype = sc.xtype
--and st.xtype = st.xusertype

select @typestring = @coltypename

-- if it's not a user defined type, script out length/prec/scale as necessary
if @colusertype = @coltype 
begin
	if @coltypename in (N'char', N'varchar', N'binary', N'varbinary')
	begin
		select @typestring = @typestring + N'(' + convert(nvarchar,@collen) + N')'
	end
	else if @coltypename in (N'nchar', N'nvarchar' )
	begin
		select @typestring = @typestring + N'(' + convert(nvarchar,@collen/2) + N')'
	end
	else if @coltype = 108 or @coltype = 106
	begin
		select @typestring = @typestring + N'(' + convert(nvarchar,@colprec) + N',' + convert(nvarchar,@colscale) + N')'
	end
	else if @coltype = 189
	begin
		select @typestring = N'binary(8)'
	end
end
    
go

EXEC dbo.sp_MS_marksystemobject sp_MSgettypestringudt
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Creating procedure sp_gettypestring'
go

create procedure sp_gettypestring @tabid int, @colid int, @typestring nvarchar(255) output
as
declare @coltypename sysname
declare @coltype  tinyint
declare @colvar   bit
declare @collen   smallint
declare @colprec  tinyint
declare @colscale tinyint

select @coltypename = st.name, @coltype = st.xtype, @colvar = st.variable, 
       @collen = sc.length, @colprec = sc.xprec, @colscale = sc.xscale
from systypes st, syscolumns sc 
where sc.id = @tabid
and sc.colid = @colid
and st.xtype = sc.xtype
and st.xtype = st.xusertype

select @typestring = @coltypename

if @coltypename in (N'char', N'varchar', N'binary', N'varbinary')
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@collen) + N')'
end
else if @coltypename in (N'nchar', N'nvarchar' )
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@collen/2) + N')'
end
else if @coltype = 108 or @coltype = 106
begin
    select @typestring = @typestring + N'(' + convert(nvarchar,@colprec) + N',' + convert(nvarchar,@colscale) + N')'
end
else if @coltype = 189
begin
    select @typestring = N'binary(8)'
end
    
go

EXEC dbo.sp_MS_marksystemobject sp_gettypestring
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

raiserror('Creating procedure sp_scriptpkwhereclause', 0,1)
go
create procedure sp_scriptpkwhereclause 
(
@src_objid int, 
@pkcolumns binary(32),
@prefix nvarchar(10) = N'@pkc',
@artcolumns binary(32) = NULL,
@mode tinyint = 1 -- 1 = use article ordering, 2 = column ordering
)
as
begin
    declare @this_col int
    declare @art_col int
    declare @spacer nvarchar(10)
    declare @isset int
    declare @cmd nvarchar(4000)

    declare @modeartorder tinyint
                ,@modecolorder tinyint

    select @modeartorder = 1
            ,@modecolorder = 2
            ,@art_col = 0
            ,@spacer = N' '
            ,@cmd = N'where'

    if (@mode not in (@modeartorder, @modecolorder))
        return 1

    -- create WHERE clause
    DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
    select colid from syscolumns where id = @src_objid order by colid asc

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
        if EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid)
    	begin
    		-- If @artcolumns is not null, it is called from 
    		-- sp_scriptxupdproc or sp_scriptxdelproc
    		-- Use counter in article column bitmap
    		-- Otherwise use counter in pk bitmap
    		if @artcolumns is not null
    		begin
    			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    			if @isset != 0
    				select @art_col = @art_col + 1
    		end
    		exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    		if @isset != 0 
    		begin
    			if @artcolumns is null
    				select @art_col = @art_col + 1
			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = ' 
			--
			-- script the var assignment based on mode
			--
			if (@mode = @modeartorder)
        			select @cmd = @cmd + @prefix + convert( nvarchar, @art_col ) 
    			else
        			select @cmd = @cmd + @prefix + convert( nvarchar, @this_col ) 
    			select @spacer = N' and '
    			if len( @cmd ) > 3000
    			begin
    				insert into #proctext(procedure_text) values( @cmd )
    				select @cmd = N''
    			end
    		end
    	end
    	FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    insert into #proctext(procedure_text) values( @cmd )
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptpkwhereclause
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'sp_MSscript_missing_row_check'
go

create procedure sp_MSscript_missing_row_check 
as

-- Note this must be done immediately after the update or delete statement.
-- create WHERE clause

insert into #proctext(procedure_text) values( N'if @@rowcount = 0' )
begin
	insert into #proctext(procedure_text) values( N'	if @@microsoftversion>0x07320000' )
	insert into #proctext(procedure_text) values( N'		exec sp_MSreplraiserror 20598' )
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSscript_missing_row_check
GO

--------------------------------------------------------------------
--------------------------------------------------------------------

print ''
print 'Create procedure sp_scriptupdateparams'
go

create procedure sp_scriptupdateparams @src_objid int, @artcolumns binary(32), 
@pkcolumns binary(32), -- If it is null we are called by sp_scriptxupdproc
@param_count int = NULL output
as
declare @this_col int
declare @art_col int
declare @spacer nvarchar(10)
declare @isset int
declare @cmd nvarchar(4000)
declare @typestring nvarchar(255)

-- add colval parameters
select @param_count = NULL
select @art_col = 1
select @spacer = N' '
select @cmd = ''

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE ( 1 = 1 )
begin
	if @@fetch_status = -1
	begin
		-- If called by sp_scriptxupdproc and it is the first time
		-- at the end of the cursor loop
		if @pkcolumns is null and @param_count is NULL
		begin
			-- Reset it so that we know we encountered cursor end once.
			select @param_count = 0
			-- Reopen cursor
			CLOSE hCColid
			OPEN hCColid
			FETCH hCColid INTO @this_col
			continue
		end
		else
			break;
	end
	exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
	if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
	begin
		exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
		select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
		select @art_col = @art_col + 1
		select @spacer = N','

		if len( @cmd ) > 3000
		begin
		insert into #proctext(procedure_text) values( @cmd )
			select @cmd = N''
		end
	end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

select @param_count = @art_col -1

-- add pkval parameters
-- If it is null we are called by sp_scriptxupdproc, no need for PK params
if @pkcolumns is not null
begin
	select @art_col = 1

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

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
	begin
	   exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
	   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
	   begin
			exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
			select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
			select @art_col = @art_col + 1
			select @spacer = N','

			if len( @cmd ) > 3000
			begin
			insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		FETCH hCColid INTO @this_col
	end
	CLOSE hCColid
	DEALLOCATE hCColid
end

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

go

EXEC dbo.sp_MS_marksystemobject sp_scriptupdateparams
GO


print ''
print 'Creating procedure sp_scriptreconwhereclause'
go

create procedure sp_scriptreconwhereclause @src_objid int, @pkcolumns binary(32), @artcolumns binary(32)
as
declare @this_col int
declare @art_col int
declare @spacer nvarchar(10)
declare @isset int
declare @cmd nvarchar(4000)

-- create WHERE clause

select @art_col = 1
select @spacer = N' '
select @cmd = N'where'

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
	exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
	if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
	begin
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
		if @isset != 0 
		begin
			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
			select @spacer = N' and '

			if len( @cmd ) > 3000
			begin
				insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		select @art_col = @art_col + 1
	end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

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

go

EXEC dbo.sp_MS_marksystemobject sp_scriptreconwhereclause
GO

--
-- Name: sp_script_reconciliation_insproc
--
-- Description: This procedure is used by Snapshot agent to script the custom 
-- command procedure for INSERT. This scripts a reconciliation custom 
-- proc - used only during initialization. 
-- Invoked on 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_reconciliation_insproc', 0,1)
go
create procedure sp_script_reconciliation_insproc (
	@artid int)
as
BEGIN
declare @retcode int
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @artcolumns   binary(32)
declare @pkcolumns    binary(32)
declare @ins_cmd      nvarchar(255)
declare @dest_proc    sysname
declare @this_col     int
declare @art_col      int
declare @isset        int

declare @typestring   nvarchar(255)
declare @spacer       nvarchar(1)
	, @identity_insert bit
	
--
-- security check
--
exec @retcode = dbo.sp_MSreplcheck_publish
if @@error <> 0 or @retcode <> 0
begin
    return (1)
end

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, @ins_cmd = ins_cmd
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid


-- save off cmd fragment

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

insert into #proctext(procedure_text) values( N'as' )

------- construct proc body

---- if already exists, apply as update

insert into #proctext(procedure_text) 
    values( N'if exists ( select * from ' + @dest_owner + QUOTENAME(@dest_tabname) )
exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output
exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
insert into #proctext(procedure_text) values( N')' )
insert into #proctext(procedure_text) values (N'begin')


if( @artcolumns != @pkcolumns )
begin
	-- construct update 

	select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

	-- create SET clause

	select @art_col = 1
	select @spacer = N' '

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

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
		if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
		begin
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
			if @isset = 0
			begin
				if not (@identity_insert = 1 and 
					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
				begin
					select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
					select @spacer = N','

					if len( @cmd ) > 3000
					begin
						insert into #proctext(procedure_text) values( @cmd )
						select @cmd = N''
					end
				end
			end
			select @art_col = @art_col + 1
		end
		FETCH hCColid INTO @this_col
   	end
	CLOSE hCColid
	DEALLOCATE hCColid

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

	exec dbo.sp_scriptreconwhereclause @src_objid, @pkcolumns, @artcolumns
end

-- all article columns are included in the PK, & PK already exists, do nothing
else 
begin
	insert into #proctext(procedure_text ) values( N'return' )
end


insert into #proctext(procedure_text) values (N'end')
insert into #proctext(procedure_text) values (N'else')
insert into #proctext(procedure_text) values (N'begin')

---- normal insert

-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end

-- prepare the column list

select @cmd = N'insert into ' + @dest_owner + QUOTENAME(@dest_tabname) + N' ('
select @art_col = 1
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col))  
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- now the data parameter list

select @cmd = @cmd + N' ) values ('
select @art_col = 1
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
    exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) 
        select @art_col = @art_col + 1
        select @spacer = N','
    end
	FETCH hCColid INTO @this_col
end
CLOSE hCColid
DEALLOCATE hCColid

-- finish up proc body

select @cmd = @cmd + N' )'

-- save off cmd fragement

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

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

insert into #proctext(procedure_text) values (N'end')

-- send fragments to client

select procedure_text from #proctext order by c1 asc
END
go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_insproc
GO

--
-- Name: sp_script_reconciliation_delproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for DELETE. This scripts a reconciliation custom proc - used only during initialization. 
-- Invoked on 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_reconciliation_delproc', 0,1)
go
create procedure sp_script_reconciliation_delproc 
( 
	@artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'


    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go

EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_delproc
GO

--
-- Name: sp_script_reconciliation_xdelproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for DELETE in XCALL format. This scripts a reconciliation custom proc - used only during initialization. 
-- Invoked on 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_reconciliation_xdelproc', 0,1)
go
create procedure sp_script_reconciliation_xdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @columns    binary(32)
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @columns = columns
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc) + N';2'

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
       FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_script_reconciliation_xdelproc
GO

--
-- Name: sp_scriptinsproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for INSERT for CALL format. Invoked on 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_scriptinsproc', 0,1)
go
create procedure sp_scriptinsproc (
	@artid int)
as
BEGIN
declare @cmd          nvarchar(4000)
		,@dest_owner   nvarchar(255)
		,@dest_tabname sysname
		,@src_objid    int
		,@columns      binary(32)
		,@ins_cmd      nvarchar(255)
		,@dest_proc    sysname
		,@this_col     int
		,@art_col      int
		,@isset        int
		,@pubid		  int

		,@identity_insert bit
		,@rc int
		,@colname sysname
		,@ccoltype     sysname
		,@typestring   nvarchar(255)
		,@spacer       nvarchar(1)
		,@queued_check bit
		,@column_string nvarchar(4000)
		,@var_string nvarchar(4000)

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

if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
begin
    raiserror (14155, 16, 1 )
    return 1
end

-------- create temp table for command fragments and insert column list

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @columns = columns, @ins_cmd = ins_cmd,
       @pubid = pubid
from sysarticles
where artid = @artid

-- Check to see if identity insert must be turned on
-- i.e. Does the table has identity that are included in the partition?
exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
--

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- Check if this is a queued publication
select @queued_check = ISNULL(allow_queued_tran, 0) 
from syspublications
where pubid = @pubid

-------- get dest proc name

if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
begin
    raiserror (14156, 16, 1 )
    return 1
end

select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) values( N'go' )
select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

-------- construct parameter list


select @art_col = 1
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
   if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
   begin
        if len( @cmd ) > 3000
        begin
        insert into #proctext(procedure_text) values( @cmd )
            select @cmd = N''
        end

        exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
        select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
        select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- save off cmd fragment

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

select @cmd = N'
AS
BEGIN
'
insert into #proctext(procedure_text) values( @cmd )

------- construct proc body

-- Generate strings for col names and variables
select @art_col = 0
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
	exec @rc = dbo.sp_MSget_colinfo @src_objid, @this_col, @columns, 1, @colname output, @ccoltype output
	if @rc = 0  and EXISTS (select name from syscolumns where id=@src_objid and colid=@this_col and iscomputed<>1)
	begin
		select @art_col = @art_col + 1
		if (@art_col = 1)
		begin
			select @column_string = QUOTENAME(@colname)
			select @var_string = N'@c' + cast(@art_col as nvarchar(4))
		end
		else
		begin
			select @column_string = @column_string + N', ' + QUOTENAME(@colname)
			select @var_string = @var_string + N', @c' + cast(@art_col as nvarchar(4))
		end

		-- transfer column list string to table if too large
		if (len(@column_string) > 3000)
		begin
			insert into #collisttab(procedure_text) values( @column_string )
			select @column_string = ' '
		end
	end
	FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- insert the remaining strings for column list and where clause
insert into #collisttab(procedure_text) values( @column_string )

--
-- If we are a part of queued publication then 
-- insert only if PK or other unique key(s) do not exist
--
if (@queued_check = 1)
begin
    select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
    insert into #proctext(procedure_text) values( @cmd )
    exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                        ,@columns = @columns
                                                        ,@prefix = '@c' 
                                                        ,@mode = 1
    if (@@error != 0 or @rc != 0)
        return 1
    select @cmd = N')
BEGIN'
    insert into #proctext(procedure_text) values( @cmd )
end

-- set identity_insert on
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
	insert into #proctext(procedure_text) values( @cmd )
end

--
-- prepare the insert statement now
--
select @cmd = N'
insert into ' +  @dest_owner + QUOTENAME(@dest_tabname)  + N'( '
insert into #proctext(procedure_text) values( @cmd )
insert into #proctext(procedure_text) 
	select procedure_text from #collisttab order by c1 asc
select @cmd = N' )'
insert into #proctext(procedure_text) values( @cmd )
if @art_col > 0
begin
	select @cmd = N'
values ( '
	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) values( @var_string )
	select @cmd = N' )
'
	insert into #proctext(procedure_text) values( @cmd )
end

-- set identity_insert off
if @identity_insert = 1
begin
	select @cmd = N'
	set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
	insert into #proctext(procedure_text) values( @cmd )
end

--
-- If we are a part of queued publication then 
-- add the block delimiter
--
drop table #collisttab
if (@queued_check = 1)
begin
	select @cmd = N'
END
END'
end
else
	select @cmd = N'
END'
insert into #proctext(procedure_text) values( @cmd )

-- send fragements to client

select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc
GO

--
-- Name: sp_scriptdelproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for DELETE in CALL format. Invoked on 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_scriptdelproc', 0,1)
go
create procedure sp_scriptdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int, @pubid int

    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    
    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 6, len( @del_cmd ) - 4 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid )
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @art_col ) + N' ' + @typestring 
            select @art_col = @art_col + 1
            select @spacer = N','
       end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if exists (select * from syspublications where pubid = @pubid and allow_queued_tran = 0)
    	exec dbo.sp_MSscript_missing_row_check
    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptdelproc
GO

--
-- Name: sp_scriptxdelproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for DELETE in XCALL format. Invoked on 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_scriptxdelproc', 0,1)
go
create procedure sp_scriptxdelproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @columns    binary(32)
    declare @pkcolumns    binary(32)
    declare @del_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @isset        int
    declare @pubid		  int
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @queued_check bit
    		,@qwhere_string nvarchar(4000)

    --
    -- security check
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error <> 0 or @retcode <> 0
    begin
        return (1)
    end
    
    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @del_cmd = del_cmd, @columns = columns
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -- Check if this is a queued publication
    select @queued_check = ISNULL(allow_queued_tran, 0) 
    from syspublications
    where pubid = @pubid

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@del_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @del_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @dest_proc = substring( @del_cmd, 7, len( @del_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)

    -------- construct parameter list


    select @art_col = 1
    select @spacer = N' '

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
       if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
       begin
            if len( @cmd ) > 3000
            begin
            insert into #proctext(procedure_text) values( @cmd )
                select @cmd = N''
            end

            exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
            select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 

    		--
    		-- Queued processing:if this is the row version column : need to add to where clause
    		--
    		if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    			select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )

            select @art_col = @art_col + 1
            select @spacer = N','
       end
       FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

    -- save off 

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )

    ------- construct proc body

    insert into #proctext(procedure_text) values( N'delete ' + @dest_owner + QUOTENAME(@dest_tabname) ) 

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @columns
    if (@queued_check = 1)
    	insert into #proctext(procedure_text) values( @qwhere_string )
    else
    	exec dbo.sp_MSscript_missing_row_check

    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptxdelproc
GO

--
-- Name: sp_scriptupdproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for UPDATE in CALL format. Invoked on 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_scriptupdproc', 0,1)
go
create procedure sp_scriptupdproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @this_col     int
    declare @art_col      int
    declare @pkart_col    int
    declare @isset        int
    declare @pkcomputed   int
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @pubid        int, @allow_queued_tran bit, @need_end bit

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -------- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'CALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 6, len( @upd_cmd ) - 4 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    insert into #proctext(procedure_text) values ( N'as' )

    -------- now create the update statement

    -- construct test to see if pk has changed 
    -- only do this if the article has columns not included in the pk

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    declare @pk_is_identity bit
    select @pk_is_identity = 0

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @cmd = N'if'

        select @art_col = 1
        select @pkart_col = 1
        select @spacer = ' '

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

        OPEN hCColid

        FETCH hCColid INTO @this_col

        select @pk_is_identity = 1
        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col ) + N' = @pkc' + convert( nvarchar, @pkart_col ) 
    					select @spacer = N' and '
    					select @pkart_col = @pkart_col + 1
    					if len( @cmd ) > 3000
    					begin
    					insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end

        CLOSE hCColid
        DEALLOCATE hCColid

    	if @pk_is_identity = 0
    	begin
    		insert into #proctext(procedure_text) values( @cmd )

    		insert into #proctext(procedure_text) values( N'begin' )

    		-- construct update if pk hasn't changed

    		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    		-- create SET clause

    		select @art_col = 1
    		select @spacer = N' '

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

    		OPEN hCColid

    		FETCH hCColid INTO @this_col
    		WHILE (@@fetch_status <> -1)
    		begin
    			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    			begin
    				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    				if @isset = 0
    				begin
    					if not (@keep_identity = 1 and 
    						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    					begin
    						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
    						select @spacer = N','

    						if len( @cmd ) > 3000
    						begin
    							insert into #proctext(procedure_text) values( @cmd )
    							select @cmd = N''
    						end
    					end
    				end
    				select @art_col = @art_col + 1
    			end
    			FETCH hCColid INTO @this_col
    		end
    		CLOSE hCColid
    		DEALLOCATE hCColid

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

    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check

    		insert into #proctext(procedure_text) values( N'end' )
    		insert into #proctext(procedure_text) values( N'else' )
    		insert into #proctext(procedure_text) values( N'begin' )

    		select @need_end = 1

    	end
    end -- end if artcols != pkcols


    -- construct update if pk has changed

    select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    -- create SET clause

    select @art_col = 1
    select @spacer = N' '

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

    OPEN hCColid

    FETCH hCColid INTO @this_col
    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = @c' + convert( nvarchar, @art_col ) 
    			select @spacer = N','

    			if len( @cmd ) > 3000
    			begin
    			insert into #proctext(procedure_text) values( @cmd )
    				select @cmd = N''
    			end
    		end
    		select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

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

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if @allow_queued_tran <> 1
    	exec dbo.sp_MSscript_missing_row_check

    if @need_end = 1
    	insert into #proctext(procedure_text) values( N'end' )
    -- flush to client

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptupdproc
GO

--
-- Name: sp_scriptmappedupdproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for UPDATE in MCALL format. Invoked on 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_scriptmappedupdproc', 0,1)
go
create procedure sp_scriptmappedupdproc 
(
    @artid int
)
as
begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @art_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @pkart_col    int
    declare @isset        int
    declare @bytestr      nvarchar(10)
    declare @bitstr       nvarchar(10)
    declare @typestring   nvarchar(255)
    declare @spacer       nvarchar(10)
    declare @update_created  bit
    declare @pkcomputed   int
    declare @pubid        int, @allow_queued_tran bit

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

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

    -------- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
    	   @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'MCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
      

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    ----- add changed data bitmap

    select @art_col = 1


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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
       begin
            select @art_col = @art_col + 1
       end
       FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- Note that bitmap size is based on number of article columns
    -- (computed by loop above) not source table columns

    select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )


    -- construct IF statement to examine colbitmap and determine if a 
    -- primary key column has been updated.  

    -- do this only if the article contains columns not included in the pk
    -- and at least one of the columns in the PK is real ( i.e. not computed )

    -- note that if all the article columns are PK columns, we will
    -- construct the 'update all columns including PK columns' statement
    -- w/o a preceeding IF, and we will NOT construct the 'only update non-pk columns' 
    -- part of the procedure

    -- also note that this is pretty much worthless since 7.0 and above are
    -- guaranteed to NEVER generate an UPDATE if a PK columns is updated... oh well.
    declare @pk_is_identity bit
    select @pk_is_identity = 0

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @art_col = 1
        select @spacer = N' '

        select @cmd = N'if'

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

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	select @pk_is_identity = 1

        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin 
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    					select @cmd = @cmd + @spacer + N'substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    							 N' = ' + @bitstr 
                    
    					select @spacer = N' or '

    					if len( @cmd ) > 3000
    					begin
    						insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
    		FETCH hCColid INTO @this_col
        end
        CLOSE hCColid
        DEALLOCATE hCColid

        if @pk_is_identity = 0
            insert into #proctext(procedure_text) values( @cmd )

    end  -- if artcolumns != pkcolumns

    -- construct update statement including PK columns

    insert into #proctext(procedure_text) values( N'begin' )

    insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )

    -- create SET clause consisting of CASE statements

    select @art_col = 1
    select @spacer = N''

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    			select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    			insert into #proctext(procedure_text) values (
    				 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    				 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
    				 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

    			select @spacer = ',' 
    		end

            select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- create where clause

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns

    if @allow_queued_tran <> 1
    	exec dbo.sp_MSscript_missing_row_check

    -- construct UPDATE that does not set PK cols
    -- only do this if the article contains columns that are not included
    -- in the pk

    if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
    begin

        -- create SET clause consisting of CASE statements

        select @art_col = 1
        select @spacer = N''

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

        OPEN hCColid

        FETCH hCColid INTO @this_col

        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0  and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns 
                if @isset = 0 
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
                		if (@update_created = 0)
                		begin
                			insert into #proctext(procedure_text) values( N'end' )
                			insert into #proctext(procedure_text) values( N'else' )
                			insert into #proctext(procedure_text) values( N'begin' )
    			    		insert into #proctext(procedure_text) values( N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set' )
    			    		select @update_created = 1
    					end
    					select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    					select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    					insert into #proctext(procedure_text) values (
    						 @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    						 N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @art_col ) + 
    						 N' else ' + QUOTENAME(col_name( @src_objid, @this_col)) + N' end' )

    					select @spacer = ',' 
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end
        CLOSE hCColid
        DEALLOCATE hCColid

        if @update_created = 1
    	begin
    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns
    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check
    	end
    end

    insert into #proctext(procedure_text) values( N'end' )
    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptmappedupdproc
GO

--
-- Name: sp_scriptdynamicupdproc
--
-- Description: This procedure is used by User to script the custom command procedure 
-- for UPDATE in MCALL format using EXEC() statements (avoids using CASE statements).
-- Invoked on 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_scriptdynamicupdproc', 0,1)
go
create procedure sp_scriptdynamicupdproc 
(
    @artid int
)
as
    begin
    declare @retcode int
    declare @cmd          nvarchar(4000)
    declare @dest_owner   nvarchar(255)
    declare @dest_tabname sysname
    declare @src_objid    int
    declare @artcolumns   binary(32)
    declare @pkcolumns    binary(32)
    declare @upd_cmd      nvarchar(255)
    declare @dest_proc    sysname
    declare @art_cols     int
    declare @this_col     int
    declare @art_col      int
    declare @pk_col       int
    declare @pkart_col    int
    declare @isset        int
    declare @ispk         int
    declare @isidentity   bit
    declare @iscomputed   bit
    declare @bytestr      nvarchar(10)
    declare @bitstr       nvarchar(10)
    declare @typestring   nvarchar(255)
    declare @spacer_param nvarchar(10)
    declare @update_created  bit
    declare @pkcomputed   int
    declare @pubid        int, @allow_queued_tran bit

    set nocount on 

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    -------- create temp table for command fragments

    create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_params ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_paramdef ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )
    create table #proctext_pkparams ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default )



    -------- get sysarticles information

    select @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd,
    	   @pubid = pubid
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -------- get dest proc name

    if( 1 != charindex( N'MCALL', upper(@upd_cmd) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    select @allow_queued_tran = allow_queued_tran from syspublications where pubid = @pubid 

    declare @keep_identity bit
    if @allow_queued_tran = 1 and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values ( N'create procedure ' + QUOTENAME(@dest_proc) + N' ' )
      

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, @pkcolumns

    ----- add changed data bitmap

    select @art_col = 1
    select @pk_col = 1

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

    OPEN hCColid

    FETCH hCColid INTO @this_col

    WHILE (@@fetch_status <> -1)
    begin
       exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
       if @isset != 0 and EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
       begin
            select @art_col = @art_col + 1
       end
       FETCH hCColid INTO @this_col
    end
    CLOSE hCColid
    DEALLOCATE hCColid

    -- Note that bitmap size is based on number of article columns
    -- (computed by loop above) not source table columns

    select @cmd = N',@bitmap binary(' + convert(nvarchar,1+(@art_col-1) / 8) + N')'

    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'as' )



    -- Find out if pk is identity
    declare @pk_is_identity bit
    select @pk_is_identity = 0

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @art_col = 1

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

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	select @pk_is_identity = 1

    	WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin 
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    				end
                end
                select @art_col = @art_col + 1
            end
    		FETCH hCColid INTO @this_col
        end
    	CLOSE hCColid
    	DEALLOCATE hCColid
    end 

    -- construct UPDATE that does not set PK cols
    -- only do this if the article contains columns that are not included
    -- in the pk
    -- Note: we assume pk columns never change. pk changes will be replicated
    -- as delete insert.

    if @artcolumns != @pkcolumns  and @pkcomputed = 0 and @pk_is_identity = 0
    begin

        -- create SET clause consisting of CASE statements

        select @art_col = 1
        select @spacer_param = N''

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

    	OPEN hCColid

    	FETCH hCColid INTO @this_col

    	WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0  
    		begin
                exec @ispk = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    			
    			if EXISTS (select name from syscolumns where colid=@this_col and iscomputed<>1 and id = @src_objid)
    				select @iscomputed = 0
    			else
    				select @iscomputed = 1
    			
    			if (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)  
    				select @isidentity = 1
    			else
    				select @isidentity = 0
    				
    			-- If not pk, not computed and not identity	
    			if @ispk = 0 and @iscomputed = 0 and @isidentity = 0
                begin
                	if (@update_created = 0)
                	begin
    			    	insert into #proctext(procedure_text) values( 
    						N'declare @stmt nvarchar(4000), @spacer nvarchar(1)')

    			    	insert into #proctext(procedure_text) values( 
    						N'select @spacer =N''''')

    			    	insert into #proctext(procedure_text) values( 
    						N'select @stmt = N''update ' + 
    						replace(@dest_owner + QUOTENAME(@dest_tabname), N'''', N'''''' ) +
    						N' set ''')

    			    	select @update_created = 1
    				end

    				select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
    				select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

    				insert into #proctext(procedure_text) values (
    					 N'if substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
    					 N' = ' + @bitstr)

    				insert into #proctext(procedure_text) values (N'begin')

    				-- Append statement
    				insert into #proctext(procedure_text) values (
    					 N'select @stmt = @stmt + @spacer + ' + 
    					 N'N''' + replace(QUOTENAME(col_name( @src_objid, @this_col)), N'''', N'''''') + N''' + ' +
    					 N'N''=@'+ convert( nvarchar, @art_col ) + N'''')

    				-- Set @spacer is the proc
    				insert into #proctext(procedure_text) values (
    					N'select @spacer = N'',''')

    				insert into #proctext(procedure_text) values (N'end')
                end
    			-- If pk or (not computed and not identity) add the param
    			if @ispk <> 0 or (@iscomputed = 0 and @isidentity = 0)
    			begin
    				-- Add to param list
    			    if (@ispk <> 0)
    				  begin
    				    -- Use primary key value
    				    insert into #proctext_params(procedure_text) values( 
    						@spacer_param + N'@pkc' + convert( nvarchar, @pk_col ))

    				    -- Increment primary key counter
    				    select @pk_col = @pk_col + 1;

    				  end
    				else
    				    -- Use column value
    					insert into #proctext_params(procedure_text) values( 
    						@spacer_param + N'@c' + convert( nvarchar, @art_col ))

    				-- Get type str
    				exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT

    				-- Append typedef
    				insert into #proctext_paramdef(procedure_text) values (
    					 @spacer_param + N'@' + convert( nvarchar, @art_col ) + 
    					 N' ' + @typestring )

    				select @spacer_param = ',' 
    			end

                select @art_col = @art_col + 1
            end
           	FETCH hCColid INTO @this_col
        end
    	CLOSE hCColid
    	DEALLOCATE hCColid

        if @update_created = 1
    	begin

    		-- Append statement of the start of where clause
    		insert into #proctext(procedure_text) values (
    			 N'	select @stmt = @stmt + N'' ')

    		-- Escape ' in the where clause
    		declare @low_mark int, @high_mark int
    		select @low_mark = max(c1) from #proctext
    		-- Pass in @artcolumns so that the where clause will use the ordinal in the
    		-- article bit map rather then one in pk bitmap. This is consistent with
    		-- the type def string.
    		-- UNDONE: change comments in sp_scriptpkwhereclause
    		-- Use prefix '@' to be consistent with type def string
    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, '@', @artcolumns
    		select @high_mark = max(c1) from #proctext
    		update #proctext set procedure_text = replace ( procedure_text, N'''', N'''''') 
    			where c1 > @low_mark and c1 <= @high_mark

    		-- Close the where clause
    		insert into #proctext(procedure_text) values (
    			 N'''')

    		-- Add call to sql_executesql and the param list
    		insert into #proctext(procedure_text) values( 
    			N'exec sp_executesql @stmt, N'' ')

    		-- Add param def
    		insert into #proctext(procedure_text) 
    			select procedure_text from #proctext_paramdef order by c1 asc

    		-- Close the param def
    		insert into #proctext(procedure_text) values (
    			 N''',')

    		-- Add param list
    		insert into #proctext(procedure_text) 
    			select procedure_text from #proctext_params order by c1 asc

    		if @allow_queued_tran <> 1
    			exec dbo.sp_MSscript_missing_row_check
    	end

    end

    select procedure_text from #proctext order by c1 asc
end
go
EXEC dbo.sp_MS_marksystemobject sp_scriptdynamicupdproc
GO

--
-- Name: sp_scriptxupdproc
--
-- Description: This procedure is used by Snapshot agent to script the custom command procedure 
-- for UPDATE in XCALL format. Invoked on 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_scriptxupdproc', 0,1)
go
create procedure sp_scriptxupdproc @artid int
as
BEGIN
    declare @cmd          nvarchar(4000),
                @dest_owner   nvarchar(255),
                @dest_tabname sysname,
                @src_objid    int,
                @artcolumns   binary(32),
                @pkcolumns    binary(32),
                @upd_cmd      nvarchar(255),
                @dest_proc    sysname,
                @this_col     int,
                @art_col      int,
                --@pkart_col    int,
                @isset        int,
                @rc int,
                @fhasnonpkuniquekeys int,
                @pkcomputed   int,
                @typestring   nvarchar(255),
                @spacer       nvarchar(10),
                @pubid		  int, 
                @param_count  int
                ,@queued_check bit, @exists_else bit
                ,@qwhere_string nvarchar(4000)

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

    if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
    begin
        raiserror (14155, 16, 1 )
        return 1
    end

    select @exists_else = 0
             ,@fhasnonpkuniquekeys = 0

    -------- create temp table for command fragments

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

    -------- get sysarticles information

    select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
           @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
    from sysarticles
    where artid = @artid

    if @dest_owner is not null
    begin
    	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
    end
    else
    begin
    	select @dest_owner = N''
    end

    -- Check if this is a queued publication
    select @queued_check = ISNULL(allow_queued_tran, 0) 
    from syspublications
    where pubid = @pubid

    -------- get dest proc name

    if( 1 != charindex( N'XCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
    begin
        raiserror (14156, 16, 1 )
        return 1
    end

    declare @keep_identity bit
    if exists (select * from syspublications where pubid = @pubid and
    	allow_queued_tran = 1) and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
        select @keep_identity = 1
    else
        select @keep_identity = 0

    select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
    select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
    insert into #proctext(procedure_text) values( @cmd )
    insert into #proctext(procedure_text) values( N'go' )
    insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')

    -------- construct parameter list

    exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output

    -- Send null as @pkcolumns. We don't need pk parameters.
    exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, NULL, @param_count output

    insert into #proctext(procedure_text) values ( N'as' )

    --
    -- If we are a part of queued publication 
    --
    if (@queued_check = 1)
    begin
        --
        -- Check if we have non PK unique keys
        --
        exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @src_objid
        if (@fhasnonpkuniquekeys = 1)
        begin
            --
            -- There are non PK unique keys
            -- update only if updated values of non PK unique key(s) do not exist
            --
            select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
            insert into #proctext(procedure_text) values( @cmd )
            exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                            ,@columns = @artcolumns
                                                            ,@prefix = '@c' 
                                                            ,@mode = 2
                                                            ,@paramcount = @param_count
            if (@@error != 0 or @rc != 0)
                return 1
            select @cmd = N')
begin'
            insert into #proctext(procedure_text) values( @cmd )
        end
    end

    -------- now create the update statement

    -- construct test to see if pk has changed 
    -- only do this if the article has columns not included in the pk

    exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns

    declare @pk_is_identity bit
    select @pk_is_identity = 0

    if @artcolumns != @pkcolumns and @pkcomputed = 0
    begin
        select @cmd = N'if'

        select @art_col = 1
        --select @pkart_col = 1
        select @spacer = ' '

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

        OPEN hCColid

        FETCH hCColid INTO @this_col

        select @pk_is_identity = 1
        WHILE (@@fetch_status <> -1)
        begin
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
            if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
            begin
                exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
                if @isset != 0
                begin
    				if not (@keep_identity = 1 and 
    					columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    				begin
    					select @pk_is_identity = 0
    					select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col + @param_count/2) + 
    						N' = @c' + convert( nvarchar, @art_col ) 
    					select @spacer = N' and '
    					--select @pkart_col = @pkart_col + 1
    					if len( @cmd ) > 3000
    					begin
    					insert into #proctext(procedure_text) values( @cmd )
    						select @cmd = N''
    					end
    				end
                end
                select @art_col = @art_col + 1
            end
            FETCH hCColid INTO @this_col
        end

        CLOSE hCColid
        DEALLOCATE hCColid

    	if @pk_is_identity = 0
    	begin
    		insert into #proctext(procedure_text) values( @cmd )

    		insert into #proctext(procedure_text) values( N'begin' )

    		-- construct update if pk hasn't changed
    		-- We know that there would be a least one column for the update below, even if
    		-- the columns outside the pk are identity or timestamp. Since identity and timestamp
    		-- will be mapped off unless it is queued tran. In that case, we have 'msrepl_tran_version'
    		select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    		-- create SET clause

    		select @art_col = 1
    		select @spacer = N' '

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

    		OPEN hCColid

    		FETCH hCColid INTO @this_col
    		WHILE (@@fetch_status <> -1)
    		begin
    			exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
    			if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
    			begin
    				exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
    				if @isset = 0
    				begin
    					if not (@keep_identity = 1 and 
    						columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    					begin
    						select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
    							N' = @c' + convert( nvarchar, @art_col + @param_count/2) 
    						select @spacer = N','

    						if len( @cmd ) > 3000
    						begin
    							insert into #proctext(procedure_text) values( @cmd )
    							select @cmd = N''
    						end

    						--
    						-- Queued processing:if this is the row version column : need to add to where clause
    						--
    						if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    							select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
    					end
    				end
    				select @art_col = @art_col + 1
    			end
    			FETCH hCColid INTO @this_col
    		end
    		CLOSE hCColid
    		DEALLOCATE hCColid

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

    		exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
    		if (@queued_check = 1)
    			insert into #proctext(procedure_text) values( @qwhere_string )
    		else
    			exec dbo.sp_MSscript_missing_row_check

    		insert into #proctext(procedure_text) values( N'end' )
    		insert into #proctext(procedure_text) values( N'else' )
    		insert into #proctext(procedure_text) values( N'begin' )

    		select @exists_else = 1

    	end
    end -- end if artcols != pkcols

    --
    -- If we are a part of queued publication then 
    -- update only if updated value of PK does not exist
    --
    if (@queued_check = 1 and @pk_is_identity = 0)
    begin
        select @cmd = N'
if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
        insert into #proctext(procedure_text) values( @cmd )
        exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
                                                            ,@columns = @artcolumns
                                                            ,@prefix = '@c' 
                                                            ,@mode = 3
                                                            ,@paramcount = @param_count
        if (@@error != 0 or @rc != 0)
            return 1
        select @cmd = N')
begin'
        insert into #proctext(procedure_text) values( @cmd )
    end

    -- construct update if pk has changed
    select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'

    -- create SET clause

    select @art_col = 1
    select @spacer = N' '

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

    OPEN hCColid

    FETCH hCColid INTO @this_col
    WHILE (@@fetch_status <> -1)
    begin
        exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
        if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
        begin
    		if not (@keep_identity = 1 and 
    			columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
    		begin
    			select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
    				N' = @c' + convert( nvarchar, @art_col + @param_count/2 ) 
    			select @spacer = N','

    			if len( @cmd ) > 3000
    			begin
    			insert into #proctext(procedure_text) values( @cmd )
    				select @cmd = N''
    			end

    			--
    			-- Queued processing:if this is the row version column : need to add to where clause
    			--
    			if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
    				select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )						
    		end
    		select @art_col = @art_col + 1
        end
    	FETCH hCColid INTO @this_col
    end

    CLOSE hCColid
    DEALLOCATE hCColid

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

    exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
    if (@queued_check = 1)
    begin
        insert into #proctext(procedure_text) values( @qwhere_string ) 
        if (@pk_is_identity = 0)
        begin
            select @cmd = N'
end'
            insert into #proctext(procedure_text) values( @cmd )
        end
    end
    else
    	exec dbo.sp_MSscript_missing_row_check

    if @exists_else = 1
    	insert into #proctext(procedure_text) values( N'end' )

    --
    -- End the if exists block for Queued publications
    --
    if (@queued_check = 1) and (@fhasnonpkuniquekeys = 1)
    begin
        select @cmd = N'
end'
        insert into #proctext(procedure_text) values( @cmd )
    end

    -- flush to client

    select procedure_text from #proctext order by c1 asc
END
go
EXEC dbo.sp_MS_marksystemobject sp_scriptxupdproc
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_MSscriptmvastablenci'
go

create procedure sp_MSscriptmvastablenci @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int
declare @status		  int
declare @unique	      nvarchar(10)
declare @cmd_sep	  nvarchar(10)


-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default
select @cmd_sep = N''

DECLARE hCIdx CURSOR LOCAL FAST_FORWARD FOR
select name, indid, status from sysindexes where id = @src_objid and indid > 1 order by indid asc

OPEN hCIdx
FETCH hCIdx INTO @constraint_name, @indid, @status

WHILE (@@fetch_status <> -1)
begin
	if @status & 2 = 2
	begin
		select @unique = N' unique '
	end
	else
	begin
		select @unique = N' '
	end

	insert into #proctext(procedure_text) values( @cmd_sep )
	select @cmd_sep = N'GO'

	select @cmd = N'create' + @unique + N'nonclustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'('
	insert into #proctext(procedure_text) values( @cmd )

	select @spacer = N' '
	select @cmd = N''

	select @indkey = 1
	while (@indkey <= 16)
	begin	
		select @colname = index_col(@srcobj, @indid, @indkey)
		if (@colname is null)
		begin
			select @indkey = 16
		end
		else
		begin
			select @cmd = @cmd + @spacer + QUOTENAME(@colname)
			select @spacer = N','

			if len( @cmd ) > 3000
			begin
				insert into #proctext(procedure_text) values( @cmd )
				select @cmd = N''
			end
		end
		select @indkey = @indkey + 1
	end

	insert into #proctext(procedure_text) values( @cmd )
	insert into #proctext(procedure_text) values( N')' )
	
	FETCH hCIdx INTO @constraint_name, @indid, @status
end

CLOSE hCIdx
DEALLOCATE hCIdx
select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablenci
GO

print ''
print 'Creating procedure sp_MSscriptmvastablepkc'
go

create procedure sp_MSscriptmvastablepkc @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default

select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0

select @cmd = N'alter table ' + @dest_owner + QUOTENAME(@dest_tabname) collate database_default + N' add constraint ' + QUOTENAME(@constraint_name) collate database_default + N' primary key clustered ('
insert into #proctext(procedure_text) values( @cmd )

select @spacer = N' '
select @cmd = N''

select @indkey = 1
while (@indkey <= 16)
begin	
	select @colname = index_col(@srcobj, @indid, @indkey)
	if (@colname is null)
	begin
		select @indkey = 16
	end
	else
	begin
		select @cmd = @cmd + @spacer + QUOTENAME(@colname) collate database_default
		select @spacer = N','

		if len( @cmd ) > 3000
		begin
			insert into #proctext(procedure_text) values( @cmd )
			select @cmd = N''
		end
	end
	select @indkey = @indkey + 1
end

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

insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastablepkc
GO

print ''
print 'Creating procedure sp_MSscriptmvastableidx'
go

create procedure sp_MSscriptmvastableidx @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @constraint_name  sysname
declare @spacer		  nvarchar(1)
declare @srcobj		  nvarchar(1000)
declare @colname	  sysname
declare @indkey		  int
declare @indid		  int

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

select @srcobj = QUOTENAME( USER_NAME(OBJECTPROPERTY(@src_objid,'OwnerId'))) collate database_default + N'.' + QUOTENAME(object_name(@src_objid)) collate database_default

select @constraint_name = name, @indid = indid from sysindexes where id = @src_objid and status & 16 <> 0

select @cmd = N'create unique clustered index ' + QUOTENAME(@constraint_name) + N' on ' +@dest_owner + QUOTENAME(@dest_tabname) + N'('
insert into #proctext(procedure_text) values( @cmd )

select @spacer = N' '
select @cmd = N''

select @indkey = 1
while (@indkey <= 16)
begin	
	select @colname = index_col(@srcobj, @indid, @indkey)
	if (@colname is null)
	begin
		select @indkey = 16
	end
	else
	begin
		select @cmd = @cmd + @spacer + QUOTENAME(@colname)
		select @spacer = N','

		if len( @cmd ) > 3000
		begin
			insert into #proctext(procedure_text) values( @cmd )
			select @cmd = N''
		end
	end
	select @indkey = @indkey + 1
end

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

insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc

go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastableidx
GO


print ''
print 'Creating procedure sp_MSscriptmvastable'
go

create procedure sp_MSscriptmvastable @artid int
as
declare @cmd          nvarchar(4000)
declare @dest_owner   nvarchar(255)
declare @dest_tabname sysname
declare @src_objid    int
declare @artcolumns   binary(32)
declare @schema_option binary(8)
declare @art_col	  int
declare @this_col	  int
declare @isset	      int
declare @use_base_type tinyint

declare @spacer		  nvarchar(1)
declare @nullability  nvarchar(10)
declare @typestring   nvarchar(255)
declare @col_name	  sysname

-------- security check, db_owner
declare @retcode int
exec @retcode = dbo.sp_MSreplcheck_publish
if @@ERROR <> 0 or @retcode <> 0
    return(1)

-------- create temp table for command fragments

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

-------- get sysarticles information

select @dest_owner = dest_owner, @dest_tabname = dest_table, 
       @src_objid = objid, @artcolumns = columns, 
	   @use_base_type = substring(schema_option,8,1) & 32
from sysarticles
where artid = @artid

if @dest_owner is not null
begin
	select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
end
else
begin
	select @dest_owner = N''
end

-- script out CREATE TABLE statement

-- begin create table
select @cmd = N'create table ' + @dest_owner + QUOTENAME(@dest_tabname) + N'('
insert into #proctext(procedure_text) values( @cmd )

-- columns
select @art_col = 1
select @spacer = N' '

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

OPEN hCColid

FETCH hCColid INTO @this_col

WHILE (@@fetch_status <> -1)
begin
   exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
   select @col_name = name, 
          @nullability = case isnullable 
		  when 0 then N'NOT NULL' 
		  else N'NULL' end
		  from syscolumns where id=@src_objid and @this_col=colid 
   if @isset != 0 and @col_name is not null
   begin
		if @use_base_type <> 0
		begin
			exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
		end
		else
		begin
			exec dbo.sp_MSgettypestringudt @src_objid, @this_col, @typestring OUTPUT
		end
        select @cmd = @spacer + QUOTENAME(@col_name) + N' ' + @typestring + N' ' + @nullability 
        insert into #proctext(procedure_text) values( @cmd )
		select @art_col = @art_col + 1
        select @spacer = N','
   end
   FETCH hCColid INTO @this_col
end

CLOSE hCColid
DEALLOCATE hCColid

-- end create table
insert into #proctext(procedure_text) values( N')' )

select procedure_text from #proctext order by c1 asc
go
EXEC dbo.sp_MS_marksystemobject sp_MSscriptmvastable
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_fetchshowcmdsinput'
go
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
go
create procedure sp_fetchshowcmdsinput @numcmds int
as
create table #rcmds( article_id int NOT NULL, partial_command int NOT NULL, command varbinary(1024) NULL, 
xactid binary(10) NOT NULL, xact_seqno binary(10) NOT NULL, publication_id int NOT NULL, 
command_id int NOT NULL, command_type int NOT NULL, originator_srvname nvarchar(128) collate database_default null, 
originator_db nvarchar(128) collate database_default null)
insert into #rcmds exec dbo.sp_replcmds @numcmds
select convert( varbinary(16), xact_seqno ), 0, 0, article_id, command_type, partial_command, command from #rcmds order by xact_seqno, article_id, command_id asc
drop table #rcmds
go
SET ANSI_NULLS OFF
go
EXEC dbo.sp_MS_marksystemobject sp_fetchshowcmdsinput
GO

--------------------------------------------------------------------------
--------------------------------------------------------------------------

print ''
print 'Creating procedure sp_replshowcmds'
go

create procedure sp_replshowcmds @maxtrans int = 1
as
declare @query nvarchar(1024)
declare @dbname sysname
select @dbname = db_name()

select @query = 'execute dbo.sp_fetchshowcmdsinput ' + convert( nvarchar, @maxtrans )
execute master..xp_printstatements @query, @dbname
go

EXEC dbo.sp_MS_marksystemobject sp_replshowcmds
GO

print ''
print 'Creating procedure sp_article_validation'
go

create procedure sp_article_validation
@publication sysname,
@article sysname,
-- The following are values passed to the sp_table_validation call at the subscriber.
@rowcount_only smallint = 1,       
/* 
The @rowcount_only param is overloaded for shiloh release due to backward compatibility concerns.
In shiloh, the checksum functionality has changed.   So 7.0 subscribers will have the old checksum 
routines, which generate different CRC values, and do not have functionality for vertical partitions,
or logical table structures where column offsets differ (due to ALTER TABLEs that DROP and ADD columns).

In 7.0, this was a bit column.  0 meant do not do just a rowcount - do a checksum.  1 meant just do a 
rowcount.

For Shiloh, this parameter is changed to a smallint with these options:
0 - Do a 7.0 compatible checksum
1 - Do a rowcount check only
2 - Use new Shiloh checksum functionality.  Note that because 7.0 subscribers will 
take this parameter as a bit type, not a smallint, it will be interpreted as simply
ON.  That means that passing a 2, and having a 7.0 subscriber, will result in the 7.0
subscriber doing only rowcount validation.   The Shiloh subscribers will do both
rowcount and checksum.  If you want 7.0 subscribers to do checksum validation, use 
the value of 0 for this parameter.   Shiloh subscribers can do the 7.0 compatible 
checksum, but that checksum has the same 7.0 limitations for vertical partitions 
and differences in physical table structure.)
*/
              
@full_or_fast tinyint = 2,  -- full (value 0) does COUNT(*) 
                            -- fast (value 1) uses sysindexes.rows if table (not view); 
                            -- conditional fast (VALUE 2) , first tries fast method, but
                            -- reverts to full if fast method shows differences.
@shutdown_agent bit = 0,    -- If 1 will raise error 20578, which will signal subscriber synchronization agent to shutdown
                            -- immediately after successful validation
@subscription_level bit = 0		-- Whether or not the validation is only picked up by a set of subscribers
								-- that are specified by calls to sp_marksubscriptionvalidation.
, @reserved int = NULL			-- If not null, the sp is called from sp_publication_validation.
as

declare @publication_guid uniqueidentifier
declare @publication_id int
declare @article_guid uniqueidentifier
declare @article_id int
declare @source_name sysname
declare @source_owner sysname
declare @partition_view_id sysname, @table_id sysname
declare @sync_name sysname
declare @destination_table sysname
declare @destination_owner sysname
declare @columns varbinary(32) 
declare @command varchar (4096)
declare @retcode int
declare @actual_rowcount bigint
declare @actual_checksum numeric
declare @status int
declare @active int
declare @publish_bit int
declare @table_name sysname					-- base table name var to passed to sp_table_validation
	, @allow_dts bit
	, @dts_part int
    
set nocount on


set @active = 1
set @publish_bit = 1
set @dts_part = 64

-- Check if the database is published for transactional
if not exists (select * from master..sysdatabases where name = db_name() collate database_default and (category & @publish_bit) = @publish_bit)
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Publication Information
select @publication_id = pubid, @allow_dts = allow_dts from syspublications where name = @publication
if @publication_id is null
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Article Information
select @article_id = artid, @sync_name = OBJECT_NAME(sync_objid),@partition_view_id=sync_objid,
    @destination_table = dest_table, @destination_owner = dest_owner, 
	@status = status, @table_name = OBJECT_NAME(objid),@table_id=objid,
    @columns = columns from sysarticles where name = @article and pubid=@publication_id

if @article_id is null
begin
    raiserror(20027, 16, -1, @article)
    return 1
end

-- Security check
-- Only people have 'select all' permission on the base table can do validation
if permissions(@table_id) & 1 <> 1
begin
	declare @qual_name nvarchar(512)
	exec dbo.sp_MSget_qualified_name @table_id, @qual_name output
	raiserror(20623, 16, -1, @article, @qual_name)
	return 1
end

-- Make sure article status is 'active' 
if (@status & @active) <> @active
begin
    -- Article is not active
    raiserror(20523, 16, -1, @article)
    return 1
end


if @allow_dts = 1
begin
	if @rowcount_only <> 1
	begin
		raiserror(20612, 16, -1)
		return (1) 
	end
	-- For dts horizontal partitioned article, no validation is possible, do nothing or
	-- raise error.
	if (@status & @dts_part <> 0)
	begin
		-- sp_article_validation is called directly, raise error and fail
		if @reserved is null
		begin
			raiserror(20613, 16, -1)
			return (1) 
		end
		-- sp_article_validation is called by sp_publication_validation, 
		-- raise warning and contiue.
		else
		begin
			raiserror(20613, 10, -1)
			return (0)
		end
	end
end
			
	
	

-- Check if table has vertical partition OR horizontal partition
if exists (select * from sysarticles a, syscolumns b
    where
	(
	-- horizontal partition	exists if filter column is not zero
	a.filter <> 0
	
	OR
	--vertical partition
	 (CONVERT(bit, convert(binary(2), SUBSTRING(convert(nvarchar,a.columns), CONVERT(tinyint, 16 - FLOOR((colid-1)/16)), 1)) & POWER(2, ((colid-1)%16))) = 0
           OR CONVERT(bit, convert(binary(2), SUBSTRING(convert( nvarchar,a.columns), CONVERT(tinyint, 16 - FLOOR((colid-1)/16)), 1)) & POWER(2, ((colid-1)%16))) IS NULL)
	)
           AND a.objid = b.id
           AND a.name = @article
           AND a.pubid = @publication_id)
begin
    set @source_name = @sync_name
    select @source_owner= user_name(uid) from sysobjects where id=@partition_view_id

    -- Partitions only support new shiloh checksum functionality or row count validation.
    -- If 7.0 compatible checksum was asked for (@rowcount_only=0), it will be changed to 
    -- override specified value, making it truly only check rowcounts.   If shiloh checksum 
    -- was asked for, thats ok (@rowcount_only=2), thats ok and no need to change it.
    if (@rowcount_only = 0)
    	set @rowcount_only = 1
end

else

begin
  	set @source_name = @table_name
	select @source_owner= user_name(uid) from sysobjects where id=@table_id

end


begin tran -- The table validation and posting to the log MUST happen with a transaction

-- Get publisher's rowcount and/or checksum for the article
if @rowcount_only = 1
begin
    exec @retcode = dbo.sp_table_validation @table = @source_name, @expected_rowcount = @actual_rowcount OUTPUT,
        @rowcount_only = 1, @owner=@source_owner, @full_or_fast = 0, @table_name = @table_name   -- always do full count at publisher
    if @retcode <> 0 or @@error <> 0 
    begin
        commit tran
        return 1
    end
end
else  -- get checksum
begin
    exec @retcode = dbo.sp_table_validation @table = @source_name, @expected_rowcount = @actual_rowcount OUTPUT,
        @expected_checksum = @actual_checksum OUTPUT, @rowcount_only = @rowcount_only, @owner=@source_owner,
        @full_or_fast = 0, @table_name = @table_name   -- always do full count at publisher
    if @retcode <> 0 or @@error <> 0 
    begin
        commit tran
        return 1
    end
end

-- Post sp_table_validation on behalf of the article and send to subscribers
if @rowcount_only = 1
begin
    select @command = 'exec dbo.sp_table_validation @table = ''' + @destination_table + ''', @expected_rowcount = ' +
        convert(varchar(10), @actual_rowcount) + ', @rowcount_only = 1' +
        ', @full_or_fast = ' + convert(varchar(10), @full_or_fast) +
        ', @shutdown_agent = ' + convert(varchar(10), @shutdown_agent)
end
else
begin
    select @command = 'exec dbo.sp_table_validation @table = ''' + @destination_table + ''', @expected_rowcount = ' +
        convert(varchar(10), @actual_rowcount) + ', @expected_checksum = ' + 
        convert(varchar(100), @actual_checksum) + ', @rowcount_only = ' + convert(varchar(5),@rowcount_only) +
        ', @full_or_fast = ' + convert(varchar(10), @full_or_fast) +
        ', @shutdown_agent = ' + convert(varchar(10), @shutdown_agent)
end 

-- Add owner param if destination owner is not NULL
if (@destination_owner IS NOT NULL)
begin
	select @command = @command +
	', @owner = ''' + @destination_owner + ''''
end

declare @command_type int
if @subscription_level = 0
	select @command_type = 35 -- SQL Server Only command type
else
	select @command_type = 69 -- sub validation command

exec @retcode = dbo.sp_replpostcmd 
    0,              -- partial flag
    @publication_id, 
    @article_id, 
    @command_type,            -- SQL Server Only command type
    @command
if @retcode <> 0 or @@error <> 0
begin
    commit tran
    return 1
end

commit tran

Go

EXEC dbo.sp_MS_marksystemobject sp_article_validation

print ''
print 'Creating procedure sp_publication_validation'
go


create procedure sp_publication_validation
@publication sysname,
@rowcount_only smallint = 1,
/* 
The @rowcount_only param is overloaded for shiloh release due to backward compatibility concerns.
In shiloh, the checksum functionality has changed.   So 7.0 subscribers will have the old checksum 
routines, which generate different CRC values, and do not have functionality for vertical partitions,
or logical table structures where column offsets differ (due to ALTER TABLEs that DROP and ADD columns).

In 7.0, this was a bit column.  0 meant do not do just a rowcount - do a checksum.  1 meant just do a 
rowcount.

For Shiloh, this parameter is changed to a smallint with these options:
0 - Do a 7.0 compatible checksum
1 - Do a rowcount check only
2 - Use new Shiloh checksum functionality.  Note that because 7.0 subscribers will 
take this parameter as a bit type, not a smallint, it will be interpreted as simply
ON.  That means that passing a 2, and having a 7.0 subscriber, will result in the 7.0
subscriber doing only rowcount validation.   The Shiloh subscribers will do both
rowcount and checksum.  If you want 7.0 subscribers to do checksum validation, use 
the value of 0 for this parameter.   Shiloh subscribers can do the 7.0 compatible 
checksum, but that checksum has the same 7.0 limitations for vertical partitions 
and differences in physical table structure.)
*/

@full_or_fast tinyint = 2,  -- full (value 0) does COUNT(*) 
                            -- fast (value 1) uses sysindexes.rows if table (not view); 
                            -- conditional fast (VALUE 2) , first tries fast method, but
                            -- reverts to full if fast method shows differences.
@shutdown_agent bit = 0     -- Set for last article in publication, which will signal subscriber synchronization agent to shutdown
                            -- immediately after successful validation
as

set nocount on

declare @retcode tinyint
declare @publication_id int
declare @article sysname
declare @article2 sysname
declare @publish_bit int

    
set @publish_bit = 1

-- Security Check
-- No reason anyone but Sysadmin or dbo of publishing db should run this
exec @retcode = dbo.sp_MSreplcheck_publish
if @@error <> 0 or @retcode <> 0
begin
	return (1)
end

-- Check if the database is published for transactional
if not exists (select * from master..sysdatabases where name = db_name() collate database_default and (category & @publish_bit) = @publish_bit)
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Get Publication Information
select @publication_id = pubid from syspublications where name = @publication
if @publication_id is null
begin
    raiserror(20026, 16, -1, @publication)
    return 1
end

-- Security Check will be done inside sp_article_validation
-- Security check
-- Only people have 'select all' permission on the base table can do validation
declare @table_id int

select top 1 @article = name, @table_id = objid from sysarticles where
	pubid = @publication_id and 
	(status & 1) <> 0 and   -- active articles only
	(type & 1) <> 0 and		-- only checksum tables/views.
	((permissions(objid) & 1) <> 1)

if @table_id is not null
begin
	declare @qual_name nvarchar(512)
	exec dbo.sp_MSget_qualified_name @table_id, @qual_name output
	raiserror(20623, 16, -1, @article, @qual_name)
	return 1
end

declare hC CURSOR LOCAL FAST_FORWARD for select name from sysarticles where pubid = @publication_id and
(status & 1) <> 0 and   -- active articles only
(type & 1) <> 0			-- only checksum tables/views.

open hC
fetch hC into @article
while (@@fetch_status <> -1)
begin
    set @article2 = @article

    -- Look ahead to next article
    fetch hC into @article

    -- If we are at the last article, pass the @shutdown_agent value
    if (@@fetch_status = -1) 
    begin
        exec @retcode = dbo.sp_article_validation @publication, @article2, @rowcount_only = @rowcount_only,
            @full_or_fast = @full_or_fast, @shutdown_agent = @shutdown_agent, @reserved = 1

    end
    else
        exec @retcode = dbo.sp_article_validation @publication, @article2, @rowcount_only = @rowcount_only,
            @full_or_fast = @full_or_fast, @reserved = 1
    
    if @retcode <> 0 or @@error <> 0
    begin
        close hC
        deallocate hC
        return 1
    end
end
close hC
deallocate hC
go

EXEC dbo.sp_MS_marksystemobject sp_publication_validation
GO


print ''
print 'Creating procedure sp_marksubscriptionvalidation'
go


CREATE PROCEDURE sp_marksubscriptionvalidation (
    @publication sysname,    /* publication name */
    @subscriber sysname,             /* subscriber name */
    @destination_db sysname   /* destination database name */
) AS

    DECLARE @retcode int, @pubid int

    DECLARE @artid int, @active tinyint
    DECLARE @srvid smallint
	DECLARE @non_sql_flag bit

  
    -- Initialization
    select @active = 2

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

    /* Validate names */

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

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

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

    /*
    ** 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.
    */
    SELECT @pubid = pubid FROM syspublications WHERE name = @publication
	if @pubid is null
	begin
        RAISERROR (20026, 16, -1, @publication)
        RETURN (1)
    END

    /*
    ** Parameter Check:  @subscriber
    ** Check to make sure that the subscriber exists
    */
    select @subscriber = UPPER(@subscriber)
        
	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 & 4) <> 0
	if @srvid is null
    BEGIN
        RAISERROR (14063, 16, -1)
        RETURN (1)
    END

	if @non_sql_flag = 1
	begin
        RAISERROR (20614, 16, -1)
        RETURN (1)
	end

    -- Wrong dest_db will be caught by the following query

    -- Check to make sure the subscription exists 
    IF NOT EXISTS (SELECT *
          FROM syssubscriptions sub,
               sysextendedarticlesview art,
               syspublications pub
         WHERE pub.pubid = @pubid
           AND sub.srvid = @srvid
           AND sub.artid = art.artid
           AND art.pubid = pub.pubid
           AND sub.dest_db = @destination_db)
    BEGIN
        RAISERROR (14055, 16, -1)
        RETURN (1)
    END

	-- Select an article for that is actively subscribed.
	-- If none is found, do nothing
	select top 1 @artid = art.artid 
          FROM syssubscriptions sub,
               sysextendedarticlesview art
         WHERE sub.srvid = @srvid
           AND sub.artid = art.artid
           AND art.pubid = @pubid
           AND sub.dest_db = @destination_db
           AND sub.status = @active

	if @artid is null
		return 0

	declare @command nvarchar (1000)

	-- No need to quote them
	select @command = @subscriber + @destination_db
	exec @retcode = dbo.sp_replpostcmd 
		0,              -- partial flag
		@pubid, 
		@artid, 
		68,             -- subscription validation marker
		@command
	if @retcode <> 0 or @@error <> 0
		return 1

    RETURN(0)
go

EXEC dbo.sp_MS_marksystemobject sp_marksubscriptionvalidation
GO

print ''
print 'Creating procedure sp_dropanonymousagent'
go


CREATE PROCEDURE sp_dropanonymousagent
@subid uniqueidentifier,
@type int -- 1 tran sub, 2 merge sub
as
	set nocount on 
	declare @login sysname
	-- Null @login indicates sysadmin or db_owner
	if IS_SRVROLEMEMBER ('sysadmin') = 0 and is_member('db_owner') = 0
		select @login = suser_sname()
    /*
    ** Get distribution server information for remote RPC
    ** agent verification.
    */
    declare @distributor sysname
	declare @distribdb sysname
	declare @distproc nvarchar(1000)
	declare @retcode int

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

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

    /*
    ** Call proc to change the distributor
    */
    SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
        '.dbo.sp_MSdrop_anonymous_entry'

	exec @retcode = @distproc 
		@subid = @subid,
		@login = @login,
		@type = @type

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

    RETURN (0)
go

EXEC dbo.sp_MS_marksystemobject sp_dropanonymousagent
GO

print ''
print 'Creating procedure sp_replrestart'
go


CREATE PROCEDURE sp_replrestart 
AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @retcode int
		,@lsn binary(10)
		,@dist_lsn binary(10)
		,@distributor sysname
		,@distribdb sysname
		,@distproc nvarchar(4000)
		,@dbname sysname
	/*
	** Initializations
	*/
	select @retcode = 0
	select @dbname = db_name()

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

	-- Make sure the database is published.
    IF (SELECT category & 1
          FROM master..sysdatabases
         WHERE name = @dbname collate database_default) = 0
    BEGIN
        RAISERROR (14013, 16, -1)
        RETURN (1)
    END

	-- Make sure that the log reader is not running
	-- Use 0 so that it will not hold the repl proc structure (the lock).
    exec @retcode = dbo.sp_replcmds 0
    if @@ERROR <> 0 or @retcode <> 0
	begin
		RAISERROR (20610, 16, -1, 'sp_replrestart')
        return(1)
	end

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

	-- Get max dist lsn
    SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSget_last_transaction'
    EXECUTE @retcode = @distproc 
        @publisher = @@SERVERNAME,
        @publisher_db = @dbname,
        @max_xact_seqno = @dist_lsn output
	IF @@ERROR <> 0 or @retcode <> 0
		return -1

	if @dist_lsn is null
		set @dist_lsn = 0x0

	-- To safeguard the case when the logreader is started after the check later
	-- use a tran to prevent the logreader from picking up the new lsns
	begin tran

	while 1 = 1
	begin
		-- Get publisher's lsn
		EXEC @retcode = dbo.sp_replincrementlsn @lsn OUTPUT
		IF @@ERROR <> 0 or @retcode <> 0
			goto UNDO

		if @lsn > @dist_lsn
			break
	end

	/* Mark the new starting point of the replication.*/
	exec @retcode = dbo.sp_repldone NULL, NULL, 0, 0, 1
    IF @@ERROR <> 0 or @retcode <> 0
        GOTO UNDO

	/* release our hold on the db as logreader */
	EXEC @retcode = dbo.sp_replflush
    IF @@ERROR <> 0 or @retcode <> 0
		GOTO UNDO

	commit tran
	return 0

UNDO:
	if @@trancount <> 0
		rollback tran
go

EXEC dbo.sp_MS_marksystemobject sp_replrestart
GO


print ''
print 'Creating procedure sp_MSpub_adjust_identity'
go

CREATE PROCEDURE sp_MSpub_adjust_identity
@artid int = null
as
	set nocount on

	declare @retcode int
	declare @cmd nvarchar(1000)
	declare @objid int, @threshhold int
    declare @pub_range bigint, @next_seed bigint, @current_pub_range bigint
	declare	@last_seed bigint, @identity_so_far bigint, @threshold int, @range bigint
	declare @database sysname, @table_name sysname
	declare @qualname nvarchar(512)
    DECLARE @distributor sysname
    DECLARE @distribdb sysname

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

    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                       @distribdb = @distribdb OUTPUT
    IF @@ERROR <> 0
    BEGIN
        RAISERROR (14071, 16, -1)
        RETURN (1)
    END

    DECLARE adjust_identity CURSOR LOCAL FAST_FORWARD FOR
        SELECT art1.objid
          FROM sysarticles art1,
		       sysarticleupdates art2
		  where art1.artid = art2.artid and
			    art2.identity_support = 1 and
				(art1.artid = @artid or @artid is null)
    FOR READ ONLY

	OPEN adjust_identity		
    FETCH adjust_identity INTO @objid
    WHILE (@@fetch_status <> -1)
	begin
		select @table_name = object_name(@objid)
		exec @retcode = dbo.sp_MSget_qualified_name @objid, @qualname OUTPUT
		
		select @range = range, @pub_range = pub_range, @current_pub_range = current_pub_range, 
            @last_seed = last_seed, 
            @threshold = threshold from 
			MSpub_identity_range where objid=@objid
  
		select @identity_so_far = ident_current(@qualname)

		if @last_seed is null
		begin
			-- First time
    		select @last_seed = (@identity_so_far / @pub_range) * @pub_range
			-- We always reserve a new range for the publisher without reseeding 
			-- the publisher, and we guarantee to have more slots then 
			-- a full range initially for the publisher.
			if	(@pub_range > 0 and @last_seed < @identity_so_far) or
				(@pub_range < 0 and @last_seed > @identity_so_far)
				select @last_seed = @last_seed + @pub_range

			select @next_seed = @last_seed + @pub_range
			-- Initialize distribution side entry
			SELECT @cmd = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSinsert_identity'
			EXEC @retcode = @cmd
				@publisher = @@servername,
				@publisher_db = @database,
				@tablename = @table_name,
				@identity_support = 1,
				@pub_identity_range = 0, -- We don't need this at the distributor
				@identity_range = @range,
				@threshold 	= @threshold,
                -- Make sure we don't have gap at the beginning
				@next_seed	= @next_seed,
				@max_identity = null
			IF @@ERROR <> 0 OR @retcode <> 0
				GOTO UNDO
		    -- Add constraint only without reseeding.
		    exec @retcode = dbo.sp_MSreseed
			    @objid = @objid,
			    @next_seed = @last_seed,
			    @range = @pub_range,
			    @is_publisher = -1,
                @check_only = 1,
				@initial_setting = 1,
				@bound_value = @identity_so_far

		    IF @@ERROR <> 0 OR @retcode <> 0
			    GOTO UNDO
		    update MSpub_identity_range set last_seed = @last_seed where objid = @objid
		    IF @@ERROR <> 0
			    GOTO UNDO
		end
		else
		begin

			-- Leave one slot unused. This is to prevent violation of primary key constraint
			-- if the next value is used by a subscriber and the publisher has received it.
			-- It seems the pk constraint will be validated before this check.
			declare @actual_range int
			if @current_pub_range > 0
				select @actual_range = @current_pub_range -1
			else
				select @actual_range = @current_pub_range +1

			-- Calculate the current ratio
			if 100*(@identity_so_far - @last_seed)/@actual_range >= @threshold
			-- need bump up
			begin
				SELECT @cmd = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSfetchAdjustidentityrange'
				EXEC @retcode = @cmd
					@publisher = @@servername,
					@publisher_db = @database,
					@tablename = @table_name,
					@adjust_only = 1,
					@for_publisher = 1,
					@range = @pub_range,
					@next_seed = @next_seed output
				IF @@ERROR <> 0 OR @retcode <> 0
					GOTO UNDO

				select @last_seed = @next_seed - @pub_range
				
				update MSpub_identity_range set last_seed = @last_seed,
					current_pub_range = @pub_range
					where objid = @objid
				IF @@ERROR <> 0
					GOTO UNDO
				-- RESEED and change constraint
				exec @retcode = dbo.sp_MSreseed
					@objid = @objid,
					@next_seed = @last_seed,
					@range = @pub_range,
					@is_publisher = -1
				IF @@ERROR <> 0 OR @retcode <> 0
					GOTO UNDO
			end
		end

		FETCH adjust_identity INTO @objid
	end
	return 0
UNDO:
	-- No need to start a transaction.
    return 1
go

EXEC dbo.sp_MS_marksystemobject sp_MSpub_adjust_identity
GO


print ''
print 'Creating procedure sp_helparticledts'
go

CREATE PROCEDURE sp_helparticledts (
    @publication sysname,        /* Publication name */
    @article sysname	         /* Article name */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @artid int
    DECLARE @pubid int
    DECLARE @retcode int
	declare @article_name sysname

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

	declare @allow_dts bit

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

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


	if @allow_dts = 0
	begin
		RAISERROR ('The publication ''%s'' does not allow DTS.', 11, -1, @publication)
		RETURN (1)
	end

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

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

    /*
    EXECUTE @retcode = dbo.sp_validname @article

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

    SELECT @artid = artid, @article_name = name
      FROM sysarticles
     WHERE name = @article
       AND pubid = @pubid
    IF @artid IS NULL
        BEGIN
            RAISERROR (20027, 11, -1, @article)
            RETURN (1)
        END
	
	select 
		N'pre_script_ignore_error_task_name' = @article_name + N'_pre_ignore_error',
		N'pre_script_task_name' = @article_name + N'_pre',
		N'transformation_task_name' = @article_name,
		N'post_script_ignore_error_task_name' = @article_name + N'_post_ignore_error',
		N'post_script_task_name' = @article_name + N'_post'
go

EXEC dbo.sp_MS_marksystemobject sp_helparticledts
GO


print ''
print 'Creating procedure sp_changesubscriptiondtsinfo'
go

CREATE PROCEDURE sp_changesubscriptiondtsinfo (
    @job_id varbinary(16),
    @dts_package_name sysname = NULL,
	@dts_package_password sysname = NULL,
	@dts_package_location nvarchar(12) = NULL

    ) AS

    /*
    ** Declarations.
    */

    DECLARE @srvid smallint
    DECLARE @artid int
    DECLARE @retcode int
	declare @login_name sysname
	declare @update_mode int
	declare @subscription_type int
	declare @dts_package_location_id int

    /*
    ** Initializations.
    */
    SET NOCOUNT ON
    
	
    /* 
    ** Get subscription properties and do Security Check.
    ** We use login_name stored in syssubscriptions to manage security 
    */

	select @update_mode = update_mode, @login_name = login_name,
		@subscription_type = subscription_type,
		@artid = artid              
		FROM syssubscriptions s WHERE 
			s.distribution_jobid = @job_id

    /*
    ** Check if the subscription exists.
    */
    IF @update_mode is null
	BEGIN
        RAISERROR (14055, 11, -1)
        RETURN (1)
    END

	if	@update_mode != 0
	begin
		RAISERROR(21180, 16, -1)    
		RETURN (1)
	end

	-- Only push store DTS info at distributor.
	if @subscription_type <> 0
	begin
		RAISERROR(21181, 16, -1)    
		RETURN (1)
	end

	--Security check

    IF  suser_sname(suser_sid()) <> @login_name AND is_srvrolemember('sysadmin') <> 1  
        AND is_member ('db_owner') <> 1
    BEGIN
		-- Only members of the sysadmin fixed server role, db_owner fixed database role or the creator of the subscription can change this subscription property.'
        RAISERROR(21175, 11, -1)
        RETURN (1)
    END

    -- Get pubid
	declare @pubid int
	select @pubid = pubid from sysarticles where artid = @artid

    /* Get subscription type of the publication */
	if not exists (select * from syspublications where
		pubid = @pubid and
		allow_dts = 1)
	begin
		RAISERROR(21178, 16, -1)    
		RETURN (1)
	end

	if @dts_package_location is null
		select @dts_package_location_id = null
	else IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = N'distributor' 
		select @dts_package_location_id = 0
	ELSE IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = N'subscriber' 
		select @dts_package_location_id = 1
	ELSE 
	begin
		raiserror(20587, 16, -1, '@dts_package_location', 'sp_changesubscriptiondtsinfo')
		return(1)
	end

	-- Encrypt DTS package password
	declare @change_password bit

	if @dts_package_password is null
		select @change_password = 0
	else
		select @change_password = 1

	-- When user sends in empty string, reset it to null.
	-- Have to do this before scramble because the result may contains invalid
	-- unicode code points which are equael to some collation.
	if @dts_package_password = N''
		select @dts_package_password = NULL

	declare @enc_dts_package_password nvarchar(524)
        select @enc_dts_package_password = @dts_package_password

	if @enc_dts_package_password is not null
	begin
		EXEC @retcode = master.dbo.xp_repl_encrypt @enc_dts_package_password OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end

    /*
    ** Get distribution server information for remote RPC
    ** agent verification.
    */
    declare @distributor sysname
	declare @distribdb sysname
	declare @distproc nvarchar(1000)

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

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

    /*
    ** Call proc to change the distributor
    */
    SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + 
        '.dbo.sp_MSchange_subscription_dts_info'

	exec @retcode = @distproc 
		@job_id = @job_id,
		@dts_package_name = @dts_package_name,
		@dts_package_password = @enc_dts_package_password,
		@dts_package_location = @dts_package_location_id,
		@change_password = @change_password

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

    RETURN (0)
go

EXEC dbo.sp_MS_marksystemobject sp_changesubscriptiondtsinfo
GO

print ''
print 'Creating procedure sp_MSdrop_6x_replication_agent'
go
create procedure sp_MSdrop_6x_replication_agent
@job_id UNIQUEIDENTIFIER,
@category_id int
as
    declare @distbit int
    declare @db_name sysname
    declare @cmd varchar(4000)

    select @distbit = 16

    declare hCdatabase CURSOR LOCAL FAST_FORWARD FOR
        select name from master.dbo.sysdatabases 
            where
            category & @distbit <> 0 
        for read only

    open hCdatabase
    fetch next from hCdatabase into @db_name
    while (@@fetch_status <> -1)
    begin

        if @category_id = 13
        begin
            select @cmd = 'delete from ' + @db_name + '.dbo.MSlogreader_agents where job_id = convert (uniqueidentifier, ''' +
                convert (varchar(100), @job_id) + ''')'
            exec (@cmd)
        end
        else if @category_id = 15   
        begin
            select @cmd = @db_name + '.dbo.sp_MSdrop_6x_publication'
            exec @cmd @job_id = @job_id
        end
        else
            return 0

        if @@ERROR <> 0
            return 1
        
        fetch next from hCdatabase into @db_name
    end
    close hCdatabase
    deallocate hCdatabase
go

EXEC dbo.sp_MS_marksystemobject sp_MSdrop_6x_replication_agent
GO

print ''
print 'Creating procedure sp_MSreinit_article'
go
create procedure sp_MSreinit_article (
	@publication sysname
	,@article sysname = N'%'
	,@need_new_snapshot bit = 0
	,@need_reinit_subscription bit = 0
	,@force_invalidate_snapshot bit	= 0
	,@force_reinit_subscription bit = 0
	,@check_only bit = 0
)
as
	declare @retcode int
		,@active tinyint
		,@subscribed tinyint
		,@artid int
		,@pubid int
		,@none tinyint
		,@immediate_sync_ready bit
		,@allow_anonymous bit

    -- Initialization
    select @active = 2
    select @subscribed = 1
    SELECT @none = 2            /* Const: synchronization type 'none' */
    select @active = 2
	select @pubid = pubid, @immediate_sync_ready = immediate_sync_ready,
		@allow_anonymous = allow_anonymous 
		from syspublications where name = @publication
	
	if @article = N'%'
		select @artid = 0
	else
		select @artid = artid from sysarticles where name = @article and pubid = @pubid

	begin tran 
	save tran sp_MSreinit_article

	if @need_new_snapshot = 1 and @immediate_sync_ready = 1
	begin
		-- If at publication level, we know that we should do it since 
		-- @immediate_sync_ready = 1
		-- If at article level, we only do it for the articles that have been
		-- processed by the snapshot agent, but not new articles.
		-- sp_addarticle calls this proc at publication level.
		-- It also make calls to sp_articlecolumn and sp_articleview which in turn
		-- call this sp. We don't want to do anything here with those calls.
		if @artid = 0 or exists (select * from syssubscriptions s where 
			s.srvid < 0 and
			s.status = @active and
			s.artid = @artid)
		begin
			-- Fail and raiserror error
			if @force_invalidate_snapshot = 0
			begin
				raiserror(20607, 16, -1)
				goto UNDO
			end

			if @check_only = 0
			begin
				UPDATE syspublications SET immediate_sync_ready = 0 WHERE 
					pubid = @pubid and
					immediate_sync_ready <> 0
                IF @@ERROR <> 0
					goto UNDO

				DECLARE @distributor sysname
					, @distribdb sysname
					, @distproc nvarchar (255)
					, @dbname sysname

				select @dbname = db_name()

				EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
												   @distribdb = @distribdb OUTPUT
				IF @retcode <> 0 OR @@ERROR <> 0
					goto UNDO

				IF @distribdb IS NULL OR @distributor IS NULL
				BEGIN
					RAISERROR (14071, 16, -1)
					goto UNDO
				END

				-- Deactivate virtual (but not virtual anonymous) subscriptions at the distributor
				SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSinvalidate_snapshot'
				EXEC @retcode = @distproc 
					@publisher = @@SERVERNAME, 
					@publisher_db = @dbname, 
					@publication = @publication

				IF @@ERROR <> 0 OR @retcode <> 0
					goto UNDO

				-- Raise a warning. Snapshot is invalidated. Need to run
				-- snapshot agent again..
				raiserror(20605, 10, -1)
			end
		end
	end
	
	if @need_reinit_subscription = 1
	begin
		-- Reinitialize the subscriptions if there are any.
		-- No need to reinit no_sync subscriptions.
		-- The query below works for an article or whole publication (@artid == 0)
		-- Including virtual subscriptions to take care anonymous.
		if exists (select * from syssubscriptions s where
			s.status = @active and
			-- Only include virtual subscription if allow anonymous
			(s.srvid >= 0 or (@allow_anonymous = 1 and @immediate_sync_ready = 1)) and
			s.sync_type <> @none and
			(s.artid = @artid or 
			(@artid = 0 and exists (select * from 
				syspublications p, sysarticles a where
				a.artid = s.artid and 
				a.pubid = p.pubid and
				p.pubid = @pubid))))
		begin
			-- Fail and raiserror error
			if @force_reinit_subscription = 0
			begin
				raiserror(20608, 16, -1)
				goto UNDO
			end

			if @check_only = 0
			begin
				EXEC @retcode = dbo.sp_reinitsubscription 
					@publication = @publication, 
					@article = @article,
					@subscriber = 'all',
					@for_schema_change = 1
				IF @@ERROR <> 0 OR @retcode <> 0
				BEGIN
					GOTO UNDO
				END
				-- Raise a warning. Subscriptions is reintialized.
				raiserror(20606, 10, -1)
			end
		end
	end

	COMMIT TRAN sp_MSreinit_article
	
	return 0
UNDO:
    IF @@TRANCOUNT > 0
    begin
        ROLLBACK TRAN sp_MSreinit_article
        COMMIT TRAN 
    end
    return 1
go

EXEC dbo.sp_MS_marksystemobject sp_MSreinit_article
GO


print ''
print 'Creating procedure sp_MScomputearticlescreationorder'
go
CREATE PROCEDURE sp_MScomputearticlescreationorder
    @publication sysname
AS
    SET NOCOUNT ON
    DECLARE @pubid int 
    DECLARE @max_level int
    DECLARE @current_level int
    DECLARE @update_level int
    DECLARE @limit int
    DECLARE @result int
    DECLARE @retcode int

    SELECT @retcode = 0

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

    SELECT @pubid = NULL
    -- Get the pubid from syspublications 
    SELECT @pubid = pubid 
      FROM syspublications
     WHERE name = @publication

    IF @@ERROR <> 0
        RETURN (1)

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

    EXEC @result = sp_getapplock @Resource = @publication, 
				@LockMode = N'Shared', 
				@LockOwner = N'Session', 
				@LockTimeout = 0

    IF @result < 0
    BEGIN
        RAISERROR(21385, 16, -1, @publication)
        RETURN (1)
    END

    -- Find out the total number of articles in this publication and
    -- compute the maximum tree height based on the number of articles in 
    -- the publication. Here, the tree height is counted from the
    -- leaf-nodes towards the root(s)
    SELECT @max_level = COUNT(*) + 10,
           @limit =2 *  COUNT(*) + 11 
      FROM sysextendedarticlesview 
     WHERE pubid = @pubid
 
    IF @@ERROR <> 0
    BEGIN
        RETURN (1)
    END
   
    -- The following temp table contains the minimal amount of 
    -- article information that we want to keep around and the current
    -- computed tree level of the article
    CREATE TABLE #article_level_info
    (
        article         sysname collate database_default not null,
        source_objid    INT     NOT NULL,
        tree_level      INT     NOT NULL,
        ref_level       INT     NOT NULL,
        major_type      TINYINT NOT NULL  -- 1-view&func, 0-other 
    )  
   
    CREATE CLUSTERED INDEX ucarticle_level_info 
        ON #article_level_info(source_objid)

    IF @@ERROR <> 0
    BEGIN
        GOTO Failure
    END

    -- Populate the article level info table. All articles will be
    -- assigned 0 as their initial tree level. Having 
    -- a tree level of 0 means that the algorithm hasn't discovered 
    -- any objects that the article depends on within the publication.

    INSERT INTO #article_level_info 
    SELECT name, objid, 0, 0, 
        CASE type    
            WHEN 0x40 THEN 1
            WHEN 0x80 THEN 1
            ELSE 0 
        END
      FROM sysextendedarticlesview
     WHERE pubid = @pubid
      
    -- To jump-start the algorithm, update the tree_level of 
    -- all articles with no dependency to @max_level.

    UPDATE #article_level_info 
       SET tree_level = @max_level
     WHERE NOT EXISTS (SELECT * 
                         FROM sysdepends 
                        WHERE source_objid = id
                          and id <> depid)
    IF @@ERROR <> 0
        GOTO Failure

    -- For each increasing tree level starting from @max_level, update the 
    -- the tree_level of articles depending on objects at the current
    -- level to current level + 1
    SELECT @current_level = @max_level
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1

        UPDATE #article_level_info
           SET tree_level = @update_level
          FROM #article_level_info 
        INNER JOIN sysdepends d
            ON #article_level_info.source_objid = d.id 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid       
               AND ali1.tree_level = @current_level
               AND d.id <> d.depid)
    
        -- Terminate the algorithm if we cannot find any articles 
        -- depending on articles at the current level     
        IF @@ROWCOUNT = 0
            GOTO PHASE1

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1

        -- Although there should not be any circular 
        -- dependencies among the articles, the following
        -- check is performed to guarantee that 
        -- the algorithm will terminate even if there 
        -- is circular dependency among the articles
        
        -- Note that with at least one node per level,
        -- the current level can never exceed the total 
        -- number of articles (nodes) unless there is
        -- circular dependency among the articles.
        
        -- @limit is defined to be # of articles + 1
        -- although @limit = # of articles - 1 will be
        -- sufficient. This is to make absolutely sure that 
        -- the algorithm will never terminate too early

        IF @current_level > @limit
            GOTO PHASE1
    END

PHASE1:

    -- There may be interdependencies among articles 
    -- that haven't been included in the previous calculations so
    -- we compute the proper order among these articles here.
    SELECT @limit = @max_level - 9
    SELECT @current_level = 0
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info 
           SET tree_level = @update_level
          FROM #article_level_info
        INNER JOIN sysdepends d
            ON (#article_level_info.source_objid = d.id
                AND #article_level_info.tree_level < @max_level) 
        INNER JOIN #article_level_info ali1
            ON (d.depid = ali1.source_objid
                AND ali1.tree_level = @current_level
                AND d.id <> d.depid)
        IF @@ROWCOUNT = 0
            GOTO PHASE2
        
        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE2
    END         

PHASE2:

    -- Since transactional doesn't keep the nickname around in 
    -- sysmergearticles as merge does, we need to compute FK/PK ordering on 
    -- the fly. 
    SELECT @current_level = 0
    SELECT @limit = @max_level - 9
    WHILE 1 = 1
    BEGIN
        SELECT @update_level = @current_level + 1
        
        UPDATE #article_level_info
           SET ref_level = @update_level
          FROM #article_level_info
        INNER JOIN sysreferences r
            ON (#article_level_info.source_objid = r.fkeyid
                and r.rkeyid <> r.fkeyid)
        INNER JOIN #article_level_info ali1
            ON (r.rkeyid = ali1.source_objid 
                AND ali1.ref_level = @current_level)
        IF @@ROWCOUNT = 0
            GOTO PHASE3

        IF @@ERROR <> 0
            GOTO Failure

        SELECT @current_level = @current_level + 1
        IF @current_level > @limit
            GOTO PHASE3
    END

PHASE3:

    -- Select the articles out of #article_level_info 
    -- in ascending order of tree_level. This will give
    -- the proper order in which articles can be created
    -- without violating the internal dependencies among
    -- themselves. Note that this algorithm still allows 
    -- unresolved external references outside the publication.
    -- All this algorithm can guarantee is that all articles will
    -- be created successfully using the resulting order if 
    -- there is no dependent object outside the publication. 
    -- We need to order the articles in reverse ref_level
    -- to account for FK/PK constraints when dropping/deleting rows/truncating
    -- tables on the Subscriber.

    SELECT article
      FROM #article_level_info
    ORDER BY major_type ASC, tree_level ASC, ref_level DESC

    DROP TABLE #article_level_info
    RETURN (0)

Failure:

    DROP TABLE #article_level_info
    RETURN (1)
GO

exec dbo.sp_MS_marksystemobject sp_MScomputearticlescreationorder
go

print ''
print 'Creating procedure sp_MScomputeunresolvedrefs'
go
CREATE PROCEDURE sp_MScomputeunresolvedrefs
    @publication sysname, -- Must provide the publication name
    @article     sysname = '%' -- '%' means all articles in the specified publication, otherwise an exact match is performed
AS
    SET NOCOUNT ON 
    DECLARE @pubid int 
    
    -- Parameter check: @publication

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

    SELECT @pubid = NULL 
    -- Get the pubid of the publication
    SELECT @pubid = pubid 
      FROM syspublications
     WHERE name = @publication
    
    IF @pubid IS NULL
    BEGIN
        RAISERROR (20026, 11, -1, @publication)
        RETURN (1)    
    END

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


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

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

create procedure sp_MShelptranconflictpublications (
 	@publication_type	sysname = 'queued' )		-- '%'==ALL | 'queued'
as
begin
	set nocount on
	declare @merge_pub_id uniqueidentifier
	
	--
	-- validate
	--
	if (@publication_type NOT IN ('%', 'queued'))
	begin
		raiserror('sp_MShelptranconflictpublications(debug): Invalid @publication_type=%s specified', 16, 1, @publication_type)
		return (1)
	end
		
	--
	-- create a temp table for results
	--
 	create table #cftpublications ( publication sysname collate database_default, t_pub_id integer, s_agent_id integer)

 	--
 	-- process publisher info
 	--
 	if exists (select * from sysobjects where name = 'syspublications')
 	begin
 		insert into #cftpublications(publication, t_pub_id)
 			select name, pubid from syspublications
 		if (@@error != 0)
 		begin
			raiserror('sp_MShelptranconflictpublications(debug): insert for tran publications failed', 16, 1)
			return (1)
 		end
 	end

 	--
 	-- process subscriber info
 	--
 	if exists (select * from sysobjects where name = 'MSsubscription_agents')
 	begin
 		insert into #cftpublications(publication, s_agent_id)
 			select publication, id from MSsubscription_agents where update_mode in (2,3,4,5)
 	end

 	--
 	-- now do a select on the temp table
 	--
 	select	'name'				= publication,
 			'publication_type'	= N'queued',
 			'merge_pub_id' 		= @merge_pub_id,
 			'tran_pub_id' 		= t_pub_id,
 			'sub_agent_id'		= s_agent_id
 	from 	#cftpublications
 			
 	--
 	-- all done
 	--
 	return 0
end
go

exec dbo.sp_MS_marksystemobject sp_MShelptranconflictpublications
go

/*
 * Name :       sp_MShelptranconflictcounts
 * Description: This sp returns the count of conflicts (from each conflict table) in 
 *    each publication. Results can optionally be filtered to include only a 
 *    single publication. Results are always ordered by article name. Only 
 *    articles with non-zero conflict counts are returned.
 * Parameters:  1. Publication Name( sysname; default '%'==ALL PUBLICATIONS)
 * Output Result Set has the following structure:
 *  
----------------------------------------------------------------------------------
 *      Name                Datatype                Description
 *  
----------------------------------------------------------------------------------
 *  a. article    (nvarchar(256))      owner qualified Article name
 *  b. conflict_table  (sysname)   Associated conflict table (owner qualified)
 *  c. queued_source_proc (sysname)   Queued proc to get source row - sp_MSgettrancftsrcrow
 *  d. centralized_conflicts(bit)    Centralized (1) or Decentralized (0) 
 *            conflicts specified by the article
 *  e. conflict_count  (integer)           Count of (insert, update and delete) conflicts in 
 *            the conflict table for this article
 */
raiserror('Creating procedure sp_MShelptranconflictcounts', 0,1)
GO

create procedure sp_MShelptranconflictcounts ( 
	@publication_name sysname = '%' )
as 
begin
	set nocount on 

	declare @pubid int
			,@centralized_conflicts bit
			,@article sysname
			,@artid int
			,@conflict_table sysname
			,@cft_tabid int
			,@spname sysname
			,@cmd nvarchar(4000)
			,@conflicts_count int
			,@publisher sysname
			,@publisher_db sysname
			,@owner sysname

	select @spname = 'sp_MSgettrancftsrcrow'

	--
	-- create temp table for results
	--
	create table #result_list ( article nvarchar(256) collate database_default, conflict_table sysname collate database_default null,  
		centralized_conflicts bit, conflict_count integer)

	create table #conflict_list ( artid sysname collate database_default, conflict_count int, sub_agent_id int )

	-- 
	-- process publisher
	--
	if exists ( select * from sysobjects where name = 'sysarticles')
	begin
		--
		-- Walk through each publication that allows queued operation
		--
		if ( @publication_name = '%' )
			declare hCPubCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select pubid, centralized_conflicts
				from syspublications
				where allow_queued_tran = 1
		else
			declare hCPubCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select pubid, centralized_conflicts
				from syspublications
				where allow_queued_tran = 1
					and name = @publication_name

		open hCPubCursor
		fetch hCPubCursor into @pubid, @centralized_conflicts
		while ( @@fetch_status != -1 )
		begin
			--
			-- Walk through each article in this publication
			--
			declare hCArtCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select a.name, b.conflict_tableid, a.artid
				from sysarticles a join
					sysarticleupdates b on
						a.artid = b.artid and
						a.pubid = b.pubid
				where a.pubid = @pubid

			open hCArtCursor
			fetch hCArtCursor into @article, @cft_tabid, @artid
			while ( @@fetch_status != -1 )
			begin
				--
				-- get the owner qualified conflict table name
				--
				select @owner = QUOTENAME(user_name(OBJECTPROPERTY(@cft_tabid, 'OwnerId')))
				select @conflict_table = @owner + N'.' + QUOTENAME(OBJECT_NAME(@cft_tabid))

				--
				-- Get all the conflict counts
				--
				select @cmd = 'select ' + cast(@artid as nvarchar(10)) +  
					', count(*) from ' + @conflict_table + 
					' where conflict_type in (1, 5, 7) and pubid = ' + 
					cast(@pubid as nvarchar(10))
				insert into #conflict_list ( artid, conflict_count )
					exec ( @cmd )

				select @conflicts_count = NULLIF(conflict_count, 0)
				from #conflict_list
				where artid = @artid
				
				if (@conflicts_count > 0)
				begin
					--
					-- add a row to the #result_list
					--
					insert into #result_list ( article, conflict_table, centralized_conflicts, conflict_count )
						select @owner + N'.' + QUOTENAME(@article), @conflict_table, @centralized_conflicts, @conflicts_count
				end
				
				--
				-- fetch next row from hCArtCursor
				--
				fetch hCArtCursor into @article, @cft_tabid, @artid
			end
			close hCArtCursor
			deallocate hCArtCursor

			--
			-- fetch next row from hCPubCursor
			--
			fetch hCPubCursor into @pubid, @centralized_conflicts	
		end
		close hCPubCursor
		deallocate hCPubCursor
	end

	--
	-- process subscriber side
	--
	delete #conflict_list
	if exists ( select * from sysobjects where name = 'MSsubscription_articles')
	begin
		--
		-- Walk through each subscription that allows queued operation
		--
		if ( @publication_name = '%' )
			declare hCPubCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select id, 0, publisher, publisher_db 
				from MSsubscription_agents 
				where update_mode in (2,3,4,5)
		else
			declare hCPubCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select id, 0, publisher, publisher_db 
				from MSsubscription_agents 
				where update_mode in (2,3,4,5)
					and publication = @publication_name

		open hCPubCursor
		fetch hCPubCursor into @pubid, @centralized_conflicts, @publisher, @publisher_db
		while ( @@fetch_status != -1 )
		begin
			--
			-- Walk through each article in this subscribed publication
			--
			declare hCArtCursor CURSOR LOCAL FAST_FORWARD fast_forward for
				select a.article, OBJECT_ID(a.cft_table), a.artid
				from MSsubscription_articles a join
					MSsubscription_agents b on
						a.agent_id = b.id
				where b.id = @pubid

			open hCArtCursor
			fetch hCArtCursor into @article, @cft_tabid, @artid
			while ( @@fetch_status != -1 )
			begin
				--
				-- get the owner qualified conflict table name
				--
				select @owner = QUOTENAME(user_name(OBJECTPROPERTY(@cft_tabid, 'OwnerId')))
				select @conflict_table = @owner + N'.' + QUOTENAME(OBJECT_NAME(@cft_tabid))

				--
				-- Get all the conflict counts
				--
				select @cmd = 'select ' + cast(@artid as nvarchar(10)) +  
					', count(*), ' + cast(@pubid as nvarchar(10)) + 
					' from ' + @conflict_table + 
					' where conflict_type in (1, 5, 7) 
						and origin_datasource = ''' + @publisher + '.' + @publisher_db + ''''
					
				insert into #conflict_list ( artid, conflict_count, sub_agent_id )
					exec ( @cmd )

				select @conflicts_count = NULLIF(conflict_count, 0)
				from #conflict_list
				where artid = @artid and sub_agent_id = @pubid
				
				if (@conflicts_count > 0)
				begin
					--
					-- add a row to the #result_list
					--
					insert into #result_list ( article, conflict_table, centralized_conflicts, conflict_count )
						select @owner + N'.' + QUOTENAME(@article), @conflict_table, @centralized_conflicts, @conflicts_count
				end
				
				--
				-- fetch next row from hCArtCursor
				--
				fetch hCArtCursor into @article, @cft_tabid, @artid
			end
			close hCArtCursor
			deallocate hCArtCursor

			--
			-- fetch next row from hCPubCursor
			--
			fetch hCPubCursor into @pubid, @centralized_conflicts, @publisher, @publisher_db	
		end
		close hCPubCursor
		deallocate hCPubCursor
	end

	--
	-- do a select for results
	--
	select 	article,
			conflict_table,
			'queued_source_proc' = @spname,
			centralized_conflicts,
			conflict_count
	from #result_list

	--
	-- all done
	--
	return (0)
end
go

exec dbo.sp_MS_marksystemobject sp_MShelptranconflictcounts
go 

/*
 * Name :       sp_MSgettranconflictrow
 * Description: This sp returns a result set containing the requested conflict row(s) 
 *    for a queued publication. Result set ordered by transaction id and 
 *    row identifier.
 * Parameters:  
 *	  1. tran_id	nvarchar(70). ('%'==ALL transactions for the article)
 *    2. row_id ( uniqueidentifer or '%'==ALL rows for a given transaction)
 *    3. conflict_table    (sysname)
 * Output Result Set has the following structure:
 *  
----------------------------------------------------------------------------------
 *      Name                Datatype                Description
 *  
----------------------------------------------------------------------------------
 * returns the current row (all columns) from conflict table with specified tran_id, (row_id)insert_date
 */
raiserror('Creating procedure sp_MSgettranconflictrow', 0,1)
GO

create procedure sp_MSgettranconflictrow ( 
	@tran_id sysname = '%',						-- % = ALL
	@row_id sysname = '%',						-- % = ALL
	@conflict_table sysname)
as 
begin
	set nocount on
	declare @cmd nvarchar(4000)
	    ,@whcmd nvarchar(4000)
            ,@retcode int

        /*
        **  Security check.  restrict to 'sysadmin' and member of db_owner role
        */ 
        exec @retcode = dbo.sp_MSreplcheck_publish
        if @@ERROR <> 0 or @retcode <> 0
            return (1)

	select @cmd = N'select * from ' + @conflict_table 
	if (@tran_id != N'%')
	begin
		if (@whcmd is null)
			select @whcmd = N'tranid = ''' + @tran_id + N''''
		else
			select @whcmd = @whcmd + N' and tranid = ''' + @tran_id + N''''		
	end
	if (@row_id != N'%')
	begin
		if (@whcmd is null)
			select @whcmd = N'qcfttabrowid = ''' + @row_id + N''''
		else
			select @whcmd = @whcmd + N' and qcfttabrowid = ''' + @row_id + N''''
	end

	if (@whcmd is not null)
	begin
		select @cmd = @cmd + N' where ' + @whcmd
	end
	
	execute (@cmd)
end
go

exec dbo.sp_MS_marksystemobject sp_MSgettranconflictrow
go

/*
 * Name :       sp_MSgettrancftsrcrow
 * Description: This sp returns a result set containing the requested source row 
 *     pertaining to a respective conflict row in conflict table (same PK/unique key)
 *     for a queued publication. Result set ordered by transaction id and row identifier
 *	   for the conflict table.
 * Parameters:  1. tran_id (nvarchar(70))
 *	  2. row_id uniqueidentifer - cannot be null
 *    3. conflict_table (nvarchar(256) - owner qualified table name - [owner].[tabname]
 *	  4. is_subscriber bit=0						-- Publisher = 0, Subscriber = 1
 * Output Result Set has the following structure:
 *  
----------------------------------------------------------------------------------
 *      Name                Datatype                Description
 *  
----------------------------------------------------------------------------------
 * returns the current row (all columns) from from source table with same PK for the row in 
 * conflict table with specified tran_id, insert_date
 */
raiserror('Creating procedure sp_MSgettrancftsrcrow', 0,1)
GO

create procedure sp_MSgettrancftsrcrow ( 
	@tran_id sysname,
	@row_id sysname,
	@conflict_table nvarchar(256),
	@is_subscriber bit,
	@is_debug bit=0 )
as 
begin
	set nocount on
	declare @decllist nvarchar(4000)
			,@sellist nvarchar(4000)
			,@wherelist nvarchar(4000)
			,@cmd nvarchar(4000)
			,@cmdrow nvarchar(4000)
			,@srctable sysname
			,@srctabid int
			,@srcowner sysname
			,@columns  binary(32)
			,@indid int
			,@indkey int
			,@key sysname
			,@this_col int
			,@col sysname
			,@typestring nvarchar(60)
			,@dbname sysname
			,@retcode smallint
			,@unqualified_cft_tab sysname
			,@startoffset int

        /*
        **  Security check.  restrict to 'sysadmin' and member of db_owner role
        */ 
        exec @retcode = dbo.sp_MSreplcheck_publish
        if @@ERROR <> 0 or @retcode <> 0
            return (1)
			
	--
	-- validate
	--
	if ((@tran_id is null) or (@row_id is null) or 
		(@conflict_table is null) or (@is_subscriber is null))
	begin
		raiserror('sp_MSgettrancftsrcrow(debug): @tran_id,@row_id,@conflict_table,@is_subscriber cannot be null', 16, 1)
		return (1)
	end

	--
	-- check if the conflict table is owner qualified
	--
	select @startoffset = charindex(N'].[', @conflict_table, 0)
	select @unqualified_cft_tab = case when (@startoffset > 0) 
		then substring(@conflict_table, @startoffset + 2, len(@conflict_table) - @startoffset - 1)
		else quotename(@conflict_table) end
		
	--
	-- get the source table info
	--
	if (@is_subscriber = 1)
	begin
		select @srcowner = owner, @srctable = dest_table, 
			@srctabid = OBJECT_ID(dest_table), @columns = columns
		from MSsubscription_articles
		where quotename(cft_table) = @unqualified_cft_tab
	end
	else
	begin
		select @srcowner = user_name(OBJECTPROPERTY(objid,'OwnerId')), @srctable = OBJECT_NAME(objid), 
			@srctabid = objid, @columns = columns
		from sysarticles a join sysarticleupdates b on
			a.pubid = b.pubid and 
			a.artid = b.artid
		where b.conflict_tableid = OBJECT_ID(@conflict_table)
	end

    --
    -- create code for the following :
    -- select the row of conflict with given tranid and insertdate
    -- retrieve the values of the PK/UI columns for the source table from this row in cft_table
    -- select all columns from source table using the values in a where clause for PK/UI
    --

    --
    -- PK/UI check for source table
    --
	exec @indid = dbo.sp_MStable_has_unique_index @srctabid
	if (@indid = 0)
	begin
		raiserror('sp_MSgettrancftsrcrow(debug):source table %s does not have unique index', 16, 1, @srctable)
		return (1)
	end

	--
	-- create temp tables
	--
    create table #decltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
    create table #seltext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)
    create table #wheretext ( c1 int identity NOT NULL, cmdtext nvarchar(4000) collate database_default null)

	--
	-- walk through each column in PK/UI and build parts of code
	--
	select @indkey = 1
	while (@indkey <= 16)
	begin	
		select @key = index_col(@srctable, @indid, @indkey)
		if (@key is null)
		begin
			select @indkey = 16
		end
		else
		begin
			--
			-- get the column index in the source table for this index key
			--
			exec dbo.sp_MSget_col_position @srctabid, @columns, @key, @col output, @this_col output

			--
			-- get the typestring for this column in source table
			--
			exec dbo.sp_gettypestring @srctabid, @this_col, @typestring OUTPUT

			--
			-- build command strings
			--
			if (@decllist is NULL)
				select @decllist = N'declare @' + @col + N' ' + @typestring
			else
				select @decllist = N' ,@' + @col + N' ' + @typestring
			
			if (@sellist is NULL)
				select @sellist = N'select @' + @col + N' = ' + quotename(@key)
			else
				select @sellist = N' ,@' + @col + N' = ' + quotename(@key)
				
			if (@wherelist is NULL)
				select @wherelist = N'where ' + quotename(@key) + N' = @' + @col
			else
				select @wherelist = N' and ' + quotename(@key) + N' = @' + @col

			--
			-- store them in the temp tables
			--
			insert into #decltext(cmdtext) values(@decllist)
			insert into #seltext(cmdtext) values(@sellist)
			insert into #wheretext(cmdtext) values(@wherelist)
			
		end
		select @indkey = @indkey + 1
	end

    --
    -- Now put all the code in order in the codetext
    --
    if exists (select * from sysobjects where name = 'MSsrcrow_codetext')
    	drop table MSsrcrow_codetext
    	
    create table dbo.MSsrcrow_codetext ( step int identity NOT NULL, cmdtext nvarchar(4000) NULL)

    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #decltext order by c1
    insert into MSsrcrow_codetext(cmdtext) values (N' ')
    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #seltext order by c1
    select @cmd = N' 
	from ' 

	if (@startoffset > 0)
		select @cmd = @cmd + @conflict_table
	else
		select @cmd = @cmd + quotename(@srcowner) + N'.' + @unqualified_cft_tab
		
	select @cmd = @cmd + N'
	where tranid = ''' + @tran_id + ''' and qcfttabrowid = ''' + @row_id + ''' '
    insert into MSsrcrow_codetext(cmdtext) values (@cmd)
    select @cmd = N'select * from ' + quotename(@srcowner) + N'.' + quotename(@srctable) + N' '
    insert into MSsrcrow_codetext(cmdtext) values (@cmd)
    insert into MSsrcrow_codetext(cmdtext)
    	select cmdtext from #wheretext order by c1

	--
	-- now execute the code we just built
	--
	if (@is_debug = 0)
	begin
		--
		-- Build 139:
		-- NOTE xp_execresultset should work here but does not
		-- return for a long time. Using exec() - should revisit
		-- this for more stable builds
		--
		declare #srccursor cursor local FAST_FORWARD FOR 
		select cmdtext from MSsrcrow_codetext order by step 
		FOR READ ONLY

		select @cmd = N' '
		select @dbname = db_name()
		open #srccursor
		fetch #srccursor into @cmdrow
		while (@@FETCH_STATUS = 0)
		begin
			select @cmd = @cmd + @cmdrow
			fetch #srccursor into @cmdrow	
		end		
		close #srccursor
		deallocate #srccursor
		
		execute(@cmd)
		if (@@error != 0)
		begin
			raiserror('sp_MSgettrancftsrcrow(debug): execute() failed for [%s] in db [%s] ', 16, 1, @cmd, @dbname)
			return (1)
		end

	end
	else
		select cmdtext from MSsrcrow_codetext order by step 

	--
	-- all done
	--
	drop table MSsrcrow_codetext
	return 0
end
go

exec dbo.sp_MS_marksystemobject sp_MSgettrancftsrcrow
go

/*
 * Name :       sp_MSdeletetranconflictrow
 * Description: This sp deletes the requested conflict row(s) for a queued publication. 
 *    Can delete all conflicts in a transaction by specifying only tran_id.
 * Parameters:  1. tran_id	(nvarchar(70))
 *    2. row_id ( uniqueidentifier or '%'==ALL conflicts for a given transaction)
 * Output  None.
 *  
----------------------------------------------------------------------------------
 *      Name                Datatype                Description
 *  
----------------------------------------------------------------------------------
 */ 
raiserror('Creating procedure sp_MSdeletetranconflictrow', 0,1)
GO

create procedure sp_MSdeletetranconflictrow ( 
	@tran_id sysname,
	@row_id sysname = '%',						-- % = ALL
	@conflict_table sysname)
as 
begin
	set nocount on
	declare @cmd nvarchar(4000),
            @retcode int

        /*
        **  Security check.  restrict to 'sysadmin' and member of db_owner role
        */ 
        exec @retcode = dbo.sp_MSreplcheck_publish
        if @@ERROR <> 0 or @retcode <> 0
            return (1)

	if (@conflict_table is NULL)
	begin
		raiserror('sp_MSdeletetranconflictrow(debug) - @conflict_table cannot be null', 16, 1)
		return (1)
	end

	select @cmd = 'delete ' + @conflict_table +
		' where tranid = ''' + @tran_id + ''''

	if (@row_id != N'%')
	begin
		select @cmd = @cmd +
		' and qcfttabrowid = ''' + @row_id + ''''
	end
	
	execute (@cmd)
end
go

exec dbo.sp_MS_marksystemobject sp_MSdeletetranconflictrow
go


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

create procedure sp_MSexternalfkreferences
    @publication sysname,
    @article     sysname
as
    declare @pubid int
    declare @objid int
    declare @retcode int

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

    select @pubid = pubid from dbo.syspublications where name = @publication
    select @objid = objid from dbo.sysarticles where pubid = @pubid and name = @article

    select rkeyid, fkeyid from dbo.sysreferences
        where fkeyid = @objid
          and rkeyid not in (select objid from dbo.sysarticles where pubid = @pubid)      
go
exec dbo.sp_MS_marksystemobject sp_MSexternalfkreferences
go

--
-- Name: sp_MSgetarticlereinitvalue
--
-- Description: This proc is called by sync/queued tran generated article procs
-- to get the reinitialization status of a subscription for a given article
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does PAL security check. 
--
raiserror('Creating procedure sp_MSgetarticlereinitvalue', 0,1)
go
create procedure sp_MSgetarticlereinitvalue (
	@subscriber 			sysname,
	@subscriberdb 		sysname,
	@artid	 			int, 
	@reinit		 		int output
)
as
begin
	set NOCOUNT ON
	declare @orig_srvid int
		,@retcode int
		,@publication sysname

	--
	-- PAL security check
	-- Get publication name using artid
	--
	select @publication = p.name
	from syspublications p join sysarticles a on p.pubid = a.pubid
	where a.artid = @artid
	if (@publication is null)
	begin
		return 1
	end
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	--
	-- get the value of reinit flag
	--
	select @orig_srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
	select @reinit = queued_reinit 
	from syssubscriptions 
	where 
		artid = @artid 
		and srvid = @orig_srvid
		and dest_db = @subscriberdb

	-- All done
	return 0
end
go

exec dbo.sp_MS_marksystemobject sp_MSgetarticlereinitvalue
go

--
-- Name: sp_MSispkupdateinconflict
--
-- Description: This procedure is be used by queued tran UPDATE conflict resolution SPs. It
-- takes as input a given article and the update bitmask and decides if 
-- PRIMARY KEY update is taking place returns the following return codes
--
-- Parameter: as defined below
--
-- Returns: 1 or 0, -1
--	-1 : Error in execution
-- 	 0 : Not a PK update
--	 1 : PK update
--
-- Security: Public procedure - publish security check inside. 
--
raiserror('Creating procedure sp_MSispkupdateinconflict', 0,1)
go
create proc sp_MSispkupdateinconflict (
	@pubid int
	,@artid int
	,@bitmap varbinary(4000)
)
as
begin
	declare @retcode int
		,@columns binary(32)
		,@tabname sysname
		,@tabid int
		,@indid int
		,@indkey int
		,@key sysname
		,@colid int
		,@isset int
		,@artcol int
		,@bytepos int
		,@bitpos int

	--
	-- security check
	--
	exec @retcode = dbo.sp_MSreplcheck_publish
	if @@ERROR != 0 or @retcode != 0
		return -1
	--
	-- initalize and validate
	--
	select @columns = [columns]
		,@tabid = objid
		,@indkey = 1
		,@artcol = 0
	from dbo.sysarticles
	where (artid = @artid) and (pubid = @pubid)

	if (@tabid is null)
	begin
		raiserror('sp_MSispkupdateinconflict(Debug): invalid pub and article id : %s.%s', 
				16, -1, @pubid, @artid)
		return -1
	end
	
	select @tabname = QUOTENAME(user_name(OBJECTPROPERTY(@tabid, 'OwnerId'))) collate database_default 
			+ N'.' + QUOTENAME(object_name( @tabid )) collate database_default

	--
	-- get the Primary Key Index
	--
	select @indid = i.indid 
	from dbo.sysindexes i 
	where ((i.status & 2048) != 0) and (i.id = @tabid)
	if (@indid is null)
	begin
		raiserror('sp_MSispkupdateinconflict(Debug): Cannot find primary key for %s', 
				16, -1, @tabname)
		return -1
	end
	
	--
	-- create an enumeration of all the columns that are part of PK
	--
	create table #pkcoltab(pkindex int identity, keyname sysname collate database_default not null)
	while (@indkey <= 16)
	begin
		select @key = index_col( @tabname, @indid, @indkey )
		if (@key is null)
			break
		else
			insert into #pkcoltab(keyname) values(@key)

		select @indkey = @indkey + 1
	end

	--
	-- now walk through each article col and if it is
	-- a part of PK, then check if the update bitmap bit 
	-- corresponding to any article column is set
	--
	DECLARE #hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid, [name] from dbo.syscolumns 
		where id = @tabid order by colid asc

	OPEN #hCColid
	FETCH #hCColid INTO @colid, @key
	WHILE (@@fetch_status != -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @colid, @columns
		if (@isset != 0)
		begin
			--
			-- this column is part of the article
			--
			select @artcol = @artcol + 1
			if exists (select * from #pkcoltab where keyname = @key)
			begin
				--
				-- this column is part of PK
				--
				select 	@bytepos = 1 + (@artcol-1) / 8 
					,@bitpos = power(2, (@artcol-1) % 8 )

				--
				-- if the update bitmap has bit set then
				-- then it is a PK update
				--
				if ((substring(@bitmap, @bytepos, 1) & @bitpos) = @bitpos)
					return 1
			end
		end		

		--
		-- get the next column
		--
		FETCH #hCColid INTO @colid, @key
	end
	CLOSE #hCColid
	DEALLOCATE #hCColid
	drop table #pkcoltab

	--
	-- if we have reached here then it mean the update does not
	-- affect PK columns, cleanup and return
	--
	return 0
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSispkupdateinconflict
GO

--
-- Name: sp_MSisnonpkukupdateinconflict
--
-- Description: This procedure is by queued updating syctran procedures
-- to check if non PK unique index keys were updated in a given queued
-- UPDATE command
--
-- Parameter: as defined below
--
-- Returns: 1 or 0, -1
-- 1 = non PK unique key column(s) was(were) updated
-- 0 = non PK unique key column was not updated
-- -1 = processing error
--
-- Security: Public procedure - publish security check inside. 
--
raiserror('Creating procedure sp_MSisnonpkukupdateinconflict', 0,1)
go
create proc sp_MSisnonpkukupdateinconflict (
	@pubid int
	,@artid int
	,@bitmap varbinary(4000)
)
as
begin
	declare @retcode int
		,@columns binary(32)
		,@tabname sysname
		,@tabid int
		,@indid int
		,@indkey int
		,@key sysname
		,@colid int
		,@isset int
		,@artcol int
		,@bytepos int
		,@bitpos int
	declare @ukcoltab table(ukindex int identity, keyname sysname collate database_default not null)

	--
	-- security check
	--
	exec @retcode = dbo.sp_MSreplcheck_publish
	if @@ERROR != 0 or @retcode != 0
		return -1
	--
	-- initalize and validate
	--
	select @columns = [columns]
		,@tabid = objid
		,@artcol = 0
	from dbo.sysarticles
	where (artid = @artid) and (pubid = @pubid)
	--
	-- validate article
	--
	if (@tabid is null)
	begin
		raiserror(21344, 16, -1, '@pubid, @artid')
		return -1
	end
	--
	-- the table should have non PK unique keys
	--
	exec @retcode = dbo.sp_repltablehasnonpkuniquekey @tabid
	if (@retcode != 1)
	begin
		return 0
	end
	--
	-- get fully qualified table
	--
	select @tabname = QUOTENAME(user_name(OBJECTPROPERTY(@tabid, 'OwnerId'))) collate database_default 
			+ N'.' + QUOTENAME(object_name( @tabid )) collate database_default

	--
	-- get the non PK unique indices
	--
	declare #hcindid cursor local fast_forward for
		select indid from sysindexes 
		where id = @tabid 
			and (status & 2) != 0
			and (status & 2048) = 0
			and indid > 0 and indid < 255
		order by indid asc
	open #hcindid
	fetch #hcindid into @indid
	while (@@fetch_status != -1)
	begin
		--
		-- create an enumeration of all the columns 
		-- that are part of selected unique index
		--
		select @indkey = 1
		while (@indkey <= 16)
		begin
			select @key = index_col( @tabname, @indid, @indkey )
			if (@key is null)
				break
			else
			begin
				if not exists (select * from @ukcoltab where keyname = @key)
					insert into @ukcoltab(keyname) values(@key)
			end
			select @indkey = @indkey + 1
		end
		--
		-- fetch next index
		--
		fetch #hcindid into @indid
	end
	close #hcindid
	deallocate #hcindid
	--
	-- now walk through each article col and if it is
	-- a part of any of the unique keys, then check if the update bitmap bit 
	-- corresponding to any article column is set
	--
	declare #hccolid cursor local fast_forward for
		select colid, [name] from dbo.syscolumns 
		where id = @tabid order by colid asc

	open #hccolid
	fetch #hccolid INTO @colid, @key
	while (@@fetch_status != -1)
	begin
		exec @isset = dbo.sp_isarticlecolbitset @colid, @columns
		if (@isset != 0)
		begin
			--
			-- this column is part of the article
			--
			select @artcol = @artcol + 1
			if exists (select * from @ukcoltab where keyname = @key)
			begin
				--
				-- this column is part of an unique key
				--
				select @bytepos = 1 + (@artcol-1) / 8 
					,@bitpos = power(2, (@artcol-1) % 8 )
				--
				-- if the update bitmap has bit set then
				-- then it is a nonPK key update
				--
				if ((substring(@bitmap, @bytepos, 1) & @bitpos) = @bitpos)
					return 1
			end
		end		
		--
		-- get the next column
		--
		fetch #hccolid INTO @colid, @key
	end
	close #hccolid
	deallocate #hccolid
	--
	-- if we have reached here then it mean the update does not
	-- affect PK columns, cleanup and return
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSisnonpkukupdateinconflict
go

--
-- sp_ivindexhasnullcols
--
-- Proc to validate a indexed view - prior to enabling a indexed view
-- ,this proc is used to make sure the I.V. clustered index is unique
-- and does contain any column that can be NULL
-- 
-- Parameters:
--
--	@viewname sysname 		name of the view
--	,@fhasnullcols bit 		value of 1 if view index has columns that allow NULL
--							value of 0 otherwise (returns 0 if error in execution)
--
-- Returns:
-- 		0 if success
--		1 if failure
--
create proc sp_ivindexhasnullcols (
	@viewname sysname
	,@fhasnullcols bit OUTPUT
)
as
begin
	declare	@f_ind_unique bit
			,@f_ind_clustered bit
			,@ivobject_id int
			,@indkey int
			,@key sysname

	--
	-- validate view object
	--
	select @ivobject_id = object_id(@viewname)
			,@fhasnullcols = 0
			
	if (@ivobject_id IS NULL or @ivobject_id = 0)
	begin
		raiserror('sp_ivindexhasnullcols(debug): invalid view object [%s]', 16, 1, @viewname)
		return 1
	end

	--
	-- get the clustered index and validate
	--
	select @f_ind_unique = case (status & 2) when 0 then 0 else 1 end
			,@f_ind_clustered = case (status & 16) when 0 then 0 else 1 end 
	from dbo.sysindexes
	where id = @ivobject_id and indid = 1
	
	if (@f_ind_unique != 1) or (@f_ind_clustered != 1)
	begin
		raiserror('sp_ivindexhasnullcols(debug): cannot find unique clustered index for the view [%s]', 16, 1, @viewname)
		return 1
	end
	
	--
	-- create an enumeration of all the columns that are part of the view index
	--
	create table #indcoltab(vindexcol int identity, keyname sysname collate database_default not null)
	select @indkey = 1
	while (@indkey <= 16)
	begin
		select @key = index_col( @viewname, 1, @indkey )
		if (@key is null)
			break
		else
			insert into #indcoltab(keyname) values(@key)

		select @indkey = @indkey + 1
	end

	--
	-- We should not have any column participating in this index
	-- that allows NULL if we do
	-- mark the output flag to TRUE
	--
	if exists (select * 
		from dbo.syscolumns 
		where id = @ivobject_id 
			and isnullable = 1
			and name in (select keyname from #indcoltab))
	begin
		select @fhasnullcols = 1
	end

	--
	-- all done, cleanup and return
	--
	drop table #indcoltab
	return 0
end
go

EXEC dbo.sp_MS_marksystemobject sp_ivindexhasnullcols
GO


--
-- fn_sqlvarbasetostr
--
-- UDF to generate string from a given sqlvariant using its base type.
-- This function is used by compensating commands and use special rules
-- for generating strings :
-- For datatypes - varchar, nvarchar, char, nchar, uniqueidenfier, 
-- datetime, smalldatetime, invalid date : The value is quoted with single
-- quotes and any embedded quotes are prefixed with single quote
-- For other datatypes - The value is not quoted
-- 
-- Parameters:
--	@ssvar sql_variant 		input sqlvariant parameter (could be NULL)
--
-- Returns:
-- 	nvarchar(4000) NULL		generated string. Is NULL if input is NULL
--
create function dbo.fn_sqlvarbasetostr (
	@ssvar sql_variant
)
returns nvarchar(4000)
as
begin
	declare @pstrout nvarchar(4000)
			,@basetype sysname

	select @basetype = CAST(SQL_VARIANT_PROPERTY ( @ssvar, 'BaseType' ) as nvarchar(255))
	if (@ssvar IS NOT NULL and @basetype IS NOT NULL)
	begin
		if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
			select @pstrout = N'''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
			select @pstrout = N'N''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
			select @pstrout = N'''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
			select @pstrout = N'N''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
			select @pstrout = master.dbo.fn_varbintohexsubstring(1, CAST(@ssvar as varbinary(8000)), 1, 0)
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
			select @pstrout = CAST(@ssvar as nvarchar(40))
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
			select @pstrout = CONVERT(nvarchar(60), @ssvar, 2)
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
			select @pstrout = CONVERT(nvarchar(40), @ssvar, 2)
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
			select @pstrout = N'''' + CAST(@ssvar as nvarchar(40)) + N''''
		else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
			select @pstrout = N'''' + CONVERT(nvarchar(40), @ssvar, 112) + N' ' + CONVERT(nvarchar(40), @ssvar, 114) + N''''
		else
			select @pstrout = N'''Invalid Datatype' + lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) + N'(' + CAST(@ssvar as nvarchar) + N')'''
	end

	-- All done
	return @pstrout
end
go
exec dbo.sp_MS_marksystemobject fn_sqlvarbasetostr
go

--
-- sp_replqueuemonitor
--
-- Description: this stored procedure displays the messages stored in the 
--  	queue for a given subscription to a queued publication
--
-- Parameters:  
--    1. publisher (sysname, NULL for all publishers)
--    2. publisherdb (sysname, NULL for all publisherdbs)
--    3. publication (sysname , NULL for all publications)
--    4. tranid ( nvarchar(70) NULL for all transactions)
--	  5. queuetype (tinyint 0 for all types of queues, 1 for MSMQ, 2 for SQL)
--
-- Results:
--  Rows of Messages stored in the queue (all types) in the following format:
--	publisher 		sysname,
--	publisher_db 	sysname,
--	publication 	sysname,
--	tranid 			sysname,
--	commandlen 		int,
--	command 		nvarchar(4000)
-- The command is truncated (less than 4000 characters) if
--	1. The total rowsize exceeds the maximum of 8060 bytes
--	2. The SQL command spans multiple queue messages
-- The queue messages that do not contain SQL command or are part of a spanning
-- SQL command are not displayed
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_replqueuemonitor', 0,1)
go
create proc sp_replqueuemonitor (
	@publisher 		sysname = NULL
	,@publisherdb 	sysname = NULL
	,@publication 	sysname = NULL
	,@tranid		 	sysname = NULL
	,@queuetype		tinyint = 0	-- 0 = All Queues, 1 = MSMQ, 2 = SQL
)
as
begin
	set nocount on
	declare @retcode int
			,@queue_server sysname
			,@queue_id sysname
			,@data varbinary(8000)
			,@datalen int
			,@commandtype int
			,@cmdstate bit
			,@mesglen int
			,@command nvarchar(4000)
			,@partialindex int
			,@rowlen int
			,@comandlen int

	declare	@k_mesg_partial_state bit
			,@k_mesg_complete_state bit
			,@k_mesg_tran_cmd int
			,@k_max_rowlen int
			,@k_queuetype_all tinyint
			,@k_queuetype_msmq tinyint
			,@k_queuetype_sql tinyint

	create table #mesgs (mesgid int identity PRIMARY KEY, queuetype tinyint default 1, publisher sysname collate database_default, publisher_db sysname collate database_default, publication sysname collate database_default, 
							tranid sysname collate database_default, commandlen int, command ntext)

	--
	-- Check if need to look for subscriptions
	--
	if exists (select * from dbo.sysobjects where name = 'MSsubscription_agents')
	begin
		--
		-- Are there any qualifying subscriptions
		--
		if exists (select * from dbo.MSsubscription_agents where
				publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
				publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
				publication = case when @publication is NULL then publication else @publication end )
		begin
			--
			-- initialize
			--
			select 	@k_queuetype_all = 0
					,@k_queuetype_msmq = 1
					,@k_queuetype_sql = 2
					
			--
			-- MSMQ based
			--
			if (@queuetype in (@k_queuetype_all, @k_queuetype_msmq) and
				exists (select * from dbo.MSsubscription_agents where
					publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
					publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
					publication = case when @publication is NULL then publication else @publication end  AND
					update_mode IN (2,3) AND
					substring(queue_id, 1, 10) != N'mssqlqueue'))
			begin
				--
				-- enumerate each queue
				--
				create table #queues (publisher sysname collate database_default, publisher_db sysname collate database_default, publication sysname collate database_default, queue_id sysname collate database_default)
				declare #htempcursor cursor local for
					select publisher, publisher_db, publication, queue_server, queue_id 
					from dbo.MSsubscription_agents 
					where
						publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
						publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
						publication = case when @publication is NULL then publication else @publication end  AND
						update_mode IN (2,3) AND
						substring(queue_id, 1, 10) != N'mssqlqueue'

				open #htempcursor
				fetch #htempcursor into @publisher, @publisherdb, @publication, @queue_server, @queue_id
				while (@@fetch_status = 0)
				begin
					--
					-- add the queue server prefix
					--
					select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
					
					--
					-- Display all the messages in this queue
					--
					insert into #mesgs (publisher, publisher_db, publication, tranid, commandlen, command)
						exec @retcode = master.dbo.xp_displayqueuemesgs @publisher, @publisherdb, @publication, @queue_id, @tranid
					if (@retcode != 0 or @@error != 0)
						return 1

					--
					-- fetch next row
					--
					fetch #htempcursor into @publisher, @publisherdb, @publication, @queue_server, @queue_id
				end
				close #htempcursor
				deallocate #htempcursor
	
				--
				-- All MSMQ Queues processed
				--
				drop table #queues
			end
			
			--
			-- SQL Queued based
			--
			if (@queuetype in (@k_queuetype_all, @k_queuetype_sql) and
				exists (select * from dbo.MSsubscription_agents where
					publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
					publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
					publication = case when @publication is NULL then publication else @publication end  AND
					update_mode IN (4,5) AND
					substring(queue_id, 1, 10) = N'mssqlqueue'))
			begin
				--
				-- check if we have a queue
				--
				if exists (select * from dbo.sysobjects where name = 'MSreplication_queue')
				begin
					--
					-- initialize
					--
					select @mesglen = 0
							,@partialindex = 0
							,@k_mesg_partial_state = 1
							,@k_mesg_complete_state = 0
							,@k_mesg_tran_cmd = 1
							,@k_max_rowlen = 8000
					
					--
					-- select the messages that qualify
					--
											
					declare #htempcursor cursor local for
						select publisher, publisher_db, publication, tranid, datalen, data, commandtype, cmdstate
						from dbo.MSreplication_queue 
						where
							publisher = case when @publisher is NULL then publisher else UPPER(@publisher) end AND
							publisher_db = case when @publisherdb is NULL then publisher_db else @publisherdb end AND
							publication = case when @publication is NULL then publication else @publication end  AND
							tranid = case when @tranid IS NULL then tranid else @tranid end
					open #htempcursor
					fetch #htempcursor into @publisher, @publisherdb, @publication, @tranid, @datalen, @data, @commandtype, @cmdstate
					while (@@fetch_status = 0)
					begin
						--
						-- check the message state
						--
						if (@cmdstate = @k_mesg_partial_state)
							select @partialindex = @partialindex + 1
						select @mesglen = @mesglen + @datalen

						--
						-- process the body only for command type messages
						-- and if the command spans multiple rows, then
						-- display only the first row
						--
						if ((@commandtype = @k_mesg_tran_cmd) and
							((@cmdstate = @k_mesg_complete_state and @partialindex = 0) or
							(@cmdstate = @k_mesg_partial_state and @partialindex = 1)))
						begin
							--
							-- decode the command
							--
							exec @retcode = master.dbo.xp_decodequeuecmd @data, @command OUTPUT
							if (@retcode != 0 or @@error != 0)
								return 1
						end
						
						--
						-- Are processing the final row for this command
						--
						if (@cmdstate = @k_mesg_complete_state)
						begin
							--
							-- reset partial index
							--
							if (@partialindex > 0)
								select @partialindex = 0

							if (@command IS NOT NULL)
							begin
								--
								-- check if the command needs to truncated to fit the max rowsize
								--
								select @rowlen = 4 + DATALENGTH(@k_queuetype_sql) + 
												 DATALENGTH(@publisher) + DATALENGTH(@publisherdb) +
												 DATALENGTH(@publication) + DATALENGTH(@tranid) + 
												 DATALENGTH(@mesglen)
										,@comandlen = DATALENGTH(@command)
								if (@rowlen + @comandlen > @k_max_rowlen)
								begin
									select @comandlen = @k_max_rowlen - @rowlen
									select @comandlen = @comandlen / 2
									select @command = SUBSTRING(@command, 1, @comandlen)
								end
								
								insert into #mesgs (queuetype, publisher, publisher_db, publication, tranid, commandlen, command)
								values (@k_queuetype_sql, @publisher, @publisherdb, @publication, @tranid, @mesglen, @command)
								if (@retcode != 0 or @@error != 0)
									return 1

								select @command = NULL
							end

							--
							-- reset command len
							--
							if (@mesglen > 0)
								select @mesglen = 0
						end
						
						--
						-- fetch next row
						--
						fetch #htempcursor into @publisher, @publisherdb, @publication, @tranid, @datalen, @data, @commandtype, @cmdstate
					end
					close #htempcursor
					deallocate #htempcursor
				end 
	
				--
				-- All SQL Queues processed
				--
			end
		end
	end
	
	--
	-- return result
	--
	select 	queue = case when queuetype = @k_queuetype_msmq then N'MSMQ'
						when queuetype = @k_queuetype_sql then N'SQLQ' end 
			,publisher
			,publisher_db
			,publication
			,tranid
			,commandlen
			,command 
	from #mesgs
	order by mesgid
	
	--
	-- All done
	--
	drop table #mesgs
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_replqueuemonitor
go

--
-- sp_replsqlqgetrows
--
-- Description: this stored procedure returns the queued data stored in the 
-- 	MSreplication_queue for a specific subscription to a queued publication.
--	This SP is used by Queue Reader Agent to service SQL based Queues.
--
-- Parameters:  
--    1. publisher 		(sysname, NOT NULL)
--    2. publisherdb 	(sysname, NOT NULL)
--    3. publication 	(sysname, NOT NULL)
--
-- Results:
--  Rows of Queued Data stored in MSreplication_queue in the following format:
--	tranid				sysname
--	datalen				int
--	data				image
--	commandtype			int
--	insertdate			datetime
--	orderkey			bigint
--	cmdstate			bit
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_replsqlqgetrows', 0,1)
go
create proc sp_replsqlqgetrows 
(
	@publisher sysname
	,@publisherdb sysname
	,@publication sysname
	,@batchsize int = 1000
)
as
begin
	declare @retcode int
	set nocount on
	--
	-- Security check
	--
	exec @retcode = dbo.sp_MSreplcheck_subscribe
	if @@error != 0 or @retcode != 0
		return 1
	--
	-- does the queue table exist
	--
	if exists (select * from dbo.sysobjects where name = 'MSreplication_queue')
	begin
		declare @totcommandcount bigint
				,@trancount bigint
		--
		-- does the tran info table exist
		--
		if not exists (select * from dbo.sysobjects where name = 'MSrepl_queuedtraninfo')
		begin
			--
			-- tran info table does not exist - create and populate it
			--
			exec @retcode = sp_MScreate_sub_tables
				@tran_sub_table = 0,
				@property_table = 0,
				@sqlqueue_table = 1
			if  (@@error != 0 or @retcode != 0)
				return 1
		end	
		--
		-- At this point both queue table and tran info table exist
		-- check the command count
		--
		select @totcommandcount = sum(commandcount)
			,@trancount = count(tranid)
		from dbo.MSrepl_queuedtraninfo with (READPAST)
		where publisher = UPPER(@publisher)
			and publisher_db = @publisherdb 
			and publication = @publication

		if (@trancount > 1 and @totcommandcount > @batchsize)
		begin
			--
			-- prepare a list of transactions to read
			--
			declare @tranid sysname
					,@batchcount bigint
					,@curtrancommandcount bigint
			declare @trantab table (tranid sysname primary key)

			select @batchcount = 0
			declare #htcdataseq cursor local for
				select tranid, commandcount
				from dbo.MSrepl_queuedtraninfo with (READPAST) 
				where publisher = UPPER(@publisher) 
					and publisher_db = @publisherdb 
					and publication = @publication
				order by maxorderkey asc
			open #htcdataseq
			fetch #htcdataseq into @tranid, @curtrancommandcount
			if (@@error != 0)
				return 1
			while (@@fetch_status != -1)
			begin
				--
				-- Are we done
				--
				if (@batchcount > @batchsize)
				begin
					--
					-- we are done selecting the transactions to process
					--
					break
				end
				else
				begin
					--
					-- include this transaction
					-- update the batch counter
					--
					insert into @trantab (tranid) values (@tranid)
					if (@@error != 0)
						return 1
					select @batchcount = @batchcount + @curtrancommandcount
				end
				--
				-- fetch next transaction to process
				--
				fetch #htcdataseq into @tranid, @curtrancommandcount
			end
			close #htcdataseq
			deallocate #htcdataseq
			if (@@error != 0)
				return 1
			--
			-- do the join for the select transactions
			-- select the transactions in the order they were committed (maxorderkey ascending).
			-- for each transaction - the commands are ordered using orderkey (ascending)
			--
			select q.tranid, q.datalen, q.data, q.commandtype, q.insertdate, q.orderkey, q.cmdstate 
			from (dbo.MSreplication_queue as q with (READPAST) 
				join (dbo.MSrepl_queuedtraninfo as t with (READPAST)
					join @trantab as tt
					on t.tranid = tt.tranid collate database_default) 
				on q.publisher = t.publisher
					and q.publisher_db = t.publisher_db 
					and q.publication = t.publication
					and q.tranid = t.tranid)
			where t.publisher = UPPER(@publisher)
				and t.publisher_db = @publisherdb 
				and t.publication = @publication
			order by t.maxorderkey asc, q.orderkey asc
		end
		else
		begin
			--
			-- do the join for all the transactions
			-- select the transactions in the order they were committed (maxorderkey ascending).
			-- for each transaction - the commands are ordered using orderkey (ascending)
			--
			select q.tranid, q.datalen, q.data, q.commandtype, q.insertdate, q.orderkey, q.cmdstate 
			from (dbo.MSreplication_queue as q with (READPAST) 
				join dbo.MSrepl_queuedtraninfo as t with (READPAST)
				on q.publisher = t.publisher
					and q.publisher_db = t.publisher_db 
					and q.publication = t.publication
					and q.tranid = t.tranid)
			where t.publisher = UPPER(@publisher)
				and t.publisher_db = @publisherdb 
				and t.publication = @publication
			order by t.maxorderkey asc, q.orderkey asc
		end
	end
	else
	begin
		--
		-- Queue table does not exist
		-- create empty rowset
		--
		declare @nomesgs TABLE (tranid sysname, datalen int, data varbinary(8000),
			commandtype int, insertdate datetime, orderkey bigint, cmdstate bit)
		select * from @nomesgs
	end	
	--
	-- check error
	--
	if (@@error != 0)
		return 1
	--
	-- All done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_replsqlqgetrows
go

--
-- sp_repldeletequeuedtran
--
-- Owner: KaushikC
--
-- Description: this stored procedure is invoked on subscriber by queue reader
-- agent and deletes a transaction from MSreplication_queue. It also removes
-- the entry from MSrepl_queuedtraninfo 
--
-- Parameters:  
--  Look at the create procedure definition
--
-- Returns:
--      0 if success
--      1 if failure
--
-- Security : Public access. Internal check for subscribe access
--
raiserror('Creating procedure sp_repldeletequeuedtran', 0,1)
go
create proc sp_repldeletequeuedtran 
(
    @publisher sysname
    ,@publisher_db sysname
    ,@publication sysname
    ,@tranid sysname
    ,@orderkeylow bigint
    ,@orderkeyhigh bigint
)
as
begin
    declare @retcode int
    set nocount on
    --
    -- Security check
    --
    exec @retcode = dbo.sp_MSreplcheck_subscribe
    if @@error != 0 or @retcode != 0
        return 1
    --
    -- validate inputs
    --
    if (@tranid is null 
            or @orderkeylow is null or @orderkeylow = 0 
            or @orderkeyhigh is null or @orderkeyhigh = 0
            or @orderkeyhigh < @orderkeylow)
        return 1
    --
    -- begin local transaction
    --
    begin transaction sp_repldeletequeuedtran
    save transaction sp_repldeletequeuedtran
    --
    -- delete rows from MSreplication_queue
    --
    delete dbo.MSreplication_queue with (rowlock)
    where publisher = UPPER(@publisher)
        and publisher_db = @publisher_db
        and publication = @publication
        and tranid = @tranid 
        and orderkey between @orderkeylow and @orderkeyhigh
    if (@@error != 0)
        goto Error
    --
    -- delete row from MSrepl_queuedtraninfo
    --
    delete dbo.MSrepl_queuedtraninfo with (rowlock)
    where publisher = UPPER(@publisher)
        and publisher_db = @publisher_db
        and publication = @publication
        and tranid = @tranid 
    if (@@error != 0)
        goto Error
    --
    -- commit local transaction
    --
    commit transaction sp_repldeletequeuedtran
    --
    -- all done
    --
    return 0

Error:
    rollback transaction sp_repldeletequeuedtran
    commit transaction
    return 1
end
go
exec dbo.sp_MS_marksystemobject sp_repldeletequeuedtran
go

--
-- sp_MSpost_auto_proc
--
-- Description: Helper store proc, used by schema replication.
--		Scripts out custom proc generation code and post to the log.
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSpost_auto_proc', 0,1)
go
create proc sp_MSpost_auto_proc 
		@pubid int, 
		@artid int, 
		@procname nvarchar(128)
as
begin
	declare @proctext nvarchar(4000)
	declare @retcode int
	
	set nocount on
	select @retcode = 0
	
    /*
    ** Security Check
    */
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return(1)

	-- save the geneartion code
	create table #temptext (colidx int identity, col nvarchar(4000) collate database_default)
	insert #temptext (col) exec @procname @artid
	
	-- post to the log
	declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
		select col from #temptext order by colidx
	open #trancolumn
	fetch #trancolumn into @proctext
	while (@@fetch_status <> -1)
	BEGIN
		if(@proctext = N'go') -- post the drop as one command
		begin
			exec @retcode = sp_replpostcmd 0, @pubid, @artid, 35, N' -- '
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else
		begin
			select @proctext = @proctext + N' '
			exec @retcode = sp_replpostcmd 1, @pubid, @artid, 35, @proctext
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		fetch #trancolumn into @proctext
	END
	exec @retcode = sp_replpostcmd 0, @pubid, @artid, 35, N' --'
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	close #trancolumn
	deallocate #trancolumn
	return 0
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSpost_auto_proc
go
--
-- sp_MSrepl_schema 
--
-- Description: Helper store proc, used by schema replication.
--		constructs schema modification code and post to the log.
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSrepl_schema', 0,1)
go

create proc sp_MSrepl_schema @pubname sysname
				,@artid int 
				,@qual_source_object nvarchar(362) -- quoted table name
				,@column sysname -- column name, not quoted, as we need to search in syscolumns by it.
				,@operation int -- 0 is add, 1 is drop
				,@typetext nvarchar(3000) = NULL	
				,@schema_change_script nvarchar(4000) = NULL
as
begin
	declare @retcode int
	declare @pubid int
	declare @objid int
	declare @schema_option binary(8)
	declare @auto_gen int
	declare @cmd_type int
	declare @ins_cmd nvarchar(510)
	declare @del_cmd nvarchar(510)
	declare @upd_cmd nvarchar(510)
	declare @repub_command nvarchar(4000)
	declare @nopub_command nvarchar(4000)
	declare @prefix nvarchar(32)
	declare @post_cmd nvarchar(4000)
	declare @qual_column sysname
	declare @use_script bit
	declare @allow_dts bit
	
	set nocount on
	select @retcode = 0
	select @auto_gen = 2 -- auto generate custom procs
	select @cmd_type = 35 -- SQL statement
	select @qual_column = QUOTENAME(@column)
	select @objid = object_id(@qual_source_object)

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

	if (@schema_change_script is not NULL) and (len(@schema_change_script) > 0)
		select @use_script = 1
	else
		select @use_script = 0
	
	
	select @pubid = a.pubid, @schema_option = schema_option, @ins_cmd = ins_cmd, @del_cmd = del_cmd, @upd_cmd = upd_cmd, @allow_dts = allow_dts 
		from sysarticles a join syspublications p on a.pubid = p.pubid where artid = @artid
	
	if (@allow_dts = 1)
		goto SCRIPTONLY

	if(@operation = 0)
	begin
		select @repub_command = N'exec sp_repladdcolumn @source_object=N''' + @qual_source_object + N''',@column=N''' + replace(@column  , N'''', N'''''')
						+ N''',@typetext=N''' + replace(@typetext, N'''', N'''''') + N''' '
		select @nopub_command = N'else alter table ' + @qual_source_object + N' add ' + @qual_column + N' ' + @typetext + N' ' 
		select @prefix = N'if not exists '
	end
	else
	begin
		select @repub_command = N'exec sp_repldropcolumn @source_object=N''' + @qual_source_object + N''',@column=N''' + @column  + N''' '
		select @nopub_command = N'else alter table ' + @qual_source_object + N' drop column ' + @qual_column + N' '
		select @prefix = N'if exists '
	end
	if (@use_script = 1)--Need to pass the script file along if sub is republished.
		select @repub_command = @repub_command  + N',@schema_change_script=N''' + @schema_change_script + N''' '
	select @post_cmd = @prefix + N'(select * from syscolumns where name=''' + @column + ''' and id = object_id('''+ PARSENAME(@qual_source_object, 1) + ''')) begin '
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @post_cmd 
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	select @post_cmd = N'if exists (select * from sysobjects where name=''syspublications'') if exists (select * from sysarticles where objid=object_id('''+ PARSENAME(@qual_source_object, 1) + ''')) and @@microsoftversion >= 0x07320000 '
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @post_cmd 
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @repub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @nopub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 1, @pubid, @artid, @cmd_type, @nopub_command
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	exec @retcode = sp_replpostcmd 0, @pubid, @artid, @cmd_type, N' end '
	if(@retcode <> 0) or (@@error <> 0)
		return 1
	
	if ((convert(int, @schema_option) & @auto_gen) > 0)-- No script, but custom procs were auto-generated
	begin
		if(UPPER(LEFT(LTRIM(@ins_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptinsproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		if(UPPER(LEFT(LTRIM(@del_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptdelproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@del_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('XCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptxdelproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		if(UPPER(LEFT(LTRIM(@upd_cmd), 4) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('CALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@upd_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('MCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptmappedupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
		else if(UPPER(LEFT(LTRIM(@upd_cmd), 5) collate SQL_Latin1_General_CP1_CS_AS) = UPPER('XCALL' collate SQL_Latin1_General_CP1_CS_AS))
		begin
			exec @retcode = sp_MSpost_auto_proc @pubid, @artid, 'sp_scriptxupdproc' 
			if(@retcode <> 0) or (@@error <> 0)
				return 1
		end
	end
SCRIPTONLY:

	if (@use_script = 1)
	begin
		exec @retcode = sp_addscriptexec @publication = @pubname, @scriptfile = @schema_change_script
		if @retcode<>0 or @@ERROR<>0
			return 1
	end 
	return 0
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSrepl_schema 
go
--
-- sp_MSreplupdateschema
--
-- Description: Wrapper store proc, check for admin\dbowner credential before invoking sp_replupdateschema
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSreplupdateschema', 0,1)
go

create proc sp_MSreplupdateschema  @object_name sysname
as
begin
	declare @retcode int
	IF @object_name IS NULL
	BEGIN
		RAISERROR (14043, 16, -1, '@object_name')
		RETURN (1)
	END

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

	exec dbo.sp_replupdateschema @object_name
	return 0
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSreplupdateschema
go
--
-- sp_MSdefer_check
--
-- Description: disable constraints (Foreign Key and Check) and triggers during concurrent snapshot
--		and script enable cmds for later
--
-- Note: 	this stored procedure loops through the list of Foreign Key, Check constraints and Triggers
--		which are not disabled and not marked 'not for replicaiton', it uses 'alter table' to disable 
--		these entries (nocheck/disable), and copies the corresponding enable code into a temp table.
--		at the end, cmds in temp table is used to build a stored procedure which will be used by dist 
--		agent to enable these cnst/triggers at the end of concurrent snapshot. if it failed to create 
--		the stored procedure, a default one (sp_MSreenable_check) will be used, the key difference here
--		is the sp created here will only enable the ones we disabled here, while the default one will 
--		enable all in current table.
--
--		the sp created within sp_MSdefer_check will enable all the entries disabled by sp_MSdefer_check, 
--		then drop itself at the end.
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSdefer_check', 0,1)
go
create proc sp_MSdefer_check @objname sysname, @objowner sysname = NULL
as
	set nocount on
	declare @cnstname sysname
	declare @cnstid int
	declare @objid int
	declare @enable_cmd nvarchar(4000)
	declare @disable_cmd nvarchar(4000)
	declare @quotedproc nvarchar(240)
	declare @dest nvarchar(514)
	declare @dbname sysname
	declare @proc_exists bit

	if(@objowner is not null)
		select @dest = quotename(@objowner) + N'.' + quotename(@objname)
	else
		select @dest = quotename(@objname)

	declare @retcode int
	IF @objname IS NULL
	BEGIN
		RAISERROR (14043, 16, -1, '@objname')
		RETURN (1)
	END

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

	select @objid = object_id(@dest)
	select @enable_cmd = N'sp_MSenable_' + convert(varchar(64), @objid)
	if exists(select name from sysobjects where name = @enable_cmd and ObjectProperty(id, 'IsProcedure') = 1)
		select @proc_exists = 1
	else
		select @proc_exists = 0

	select @quotedproc = quotename(@enable_cmd)
	select @enable_cmd = N'create proc ' + @quotedproc + N' as '
	create table #proccmd (c1 int identity, c2 nvarchar(3000) collate database_default)
	insert #proccmd (c2) values (@enable_cmd)
	
	declare ms_crs_cnst cursor local static for
	select name, id from sysobjects where parent_obj = @objid and 
		   ((OBJECTPROPERTY(id, 'CnstIsDisabled') = 0 and OBJECTPROPERTY(id, 'CnstIsNotRepl') = 0 and 
		    (OBJECTPROPERTY(id, 'IsCheckCnst') = 1 or OBJECTPROPERTY(id, 'IsForeignKey') = 1))
		or (ObjectProperty(id, 'IsTrigger') = 1 and OBJECTPROPERTY(id, 'ExecIsTriggerNotForRepl') = 0 and ObjectProperty(id, 'ExecIsTriggerDisabled') = 0))
	for read only

	open ms_crs_cnst
	fetch ms_crs_cnst into @cnstname, @cnstid
	while @@fetch_status >= 0
	begin
		if(ObjectProperty(@cnstid, 'IsTrigger') = 1)
		begin
			select @disable_cmd = N'alter table ' + @dest + N' disable trigger ' + quotename(@cnstname)
			select @enable_cmd = N'alter table ' + @dest + N' enable trigger '+quotename(@cnstname)
		end
		else
		begin
			select @disable_cmd = N'alter table ' + @dest + N' nocheck constraint ' + quotename(@cnstname)
			select @enable_cmd = N'alter table ' + @dest + N' check constraint ' + quotename(@cnstname)
		end
		insert #proccmd (c2) values (@enable_cmd)

		execute(@disable_cmd)
		fetch ms_crs_cnst into @cnstname, @cnstid
	end		--of major loop
	deallocate ms_crs_cnst
	if(@proc_exists = 1) -- don't try to recreate the proc
	begin 
		select N'exec ' + @quotedproc
		drop table #proccmd
		return 0
	end

	select @enable_cmd = N'drop proc ' + @quotedproc
	insert #proccmd (c2) values (@enable_cmd)
	select @enable_cmd = N'select c2 from #proccmd order by c1'
	select @dbname = db_name()
	exec @retcode = master..xp_execresultset @enable_cmd, @dbname
	if @@error <> 0 or @retcode <> 0 or @quotedproc is NULL
	begin
		declare @cmd_param nvarchar(4000)
		if (@objowner is null)
			select @cmd_param = N' @objname = N''' + @objname + N''''
		else
			select @cmd_param = N' @objname = N''' + @objname + N''', @objowner = N''' + @objowner + N''''
		select N'exec sp_MSreenable_check ' + @cmd_param
	end
	else
		select N'exec ' + @quotedproc
	drop table #proccmd
	return 0
go
EXEC dbo.sp_MS_marksystemobject sp_MSdefer_check
go
--
-- sp_MSreenable_check
--
-- Description: default sp to enable constraints (Foreign Key and Check) and triggers at 
--		the end of compensation mode in concurrent snapshot.
--
-- Note : 	this default sp doesn't get used unless we failed to construct a temp one at runtime.
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSreenable_check', 0,1)
go
create proc sp_MSreenable_check @objname sysname, @objowner sysname = NULL
as
	set nocount on
	
	declare @cnstname sysname
	declare @cnstid int
	declare @objid int
	declare @enable_cmd nvarchar(4000)
	declare @dest nvarchar(514)

	declare @retcode int
	IF @objname IS NULL
	BEGIN
		RAISERROR (14043, 16, -1, '@objname')
		RETURN (1)
	END

	if(@objowner is not null)
		select @dest = quotename(@objowner) + N'.' + quotename(@objname)
	else
		select @dest = quotename(@objname)

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

	select @objid = object_id(@objname)
	
	declare ms_crs_cnst cursor local static for
	select name, id from sysobjects where parent_obj = @objid and 
		   ((OBJECTPROPERTY(id, 'CnstIsDisabled') = 1 and OBJECTPROPERTY(id, 'CnstIsNotRepl') = 0 and 
		    (OBJECTPROPERTY(id, 'IsCheckCnst') = 1 or OBJECTPROPERTY(id, 'IsForeignKey') = 1))
		or (ObjectProperty(id, 'IsTrigger') = 1 and OBJECTPROPERTY(id, 'ExecIsTriggerNotForRepl') = 0 and ObjectProperty(id, 'ExecIsTriggerDisabled') = 1))
	for read only

	open ms_crs_cnst
	fetch ms_crs_cnst into @cnstname, @cnstid
	while @@fetch_status >= 0
	begin
		if(ObjectProperty(@cnstid, 'IsTrigger') = 1)
			select @enable_cmd = N'alter table ' + @dest + N' enable trigger ' + quotename(@cnstname)
		else
			select @enable_cmd = N'alter table ' + @dest + N' check constraint ' + quotename(@cnstname)

		execute(@enable_cmd)
		fetch ms_crs_cnst into @cnstname, @cnstid
	end		--of major loop
	deallocate ms_crs_cnst
	return 0
go
EXEC dbo.sp_MS_marksystemobject sp_MSreenable_check
go

--
-- sp_getqueuedrows
--
-- sp_getqueuedrows is invoked by user to find the rows of given table on
-- a subscriber database that have participated in a queued update and 
-- currently have not been resolved by the queue reader agent - i.e. current
-- have an outstanding queued transaction. The table has to be part of 
-- queued subscription.
-- 
-- Parameters
-- 	@tablename	sysname -- name of table
--	@user		sysname -- optional name of user
--	@tranid		nvarchar(70) -- optional tranid to filter results on
--
-- Returns
--	0 if success 
--	1 if failure
--
-- Resultset
-- 	Rows that currently have at least one queued transaction for this
--	subscribed table
--
raiserror('Creating procedure sp_getqueuedrows', 0,1)
go
create proc sp_getqueuedrows (
	@tablename sysname
	,@owner sysname = NULL
	,@tranid nvarchar(70) = NULL
)
as
begin
	set nocount on
	declare @retcode int
		,@dbname sysname
		,@qualified_tabname nvarchar(1000)
		,@tabid int
		,@agent_id int
		,@publisher sysname
		,@publisher_db sysname
		,@publication sysname
		,@queue_id sysname
		,@update_mode int
		,@failover_id int
		,@cmd nvarchar(4000)
		,@queue_server sysname
		,@indid int
		,@indkey int
		,@key sysname
		,@colid int
		,@typestring nvarchar(4000)
		,@artcol int
		,@xpinputstr nvarchar(4000)
		,@selectcl nvarchar(4000)
		,@joincl nvarchar(4000)

	--
	-- prepare the fully qualified table
	--
	select @owner = case when (@owner IS NULL) then N'dbo' else @owner end
			,@dbname = db_name()	
	select @qualified_tabname = quotename(@dbname) + N'.' 
					+ quotename(@owner) + N'.' + quotename(@tablename)
	select @tabid = object_id(@qualified_tabname)
	if (@tabid IS NULL) or (@tabid = 0)
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): could not locate table %s', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- current user should have SELECT permission on the table
	--
	if ( permissions(@tabid) & 0x1 = 0 )
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): current user does not have SELECT permission on table %s', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- make sure the table is participating in a active queued subscription
	--
	select @agent_id = agent_id 
	from dbo.MSsubscription_articles 
	where dest_table = @tablename and owner = @owner

	if (@agent_id IS NULL)
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): table %s is not part of any active initialized queued subscription. Make sure your queued subscriptions are properly initialized', 16, 1, @qualified_tabname)
		return 1
	end

	--
	-- get the details for the subscription
	--
	select @publisher = publisher
			,@publisher_db = publisher_db
			,@publication = publication
			,@update_mode = update_mode
			,@queue_server = queue_server
			,@queue_id = queue_id
			,@failover_id = failover_mode
	from dbo.MSsubscription_agents where id = @agent_id
	if (@update_mode not in (2,3,4,5))
	begin
		-- error
		raiserror('sp_getqueuedrows(debug): table %s is not part of any active initialized queued subscription. Make sure your queued subscriptions are properly initialized', 16, 2, @qualified_tabname)
		return 1
	end
	
	--
	-- If we are in Immediate Failover mode - no queued messages
	--
	if (@update_mode in (3,5) and (@failover_id = 0))
	begin
		--
		-- do an empty select on the source table and return
		--
		select @cmd = N'declare @dummy_action nvarchar(10), @dummy_tranid nvarchar(70)
					select action=@dummy_action, tranid=@dummy_tranid, * from ' + 
					@qualified_tabname + N' where 1 = 2 '
		exec (@cmd)
		return 0
	end

	if (@update_mode in (2,3))
	begin
		--
		-- set queue prefix for MSMQ cases
		--
		select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
	end
	else
	begin
		--
		-- Check the queue table for SQLQ
		--
		if not exists (select * from dbo.MSreplication_queue
		where publisher = UPPER(@publisher) and
				publisher_db = @publisher_db and
				publication = @publication and
				tranid = case when @tranid IS NULL then tranid else @tranid end)
		begin
			--
			-- do an empty select on the source table and return
			--
			select @cmd = N'declare @dummy_action nvarchar(10), @dummy_tranid nvarchar(70)
					select action=@dummy_action, tranid=@dummy_tranid, * from ' + 
					@qualified_tabname + N' where 1 = 2 '
			exec (@cmd)
			return 0
		end
	end

	--
	-- Now find the PK columns for this table
	--
	select @indkey = 1
		,@artcol = 0
		,@xpinputstr = N''
		,@selectcl = N''
		,@joincl = N''
		,@retcode = 0

	select @indid = i.indid 
	from dbo.sysindexes i 
	where ((i.status & 2048) != 0) and (i.id = @tabid)
	if (@indid is null)
	begin
		raiserror('sp_getqueuedrows(debug): Cannot find primary key for %s', 
				16, -1, @qualified_tabname)
		return 1
	end
	
	--
	-- create an enumeration of all the columns that are part of PK
	--
	create table #pkcoltab(pkindex int identity, keyname sysname collate database_default not null)
	while (@indkey <= 16)
	begin
		select @key = index_col( @qualified_tabname, @indid, @indkey )
		if (@key is null)
			break
		else
			insert into #pkcoltab(keyname) values(@key)

		select @indkey = @indkey + 1
	end

	--
	-- initialize the commands that we need to build
	--
	if exists (select * from dbo.sysobjects where name = 'tempcrtcmd')
		drop table tempcrtcmd
	create table tempcrtcmd (c1 int identity NOT NULL, procedure_text nvarchar(4000) NULL)
	
	select @cmd = N'create table tempqjointab (action nvarchar(10), tranid nvarchar(70) '
	insert into tempcrtcmd(procedure_text) values(@cmd)

	--
	-- now walk through each article col and if it is
	-- a part of PK, then check find the column position of the key
	-- corresponding to any article column is set
	--
	DECLARE #hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid, [name] from dbo.syscolumns 
		where id = @tabid order by colid asc

	OPEN #hCColid
	FETCH #hCColid INTO @colid, @key
	WHILE (@@fetch_status != -1)
	begin
		exec sp_MSget_type @tabid, @colid, NULL, @typestring output
		if ((@typestring IS NOT NULL) and (@typestring != N'timestamp'))
		begin
			--
			-- this column is part of the article
			--
			select @artcol = @artcol + 1
			if exists (select * from #pkcoltab where keyname = @key)
			begin
				--
				-- this column is part of PK (offset and precision, scale)
				-- prepare the input string for XP
				-- prepare the create join table command
				-- prepare the join and select clause for the result
				--
				select @xpinputstr = @xpinputstr + N';' + cast(@artcol as nvarchar) 
				if (@typestring = N'bigint')
					select @xpinputstr = @xpinputstr + N'(19,0)'
				else if (@typestring like N'decimal%') or (@typestring like N'numeric%')
				begin
					declare @startpos int
							,@endpos  int

					select @startpos = charindex(N'(', @typestring, 1)
					select @endpos = charindex(N')', @typestring, @startpos)
					select @xpinputstr = @xpinputstr + substring(@typestring, @startpos, (@endpos - @startpos + 1))
				end
				select @cmd = N',' + quotename(@key) + N' ' + @typestring
				insert into tempcrtcmd(procedure_text) values(@cmd)
				select @selectcl = @selectcl + N', b.' + quotename(@key)
				
				if (@joincl = N'')
				begin
					select @joincl = @joincl + N'a.' + quotename(@key) + N' = b.' + quotename(@key)
				end
				else
				begin
					select @joincl = @joincl + N'and a.' + quotename(@key) + N' = b.' + quotename(@key)
				end				
			end
			else
			begin
				--
				-- this column is not part of PK
				-- build the select clause for this column
				--
				select @selectcl = @selectcl + N', a.' + quotename(@key)
			end
		end		

		--
		-- get the next column
		--
		FETCH #hCColid INTO @colid, @key
	end
	CLOSE #hCColid
	DEALLOCATE #hCColid
	drop table #pkcoltab

	--
	-- create the join table now
	--
	select @cmd = N') '
	insert into tempcrtcmd(procedure_text) values(@cmd)
	if exists (select * from dbo.sysobjects where name = N'tempqjointab')
		drop table tempqjointab
	select @cmd = 'select procedure_text from dbo.tempcrtcmd order by c1'
	exec @retcode = master..xp_execresultset @cmd, @dbname
	if (@retcode != 0)
		goto cleanup

	--
	-- populate the join table now
	--
	if (@update_mode in (2,3))
	begin
		--
		-- MSMQ case : one call to the xp should populate the join table
		--
		insert into tempqjointab
			exec master.dbo.xp_readpkfromqueue @tablename, @queue_id, @xpinputstr, @tranid
	end
	else
	begin
		--
		-- SQLQ case : select the data for this subscription and call the
		-- xp for each row in the cursor to populate the join table
		--
		declare @spancount int
				,@data varbinary(8000)
				,@state bit
		
		declare #hcurQInfo cursor local FAST_FORWARD FOR
		select data, cmdstate, tranid
		from dbo.MSreplication_queue
		where publisher = UPPER(@publisher) and
				publisher_db = @publisher_db and
				publication = @publication and
				tranid = case when @tranid IS NULL then tranid else @tranid end and
				commandtype = 1
		order by orderkey
		FOR READ ONLY

		select @spancount = 0
		open #hcurQInfo
		fetch #hcurQInfo into @data, @state, @tranid
		while (@@FETCH_STATUS = 0)
		begin
			declare @qbdata0 varbinary(8000)
					,@qbdata1 varbinary(8000)

			if (@state = 1)
			begin
				--
				-- command spanning more than a row
				-- we will allow spanning upto 2 rows
				--
				if (@spancount = 0)
					select @qbdata0 = @data
				else
				begin
					raiserror('sp_getqueuedrows(debug): Queued data spans 3 rows, cannot proceed', 16, -1)
					close #hcurQInfo
					deallocate #hcurQInfo
					select @retcode = 1
					goto cleanup
				end
				select @spancount = @spancount + 1
			end
			else
			begin
				--
				-- final row for the command
				--
				if (@spancount = 0)
					select @qbdata0 = @data				
				else if (@spancount = 1)
					select @qbdata1 = @data
				else
				begin
					raiserror('sp_getqueuedrows(debug): Queued data spans 3 rows, cannot proceed', 16, -1)
					close #hcurQInfo
					deallocate #hcurQInfo
					select @retcode = 1
					goto cleanup
				end

				--
				-- call the xp to populate the join table
				--
				insert into tempqjointab
					exec master.dbo.xp_readpkfromvarbin @tablename, @xpinputstr, @tranid, @spancount, @qbdata0, @qbdata1

				--
				-- reset the span count
				--
				select @spancount = 0
			end

			--
			-- fetch the next row
			--
			fetch #hcurQInfo into @data, @state, @tranid
		end
		close #hcurQInfo
		deallocate #hcurQInfo
	end

	--
	-- Now perform the join
	--
	select @cmd = N'select b.action, b.tranid ' + @selectcl 
		+ N'from ' + @qualified_tabname + N' a right join tempqjointab b on (' + @joincl + N') '
	exec (@cmd)
	
	--
	-- all done
	--
cleanup:	
	if exists (select * from dbo.sysobjects where name = N'tempqjointab')
		drop table tempqjointab
	if exists (select * from dbo.sysobjects where name = 'tempcrtcmd')
		drop table tempcrtcmd
	return @retcode
end
go

EXEC dbo.sp_MS_marksystemobject sp_getqueuedrows
GO
--
-- sp_MSprep_exclusive
--
-- Description: Helper sp for schema change, acquires shc-m lock on the source table, 
--		and 'Exclusive' application lock on all the publications it belongs to.
--
-- Note : 	@objname should be owner qualified
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_MSprep_exclusive', 0,1)
go
create proc sp_MSprep_exclusive @objname sysname
as
	set nocount on
	declare @retcode int
	declare @objid int
	declare @tran_pubname sysname

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

	if @objname is NULL
	begin
		RAISERROR (14043, 16, -1, '@objname')
		return (1)
	end

	select @objid = object_id(@objname)
	if @objid is NULL
	begin
		raiserror(14027, 16, -1, @objname)
		return (1)
	end

	exec sp_replupdateschema @objname
	if @@ERROR<>0
		return (1)

	declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select p.name from sysarticles a, syspublications p where a.objid=@objid
					and p.pubid = a.pubid
	open #trancolumn
	fetch #trancolumn into @tran_pubname
	while (@@fetch_status <> -1)
	BEGIN
		EXEC @retcode = sp_getapplock 	@Resource = @tran_pubname, 
						@LockMode = N'Exclusive', 
						@LockOwner = N'Transaction', 
						@LockTimeout = 0
		if @retcode = -1
		begin 
			raiserror(21386, 16, -1, @objname)
			goto FAILURE	
		end 
		if @@ERROR<>0 or @retcode < 0
			goto FAILURE
		fetch #trancolumn into @tran_pubname			
	END
	close #trancolumn
	deallocate #trancolumn
	return 0
FAILURE:
	close #trancolumn
	deallocate #trancolumn
	return (1)
go
EXEC dbo.sp_MS_marksystemobject sp_MSprep_exclusive
--
-- sp_verify_publication
--
-- Description: Invoked by user on a distributor server to perform a simple replication plumbing check.
--		Tests the connectivity of all the push subscriptions for a given publication.
--		(doesn't test pull or anonymous subscriptions)
--
-- Returns:
-- 		0 if success
--		1 if failure
--
raiserror('Creating procedure sp_verify_publication', 0,1)
go
create proc sp_verify_publication (
	@publisher sysname,		/*name of the publisher*/
	@publisher_db sysname,		/*the database for the publication*/
	@publication sysname,		/*name of the publication*/
	@reserved int = 0		/*reserved -- should not be used directly by user.
					  For internal use only.*/
)
AS
BEGIN
set nocount on

if( @reserved = 0 )
begin
  declare @proc nvarchar(255),
	  @distribution_db sysname,
	  @recurse_retcode int
  --
  --verify that this server is a distributor.
  --
  if (not exists( select * from msdb..sysobjects where name = 'MSdistpublishers') )
  begin
    RAISERROR(14114, 16, -1, @@SERVERNAME)
    return(1)
  end
  --
  --get the distribution database
  --
  select @distribution_db = distribution_db from msdb.dbo.MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default
  if( @distribution_db is NULL )
  begin
    RAISERROR(21169, 16, -1, @publisher, @@SERVERNAME, @publisher)
    return(1)
  end

  select @proc = @distribution_db + '.dbo.sp_verify_publication'
  exec @recurse_retcode = @proc @publisher, @publisher_db, @publication, 1
  return(@recurse_retcode)
end

declare @publisher_id smallint,
	@subscriber sysname,
	@subscriber_db sysname,
	@type tinyint,
	@job_id binary(16),
	@publication_type int,
	@agent_type varchar(15),
	@command nvarchar(3200),
	@success varchar(300),
	@srvid smallint

select @srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
if @srvid is NULL
begin
  RAISERROR(21169, 16, -1, @publisher, @@SERVERNAME, @publisher)
  return(1)
end

select @publication_type = publication_type from MSpublications
  where publisher_id = @srvid and
  publisher_db = @publisher_db and
  publication = @publication

if @publication_type is NULL
begin
  RAISERROR(21332, 16, -1, @publication)
  return(1)
end

create table #T_VERIFICATION_RESULTS (
  subscriber sysname NOT NULL, subscriber_db sysname NOT NULL, type int NOT NULL,
  job_id binary(16) NULL, results varchar(300) NULL
)

-- Parameter Check: @publication_type
-- Make sure that the publication type is one of the following:
-- 0  transactional
-- 1  snapshot
-- 2  merge
if( @publication_type = 0 or @publication_type = 1 )
  begin
    select @agent_type = 'distribution'

    create table #T_SUBSCRIPTIONS (subscriber sysname NOT NULL,  status int NOT NULL, 
	subscriber_db sysname NOT NULL,
	type tinyint NOT NULL, distribution_agent nvarchar(100) NOT NULL, last_action nvarchar(255) NULL, 
	action_time nvarchar(24) NULL, start_time nvarchar(24) NULL, duration int NULL, 
	delivery_rate float NULL,
	delivery_latency int NULL, delivered_transactions int NULL, 
	delivered_commands int NULL,
	delivery_time int NULL, average_commands int NULL, 
	error_id int NULL, 
	job_id binary(16) NULL, local_job bit NULL, profile_id int NOT NULL,
	agent_id int NOT NULL, last_timestamp binary(8) NOT NULL, offload_enabled bit NOT NULL, 
	offload_server sysname NULL, subscriber_type tinyint NULL)

    insert #T_SUBSCRIPTIONS
      exec sp_MSenum_subscriptions @publisher, @publisher_db, @publication

    insert into #T_VERIFICATION_RESULTS (subscriber, subscriber_db, type, job_id)
	(select subscriber, subscriber_db, type, job_id from #T_SUBSCRIPTIONS)

    drop table #T_SUBSCRIPTIONS
  end
else if( @publication_type = 2 )
  begin
    select @agent_type = 'merge'

    create table #T_MERGE_SUBSCRIPTIONS (subscriber sysname NOT NULL,  status int NOT NULL, 
        subscriber_db sysname NOT NULL, type int NOT NULL, agent_name nvarchar(100) NOT NULL, last_action nvarchar(255) NULL, 
        action_time nvarchar(24) NULL, start_time nvarchar(24) NULL, duration int NULL, 
        delivery_rate float NULL,
        publisher_insertcount int NULL, publisher_updatecount int NULL, publisher_deletecount int NULL,
        publisher_conficts int NULL, 
        subscriber_insertcount int NULL, subscriber_updatecount int NULL, subscriber_deletecount int NULL,
        subscriber_conficts int NULL, error_id int NULL, job_id binary(16) NULL,
        local_job bit NULL, profile_id int NOT NULL, 
        agent_id int NOT NULL, last_timestamp binary(8) NOT NULL, offload_enabled bit NOT NULL, 
	offload_server sysname NULL, subscriber_type tinyint NULL)

    insert #T_MERGE_SUBSCRIPTIONS
      exec sp_MSenum_merge_subscriptions @publisher, @publisher_db, @publication

    insert into #T_VERIFICATION_RESULTS (subscriber, subscriber_db, type, job_id)
	(select subscriber, subscriber_db, type, job_id from #T_MERGE_SUBSCRIPTIONS)

    drop table #T_MERGE_SUBSCRIPTIONS
  end
else
  begin
    drop table #T_VERIFICATION_RESULTS
    RAISERROR(20033, 16, -1)
    return(1)
  end

if( not exists( select * from #T_VERIFICATION_RESULTS ) )
begin
  --
  --if #T_VERIFICATION_RESULTS is empty, then there's no subscriptions
  --
  RAISERROR(14135, 16, -1, @publisher, @publisher_db, @publication)
  drop table #T_VERIFICATION_RESULTS
  return(1)
end

declare subscribers_cursor cursor LOCAL FAST_FORWARD for
select subscriber, subscriber_db, type, job_id
  from #T_VERIFICATION_RESULTS
  order by subscriber, subscriber_db

open subscribers_cursor
fetch next from subscribers_cursor
  into @subscriber, @subscriber_db, @type, @job_id
while @@FETCH_STATUS = 0
begin
  if( @type = 0 )
  begin
    --
    --local push subscription
    --
    select @command = ''
    select @success = 'unknown'
    select @command = command from msdb.dbo.sysjobsteps
      where job_id = @job_id and
	    subsystem = case @publication_type  -- 0 = Transactional 1 = Snapshot 2 = Merge
	      when 0 then N'Distribution'
	      when 1 then N'Distribution'
	      when 2 then N'Merge'
	    end

    exec master.dbo.xp_replproberemsrv 'local', @agent_type, @success OUTPUT, @command, 1 --(islocal)
    if( @@ERROR <> 0) return(1)
    if UPPER(@success collate SQL_Latin1_General_CP1_CS_AS) = 'FALSE'
      select 'subscriber' = @subscriber, 'subscriber database' = @subscriber_db,
	     'subscription type' = case @type
		    when 0 then 'push'
		    when 1 then 'pull'
		    when 2 then 'anonymous'
		    else 'unknown'
		  end
	     , 'results' = 'connection failed'
    else if( ( CHARINDEX('TRUE', UPPER(@success collate SQL_Latin1_General_CP1_CS_AS)) = 1 ) and (LEN(@success) = 4) )
      select @success = 'connection succeeded'
  end
  else
  begin
    --
    --non-push subscription, not supported
    --
    select @success = 'only push subscriptions can be verified with this stored procedure'
  end

  update #T_VERIFICATION_RESULTS set results = @success where
    subscriber = @subscriber and
    subscriber_db = @subscriber_db and
    type = @type and
    job_id = @job_id
  --
  --get next subscription
  --
  fetch next from subscribers_cursor
    into @subscriber, @subscriber_db, @type, @job_id
end
close subscribers_cursor
deallocate subscribers_cursor

select subscriber, subscriber_db as 'subscriber database', 'subscription type' =
  case type
    when 0 then 'push'
    when 1 then 'pull'
    when 2 then 'anonymous'
    else 'unknown'
  end
, results from #T_VERIFICATION_RESULTS where UPPER(results collate SQL_Latin1_General_CP1_CS_AS) != 'FALSE'

drop table #T_VERIFICATION_RESULTS
END
go
EXEC dbo.sp_MS_marksystemobject sp_verify_publication

raiserror('Creating procedure sp_scriptpublicationcustomprocs',0,-1)
go
--
-- Name: sp_scriptpublicationcustomprocs
--
-- Description: This is a utility procedure for scripting out the 
--              article "custom" ins/upd/del procedures for all 
--              table articles in a publication with the auto-generate custom
--              procedure schema option enabled. This is particularly useful 
--              and in fact specifically designed for setting up no-sync 
--              subscriptions. 
-- 
-- Notes: 1) Reconciliation procedures for concurrent snapshot will
--           not be scripted by this procedure. It does not really make 
--           sense to have concurrent snapshots for no-sync subscriptions.
--        2) Custom procedures will not be scripted out for articles 
--           without the auto-generate custom procedure (0x2) schema_option.
--
-- Parameter: @publication sysname
--
-- Security: Execute permission is granted to public; procedural security 
--           check is performed inside the procedure to restrict access
--           to sysadmins and db_owners of current database. 
--
-- Example: exec Northwind.dbo.sp_scriptpublicationcustomprocs @publication = N'Northwind'
--
create procedure dbo.sp_scriptpublicationcustomprocs
    @publication sysname
as
begin
    set nocount on

    declare @retcode          int,
            @artid            int,
            @pubid            int,
            @cursor_allocated bit,
            @cursor_opened    bit,
            @table_created    bit,
            @ins_cmd          nvarchar(255),
            @upd_cmd          nvarchar(255),
            @del_cmd          nvarchar(255),
            @article          sysname,
            @schema_option    int,
            @repl_freq        int,
            @formattedmessage nvarchar(4000)
    
    -- Initializations 
    select @retcode = 0,
           @pubid = null,
           @cursor_allocated = 0,
           @cursor_opened = 0,
           @table_created = 0

    -- Security check: Sysadmins and db_owners only
    exec @retcode = sp_MSreplcheck_publish
    if @retcode <> 0 or @@error <> 0
    begin
        return 1
    end

    -- Make sure the current database is enabled for transaction replication
    if not exists (select * 
                     from master..sysdatabases 
                    where name = db_name() collate database_default
                      and (category & 0x1) <> 0)
    begin
        raiserror(14013, 16, -1)
        return 1
    end
 
    -- Parameter check: The specified @publication is a valid Transactional publication

    select @pubid = pubid, 
           @repl_freq = repl_freq
      from dbo.syspublications
     where name = @publication
    if @pubid is null
    begin
        raiserror(20026, 16, -1, @publication)
        return 1            
    end
    
    -- Don't script out custom procs for a snapshot publication
    if @repl_freq = 1
    begin
        raiserror(21515, 16, -1, @publication) 
        return 1
    end
    -- Create temp table for procedure text
    create table #proctext_scriptpublicationcustomprocs
    (
        line_no int identity(1,1) primary key,
        line nvarchar(4000)
    ) 
    if @@error<>0
    begin
        return 1
    end    
    select @table_created = 1
    
    -- Script header
    select @formattedmessage = formatmessage(21516, @publication, db_name())
    if @@error <> 0 begin select @retcode = 1 goto Failure end
    insert into #proctext_scriptpublicationcustomprocs values(N'--')
    insert into #proctext_scriptpublicationcustomprocs values(N'-- ' + @formattedmessage)
    insert into #proctext_scriptpublicationcustomprocs values(N'--')
    insert into #proctext_scriptpublicationcustomprocs values(N'')
    insert into #proctext_scriptpublicationcustomprocs values(N'')

    -- Open cursor through all table articles in the specified publication and script out
    -- custom procs as necessary
    
    declare harticle cursor local fast_forward for
        select artid, ins_cmd, upd_cmd, del_cmd, name, fn_replgetbinary8lodword(schema_option)
          from sysarticles
         where pubid = @pubid
           and (type & 1) <> 0
    if @@error <> 0
    begin
        select @retcode = 1
        goto Failure
    end
    select @cursor_allocated = 1

    open harticle
    if @@error <> 0
    begin
        select @retcode = 1
        goto Failure
    end
    select @cursor_opened = 1
    
    fetch harticle into @artid, @ins_cmd, @upd_cmd, @del_cmd, @article, @schema_option

    while (@@fetch_status<>-1)
    begin        
        
        if (@schema_option & 2) = 0
        begin
            
            select @formattedmessage = formatmessage(21517,@article)
            if @@error <> 0 begin select @retcode = 1 goto Failure end
            insert into #proctext_scriptpublicationcustomprocs values(N'----')
            insert into #proctext_scriptpublicationcustomprocs values(N'---- ' + @formattedmessage)
            insert into #proctext_scriptpublicationcustomprocs values(N'----')
            insert into #proctext_scriptpublicationcustomprocs values(N'')
            goto SkipArticle
        end 

        select @formattedmessage = formatmessage(21518,@article)
        if @@error <> 0 begin select @retcode = 1 goto Failure end
        insert into #proctext_scriptpublicationcustomprocs values(N'----')
        insert into #proctext_scriptpublicationcustomprocs values(N'---- ' + @formattedmessage)
        insert into #proctext_scriptpublicationcustomprocs values(N'----')
        insert into #proctext_scriptpublicationcustomprocs values(N'')

        if lower(substring(@ins_cmd,1,len(N'call'))) = N'call'
        begin
            
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptinsproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@ins_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@ins_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end

        if lower(substring(@upd_cmd,1,len(N'call'))) = N'call'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')

        end
        else if lower(substring(@upd_cmd,1,len(N'mcall'))) = N'mcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptmappedupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@upd_cmd,1,len(N'xcall'))) = N'xcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptxupdproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@upd_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@upd_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end

        if lower(substring(@del_cmd,1,len(N'call'))) = N'call'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptdelproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@del_cmd,1,len(N'xcall'))) = N'xcall'
        begin
            insert into #proctext_scriptpublicationcustomprocs exec @retcode = sp_scriptxdelproc @artid
            if @@error <> 0 or @retcode <> 0
            begin
                select @retcode = 1
                goto Failure
            end
            insert into #proctext_scriptpublicationcustomprocs values('go')
            insert into #proctext_scriptpublicationcustomprocs values('')
        end
        else if lower(substring(@del_cmd,1,len(N'sql'))) = N'sql'
        begin
            select @formattedmessage = formatmessage(21519)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
        else
        begin
            select @formattedmessage = formatmessage(21520,@del_cmd)
            if @@error <> 0 begin select @retcode = 1 goto Failure end                
            insert #proctext_scriptpublicationcustomprocs values('-- ' + @formattedmessage)
            insert #proctext_scriptpublicationcustomprocs values('')
        end
SkipArticle:
        fetch harticle into @artid, @ins_cmd, @upd_cmd, @del_cmd, @article, @schema_option
    end
    
    select '--' = line from #proctext_scriptpublicationcustomprocs order by line_no asc
   
Failure:
    if @table_created <> 0
    begin
        drop table #proctext_scriptpublicationcustomprocs
    end
    
    if @cursor_opened <> 0
    begin
        close harticle
    end

    if @cursor_allocated <> 0
    begin
        deallocate harticle
    end 
    return @retcode    
end
go

exec sp_MS_marksystemobject sp_scriptpublicationcustomprocs


raiserror('Creating procedure sp_repltablehasnonpkuniquekey',0,-1)
go
--
-- Name: sp_repltablehasnonpkuniquekey
--
-- Description: This procedure is by queued updating replication to check
-- if a given table has non PK unique index keys
--
-- Parameter: @tabid int
--
-- Returns: 1 or 0  1 = The table has one or more unique index that is not PK
--
-- Security: Internal procedure - exec permission not granted explicitly. 
--
create procedure sp_repltablehasnonpkuniquekey 
(
    @tabid int              -- id of the table
)
as
begin
    set nocount on
    declare @retcode int
    --
    -- security check - should be dbo or sysadmin
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR != 0 or @retcode != 0
        return -1
    --
    -- process if the object is a table and has index
    --
    if (ObjectProperty(@tabid, 'IsTable') = 1) and (ObjectProperty(@tabid, 'TableHasIndex') = 1)
    begin
        --
        -- Set return flag if it is Unique key but not PK
        --
        if exists (select indid from sysindexes 
                where id = @tabid 
                    and indid > 0 and indid < 255
                    and (status & 2) != 0 and (status & 2048) = 0 )
        begin
            select @retcode = 1
        end
    end
    --
    -- all done
    --
    return @retcode
end
go
exec sp_MS_marksystemobject sp_repltablehasnonpkuniquekey
go

raiserror('Creating procedure sp_replscriptuniquekeywhereclause',0,-1)
go
--
-- Name: sp_replscriptuniquekeywhereclause
--
-- Description: This procedure is by queued updating replication to generate
-- where clause using all the unique keys (including PK)
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Internal procedure - exec permission not granted explicitly. 
--
create procedure sp_replscriptuniquekeywhereclause 
(
    @tabid int                                  -- id of the table
    ,@columns binary(32)                 -- column map for the article
    ,@prefix nvarchar(10) = '@c'       -- prefix for the scripted column variables
    ,@suffix nvarchar(10) = null	   -- suffix for the scripted column variables
    ,@mode tinyint                           
    -- 1 = insert custom proc, 
    -- 2 = upd custom proc non PK, 
    -- 3 = upd custom proc PK only 
    -- 4 = compensating where all keys, 
    -- 5 = compensating where non PK keys, 
    -- 6 = refresh cursor all keys,
    -- 7 = refresh cursor non PK keys
    -- 8 = compensating where PK only
    ,@paramcount int = null              -- Total number of parameters - needed for mode = 2 and 3
 )
as
begin
    set nocount on
    declare @retcode int
                ,@indid int
                ,@indstatus int
                ,@indkey int
                ,@qualname nvarchar(512)
                ,@colname sysname
                ,@var sysname
                ,@artcol int
                ,@thiscol int
                ,@cmd nvarchar(4000)
                ,@findexstarted bit
                ,@fisfirstindex bit
    --
    -- constants
    --
                ,@modeinscustproc tinyint
                ,@modeupdcustprocnonpk tinyint
                ,@modeupdcustprocpkonly tinyint
                ,@modecompensatingallkeys tinyint
                ,@modecompensatingnonpkkeys tinyint
                ,@modecompensatingpkonly tinyint
                ,@moderefreshcursordeclareallkeys tinyint
                ,@moderefreshcursordeclarenonpkkeys tinyint

    --
    -- initialize
    --
    select @modeinscustproc = 1
            ,@modeupdcustprocnonpk = 2
            ,@modeupdcustprocpkonly = 3
            ,@modecompensatingallkeys = 4
            ,@modecompensatingnonpkkeys = 5
            ,@moderefreshcursordeclareallkeys = 6
            ,@moderefreshcursordeclarenonpkkeys = 7
            ,@modecompensatingpkonly = 8
    --
    -- security check - should be dbo or sysadmin
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error != 0 or @retcode != 0
        return (1)
    --
    -- process if the object is a table and has index
    --
    if (ObjectProperty(@tabid, 'IsTable') != 1) or (ObjectProperty(@tabid, 'TableHasIndex') != 1)
        return (1)
    --
    -- Get the qualified name of the table
    --
    exec @retcode = sp_MSget_qualified_name @tabid, @qualname OUTPUT
    if @@error != 0 or @retcode != 0 or @qualname is null
        return (1)
    --
    -- @columns cannot be null
    --
    if (@columns is null)
        return (1)
    --
    -- Check @mode
    --
    if (@mode not in (@modeinscustproc, @modeupdcustprocnonpk, @modeupdcustprocpkonly, 
                                @modecompensatingallkeys, @modecompensatingnonpkkeys, 
                                @moderefreshcursordeclareallkeys, @moderefreshcursordeclarenonpkkeys,
                                @modecompensatingpkonly))
    begin
        return (1)
    end
    --
    -- validate @paramcount
    --
    if ((@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) and (@paramcount is null))
    begin
        return (1)
    end
    --
    -- enumerate indices
    -- The scripting will be done as follows :
    -- A) all keys will include PK and all unique keys
    --      where (pk1 = @cv and pk2 = @cw ...) or (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ...
    -- B) non PK keys will use only the unique keys that are not part of PK
    --      where (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ...
    --
    select @cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
                            then N' '' where '
                            else N' where ' end
            ,@findexstarted = 0
            ,@fisfirstindex = 1
    declare #hcindid cursor local fast_forward for
        select indid, status from sysindexes 
                where id = @tabid and (status & 2) != 0
                    and indid > 0 and indid < 255
                    order by indid asc
    open #hcindid
    fetch #hcindid into @indid, @indstatus
    while (@@fetch_status != -1)
    begin
        --
        -- If we are in (@modeupdcustprocnonpk, @modecompensatingnonpkkeys, 
        -- @moderefreshcursordeclarenonpklkeys) mode then skip processing the PK index.
        -- If we are in (@modeupdcustprocpkonly, @modecompensatingpkonly) mode 
        -- skip processing the non PK index
        --
        if ((@mode in (@modeupdcustprocnonpk,@modecompensatingnonpkkeys,
                    @moderefreshcursordeclarenonpkkeys)) and (@indstatus & 2048) != 0) 
            or ((@mode in (@modeupdcustprocpkonly, @modecompensatingpkonly)) and (@indstatus & 2048) = 0)
        begin
            --
            -- fetch next unique index
            --
            fetch #hcindid into @indid, @indstatus
            continue
        end
        --
        -- Enumerate the keys in this index
        --
        select @indkey = 1
        while (@indkey <= 16)
        begin
            --
            -- get the column name for the key
            --
            select @colname = index_col(@qualname, @indid, @indkey)
            if (@colname is null) 
                break
            --
            -- check if this column is enabled for replication
            --
            select @artcol = 0
            exec dbo.sp_MSget_col_position @tabid, @columns, @colname, NULL, @artcol output, 0, NULL, @thiscol output
            if (@artcol > 0)
            begin
                --
                -- check if we are scripting the first key for this index
                --
                if (@findexstarted = 1)
                begin
                    select @cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
                                            then @cmd + N' + '' and '
                                            else @cmd + N' and ' end
                end
                else
                begin
                    --
                    -- check if we are scripting the first index. 
                    --
                    if (@fisfirstindex = 0)
                    begin
                        select @cmd =  @cmd + N' or ' 
                    end
                    else
                    begin
                        select @fisfirstindex = 0
                    end
                    --
                    -- set @findexstarted while processing the first key
                    --
                    select @findexstarted = 1
                    select @cmd = @cmd + N' ( ' 
                end
                --
                -- script this column
                --
                if (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly))
                begin
                    --
                    -- scripting a delete compensating command for synctran proc - we are building a dynamic string
                    -- case when @c<this_col> is null then '[col<this_col>] is null' else '[col<this_col>] = @c<this_col>' end
                    --
                    declare @ccoltype sysname

                    select @var = @prefix + cast(@thiscol as nvarchar(10))
                    if (@suffix is not null)
                        select @var = @var + @suffix
                    select @cmd = @cmd + N''' + case when ( ' + @var + N' is null) then  '' ' + quotename(@colname) + N' is null '' else '' ' + quotename(@colname)
                    exec dbo.sp_MSget_colinfo @tabid, @thiscol, @columns, 0, NULL, @ccoltype output
                    if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar' )
                        select @cmd = @cmd + N' = '''''' + CAST( master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default as varchar) + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
                        select @cmd = @cmd + N' = N'''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
                        select @cmd = @cmd + N' = '''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
                        select @cmd = @cmd + N' = N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
                        select @cmd = @cmd + N' = '' + master.dbo.fn_varbintohexstr(' + @var + N') collate database_default end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
                        select @cmd = @cmd + N' = '' + CAST( ' + @var + N' as nvarchar) end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
                        select @cmd = @cmd + N' = '' + CONVERT(nvarchar(60), ' + @var + N' , 2) end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
                        select @cmd = @cmd + N' = '' + CONVERT(nvarchar(40), ' + @var + N' , 2) end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
                        select @cmd = @cmd + N' = '''''' + CAST( ' + @var + N' as nvarchar(40)) + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
                        select @cmd = @cmd + N' = '''''' + CONVERT(nvarchar(40), ' + @var + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @var + N', 114) + '''''''' end ' 
                    else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
                        select @cmd = @cmd + N' = '' + master.dbo.fn_sqlvarbasetostr( ' + @var + N' ) collate database_default  end ' 
                    else
                        select @cmd = @cmd + N' = '' + CAST( ' + @var + N' as nvarchar) end ' 

                        --select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''', ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL('''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''', ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_varbintohexstr(' + @var + N') collate database_default, ''null'') ' 
                        --select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL(CONVERT(nvarchar(40),' + @var + N', 2), ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL('''''''' + CAST(' + @var + N' as nvarchar(40)) + '''''''', ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL('''''''' + CONVERT(nvarchar(40), ' + @var + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @var + N', 114) + '''''''', ''null'') '	
                        --select @cmd = @cmd + N' = '' + ISNULL(master.dbo.fn_sqlvarbasetostr(' + @var + N' ) collate database_default, ''null'') '
                        --select @cmd = @cmd + N' = '' + ISNULL(CAST(' + @var + N' as nvarchar), ''null'') '
                end
                else
                begin
                    --
                    -- scripting for custom procs - static script
                    -- For publisher scripting - use @thiscol
                    -- For custom proc scripting - use @artcol
                    -- For Update custom proc scripting special cases - use variation of @artcol
                    --
                    select @var = case when (@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) 
                                                    then @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
                                                when (@mode in (@moderefreshcursordeclareallkeys, @moderefreshcursordeclarenonpkkeys))
                                                    then @prefix + cast(@thiscol as nvarchar(10)) 
                                                else @prefix + cast(@artcol as nvarchar(10)) end
                    if (@suffix is not null)
                        select @var = @var + @suffix
                    --
                    -- Does the column allow NULLs
                    --
                    if (columnproperty( @tabid , @colname , 'AllowsNull' ) = 1)
                    begin
                        --
                        -- static scripting should handle NULL valued column
                        -- ((<@var> is null and <colname> is null) or (<@var> is not null and <colname> = <@var>)) 
                        --
                        select @cmd = @cmd + N'((' + @var + N' is null and ' + quotename(@colname) + N' is null) or (' 
                                                + @var + N' is not null and ' + quotename(@colname) + N' = ' + @var + N'))' 
                    end
                    else
                    begin
                        --
                        -- static scripting does not need to check for NULL values
                        -- <colname> = <@var>
                        --
                        select @cmd = @cmd + quotename(@colname) + N' = ' + @var
                    end
                    --
                    -- special processing for @modeupdcustprocnonpk
                    --
                    if (@mode = @modeupdcustprocnonpk)
                    begin
                        select @cmd = @cmd + N' and ' + @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
                        if (@suffix is not null)
                            select @cmd = @cmd + @suffix
                        select @cmd = @cmd + N' != ' + @prefix + cast(@artcol as nvarchar(10))
                        if (@suffix is not null)
                            select @cmd = @cmd + @suffix
                    end
                end
                --
                -- transfer command string to table if too large
                --
                if (len(@cmd) > 3000)
                    exec dbo.sp_MSflush_command @cmd output, 1, 0                
            end            
            --
            -- get the next key for the index
            --
            select @indkey = @indkey + 1
        end
        --
        -- done with current index
        --
        select @findexstarted = 0
                ,@cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
                                        then @cmd + N' + '' ) '
                                        else @cmd + N' ) ' end
        --
        -- fetch next unique index
        --
        fetch #hcindid into @indid, @indstatus
    end
    close #hcindid
    deallocate #hcindid
    --
    -- Final flush
    --
    if (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly))
        select @cmd = @cmd + N''''
    if (len(@cmd) > 0)
        exec dbo.sp_MSflush_command @cmd output, 1, 0                
    --
    -- all done
    --
    return 0
end
go
exec sp_MS_marksystemobject sp_replscriptuniquekeywhereclause
go

--
-- Name: sp_getqueuedarticlesynctraninfo
--
-- Description: This procedure is by Queue reader agent to query the article
-- 	metadata from the publisher - the name of synctran procedures, etc
--   Invoked on publishing database on publisher.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - internal security check. 
--
raiserror('Creating procedure sp_getqueuedarticlesynctraninfo',0,-1)
go
create procedure sp_getqueuedarticlesynctraninfo 
(
    @publication sysname    -- publication - cannot be null
    ,@artid int                     -- article id - cannot be null
)
as
begin
    set nocount on
    declare @retcode int
                ,@owner sysname
                ,@synctraninsproc sysname
                ,@synctranupdproc sysname
                ,@synctrandelproc sysname
                ,@cftprocname sysname
    --
    -- security check - should be dbo or sysadmin
    --
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@error != 0 or @retcode != 0
        return 1
    if exists (select * from sysobjects where name = N'sysarticleupdates') 
        and exists (select * from sysobjects where name = N'syspublications') 
    begin
        --
        -- get the information needed for resultset
        --
        select user_name(objectproperty(a.sync_ins_proc, 'OwnerId'))
                ,object_name(a.sync_ins_proc)
                ,object_name(a.sync_upd_proc)
                ,object_name(a.sync_del_proc)
                ,object_name(a.ins_conflict_proc)
        from (sysarticleupdates as a join syspublications p
                    on a.pubid = p.pubid)
        where a.artid = @artid
            and p.name = @publication
    end
    else
    begin
        --
        -- replication not installed properly
        --
        return 1
    end
    --
    -- all done
    --
    return 0
end
go
exec sp_MS_marksystemobject sp_getqueuedarticlesynctraninfo
go

--
-- Name: sp_getsqlqueueversion
--
-- Description: This procedure is by Queue reader agent to retrieve the 
-- 	SQL queue version for a given subscription. Invoked on subscribing
--	database on subscriber.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - internal security check. 
--
raiserror('Creating procedure sp_getsqlqueueversion',0,-1)
go
create procedure sp_getsqlqueueversion 
(
    @publisher sysname       -- pubisher - cannot be null
    ,@publisher_db sysname -- publisher_db - cannot be null
    ,@publication sysname    -- publication - cannot be null
    ,@version int output        -- version of the queue > 0
)
as
begin
    set nocount on
    declare @retcode int
                ,@queueidstring sysname

    --
    -- Security check
    --
    exec @retcode = dbo.sp_MSreplcheck_subscribe
    if @@error != 0 or @retcode != 0
        return 1
    --
    -- the subscription must be initialized
    --
    if exists (select * from sysobjects where name = 'MSsubscription_agents')
    begin
        --
        -- do the select for sql queues
        --
        select @queueidstring = substring(queue_id, 1, 10) 
                 ,@version = cast(substring(queue_id, 12, 10)  as int)
        from dbo.MSsubscription_agents
        where publisher = UPPER(@publisher) 
            and publisher_db = @publisher_db 
            and publication = @publication
            and update_mode in (4,5)
        if (@queueidstring = N'mssqlqueue')
        begin
            --
            -- found the entry
            --
            if (@version = 0)
                select @version = 1
        end
        else
        begin
            --
            -- No subscription exists
            --
            select @version = 0
            return 0
        end
    end
    else
    begin
        --
        -- No subscription exists
        --
        select @version = 0
        return 0
    end
    --
    -- all done
    --
    return 0
end
go
exec sp_MS_marksystemobject sp_getsqlqueueversion
go


---------------------------------------------------------------------------
---------------------------------------------------------------------------

grant execute on dbo.sp_scriptpublicationcustomprocs to public
grant execute on dbo.sp_enumfullsubscribers to public
grant execute on dbo.sp_addpublication to public
grant execute on dbo.sp_changepublication to public
grant execute on dbo.sp_changesubscription to public
grant execute on dbo.sp_articlecolumn to public
grant execute on dbo.sp_helparticle to public
grant execute on dbo.sp_helparticlecolumns to public
grant execute on dbo.sp_helppublication to public
grant execute on dbo.sp_publication_validation to public
grant execute on dbo.sp_marksubscriptionvalidation to public
grant execute on dbo.sp_article_validation to public
grant execute on dbo.sp_helpsubscription to public
grant execute on dbo.sp_MSscript_article_view to public
grant execute on dbo.sp_articlefilter to public
grant execute on dbo.sp_articleview to public
grant execute on dbo.sp_addarticle to public
--grant execute on dbo.sp_MSgettranconflictname to public
--grant execute on dbo.sp_MSmaketrancftproc to public
--grant execute on dbo.sp_MSmakeconflicttable to public
grant execute on dbo.sp_scriptsubconflicttable to public
grant execute on dbo.sp_changesubstatus to public
grant execute on dbo.sp_addsubscription to public
grant execute on dbo.sp_changearticle to public
grant execute on dbo.sp_droparticle to public
grant execute on dbo.sp_droppublication to public
grant execute on dbo.sp_dropsubscription to public
grant execute on dbo.sp_subscribe to public
grant execute on dbo.sp_unsubscribe to public
grant execute on dbo.sp_refreshsubscriptions to public
grant execute on dbo.sp_reinitsubscription to public
--grant exec on dbo.sp_articlesynctranprocs to public
go

--grant exec on dbo.sp_gettypestring to public
--grant exec on dbo.sp_scriptpkwhereclause to public
--grant exec on dbo.sp_scriptupdateparams to public
--grant exec on dbo.sp_scriptreconwhereclause to public
grant exec on dbo.sp_script_reconciliation_insproc to public
grant exec on dbo.sp_script_reconciliation_delproc to public
grant exec on dbo.sp_script_reconciliation_xdelproc to public
grant exec on dbo.sp_scriptinsproc to public
grant exec on dbo.sp_scriptdelproc to public
grant exec on dbo.sp_scriptxdelproc to public
grant exec on dbo.sp_scriptupdproc to public
grant exec on dbo.sp_scriptmappedupdproc to public
grant exec on dbo.sp_scriptdynamicupdproc to public
grant exec on dbo.sp_scriptxupdproc to public
grant exec on dbo.sp_MSscriptmvastablenci to public
grant exec on dbo.sp_MSscriptmvastablepkc to public
grant exec on dbo.sp_MSscriptmvastableidx to public
grant exec on dbo.sp_MSscriptmvastable to public
grant exec on dbo.sp_script_synctran_commands to public
grant exec on dbo.sp_MSget_synctran_commands to public
grant exec on dbo.sp_MSactivate_auto_sub to public
grant exec on dbo.sp_dropanonymousagent to public
go

--grant execute on dbo.sp_MSscript_compensating_send to public
--grant execute on dbo.sp_MSscript_insert_statement to public
--grant execute on dbo.sp_MSscript_insert_subwins to public
--grant execute on dbo.sp_MSscript_insert_pubwins to public
--grant execute on dbo.sp_MSscript_update_statement to public
--grant execute on dbo.sp_MSscript_update_subwins to public
--grant execute on dbo.sp_MSscript_update_pubwins to public
--grant execute on dbo.sp_MSscript_delete_statement to public
--grant execute on dbo.sp_MSscript_delete_subwins to public
--grant execute on dbo.sp_MSscript_compensating_insert to public
--grant execute on dbo.sp_MSscript_delete_pubwins to public
--grant execute on dbo.sp_MSscript_beginproc  to public
--grant execute on dbo.sp_MSscript_security  to public
--grant execute on dbo.sp_MSscript_endproc  to public
grant execute on dbo.sp_MSscript_sync_ins_proc  to public
grant execute on dbo.sp_MSscript_sync_upd_proc  to public
grant execute on dbo.sp_MSscript_sync_del_proc  to public
--grant execute on dbo.sp_MSscript_ExecutionMode_stmt to public
grant execute on dbo.sp_MSscript_pub_upd_trig  to public
--grant execute on dbo.sp_MSmark_proc_norepl to public
grant execute on dbo.sp_MSpub_adjust_identity to public
grant execute on dbo.sp_helparticledts to public
grant execute on dbo.sp_changesubscriptiondtsinfo to public
grant execute on dbo.sp_MSvalidate_subscription to public
grant exec on dbo.sp_MScomputearticlescreationorder to public
grant exec on dbo.sp_MScomputeunresolvedrefs to public
go

grant execute on dbo.sp_MShelptranconflictpublications to public
grant execute on dbo.sp_MShelptranconflictcounts to public
grant execute on dbo.sp_MSgettranconflictrow to public
grant execute on dbo.sp_MSgettrancftsrcrow to public
grant execute on dbo.sp_MSdeletetranconflictrow to public
grant execute on dbo.sp_MSgetarticlereinitvalue to public
--grant execute on dbo.sp_MSispkupdateinconflict to public
grant execute on dbo.sp_ivindexhasnullcols to public
grant execute on dbo.fn_sqlvarbasetostr to public
grant execute on dbo.sp_replrestart to public
grant execute on dbo.sp_replsqlqgetrows to public
grant execute on dbo.sp_repldeletequeuedtran to public
grant execute on dbo.sp_MSrepl_schema to public
grant execute on dbo.sp_MSpost_auto_proc to public
grant execute on dbo.sp_MSreplupdateschema to public
grant execute on dbo.sp_MSdefer_check to public
grant execute on dbo.sp_MSreenable_check to public
grant execute on dbo.sp_getqueuedrows to public
grant execute on dbo.sp_MSprep_exclusive to public
grant execute on dbo.sp_MSexternalfkreferences to public
grant execute on dbo.sp_getqueuedarticlesynctraninfo to public
grant execute on dbo.sp_getsqlqueueversion to public
go 

dump tran master with no_log
go
sp_configure 'allow updates',0
go
reconfigure with override
go

print ''
print 'Checking objects created by repltran.sql.'
go

--obsolete   exec dbo.sp_check_objects 'repl'
-- exec dbo.sp_MS_upd_sysobj_category 2  --set sysobjects.category | 2 based on crdate.
go


print ''
print 'repltran.sql completed successfully.'
go

dump tran master with no_log
go
checkpoint
go
