
/*
** replsys.sql            1997/02/12 22:03
**
**
** Copyright Microsoft, Inc. 1998-2000
** All Rights Reserved.
*/


dump tran master with no_log
go

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

set ANSI_NULLS off
go

use master
go

exec dbo.sp_MS_upd_sysobj_category 1 --Capture time for use at the end
go

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

go

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

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

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

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

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

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

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

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

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

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

-- this proc renamed
if exists (select * from sysobjects
	where type = 'P '
			and name = 'sp_vupdate_syscol_status')
	drop procedure sp_vupdate_syscol_status

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MSgetreplnick')
	drop procedure sp_MSgetreplnick
		
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MStestbit')		
	drop procedure sp_MStestbit
		
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MSsetbit')
	drop procedure sp_MSsetbit
		
		
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MSinsertcontents')
	drop procedure sp_MSinsertcontents
		
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MSupdatecontents')
	drop procedure sp_MSupdatecontents
			
if exists (select * from sysobjects
		where type = 'P' and name = 'sp_MSdeletecontents')
	drop procedure sp_MSdeletecontents

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

IF EXISTS (select * from sysobjects where
   name = 'sp_MScheck_agent_instance' and type = 'P')
      DROP PROCEDURE sp_MScheck_agent_instance

IF EXISTS (select * from sysobjects where
   name = 'sp_MSenum_replsqlqueues' and type = 'P')
      DROP PROCEDURE sp_MSenum_replsqlqueues

IF EXISTS (select * from sysobjects where
   name = 'sp_MSenum_replqueues' and type = 'P')
      DROP PROCEDURE sp_MSenum_replqueues

if exists (select * from sysobjects
		where name = 'xp_mergexpusage')
	execute dbo.sp_dropextendedproc 'xp_mergexpusage'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

go

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

if exists (select * from sysobjects
     where type = 'FN'
            and name = 'fn_varbintohexstr')
     drop function fn_varbintohexstr
go

if exists (select * from sysobjects
     where type = 'FN'
            and name = 'fn_varbintohexsubstring')
     drop function fn_varbintohexsubstring
go

if exists ( select * from sysobjects 
	where type = 'FN' 
			and name = 'fn_MSsharedversion' )
	drop function fn_MSsharedversion
go

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

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

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

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

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

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

if exists (select * from sysobjects
     where type = 'FN'
            and name = 'fn_MSgensqescstr')
     drop function fn_MSgensqescstr
go

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

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

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

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

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


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


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

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

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

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

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

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

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

go

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

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

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

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

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

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

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

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

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

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

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

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

if exists ( select * from sysobjects
    where type = 'FN'
    and name = 'fn_isreplmergeagent' )
	drop function dbo.fn_isreplmergeagent 

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

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

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

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

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

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

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

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

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

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

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

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

if exists (select * from sysobjects
		    where  type = 'X' and name = 'xp_execresultset')
begin
	execute dbo.sp_dropextendedproc 'xp_execresultset'
end
go
if exists (select * from sysobjects
		    where type = 'P' and name = 'xp_execresultset')
begin
	drop procedure dbo.xp_execresultset
end
go
if exists (select * from sysobjects
		    where type = 'P' and name = 'sp_execresultset')
begin
	drop procedure dbo.sp_execresultset
end
go
use master
go

IF EXISTS ( SELECT * FROM sysobjects WHERE uid = USER_ID('system_function_schema') 
	AND name = 'fn_serverid' )
DROP FUNCTION system_function_schema.fn_serverid
go

sp_addextendedproc 'xp_mergexpusage', 'xprepl.dll'
go

grant exec on xp_mergexpusage to public
go

if exists (select * from sysobjects
		where name = 'xp_showlineage')
	execute dbo.sp_dropextendedproc 'xp_showlineage'
go

sp_addextendedproc 'xp_showlineage', 'xprepl.dll'
go

grant exec on xp_showlineage to public
go

if exists (select * from sysobjects
		where name = 'xp_mergelineages' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_mergelineages'
go

sp_addextendedproc 'xp_mergelineages', 'xprepl.dll'
go

if exists (select * from sysobjects	where name = 'xp_updatelineage' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_updatelineage'
go

if exists (select * from sysobjects
		where name = 'xp_mapdown_bitmap')
	execute dbo.sp_dropextendedproc 'xp_mapdown_bitmap'
go

sp_addextendedproc 'xp_mapdown_bitmap', 'xprepl.dll'
go

grant exec on xp_mapdown_bitmap to public
go

if exists (select * from sysobjects
		where name = 'xp_ORbitmap')
	execute dbo.sp_dropextendedproc 'xp_ORbitmap'
go
sp_addextendedproc 'xp_ORbitmap', 'xprepl.dll'
go

if exists (select * from sysobjects
		where name = 'xp_proxiedmetadata')
	execute dbo.sp_dropextendedproc 'xp_proxiedmetadata'
go

sp_addextendedproc 'xp_proxiedmetadata', 'xprepl.dll'
go

if exists (select * from sysobjects	where name = 'xp_initcolvs' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_initcolvs'
go

if exists (select * from sysobjects	where name = 'xp_updatecolvbm' and xtype = 'X')
	execute dbo.sp_dropextendedproc 'xp_updatecolvbm'
go

if exists (select * from sysobjects
		where name = 'xp_showcolv')
	execute dbo.sp_dropextendedproc 'xp_showcolv'
go

sp_addextendedproc 'xp_showcolv', 'xprepl.dll'
go

grant exec on xp_showcolv to public
go

if exists (select * from sysobjects
		where name = 'xp_varbintohexstr')
	execute dbo.sp_dropextendedproc 'xp_varbintohexstr'
go

sp_addextendedproc 'xp_varbintohexstr', 'xprepl.dll'
go

if exists (select * from sysobjects
		where name = 'xp_intersectbitmaps')
	execute dbo.sp_dropextendedproc 'xp_intersectbitmaps'
go

if exists (select * from sysobjects
		where name = 'xp_displayparamstmt')
	execute dbo.sp_dropextendedproc 'xp_displayparamstmt'
go

sp_addextendedproc 'xp_displayparamstmt', 'xprepl.dll'
go

if exists (select * from sysobjects
		where name = 'xp_printstatements')
	execute dbo.sp_dropextendedproc 'xp_printstatements'
go

sp_addextendedproc 'xp_printstatements', 'xprepl.dll'
go

if exists (select * from sysobjects
		where name = 'xp_createqueue')
	execute dbo.sp_dropextendedproc 'xp_createqueue'
go

if exists (select * from sysobjects
		where name = 'xp_createprivatequeue')
	execute dbo.sp_dropextendedproc 'xp_createprivatequeue'

exec sp_addextendedproc 'xp_createprivatequeue', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_deletequeue')
	execute dbo.sp_dropextendedproc 'xp_deletequeue'
go

if exists (select * from sysobjects
		where name = 'xp_deleteprivatequeue')
	execute dbo.sp_dropextendedproc 'xp_deleteprivatequeue'

exec sp_addextendedproc 'xp_deleteprivatequeue', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'sp_replsendtoqueue')
	execute dbo.sp_dropextendedproc 'sp_replsendtoqueue'
go

sp_addextendedproc 'sp_replsendtoqueue', 'sp_replsendtoqueue extended proc'
go

grant exec on sp_replsendtoqueue to public
go

if exists (select * from sysobjects
		where name = 'sp_replwritetovarbin')
	execute dbo.sp_dropextendedproc 'sp_replwritetovarbin'
go

sp_addextendedproc 'sp_replwritetovarbin', 'sp_replwritetovarbin extended proc'
go

grant exec on sp_replwritetovarbin to public
go

if exists (select * from sysobjects
		where name = 'xp_resetqueue')
	execute dbo.sp_dropextendedproc 'xp_resetqueue'
go

sp_addextendedproc 'xp_resetqueue', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_peekqueue')
	execute dbo.sp_dropextendedproc 'xp_peekqueue'
go

sp_addextendedproc 'xp_peekqueue', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_controlqueueservice')
	execute dbo.sp_dropextendedproc 'xp_controlqueueservice'
go

sp_addextendedproc 'xp_controlqueueservice', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_displayqueuemesgs')
	execute dbo.sp_dropextendedproc 'xp_displayqueuemesgs'
go

sp_addextendedproc 'xp_displayqueuemesgs', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_decodequeuecmd')
	execute dbo.sp_dropextendedproc 'xp_decodequeuecmd'
go

sp_addextendedproc 'xp_decodequeuecmd', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_readpkfromqueue')
	execute dbo.sp_dropextendedproc 'xp_readpkfromqueue'
go

sp_addextendedproc 'xp_readpkfromqueue', 'xpqueue.dll'
go

if exists (select * from sysobjects
		where name = 'xp_readpkfromvarbin')
	execute dbo.sp_dropextendedproc 'xp_readpkfromvarbin'
go

sp_addextendedproc 'xp_readpkfromvarbin', 'xpqueue.dll'
go

/*
** Add xp_makecab extended procedure
*/

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

sp_addextendedproc 'xp_makecab', 'xprepl.dll'
go
exec dbo.sp_MS_marksystemobject xp_makecab
go

/*
** Add xp_unpackcab extended procedure
*/

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

sp_addextendedproc 'xp_unpackcab', 'xprepl.dll'
go
exec dbo.sp_MS_marksystemobject xp_unpackcab
go

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

	CREATE TABLE dbo.MSreplication_options 
	(
	optname			sysname NOT NULL,
	value			bit NOT NULL,
	major_version	int NOT NULL,
	minor_version	int NOT NULL,
	revision		int NOT NULL,
	install_failures int NOT NULL
	)
END
GO

IF NOT EXISTS (SELECT * FROM MSreplication_options WHERE optname = 'transactional')
	INSERT INTO MSreplication_options VALUES
		('transactional',0,0,0,0,0)
IF NOT EXISTS (SELECT * FROM MSreplication_options WHERE optname = 'merge')
	INSERT INTO MSreplication_options VALUES
		('merge',0,0,0,0,0)
GO


SET ANSI_NULLS ON
go
-- 
-- Name:
--	xp_execresultset
--
-- Description: 
--	This is a wrapper proc to sp_execresultset and provides us
--  with the ability to change user database context based on
--  the @dbname provided.
--
-- Parameters: 
--	(see create call below)
--
-- Result:
--
-- Returns 
--	    0 - succeeded
--      1 - failed
--
-- Security: 
--	Sysadmin & DBO access only
--
raiserror('Creating procedure xp_execresultset', 0,1) with nowait
go
create procedure dbo.xp_execresultset
(
	@cmd	nvarchar(4000),
	@dbname	sysname = NULL,
	@debug	bit = 0
)
as
begin
	declare @retcode bit,
		    @proc nvarchar(4000)
	
	-- check to ensure that the @dbname provided is neither null or empty
	if isnull(rtrim(@dbname), N'') = N''
	begin
		raiserror('Internal Error : @dbname cannot be null or empty.', 16, -1)
		return 1
	end
	
	select @proc = quotename(@dbname) + N'.dbo.sp_execresultset' 

	exec @retcode = @proc @cmd, @debug
	
	return @retcode
end
go

-- 
-- Name:
--	sp_execresultset
--
-- Description: 
--	This procedure replaces the extended stored procedure xp_execresultset.
--	The proc accepts a query (@cmd) and builds a buffer with the queries
--	resultset and executes it against the current database. This proc has
--  a ~1MB limit on the resultset text that can be executed.
--
-- Parameters: 
--	(see create call below)
--
-- Result:
--
-- Returns 
--  0 - succeeded
--  1 - failed
--
-- Security: 
--	Sysadmin & DBO access only
--
raiserror('Creating procedure sp_execresultset', 0,1) with nowait
go
create procedure dbo.sp_execresultset
(
	@cmd 	nvarchar(4000),		-- Command that will return a resultset to concat and execute
	@debug	bit = 0				-- Display debug information and resultset query (no exec)
)
as
begin
	set nocount on

	declare @MAXBUFFLEN	int,
		@qPosition 		int,
		@qValue			nvarchar(4000),
		@scriptLen 		int,
		@scriptText 	nvarchar(4000),
		@maxIndex		bigint,
		@rowIndex		bigint

	-- declare 250 nvarchar(4000) (nearly 1MB worth of space)
	declare @q1 nvarchar(4000), @q2 nvarchar(4000), @q3 nvarchar(4000), @q4 nvarchar(4000), @q5 nvarchar(4000), @q6 nvarchar(4000), @q7 nvarchar(4000), @q8 nvarchar(4000), @q9 nvarchar(4000), @q10 nvarchar(4000), 
		@q11 nvarchar(4000), @q12 nvarchar(4000), @q13 nvarchar(4000), @q14 nvarchar(4000), @q15 nvarchar(4000), @q16 nvarchar(4000), @q17 nvarchar(4000), @q18 nvarchar(4000), @q19 nvarchar(4000), @q20 nvarchar(4000), 
		@q21 nvarchar(4000), @q22 nvarchar(4000), @q23 nvarchar(4000), @q24 nvarchar(4000), @q25 nvarchar(4000), @q26 nvarchar(4000), @q27 nvarchar(4000), @q28 nvarchar(4000), @q29 nvarchar(4000), @q30 nvarchar(4000), 
		@q31 nvarchar(4000), @q32 nvarchar(4000), @q33 nvarchar(4000), @q34 nvarchar(4000), @q35 nvarchar(4000), @q36 nvarchar(4000), @q37 nvarchar(4000), @q38 nvarchar(4000), @q39 nvarchar(4000), @q40 nvarchar(4000), 
		@q41 nvarchar(4000), @q42 nvarchar(4000), @q43 nvarchar(4000), @q44 nvarchar(4000), @q45 nvarchar(4000), @q46 nvarchar(4000), @q47 nvarchar(4000), @q48 nvarchar(4000), @q49 nvarchar(4000), @q50 nvarchar(4000), 
		@q51 nvarchar(4000), @q52 nvarchar(4000), @q53 nvarchar(4000), @q54 nvarchar(4000), @q55 nvarchar(4000), @q56 nvarchar(4000), @q57 nvarchar(4000), @q58 nvarchar(4000), @q59 nvarchar(4000), @q60 nvarchar(4000), 
		@q61 nvarchar(4000), @q62 nvarchar(4000), @q63 nvarchar(4000), @q64 nvarchar(4000), @q65 nvarchar(4000), @q66 nvarchar(4000), @q67 nvarchar(4000), @q68 nvarchar(4000), @q69 nvarchar(4000), @q70 nvarchar(4000), 
		@q71 nvarchar(4000), @q72 nvarchar(4000), @q73 nvarchar(4000), @q74 nvarchar(4000), @q75 nvarchar(4000), @q76 nvarchar(4000), @q77 nvarchar(4000), @q78 nvarchar(4000), @q79 nvarchar(4000), @q80 nvarchar(4000), 
		@q81 nvarchar(4000), @q82 nvarchar(4000), @q83 nvarchar(4000), @q84 nvarchar(4000), @q85 nvarchar(4000), @q86 nvarchar(4000), @q87 nvarchar(4000), @q88 nvarchar(4000), @q89 nvarchar(4000), @q90 nvarchar(4000), 
		@q91 nvarchar(4000), @q92 nvarchar(4000), @q93 nvarchar(4000), @q94 nvarchar(4000), @q95 nvarchar(4000), @q96 nvarchar(4000), @q97 nvarchar(4000), @q98 nvarchar(4000), @q99 nvarchar(4000), @q100 nvarchar(4000), 
		@q101 nvarchar(4000), @q102 nvarchar(4000), @q103 nvarchar(4000), @q104 nvarchar(4000), @q105 nvarchar(4000), @q106 nvarchar(4000), @q107 nvarchar(4000), @q108 nvarchar(4000), @q109 nvarchar(4000), @q110 nvarchar(4000), 
		@q111 nvarchar(4000), @q112 nvarchar(4000), @q113 nvarchar(4000), @q114 nvarchar(4000), @q115 nvarchar(4000), @q116 nvarchar(4000), @q117 nvarchar(4000), @q118 nvarchar(4000), @q119 nvarchar(4000), @q120 nvarchar(4000), 
		@q121 nvarchar(4000), @q122 nvarchar(4000), @q123 nvarchar(4000), @q124 nvarchar(4000), @q125 nvarchar(4000), @q126 nvarchar(4000), @q127 nvarchar(4000), @q128 nvarchar(4000), @q129 nvarchar(4000), @q130 nvarchar(4000), 
		@q131 nvarchar(4000), @q132 nvarchar(4000), @q133 nvarchar(4000), @q134 nvarchar(4000), @q135 nvarchar(4000), @q136 nvarchar(4000), @q137 nvarchar(4000), @q138 nvarchar(4000), @q139 nvarchar(4000), @q140 nvarchar(4000), 
		@q141 nvarchar(4000), @q142 nvarchar(4000), @q143 nvarchar(4000), @q144 nvarchar(4000), @q145 nvarchar(4000), @q146 nvarchar(4000), @q147 nvarchar(4000), @q148 nvarchar(4000), @q149 nvarchar(4000), @q150 nvarchar(4000), 
		@q151 nvarchar(4000), @q152 nvarchar(4000), @q153 nvarchar(4000), @q154 nvarchar(4000), @q155 nvarchar(4000), @q156 nvarchar(4000), @q157 nvarchar(4000), @q158 nvarchar(4000), @q159 nvarchar(4000), @q160 nvarchar(4000), 
		@q161 nvarchar(4000), @q162 nvarchar(4000), @q163 nvarchar(4000), @q164 nvarchar(4000), @q165 nvarchar(4000), @q166 nvarchar(4000), @q167 nvarchar(4000), @q168 nvarchar(4000), @q169 nvarchar(4000), @q170 nvarchar(4000), 
		@q171 nvarchar(4000), @q172 nvarchar(4000), @q173 nvarchar(4000), @q174 nvarchar(4000), @q175 nvarchar(4000), @q176 nvarchar(4000), @q177 nvarchar(4000), @q178 nvarchar(4000), @q179 nvarchar(4000), @q180 nvarchar(4000), 
		@q181 nvarchar(4000), @q182 nvarchar(4000), @q183 nvarchar(4000), @q184 nvarchar(4000), @q185 nvarchar(4000), @q186 nvarchar(4000), @q187 nvarchar(4000), @q188 nvarchar(4000), @q189 nvarchar(4000), @q190 nvarchar(4000), 
		@q191 nvarchar(4000), @q192 nvarchar(4000), @q193 nvarchar(4000), @q194 nvarchar(4000), @q195 nvarchar(4000), @q196 nvarchar(4000), @q197 nvarchar(4000), @q198 nvarchar(4000), @q199 nvarchar(4000), @q200 nvarchar(4000), 
		@q201 nvarchar(4000), @q202 nvarchar(4000), @q203 nvarchar(4000), @q204 nvarchar(4000), @q205 nvarchar(4000), @q206 nvarchar(4000), @q207 nvarchar(4000), @q208 nvarchar(4000), @q209 nvarchar(4000), @q210 nvarchar(4000), 
		@q211 nvarchar(4000), @q212 nvarchar(4000), @q213 nvarchar(4000), @q214 nvarchar(4000), @q215 nvarchar(4000), @q216 nvarchar(4000), @q217 nvarchar(4000), @q218 nvarchar(4000), @q219 nvarchar(4000), @q220 nvarchar(4000), 
		@q221 nvarchar(4000), @q222 nvarchar(4000), @q223 nvarchar(4000), @q224 nvarchar(4000), @q225 nvarchar(4000), @q226 nvarchar(4000), @q227 nvarchar(4000), @q228 nvarchar(4000), @q229 nvarchar(4000), @q230 nvarchar(4000), 
		@q231 nvarchar(4000), @q232 nvarchar(4000), @q233 nvarchar(4000), @q234 nvarchar(4000), @q235 nvarchar(4000), @q236 nvarchar(4000), @q237 nvarchar(4000), @q238 nvarchar(4000), @q239 nvarchar(4000), @q240 nvarchar(4000), 
		@q241 nvarchar(4000), @q242 nvarchar(4000), @q243 nvarchar(4000), @q244 nvarchar(4000), @q245 nvarchar(4000), @q246 nvarchar(4000), @q247 nvarchar(4000), @q248 nvarchar(4000), @q249 nvarchar(4000), @q250 nvarchar(4000) 

	-- initialize all vars
	select @q1 = N'', @q2 = N'', @q3 = N'', @q4 = N'', @q5 = N'', @q6 = N'', @q7 = N'', @q8 = N'', @q9 = N'', @q10 = N'', 
		@q11 = N'', @q12 = N'', @q13 = N'', @q14 = N'', @q15 = N'', @q16 = N'', @q17 = N'', @q18 = N'', @q19 = N'', @q20 = N'', 
		@q21 = N'', @q22 = N'', @q23 = N'', @q24 = N'', @q25 = N'', @q26 = N'', @q27 = N'', @q28 = N'', @q29 = N'', @q30 = N'', 
		@q31 = N'', @q32 = N'', @q33 = N'', @q34 = N'', @q35 = N'', @q36 = N'', @q37 = N'', @q38 = N'', @q39 = N'', @q40 = N'', 
		@q41 = N'', @q42 = N'', @q43 = N'', @q44 = N'', @q45 = N'', @q46 = N'', @q47 = N'', @q48 = N'', @q49 = N'', @q50 = N'', 
		@q51 = N'', @q52 = N'', @q53 = N'', @q54 = N'', @q55 = N'', @q56 = N'', @q57 = N'', @q58 = N'', @q59 = N'', @q60 = N'', 
		@q61 = N'', @q62 = N'', @q63 = N'', @q64 = N'', @q65 = N'', @q66 = N'', @q67 = N'', @q68 = N'', @q69 = N'', @q70 = N'', 
		@q71 = N'', @q72 = N'', @q73 = N'', @q74 = N'', @q75 = N'', @q76 = N'', @q77 = N'', @q78 = N'', @q79 = N'', @q80 = N'', 
		@q81 = N'', @q82 = N'', @q83 = N'', @q84 = N'', @q85 = N'', @q86 = N'', @q87 = N'', @q88 = N'', @q89 = N'', @q90 = N'', 
		@q91 = N'', @q92 = N'', @q93 = N'', @q94 = N'', @q95 = N'', @q96 = N'', @q97 = N'', @q98 = N'', @q99 = N'', @q100 = N'', 
		@q101 = N'', @q102 = N'', @q103 = N'', @q104 = N'', @q105 = N'', @q106 = N'', @q107 = N'', @q108 = N'', @q109 = N'', @q110 = N'', 
		@q111 = N'', @q112 = N'', @q113 = N'', @q114 = N'', @q115 = N'', @q116 = N'', @q117 = N'', @q118 = N'', @q119 = N'', @q120 = N'', 
		@q121 = N'', @q122 = N'', @q123 = N'', @q124 = N'', @q125 = N'', @q126 = N'', @q127 = N'', @q128 = N'', @q129 = N'', @q130 = N'', 
		@q131 = N'', @q132 = N'', @q133 = N'', @q134 = N'', @q135 = N'', @q136 = N'', @q137 = N'', @q138 = N'', @q139 = N'', @q140 = N'', 
		@q141 = N'', @q142 = N'', @q143 = N'', @q144 = N'', @q145 = N'', @q146 = N'', @q147 = N'', @q148 = N'', @q149 = N'', @q150 = N'', 
		@q151 = N'', @q152 = N'', @q153 = N'', @q154 = N'', @q155 = N'', @q156 = N'', @q157 = N'', @q158 = N'', @q159 = N'', @q160 = N'', 
		@q161 = N'', @q162 = N'', @q163 = N'', @q164 = N'', @q165 = N'', @q166 = N'', @q167 = N'', @q168 = N'', @q169 = N'', @q170 = N'', 
		@q171 = N'', @q172 = N'', @q173 = N'', @q174 = N'', @q175 = N'', @q176 = N'', @q177 = N'', @q178 = N'', @q179 = N'', @q180 = N'', 
		@q181 = N'', @q182 = N'', @q183 = N'', @q184 = N'', @q185 = N'', @q186 = N'', @q187 = N'', @q188 = N'', @q189 = N'', @q190 = N'', 
		@q191 = N'', @q192 = N'', @q193 = N'', @q194 = N'', @q195 = N'', @q196 = N'', @q197 = N'', @q198 = N'', @q199 = N'', @q200 = N'', 
		@q201 = N'', @q202 = N'', @q203 = N'', @q204 = N'', @q205 = N'', @q206 = N'', @q207 = N'', @q208 = N'', @q209 = N'', @q210 = N'', 
		@q211 = N'', @q212 = N'', @q213 = N'', @q214 = N'', @q215 = N'', @q216 = N'', @q217 = N'', @q218 = N'', @q219 = N'', @q220 = N'', 
		@q221 = N'', @q222 = N'', @q223 = N'', @q224 = N'', @q225 = N'', @q226 = N'', @q227 = N'', @q228 = N'', @q229 = N'', @q230 = N'', 
		@q231 = N'', @q232 = N'', @q233 = N'', @q234 = N'', @q235 = N'', @q236 = N'', @q237 = N'', @q238 = N'', @q239 = N'', @q240 = N'', 
		@q241 = N'', @q242 = N'', @q243 = N'', @q244 = N'', @q245 = N'', @q246 = N'', @q247 = N'', @q248 = N'', @q249 = N'', @q250 = N''

	select @MAXBUFFLEN 	= 4000,
		@qPosition		= 1,
		@qValue			= N'',
		@scriptLen		= 0,
		@scriptText 	= N''

	-- check if our scripting table exists, if so let's drop it	
	if object_id('tempdb..#MSrepl_exec_script', 'U') is not null
	begin
		drop table #MSrepl_exec_script
	end

	-- create and load a local tmp table with the resultset based off of the cmd provided
	create table #MSrepl_exec_script (orderCol int identity(1,1) primary key clustered, scriptText nvarchar(4000))
	if @@error <> 0
	begin
		goto Error
	end

	insert into #MSrepl_exec_script(scriptText) exec(@cmd)
	if @@error <> 0
	begin
		goto Error
	end
	
	-- get the max value inserted in the identity col for 
	-- #MSrepl_exec_script table and set the rowIndex = 1
	select @maxIndex = max(orderCol),
			@rowIndex = 1
		from #MSrepl_exec_script

	-- retrieve the current scriptText row 
	select @scriptText = isnull(scriptText, N'')
		from #MSrepl_exec_script
		where orderCol = @rowIndex

	while (@rowIndex <= @maxIndex)
	begin
		select @scriptLen = @scriptLen + datalength(@scriptText)/2
		if (@scriptLen < @MAXBUFFLEN)
		begin
			-- for this case we continue to append since we know we have room
			select @qValue = @qValue + @scriptText + N' '
			
			-- add one to the script length for the space we just added
			select @scriptLen = @scriptLen + 1

			-- increment the row position counter
			select @rowIndex = @rowIndex + 1

			-- retrieve the current scriptText row
			select @scriptText = isnull(scriptText, N'')
				from #MSrepl_exec_script
				where orderCol = @rowIndex

			-- If there are no more script pieces then we will not continue
			-- instead we will set the current @qPosition and the loop will exit
			--
			-- Also be sure that if we reach the MAXBUFFLEN at this point we do not 
			-- continue. Instead we want to set the value below first before we continue.
			-- FYI: It will never be possible to be greater than MAXBUFFLEN in this section.
			if(@rowIndex <= @maxIndex and @scriptLen != @MAXBUFFLEN)
			begin
				continue
			end
		end
		else if (@scriptLen > @MAXBUFFLEN)
		begin
			-- here we have exceeded the @MAXBUFFLEN char limit so we will 
			-- fill the @qValue buffer and then store off the remaining  
			-- scriptText to be appended on the next itteration of the loop

			select @qValue = @qValue + left(@scriptText, @MAXBUFFLEN - datalength(@qValue)/2)

			select @scriptText = right(@scriptText, @scriptLen - @MAXBUFFLEN)	
		end
		else
		begin
			-- Append the entire scriptText since we know we have room. Do not 
			-- add the command seperator (space) since there is no room for that
			select @qValue = @qValue + @scriptText

			-- set the scripttext to empty so that on the next loop 
			-- we will add a space to the first qPostition buffer 
			select @scriptText = N''
		end

		-- set one of the 250 vars
		-- we need to break this 'else if' list by 100 because there is a limit of nesting levels
		-- this is a good idea in any case because it should speed things up a bit
		if @qPosition <= 100
		begin
			if @qPosition = 1 select @q1 = @qValue else if @qPosition = 2 select @q2 = @qValue else if @qPosition = 3 select @q3 = @qValue else if @qPosition = 4 select @q4 = @qValue else if @qPosition = 5 select @q5 = @qValue else if @qPosition = 6 select @q6 = @qValue else if @qPosition = 7 select @q7 = @qValue else if @qPosition = 8 select @q8 = @qValue else if @qPosition = 9 select @q9 = @qValue else if @qPosition = 10 select @q10 = @qValue 
			else if @qPosition = 11 select @q11 = @qValue else if @qPosition = 12 select @q12 = @qValue else if @qPosition = 13 select @q13 = @qValue else if @qPosition = 14 select @q14 = @qValue else if @qPosition = 15 select @q15 = @qValue else if @qPosition = 16 select @q16 = @qValue else if @qPosition = 17 select @q17 = @qValue else if @qPosition = 18 select @q18 = @qValue else if @qPosition = 19 select @q19 = @qValue else if @qPosition = 20 select @q20 = @qValue 
			else if @qPosition = 21 select @q21 = @qValue else if @qPosition = 22 select @q22 = @qValue else if @qPosition = 23 select @q23 = @qValue else if @qPosition = 24 select @q24 = @qValue else if @qPosition = 25 select @q25 = @qValue else if @qPosition = 26 select @q26 = @qValue else if @qPosition = 27 select @q27 = @qValue else if @qPosition = 28 select @q28 = @qValue else if @qPosition = 29 select @q29 = @qValue else if @qPosition = 30 select @q30 = @qValue 
			else if @qPosition = 31 select @q31 = @qValue else if @qPosition = 32 select @q32 = @qValue else if @qPosition = 33 select @q33 = @qValue else if @qPosition = 34 select @q34 = @qValue else if @qPosition = 35 select @q35 = @qValue else if @qPosition = 36 select @q36 = @qValue else if @qPosition = 37 select @q37 = @qValue else if @qPosition = 38 select @q38 = @qValue else if @qPosition = 39 select @q39 = @qValue else if @qPosition = 40 select @q40 = @qValue 
			else if @qPosition = 41 select @q41 = @qValue else if @qPosition = 42 select @q42 = @qValue else if @qPosition = 43 select @q43 = @qValue else if @qPosition = 44 select @q44 = @qValue else if @qPosition = 45 select @q45 = @qValue else if @qPosition = 46 select @q46 = @qValue else if @qPosition = 47 select @q47 = @qValue else if @qPosition = 48 select @q48 = @qValue else if @qPosition = 49 select @q49 = @qValue else if @qPosition = 50 select @q50 = @qValue 
			else if @qPosition = 51 select @q51 = @qValue else if @qPosition = 52 select @q52 = @qValue else if @qPosition = 53 select @q53 = @qValue else if @qPosition = 54 select @q54 = @qValue else if @qPosition = 55 select @q55 = @qValue else if @qPosition = 56 select @q56 = @qValue else if @qPosition = 57 select @q57 = @qValue else if @qPosition = 58 select @q58 = @qValue else if @qPosition = 59 select @q59 = @qValue else if @qPosition = 60 select @q60 = @qValue 
			else if @qPosition = 61 select @q61 = @qValue else if @qPosition = 62 select @q62 = @qValue else if @qPosition = 63 select @q63 = @qValue else if @qPosition = 64 select @q64 = @qValue else if @qPosition = 65 select @q65 = @qValue else if @qPosition = 66 select @q66 = @qValue else if @qPosition = 67 select @q67 = @qValue else if @qPosition = 68 select @q68 = @qValue else if @qPosition = 69 select @q69 = @qValue else if @qPosition = 70 select @q70 = @qValue 
			else if @qPosition = 71 select @q71 = @qValue else if @qPosition = 72 select @q72 = @qValue else if @qPosition = 73 select @q73 = @qValue else if @qPosition = 74 select @q74 = @qValue else if @qPosition = 75 select @q75 = @qValue else if @qPosition = 76 select @q76 = @qValue else if @qPosition = 77 select @q77 = @qValue else if @qPosition = 78 select @q78 = @qValue else if @qPosition = 79 select @q79 = @qValue else if @qPosition = 80 select @q80 = @qValue 
			else if @qPosition = 81 select @q81 = @qValue else if @qPosition = 82 select @q82 = @qValue else if @qPosition = 83 select @q83 = @qValue else if @qPosition = 84 select @q84 = @qValue else if @qPosition = 85 select @q85 = @qValue else if @qPosition = 86 select @q86 = @qValue else if @qPosition = 87 select @q87 = @qValue else if @qPosition = 88 select @q88 = @qValue else if @qPosition = 89 select @q89 = @qValue else if @qPosition = 90 select @q90 = @qValue 
			else if @qPosition = 91 select @q91 = @qValue else if @qPosition = 92 select @q92 = @qValue else if @qPosition = 93 select @q93 = @qValue else if @qPosition = 94 select @q94 = @qValue else if @qPosition = 95 select @q95 = @qValue else if @qPosition = 96 select @q96 = @qValue else if @qPosition = 97 select @q97 = @qValue else if @qPosition = 98 select @q98 = @qValue else if @qPosition = 99 select @q99 = @qValue else if @qPosition = 100 select @q100 = @qValue
		end
		else if @qPosition <= 200   
		begin
			if @qPosition = 101 select @q101 = @qValue else if @qPosition = 102 select @q102 = @qValue else if @qPosition = 103 select @q103 = @qValue else if @qPosition = 104 select @q104 = @qValue else if @qPosition = 105 select @q105 = @qValue else if @qPosition = 106 select @q106 = @qValue else if @qPosition = 107 select @q107 = @qValue else if @qPosition = 108 select @q108 = @qValue else if @qPosition = 109 select @q109 = @qValue else if @qPosition = 110 select @q110 = @qValue
			else if @qPosition = 111 select @q111 = @qValue else if @qPosition = 112 select @q112 = @qValue else if @qPosition = 113 select @q113 = @qValue else if @qPosition = 114 select @q114 = @qValue else if @qPosition = 115 select @q115 = @qValue else if @qPosition = 116 select @q116 = @qValue else if @qPosition = 117 select @q117 = @qValue else if @qPosition = 118 select @q118 = @qValue else if @qPosition = 119 select @q119 = @qValue else if @qPosition = 120 select @q120 = @qValue
			else if @qPosition = 121 select @q121 = @qValue else if @qPosition = 122 select @q122 = @qValue else if @qPosition = 123 select @q123 = @qValue else if @qPosition = 124 select @q124 = @qValue else if @qPosition = 125 select @q125 = @qValue else if @qPosition = 126 select @q126 = @qValue else if @qPosition = 127 select @q127 = @qValue else if @qPosition = 128 select @q128 = @qValue else if @qPosition = 129 select @q129 = @qValue else if @qPosition = 130 select @q130 = @qValue 
			else if @qPosition = 131 select @q131 = @qValue else if @qPosition = 132 select @q132 = @qValue else if @qPosition = 133 select @q133 = @qValue else if @qPosition = 134 select @q134 = @qValue else if @qPosition = 135 select @q135 = @qValue else if @qPosition = 136 select @q136 = @qValue else if @qPosition = 137 select @q137 = @qValue else if @qPosition = 138 select @q138 = @qValue else if @qPosition = 139 select @q139 = @qValue else if @qPosition = 140 select @q140 = @qValue 
			else if @qPosition = 141 select @q141 = @qValue else if @qPosition = 142 select @q142 = @qValue else if @qPosition = 143 select @q143 = @qValue else if @qPosition = 144 select @q144 = @qValue else if @qPosition = 145 select @q145 = @qValue else if @qPosition = 146 select @q146 = @qValue else if @qPosition = 147 select @q147 = @qValue else if @qPosition = 148 select @q148 = @qValue else if @qPosition = 149 select @q149 = @qValue else if @qPosition = 150 select @q150 = @qValue 
			else if @qPosition = 151 select @q151 = @qValue else if @qPosition = 152 select @q152 = @qValue else if @qPosition = 153 select @q153 = @qValue else if @qPosition = 154 select @q154 = @qValue else if @qPosition = 155 select @q155 = @qValue else if @qPosition = 156 select @q156 = @qValue else if @qPosition = 157 select @q157 = @qValue else if @qPosition = 158 select @q158 = @qValue else if @qPosition = 159 select @q159 = @qValue else if @qPosition = 160 select @q160 = @qValue 
			else if @qPosition = 161 select @q161 = @qValue else if @qPosition = 162 select @q162 = @qValue else if @qPosition = 163 select @q163 = @qValue else if @qPosition = 164 select @q164 = @qValue else if @qPosition = 165 select @q165 = @qValue else if @qPosition = 166 select @q166 = @qValue else if @qPosition = 167 select @q167 = @qValue else if @qPosition = 168 select @q168 = @qValue else if @qPosition = 169 select @q169 = @qValue else if @qPosition = 170 select @q170 = @qValue 
			else if @qPosition = 171 select @q171 = @qValue else if @qPosition = 172 select @q172 = @qValue else if @qPosition = 173 select @q173 = @qValue else if @qPosition = 174 select @q174 = @qValue else if @qPosition = 175 select @q175 = @qValue else if @qPosition = 176 select @q176 = @qValue else if @qPosition = 177 select @q177 = @qValue else if @qPosition = 178 select @q178 = @qValue else if @qPosition = 179 select @q179 = @qValue else if @qPosition = 180 select @q180 = @qValue 
			else if @qPosition = 181 select @q181 = @qValue else if @qPosition = 182 select @q182 = @qValue else if @qPosition = 183 select @q183 = @qValue else if @qPosition = 184 select @q184 = @qValue else if @qPosition = 185 select @q185 = @qValue else if @qPosition = 186 select @q186 = @qValue else if @qPosition = 187 select @q187 = @qValue else if @qPosition = 188 select @q188 = @qValue else if @qPosition = 189 select @q189 = @qValue else if @qPosition = 190 select @q190 = @qValue 
			else if @qPosition = 191 select @q191 = @qValue else if @qPosition = 192 select @q192 = @qValue else if @qPosition = 193 select @q193 = @qValue else if @qPosition = 194 select @q194 = @qValue else if @qPosition = 195 select @q195 = @qValue else if @qPosition = 196 select @q196 = @qValue else if @qPosition = 197 select @q197 = @qValue else if @qPosition = 198 select @q198 = @qValue else if @qPosition = 199 select @q199 = @qValue else if @qPosition = 200 select @q200 = @qValue
		end
		else
		begin
			if @qPosition = 201 select @q201 = @qValue else if @qPosition = 202 select @q202 = @qValue else if @qPosition = 203 select @q203 = @qValue else if @qPosition = 204 select @q204 = @qValue else if @qPosition = 205 select @q205 = @qValue else if @qPosition = 206 select @q206 = @qValue else if @qPosition = 207 select @q207 = @qValue else if @qPosition = 208 select @q208 = @qValue else if @qPosition = 209 select @q209 = @qValue else if @qPosition = 210 select @q210 = @qValue 
			else if @qPosition = 211 select @q211 = @qValue else if @qPosition = 212 select @q212 = @qValue else if @qPosition = 213 select @q213 = @qValue else if @qPosition = 214 select @q214 = @qValue else if @qPosition = 215 select @q215 = @qValue else if @qPosition = 216 select @q216 = @qValue else if @qPosition = 217 select @q217 = @qValue else if @qPosition = 218 select @q218 = @qValue else if @qPosition = 219 select @q219 = @qValue else if @qPosition = 220 select @q220 = @qValue 
			else if @qPosition = 221 select @q221 = @qValue else if @qPosition = 222 select @q222 = @qValue else if @qPosition = 223 select @q223 = @qValue else if @qPosition = 224 select @q224 = @qValue else if @qPosition = 225 select @q225 = @qValue else if @qPosition = 226 select @q226 = @qValue else if @qPosition = 227 select @q227 = @qValue else if @qPosition = 228 select @q228 = @qValue else if @qPosition = 229 select @q229 = @qValue else if @qPosition = 230 select @q230 = @qValue 
			else if @qPosition = 231 select @q231 = @qValue else if @qPosition = 232 select @q232 = @qValue else if @qPosition = 233 select @q233 = @qValue else if @qPosition = 234 select @q234 = @qValue else if @qPosition = 235 select @q235 = @qValue else if @qPosition = 236 select @q236 = @qValue else if @qPosition = 237 select @q237 = @qValue else if @qPosition = 238 select @q238 = @qValue else if @qPosition = 239 select @q239 = @qValue else if @qPosition = 240 select @q240 = @qValue 
			else if @qPosition = 241 select @q241 = @qValue else if @qPosition = 242 select @q242 = @qValue else if @qPosition = 243 select @q243 = @qValue else if @qPosition = 244 select @q244 = @qValue else if @qPosition = 245 select @q245 = @qValue else if @qPosition = 246 select @q246 = @qValue else if @qPosition = 247 select @q247 = @qValue else if @qPosition = 248 select @q248 = @qValue else if @qPosition = 249 select @q249 = @qValue else if @qPosition = 250 select @q250 = @qValue
			
			if @qPosition > 250
			begin
				raiserror('Internal Error : Command buffer limit of ~1MB has been reached! Resultset will not be executed.', 16, -1)
				goto Error
			end
		end

		-- Since we just filled a buffer move the index value by one
		-- and reset the current query row value to empty and len to 0
		select @qPosition	= @qPosition + 1,
			@qValue		= N'',
			@scriptLen	= 0
	end
	
	if @debug = 0
	begin
		-- concat all buffers and execute
		exec(@q1+@q2+@q3+@q4+@q5+@q6+@q7+@q8+@q9+@q10+
			@q11+@q12+@q13+@q14+@q15+@q16+@q17+@q18+@q19+@q20+
			@q21+@q22+@q23+@q24+@q25+@q26+@q27+@q28+@q29+@q30+
			@q31+@q32+@q33+@q34+@q35+@q36+@q37+@q38+@q39+@q40+
			@q41+@q42+@q43+@q44+@q45+@q46+@q47+@q48+@q49+@q50+
			@q51+@q52+@q53+@q54+@q55+@q56+@q57+@q58+@q59+@q60+
			@q61+@q62+@q63+@q64+@q65+@q66+@q67+@q68+@q69+@q70+
			@q71+@q72+@q73+@q74+@q75+@q76+@q77+@q78+@q79+@q80+
			@q81+@q82+@q83+@q84+@q85+@q86+@q87+@q88+@q89+@q90+
			@q91+@q92+@q93+@q94+@q95+@q96+@q97+@q98+@q99+@q100+
			@q101+@q102+@q103+@q104+@q105+@q106+@q107+@q108+@q109+@q110+
			@q111+@q112+@q113+@q114+@q115+@q116+@q117+@q118+@q119+@q120+
			@q121+@q122+@q123+@q124+@q125+@q126+@q127+@q128+@q129+@q130+
			@q131+@q132+@q133+@q134+@q135+@q136+@q137+@q138+@q139+@q140+
			@q141+@q142+@q143+@q144+@q145+@q146+@q147+@q148+@q149+@q150+
			@q151+@q152+@q153+@q154+@q155+@q156+@q157+@q158+@q159+@q160+
			@q161+@q162+@q163+@q164+@q165+@q166+@q167+@q168+@q169+@q170+
			@q171+@q172+@q173+@q174+@q175+@q176+@q177+@q178+@q179+@q180+
			@q181+@q182+@q183+@q184+@q185+@q186+@q187+@q188+@q189+@q190+
			@q191+@q192+@q193+@q194+@q195+@q196+@q197+@q198+@q199+@q200+
			@q201+@q202+@q203+@q204+@q205+@q206+@q207+@q208+@q209+@q210+
			@q211+@q212+@q213+@q214+@q215+@q216+@q217+@q218+@q219+@q220+
			@q221+@q222+@q223+@q224+@q225+@q226+@q227+@q228+@q229+@q230+
			@q231+@q232+@q233+@q234+@q235+@q236+@q237+@q238+@q239+@q240+
			@q241+@q242+@q243+@q244+@q245+@q246+@q247+@q248+@q249+@q250)
		if @@error <> 0
		begin
			goto Error
		end
	end
	else
	begin
		-- print out debug info
		select '@q1' = datalength(@q1)/2, '@q2' = datalength(@q2)/2, '@q3' = datalength(@q3)/2, '@q4' = datalength(@q4)/2, '@q5' = datalength(@q5)/2, '@q6' = datalength(@q6)/2, '@q7' = datalength(@q7)/2, '@q8' = datalength(@q8)/2, '@q9' = datalength(@q9)/2, '@q10' = datalength(@q10)/2, 
			'@q11' = datalength(@q11)/2, '@q12' = datalength(@q12)/2, '@q13' = datalength(@q13)/2, '@q14' = datalength(@q14)/2, '@q15' = datalength(@q15)/2, '@q16' = datalength(@q16)/2, '@q17' = datalength(@q17)/2, '@q18' = datalength(@q18)/2, '@q19' = datalength(@q19)/2, '@q20' = datalength(@q20)/2, 
			'@q21' = datalength(@q21)/2, '@q22' = datalength(@q22)/2, '@q23' = datalength(@q23)/2, '@q24' = datalength(@q24)/2, '@q25' = datalength(@q25)/2, '@q26' = datalength(@q26)/2, '@q27' = datalength(@q27)/2, '@q28' = datalength(@q28)/2, '@q29' = datalength(@q29)/2, '@q30' = datalength(@q30)/2, 
			'@q31' = datalength(@q31)/2, '@q32' = datalength(@q32)/2, '@q33' = datalength(@q33)/2, '@q34' = datalength(@q34)/2, '@q35' = datalength(@q35)/2, '@q36' = datalength(@q36)/2, '@q37' = datalength(@q37)/2, '@q38' = datalength(@q38)/2, '@q39' = datalength(@q39)/2, '@q40' = datalength(@q40)/2, 
			'@q41' = datalength(@q41)/2, '@q42' = datalength(@q42)/2, '@q43' = datalength(@q43)/2, '@q44' = datalength(@q44)/2, '@q45' = datalength(@q45)/2, '@q46' = datalength(@q46)/2, '@q47' = datalength(@q47)/2, '@q48' = datalength(@q48)/2, '@q49' = datalength(@q49)/2, '@q50' = datalength(@q50)/2, 
			'@q51' = datalength(@q51)/2, '@q52' = datalength(@q52)/2, '@q53' = datalength(@q53)/2, '@q54' = datalength(@q54)/2, '@q55' = datalength(@q55)/2, '@q56' = datalength(@q56)/2, '@q57' = datalength(@q57)/2, '@q58' = datalength(@q58)/2, '@q59' = datalength(@q59)/2, '@q60' = datalength(@q60)/2, 
			'@q61' = datalength(@q61)/2, '@q62' = datalength(@q62)/2, '@q63' = datalength(@q63)/2, '@q64' = datalength(@q64)/2, '@q65' = datalength(@q65)/2, '@q66' = datalength(@q66)/2, '@q67' = datalength(@q67)/2, '@q68' = datalength(@q68)/2, '@q69' = datalength(@q69)/2, '@q70' = datalength(@q70)/2, 
			'@q71' = datalength(@q71)/2, '@q72' = datalength(@q72)/2, '@q73' = datalength(@q73)/2, '@q74' = datalength(@q74)/2, '@q75' = datalength(@q75)/2, '@q76' = datalength(@q76)/2, '@q77' = datalength(@q77)/2, '@q78' = datalength(@q78)/2, '@q79' = datalength(@q79)/2, '@q80' = datalength(@q80)/2, 
			'@q81' = datalength(@q81)/2, '@q82' = datalength(@q82)/2, '@q83' = datalength(@q83)/2, '@q84' = datalength(@q84)/2, '@q85' = datalength(@q85)/2, '@q86' = datalength(@q86)/2, '@q87' = datalength(@q87)/2, '@q88' = datalength(@q88)/2, '@q89' = datalength(@q89)/2, '@q90' = datalength(@q90)/2, 
			'@q91' = datalength(@q91)/2, '@q92' = datalength(@q92)/2, '@q93' = datalength(@q93)/2, '@q94' = datalength(@q94)/2, '@q95' = datalength(@q95)/2, '@q96' = datalength(@q96)/2, '@q97' = datalength(@q97)/2, '@q98' = datalength(@q98)/2, '@q99' = datalength(@q99)/2, '@q100' = datalength(@q100)/2, 
			'@q101' = datalength(@q101)/2, '@q102' = datalength(@q102)/2, '@q103' = datalength(@q103)/2, '@q104' = datalength(@q104)/2, '@q105' = datalength(@q105)/2, '@q106' = datalength(@q106)/2, '@q107' = datalength(@q107)/2, '@q108' = datalength(@q108)/2, '@q109' = datalength(@q109)/2, '@q110' = datalength(@q110)/2, 
			'@q111' = datalength(@q111)/2, '@q112' = datalength(@q112)/2, '@q113' = datalength(@q113)/2, '@q114' = datalength(@q114)/2, '@q115' = datalength(@q115)/2, '@q116' = datalength(@q116)/2, '@q117' = datalength(@q117)/2, '@q118' = datalength(@q118)/2, '@q119' = datalength(@q119)/2, '@q120' = datalength(@q120)/2, 
			'@q121' = datalength(@q121)/2, '@q122' = datalength(@q122)/2, '@q123' = datalength(@q123)/2, '@q124' = datalength(@q124)/2, '@q125' = datalength(@q125)/2, '@q126' = datalength(@q126)/2, '@q127' = datalength(@q127)/2, '@q128' = datalength(@q128)/2, '@q129' = datalength(@q129)/2, '@q130' = datalength(@q130)/2, 
			'@q131' = datalength(@q131)/2, '@q132' = datalength(@q132)/2, '@q133' = datalength(@q133)/2, '@q134' = datalength(@q134)/2, '@q135' = datalength(@q135)/2, '@q136' = datalength(@q136)/2, '@q137' = datalength(@q137)/2, '@q138' = datalength(@q138)/2, '@q139' = datalength(@q139)/2, '@q140' = datalength(@q140)/2, 
			'@q141' = datalength(@q141)/2, '@q142' = datalength(@q142)/2, '@q143' = datalength(@q143)/2, '@q144' = datalength(@q144)/2, '@q145' = datalength(@q145)/2, '@q146' = datalength(@q146)/2, '@q147' = datalength(@q147)/2, '@q148' = datalength(@q148)/2, '@q149' = datalength(@q149)/2, '@q150' = datalength(@q150)/2, 
			'@q151' = datalength(@q151)/2, '@q152' = datalength(@q152)/2, '@q153' = datalength(@q153)/2, '@q154' = datalength(@q154)/2, '@q155' = datalength(@q155)/2, '@q156' = datalength(@q156)/2, '@q157' = datalength(@q157)/2, '@q158' = datalength(@q158)/2, '@q159' = datalength(@q159)/2, '@q160' = datalength(@q160)/2, 
			'@q161' = datalength(@q161)/2, '@q162' = datalength(@q162)/2, '@q163' = datalength(@q163)/2, '@q164' = datalength(@q164)/2, '@q165' = datalength(@q165)/2, '@q166' = datalength(@q166)/2, '@q167' = datalength(@q167)/2, '@q168' = datalength(@q168)/2, '@q169' = datalength(@q169)/2, '@q170' = datalength(@q170)/2, 
			'@q171' = datalength(@q171)/2, '@q172' = datalength(@q172)/2, '@q173' = datalength(@q173)/2, '@q174' = datalength(@q174)/2, '@q175' = datalength(@q175)/2, '@q176' = datalength(@q176)/2, '@q177' = datalength(@q177)/2, '@q178' = datalength(@q178)/2, '@q179' = datalength(@q179)/2, '@q180' = datalength(@q180)/2, 
			'@q181' = datalength(@q181)/2, '@q182' = datalength(@q182)/2, '@q183' = datalength(@q183)/2, '@q184' = datalength(@q184)/2, '@q185' = datalength(@q185)/2, '@q186' = datalength(@q186)/2, '@q187' = datalength(@q187)/2, '@q188' = datalength(@q188)/2, '@q189' = datalength(@q189)/2, '@q190' = datalength(@q190)/2, 
			'@q191' = datalength(@q191)/2, '@q192' = datalength(@q192)/2, '@q193' = datalength(@q193)/2, '@q194' = datalength(@q194)/2, '@q195' = datalength(@q195)/2, '@q196' = datalength(@q196)/2, '@q197' = datalength(@q197)/2, '@q198' = datalength(@q198)/2, '@q199' = datalength(@q199)/2, '@q200' = datalength(@q200)/2, 
			'@q201' = datalength(@q201)/2, '@q202' = datalength(@q202)/2, '@q203' = datalength(@q203)/2, '@q204' = datalength(@q204)/2, '@q205' = datalength(@q205)/2, '@q206' = datalength(@q206)/2, '@q207' = datalength(@q207)/2, '@q208' = datalength(@q208)/2, '@q209' = datalength(@q209)/2, '@q210' = datalength(@q210)/2, 
			'@q211' = datalength(@q211)/2, '@q212' = datalength(@q212)/2, '@q213' = datalength(@q213)/2, '@q214' = datalength(@q214)/2, '@q215' = datalength(@q215)/2, '@q216' = datalength(@q216)/2, '@q217' = datalength(@q217)/2, '@q218' = datalength(@q218)/2, '@q219' = datalength(@q219)/2, '@q220' = datalength(@q220)/2, 
			'@q221' = datalength(@q221)/2, '@q222' = datalength(@q222)/2, '@q223' = datalength(@q223)/2, '@q224' = datalength(@q224)/2, '@q225' = datalength(@q225)/2, '@q226' = datalength(@q226)/2, '@q227' = datalength(@q227)/2, '@q228' = datalength(@q228)/2, '@q229' = datalength(@q229)/2, '@q230' = datalength(@q230)/2, 
			'@q231' = datalength(@q231)/2, '@q232' = datalength(@q232)/2, '@q233' = datalength(@q233)/2, '@q234' = datalength(@q234)/2, '@q235' = datalength(@q235)/2, '@q236' = datalength(@q236)/2, '@q237' = datalength(@q237)/2, '@q238' = datalength(@q238)/2, '@q239' = datalength(@q239)/2, '@q240' = datalength(@q240)/2, 
			'@q241' = datalength(@q241)/2, '@q242' = datalength(@q242)/2, '@q243' = datalength(@q243)/2, '@q244' = datalength(@q244)/2, '@q245' = datalength(@q245)/2, '@q246' = datalength(@q246)/2, '@q247' = datalength(@q247)/2, '@q248' = datalength(@q248)/2, '@q249' = datalength(@q249)/2, '@q250' = datalength(@q250)/2

		select @q1+@q2+@q3+@q4+@q5+@q6+@q7+@q8+@q9+@q10+
			@q11+@q12+@q13+@q14+@q15+@q16+@q17+@q18+@q19+@q20+
			@q21+@q22+@q23+@q24+@q25+@q26+@q27+@q28+@q29+@q30+
			@q31+@q32+@q33+@q34+@q35+@q36+@q37+@q38+@q39+@q40+
			@q41+@q42+@q43+@q44+@q45+@q46+@q47+@q48+@q49+@q50+
			@q51+@q52+@q53+@q54+@q55+@q56+@q57+@q58+@q59+@q60+
			@q61+@q62+@q63+@q64+@q65+@q66+@q67+@q68+@q69+@q70+
			@q71+@q72+@q73+@q74+@q75+@q76+@q77+@q78+@q79+@q80+
			@q81+@q82+@q83+@q84+@q85+@q86+@q87+@q88+@q89+@q90+
			@q91+@q92+@q93+@q94+@q95+@q96+@q97+@q98+@q99+@q100+
			@q101+@q102+@q103+@q104+@q105+@q106+@q107+@q108+@q109+@q110+
			@q111+@q112+@q113+@q114+@q115+@q116+@q117+@q118+@q119+@q120+
			@q121+@q122+@q123+@q124+@q125+@q126+@q127+@q128+@q129+@q130+
			@q131+@q132+@q133+@q134+@q135+@q136+@q137+@q138+@q139+@q140+
			@q141+@q142+@q143+@q144+@q145+@q146+@q147+@q148+@q149+@q150+
			@q151+@q152+@q153+@q154+@q155+@q156+@q157+@q158+@q159+@q160+
			@q161+@q162+@q163+@q164+@q165+@q166+@q167+@q168+@q169+@q170+
			@q171+@q172+@q173+@q174+@q175+@q176+@q177+@q178+@q179+@q180+
			@q181+@q182+@q183+@q184+@q185+@q186+@q187+@q188+@q189+@q190+
			@q191+@q192+@q193+@q194+@q195+@q196+@q197+@q198+@q199+@q200+
			@q201+@q202+@q203+@q204+@q205+@q206+@q207+@q208+@q209+@q210+
			@q211+@q212+@q213+@q214+@q215+@q216+@q217+@q218+@q219+@q220+
			@q221+@q222+@q223+@q224+@q225+@q226+@q227+@q228+@q229+@q230+
			@q231+@q232+@q233+@q234+@q235+@q236+@q237+@q238+@q239+@q240+
			@q241+@q242+@q243+@q244+@q245+@q246+@q247+@q248+@q249+@q250
	end
	
	return 0
Error:
	return 1
end
go
exec sp_MS_marksystemobject N'dbo.sp_execresultset'
go

SET ANSI_NULLS OFF
go

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

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

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

    if @job_name is null
    begin
        goto MISMATCH
    end

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

    select @generated_job_name_length = len(@generated_job_name)

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

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

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

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

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

    if @job_name = @generated_job_name
    begin
        return 0
    end    

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

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

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

print ''
print 'Creating function fn_repltrimleadingzerosinhexstr'
go
-- 
-- Name: fn_repltrimleadingzerosinhexstr
--
-- Description: This function is used for trimming the leading zeros 
--              of a 32-bit hexadecimal string. For example,
--              select fn_repltrimleadingzerosinhexstr('0000abcd') would 
--              yield 'abcd'. A notable special case would be select
--              fn_repltrimleadingzerosinhexstr('00000000') which yields
--              the string '0' instead of ''.
--
-- Parameter:   @hexstr  nchar(8) - @hexstr is expected to be a full 
--              hexadecimal representation of a 32-bit integer without the
--              0x prefix
--
-- Notes: 
--
-- Returns:     nvarchar(8)
-- 
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_repltrimleadingzerosinhexstr (
    @hexstr nchar(8)
    ) returns nvarchar(8)
as
begin
    declare @trimmed_hexstr nvarchar(8),
            @i int    
    select @i = 1
    while @i < 8
    begin
        if substring(@hexstr,@i,1) <> N'0'
            break;
        select @i = @i + 1
    end    
    select @trimmed_hexstr = substring(@hexstr,@i,8-@i+1)
    return @trimmed_hexstr
end
go
grant execute on system_function_schema.fn_repltrimleadingzerosinhexstr to public

print ''
print 'Creating function fn_replinttobitstring'
go
--
-- Name: fn_replinttobitstring
-- 
-- Description: This function returns the bit pattern in string format for 
--              the specified 32-bit integer. For example, select 
--              fn_replinttobitstring(0x80000001) would yield
--              '10000000000000000000000000000001'
--
-- Parameter:   @number int
--
-- Returns:     char(32)
--
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replinttobitstring(
    @number int
    ) returns char(32)
as
begin

    declare @bitstring nvarchar(32)

    if (@number & 0x80000000) <> 0 select @bitstring = '1' else select @bitstring = '0'
    if (@number & 0x40000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x20000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x10000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x08000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x04000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x02000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x01000000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00800000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00400000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00200000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00100000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00080000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00040000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00020000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00010000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00008000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00004000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00002000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00001000) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000800) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000400) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000200) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000100) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000080) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000040) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000020) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000010) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000008) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000004) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000002) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'
    if (@number & 0x00000001) <> 0 select @bitstring = @bitstring + '1' else select @bitstring = @bitstring + '0'

    return @bitstring
end
go
grant execute on system_function_schema.fn_replinttobitstring to public

print ''
print 'Creating function fn_replbitstringtoint'
go
--
-- Name: fn_replbitstringtoint
--
-- Description: This function returns the integer value of the specified
--              32-bit bit pattern in string format.
--
-- Parameter:   @bitstring char(32)
--
-- Notes:
--
-- Returns:     int
--
-- Security:    Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replbitstringtoint(
    @bitstring char(32)
    ) returns int
as
begin
    declare @number int 
    select @number = 0
    if (substring(@bitstring,1,1) = '1') select @number = @number | 0x80000000 
    if (substring(@bitstring,2,1) = '1') select @number = @number | 0x40000000 
    if (substring(@bitstring,3,1) = '1') select @number = @number | 0x20000000 
    if (substring(@bitstring,4,1) = '1') select @number = @number | 0x10000000 
    if (substring(@bitstring,5,1) = '1') select @number = @number | 0x08000000 
    if (substring(@bitstring,6,1) = '1') select @number = @number | 0x04000000 
    if (substring(@bitstring,7,1) = '1') select @number = @number | 0x02000000 
    if (substring(@bitstring,8,1) = '1') select @number = @number | 0x01000000 
    if (substring(@bitstring,9,1) = '1') select @number = @number | 0x00800000 
    if (substring(@bitstring,10,1) = '1') select @number = @number | 0x00400000 
    if (substring(@bitstring,11,1) = '1') select @number = @number | 0x00200000 
    if (substring(@bitstring,12,1) = '1') select @number = @number | 0x00100000 
    if (substring(@bitstring,13,1) = '1') select @number = @number | 0x00080000 
    if (substring(@bitstring,14,1) = '1') select @number = @number | 0x00040000 
    if (substring(@bitstring,15,1) = '1') select @number = @number | 0x00020000 
    if (substring(@bitstring,16,1) = '1') select @number = @number | 0x00010000 
    if (substring(@bitstring,17,1) = '1') select @number = @number | 0x00008000 
    if (substring(@bitstring,18,1) = '1') select @number = @number | 0x00004000 
    if (substring(@bitstring,19,1) = '1') select @number = @number | 0x00002000 
    if (substring(@bitstring,20,1) = '1') select @number = @number | 0x00001000 
    if (substring(@bitstring,21,1) = '1') select @number = @number | 0x00000800 
    if (substring(@bitstring,22,1) = '1') select @number = @number | 0x00000400 
    if (substring(@bitstring,23,1) = '1') select @number = @number | 0x00000200 
    if (substring(@bitstring,24,1) = '1') select @number = @number | 0x00000100 
    if (substring(@bitstring,25,1) = '1') select @number = @number | 0x00000080 
    if (substring(@bitstring,26,1) = '1') select @number = @number | 0x00000040 
    if (substring(@bitstring,27,1) = '1') select @number = @number | 0x00000020 
    if (substring(@bitstring,28,1) = '1') select @number = @number | 0x00000010 
    if (substring(@bitstring,29,1) = '1') select @number = @number | 0x00000008 
    if (substring(@bitstring,30,1) = '1') select @number = @number | 0x00000004 
    if (substring(@bitstring,31,1) = '1') select @number = @number | 0x00000002 
    if (substring(@bitstring,32,1) = '1') select @number = @number | 0x00000001 
    return @number
end
go
grant execute on system_function_schema.fn_replbitstringtoint to public

print ''
print 'Creating function fn_replrotr'
go
--
-- Name: fn_replrotr
--
-- Description: This is just a T-SQL implementation of the C function
--              _rotr().
--
-- Parameter:  @number int
--             @shift  int
--
-- Notes:      The effective shift will the positive remainder of @shift 
--             divided by 32. _rotl() can be implemented by passing in 
--             a negative shift.
--
-- Returns:    int
--
-- Security:   Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replrotr(
    @number int,
    @shift int
    ) returns int
as
begin
    declare @bitstring char(32)
    select @shift = @shift % 32
    if @shift < 0
        select @shift = @shift + 32

    if (@shift != 0)
    begin
        select @bitstring = fn_replinttobitstring(@number)   
        select @bitstring = substring(@bitstring,32-@shift+1,@shift) + substring(@bitstring,1,32-@shift) 
        select @number = fn_replbitstringtoint(@bitstring)
    end
    return @number
end
go
grant execute on system_function_schema.fn_replrotr to public


print ''
print 'Creating function fn_replgenerateshorterfilenameprefix'
go
--
-- Name: fn_replgenerateshorterfilenameprefix
--
-- Description: This function mimics the algorithm used by the snapshot 
--              agent to shorten any overly long component of a publication
--              snapshot folder with "overly long" defined as more than
--              30 characters in length (as specified in the @truncated_len
--              parameter of this function). 
--                
-- Parameters:  @prefix nvarchar(4000)
--              @truncated_len int
--
-- Notes:
--
-- Returns: nvarchar(4000)
--
-- Security: Execute permission on this function is granted to public.
--
create function system_function_schema.fn_replgenerateshorterfilenameprefix(
    @prefix nvarchar(4000),
    @truncated_len int
    ) returns nvarchar(4000)
as
begin
    declare @HashValueIndex int,
            @HashValue int,
            @CurrentByte tinyint,
            @TruncatedString varbinary(8000),
            @i int,
            @TruncatedStringLen int,
            @prefix_to_be_returned nvarchar(4000)

    select @prefix_to_be_returned = @prefix
    if (len(@prefix) > @truncated_len)
    begin
        select @TruncatedString = convert(varbinary(8000),substring(@prefix,@truncated_len-8+1,len(@prefix)-@truncated_len+8))
        select @TruncatedStringLen = len(@TruncatedString)
        select @HashValue = 0
        select @i = 1
        select @HashValueIndex = 0
        while @i <= @TruncatedStringLen
        begin
            select @CurrentByte = convert(tinyint,substring(@TruncatedString,@i,1))
            select @HashValue = @HashValue ^ fn_replrotr(@CurrentByte, -(8*@HashValueIndex))
            select @HashValue = fn_replrotr(@HashValue, @HashValueIndex + 1)
            if @CurrentByte != 0
            begin
                select @HashValueIndex = (@HashValueIndex + 1) % 4
            end
            select @i = @i + 1
        end
        select @prefix_to_be_returned = substring(@prefix,1,@truncated_len-8) 
        select @prefix_to_be_returned = @prefix_to_be_returned + lower(fn_repltrimleadingzerosinhexstr(substring(master.dbo.fn_varbintohexstr(convert(varbinary(4),@HashValue)) collate database_default,3,8)) collate database_default)
    end
    return @prefix_to_be_returned
end
go
grant execute on system_function_schema.fn_replgenerateshorterfilenameprefix to public      

print ''
print 'Creating function fn_replcomposepublicationsnapshotfolder'
go    
--
-- Name: fn_replcomposepublicationsnapshotfolder
--
-- Description: This mimics the algorithm used by the snapshot agent for 
--              composing the name of a publication's snapshot folder.
--
-- Parameters:  @publisher    sysname
--              @publisher_db sysname 
--              @publication  sysname
--
-- Notes: 
--
-- Returns: nvarchar(255)
--
-- Security: Execute permission of this function is granted to public.
--
create function system_function_schema.fn_replcomposepublicationsnapshotfolder(
    @publisher     sysname,
    @publisher_db  sysname,
    @publication   sysname
) returns nvarchar(255)
as
begin
    declare @snapshot_folder_name nvarchar(255)
    
    select @snapshot_folder_name = fn_replgenerateshorterfilenameprefix(@publisher,30) collate database_default + N'_' +
                                   fn_replgenerateshorterfilenameprefix(@publisher_db,30) collate database_default + N'_' +
                                   fn_replgenerateshorterfilenameprefix(@publication,30) collate database_default
    return @snapshot_folder_name
end
go
grant execute on system_function_schema.fn_replcomposepublicationsnapshotfolder to public
go

--
-- Name: sp_MSdroparticleconstraints
--
-- Description: This procedure is used by the Distribution Agent to purge all
--              the existing check, PK, UK, and FK constraints on a table
--              article at the Subscriber.
--
-- Parameters:  @destination_object sysname (mandatory)
--              @destination_owner sysname (mandatory)
-- 
-- Returns: 0 - succeeded
--          1 - failed
-- 
-- Security: Procedural security check is done inside this procedure
--           to make sure that the caller is either a member of the db_owner
--           role of the subscriber database or a member of the sysadmin role
--           of the subscription server 
--
print ''
print 'Creating procedure sp_MSdroparticleconstraints'
go
create procedure dbo.sp_MSdroparticleconstraints (
    @destination_object sysname,
    @destination_owner sysname
    )
as
begin
    set nocount on
    declare @retcode      int,
            @objid        int,
            @constid      int,
            @drop_command nvarchar(4000),
            @qualified_tablename nvarchar(540),
            @publish_bit  int,
            @mergepublish_bit int

    
    select @retcode             = 0,
           @objid               = null,
           @constid             = null,
           @drop_command        = null,
           @qualified_tablename = null,
           @publish_bit         = 1,
           @mergepublish_bit    = 128

    -- Security check
    exec @retcode = sp_MSreplcheck_subscribe
    if @retcode<>0 or @@error<>0
        return 1

    -- Get object id of the target table
    select @objid = id 
      from sysobjects
     where name = @destination_object
       and (user_name(uid) = @destination_owner 
            or @destination_owner is null 
            or @destination_owner = N'')

    -- If the object is not at the subscriber, there isn't anything we 
    -- can(or need to)  do
    if @objid is null 
        return 0

    select @qualified_tablename = 
            N'['+replace(@destination_object,N']',N']]')+N']'

    if @destination_owner is not null and @destination_owner<>N''
    begin
        select @qualified_tablename = 
            N'['+replace(@destination_owner,N']',N']]')+N'].'+@qualified_tablename
    end

    -- Skip constraint dropping for republished article
    if exists (select * 
                 from sysobjects 
                where id = @objid
                  and ((replinfo & @publish_bit <> 0) or
                       (replinfo & @mergepublish_bit <> 0)))
    begin
        return 0
    end

    declare hConst cursor local fast_forward for
     select constid 
       from sysconstraints 
      where id = @objid
      order by convert(int, objectproperty(constid,'IsForeignKey')) desc
    if @@error<>0
        return 1

    open hConst
    if @@error<>0
        return 1
    
    fetch hConst into @constid 
    while (@@fetch_status<>-1)
    begin
    
        if objectproperty(@constid,N'IsUniqueCnst') = 1 or
           objectproperty(@constid,N'IsPrimaryKey') = 1 or
           objectproperty(@constid,N'IsCheckCnst') = 1 or
           objectproperty(@constid,N'IsForeignKey') = 1
        begin
            select @drop_command = 
                N'alter table '+@qualified_tablename+' drop constraint '+object_name(@constid)
            exec(@drop_command)
            if @@error <> 0
                return 1
        end
        fetch hConst into @constid        
    end
    close hConst
    deallocate hConst

    return @retcode

end
go
exec sp_MS_marksystemobject sp_MSdroparticleconstraints
grant execute on sp_MSdroparticleconstraints to public 
--
-- Name: sp_MSacquireserverresourcefordynamicsnapshot
--
-- Description: This is a light-weight wrapper of sp_MSacuireApplicationLock
--              used by dynamic snapshot for governing the maximum number of
--              concurrent dynamic snapshot sessions for a merge publication.
--
-- Parameters: @publication sysname (mandatory)
--             @max_concurrent_dynamic_snapshots int (mandatory)
--
-- Security: Procedural security check is performed inside 
--           sp_MSacquireSlotLock to make sure that the caller is 
--           either sysadmin, db_owner, or replication agent.
--
print ''
print 'Creating procedure sp_MSacquireserverresourcefordynamicsnapshot'
go
create procedure dbo.sp_MSacquireserverresourcefordynamicsnapshot (
    @publication sysname,
    @max_concurrent_dynamic_snapshots int
    )
as
begin
    set nocount on
    declare @retcode int
    declare @pubid uniqueidentifier
    declare @process_name sysname
    select @retcode = 0

    -- security check
    exec @retcode = dbo.sp_MSreplcheck_publish
    if @@ERROR <> 0 or @retcode <> 0
        return 1
        
    if object_id('sysmergepublications') is null
    begin
        raiserror(20026, 16, -1, @publication)
        return (1) 
    end

    select @pubid = null
    select @pubid = pubid 
      from sysmergepublications
     where name = @publication 
       and publisher_db = db_name()
       and upper(publisher) = upper(@@servername)
             
    if @pubid is null   
    begin
        raiserror(20026, 16, -1, @publication)
        return (1) 
    end

    -- The following string construction will never overflow
    -- sysname
    select @process_name = N'ReplicationSnapshotAgent' + 
        convert(nvarchar(40), @pubid)     

    -- Acquire head of queue lock first
    exec @retcode = sp_MSacquireHeadofQueueLock
        @process_name = @process_name,
        @queue_timeout = 0,
        @no_result = 1

    if @@error<>0
        return (1)

    if @retcode<>0
        goto Failure

    exec @retcode = sp_MSacquireSlotLock 
        @process_name = @process_name,
        @concurrent_max = @max_concurrent_dynamic_snapshots    
    
    if @@error<>0
        return (1)

Failure:

    return @retcode
end
go
exec sp_MS_marksystemobject sp_MSacquireserverresourcefordynamicsnapshot
go
grant execute on sp_MSacquireserverresourcefordynamicsnapshot to public
go

-- 
-- Name: fn_replgetbinary8lodword
--
-- Description: This function will get the lower dword of
--              a given binary(8) value. For example:
--            
--              select fn_replgetbinary8lodword(0x0000000012345678)
--              will return the integer
--              0x12345678
--
-- Parameter: @binary8_value binary(8)
--
-- Returns: int
--
-- Security: Execute permission of this function is granted 
--           to public
--
print ''
print 'Creating function fn_replgetbinary8lodword'
go
create function system_function_schema.fn_replgetbinary8lodword (
    @binary8_value binary(8)
    ) returns int
as
begin
    declare @lodword int
    select @lodword = convert(int, substring(@binary8_value, 5, 4))
    return @lodword
end
go
grant execute on system_function_schema.fn_replgetbinary8lodword to public
go

-- 
-- Name: fn_replprepadbinary8
--
-- Description: This function is typically used by replication
--              stored procedures to add padding 0s in front
--              of a user-specified schema_option value. For
--              example:
--
--              select fn_replprepadbinary8(0x01) will return
--
--              0x0000000000000001
--
-- Parameter: @varbinary8_value varbinary(8)
--
-- Returns: binary(8) 
--              
-- Security: Execute permission of this function is granted
--           to public
--               
print ''
print 'Creating function fn_replprepadbinary8'
go
create function system_function_schema.fn_replprepadbinary8 (
    @varbinary8_value varbinary(8)
    ) returns binary(8)
as
begin
    declare @padded_value binary(8)
    select @padded_value = 
        substring(0x0000000000000000, 
                  1, 
                  8 - datalength(@varbinary8_value)) 
        + @varbinary8_value
    return @padded_value
end
go
grant execute on system_function_schema.fn_replprepadbinary8 to public
go

--
-- Name: fn_replmakestringliteral
--
-- Description: This is a simple helper function for generating the unicode string 
--              literal representation of a given string. For example
--              
--                  select fn_replmakestringliteral('string''literal')
-- 
--              will return
--
--                  N'string''literal'
--
-- Parameter: @string nvarchar(4000)
-- 
-- Returns: nvarchar(4000)
--
-- Security: Public access
--
raiserror('Creating function fn_replmakestringliteral', 0,1)
go
create function system_function_schema.fn_replmakestringliteral (
    @string nvarchar(4000)
    ) returns nvarchar(4000)
as
begin
    declare @string_literal nvarchar(4000)
    select @string_literal = N'N''' + replace(@string, '''', '''''') + N''''
    return @string_literal
end
go
grant execute on system_function_schema.fn_replmakestringliteral to public
go

-- 
-- Name: sp_MSgettranlastupdatedtime
--
-- Description: This procedure retrieves the last updated time from the 
--              subscriber database for a transactional/snapshot 
--              subscription.    
--
-- Parameters: @publisher sysname (mandatory)
--             @publisher_db sysname (mandatory)
--             @publication sysname (mandatory)
--             @subscription_type int (mandatory)
-- Notes: This procedure should always be called internally by 
--        sp_MSgetlastupdatedtime
--
-- Result: 'last updated time' nvarchar
--
-- Returns 0 - succeeded
--         1 - failed
--
-- Security: Sysadmin access only 
--
print 'Creating procedure sp_MSgettranlastupdatedtime'
print ''
go
create procedure sp_MSgettranlastupdatedtime(
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @subscription_type int
    )
as
begin
    set nocount on
    declare @last_updated_time nvarchar(40)
    
    select @last_updated_time = null

    if object_id('MSreplication_subscriptions') is null
    begin
        select 'last updated time' = @last_updated_time
        raiserror(21384, 16, -1)        
        return 1
    end
    
    -- For subscriptions sharing an agent, 
    -- the control may not be passing in the publication
    -- name. 
    select @last_updated_time = convert(nvarchar(12), time, 112) +
                                substring(convert(nvarchar(24), time, 121), 11,13)
      from MSreplication_subscriptions    
     where upper(@publisher) = upper(publisher)
       and @publisher_db = publisher_db
       and (((@publication is null or @publication = N'') and independent_agent = 0)
            or (@publication = publication))
       and @subscription_type = subscription_type

    select 'last updated time' = @last_updated_time

    if @last_updated_time is null
    begin
        raiserror(21384, 16, -1)
        return 1
    end
    return 0
end
go
exec sp_MS_marksystemobject 'sp_MSgettranlastupdatedtime'

-- 
-- Name: sp_MSgetmergelastupdatedtime
-- 
-- Description: This procedure retrieves the last updated time from the
--              subscriber database for a merge subscription.
--
-- Parameters: @publisher sysname (mandatory)
--             @publisher_db sysname (mandatory)
--             @publication sysname (mandatory)
--             @subscription_type int (mandatory)
-- Notes: This procedure should always be called internally by 
--        sp_MSgetlastupdatedtime
--
-- Result: 'last updated time' nvarchar
--
-- Returns: 0 - succeeded
--          1 - failed
--
-- Security: Sysadmin access only
--
print 'Creating procedure sp_MSgetmergelastupdatedtime'
print ''
go
create procedure sp_MSgetmergelastupdatedtime(
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @subscription_type int
    )
as
begin
    set nocount on
    declare @last_updated_time nvarchar(40)
    declare @last_updated_datetime datetime

    select @last_updated_datetime = null
    select @last_updated_time = null
    
    if object_id('sysmergesubscriptions') is null or
       object_id('sysmergepublications') is null
    begin
        select 'last updated time' = @last_updated_time
        raiserror(21384, 16, -1)        
        return 1
    end

    select @last_updated_datetime = last_sync_date 
      from sysmergesubscriptions sms
    inner join sysmergepublications smp
        on sms.pubid = smp.pubid     
     where upper(@@servername) = upper(sms.subscriber_server)
       and sms.db_name =  db_name()
       and sms.subscription_type = @subscription_type
       and upper(smp.publisher) = upper(publisher)
       and smp.publisher_db = @publisher_db
       and smp.name = @publication

    if @last_updated_datetime is not null
    begin
        select @last_updated_time = convert(nvarchar(12), @last_updated_datetime, 112) +
                  substring(convert(nvarchar(24), @last_updated_datetime, 121), 11,13)
    end

    select 'last updated time' = @last_updated_time

    if @last_updated_time is null
    begin
        raiserror(21384, 16, -1)
        return 1
    end
    return 0
end
go
exec sp_MS_marksystemobject 'sp_MSgetmergelastupdatedtime'

--
-- Name: sp_MSgetlastupdatedtime
-- 
-- Description: This procedure is used internally by the ActiveX controls
--              to retrieve the last updated time of the specified 
--              subscription. 
--  
-- Parameters: @publisher sysname (mandatory)
--             @publisher_db sysname (mandatory)
--             @publication sysname (mandatory)
--             @subscription_type int (mandatory)
--             @publication_type int (mandatory) (1 - transactional/snapshot
--                                                2 - merge)
-- Returns: 0 - succeeded
--          1 - failed
--
-- Result: 'last updated time' nvarchar 
--
-- Security: Execute permission of this stored procedure is granted to public
--           but security check is performed inside the procedure to make
--           sure that only dbo of the subscriber database and server admin
--           can retrieve the last updated time successfully. 
--
print 'Creating procedure sp_MSgetlastupdatedtime'
print ''
go
create procedure sp_MSgetlastupdatedtime(
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @subscription_type int,
    @publication_type int  -- 1 - transactional/snapshot, 2 - merge
    )
as
begin
    set nocount on
    declare @retcode int
    select @retcode = 0

    -- Security check
    exec @retcode = sp_MSreplcheck_subscribe    
    if @retcode<>0 or @@error<>0
        return 1

    if @publication_type in (0,1)
    begin
        exec @retcode = sp_MSgettranlastupdatedtime @publisher,
                                                    @publisher_db,
                                                    @publication,
                                                    @subscription_type
    end
    else
    begin
        exec @retcode = sp_MSgetmergelastupdatedtime @publisher,
                                                     @publisher_db,
                                                     @publication,
                                                     @subscription_type
    end
    return @retcode
end
go
exec sp_MS_marksystemobject 'sp_MSgetlastupdatedtime'

--
-- Name: fn_repladjustcolumnmap
--
-- Description: This function adjusts the bitmap for subscriber/destination tables
-- that have been altered and the relative column order do not match the actual
-- column id. The column_updated() bitmap for such tables need to be adjusted to
-- reflect relative column order before sending them to publisher 
--
-- Parameters: 
--	@objid	int - destination table object id
-- 	,@total_col int - total number of columns in the table
-- 	,@inmap varbinary(4000) input bitmap that is based on actual column id
--
-- Returns: varbinary(4000) output column that is based on relative column order
--
-- Security: Execute permission of this function is granted to public
-- 
raiserror('Creating function fn_repladjustcolumnmap', 0,1)
go
create function system_function_schema.fn_repladjustcolumnmap
(
	@objid	int
	,@total_col int
	,@inmap varbinary(4000)
) 
returns varbinary(4000)
as
begin
	declare @colmap table (relativeorder int identity(1,1), colid int)
	declare
		@outmap varbinary(4000)
		,@relpos int
		,@colid int
		,@bytepos int
		,@bitpos int
		,@num_bytes int

	--
	-- initialize
	--
	select @outmap = 0
	insert into @colmap (colid)
		select colid from syscolumns where id = @objid order by colid
	if (@@error != 0)
	begin
		return cast(NULL as varbinary(4000))
	end

	--
	-- for each column in the column map
	--
	declare #colmap_cursor cursor local fast_forward for 
		select relativeorder, colid from @colmap 
		order by relativeorder
	for read only

	open #colmap_cursor
	fetch #colmap_cursor into @relpos, @colid
	while (@@fetch_status = 0)
	begin
		--
		-- select the absolute column position
		--
		select @bytepos = 1 + ((@colid-1) / 8)
			,@bitpos =  power(2, (@colid-1) % 8 ) 

		if (substring(@inmap, @bytepos, 1) & @bitpos = @bitpos)
		begin
			--
			-- set the relative position for this column in the output
			--
			select @bytepos = 1 + ((@relpos-1) / 8)
				,@bitpos =  power(2, (@relpos-1) % 8 )
				,@num_bytes = @total_col / 8 + 1

			select @outmap = substring(@outmap, 1, (@bytepos - 1)) + 
				(convert(binary(1), substring(@outmap, @bytepos, 1) | convert(tinyint,@bitpos))) + 
				substring(@outmap, (@bytepos + 1), (@num_bytes - @bytepos))
		end

		-- fetch next column mapping
		fetch #colmap_cursor into @relpos, @colid		
	end
	close #colmap_cursor
	deallocate #colmap_cursor

	return @outmap
end
go
grant execute on system_function_schema.fn_repladjustcolumnmap to public

--
-- Name: fn_replquotename
--
-- Description: This is simply a more complete implementation of quote_name()
--              that can handle longer strings. Note that this function is
--              hard-coded to do square-bracket quoting only.
--
-- Parameter: @string nvarchar(1998)
--
-- Returns: nvarchar(4000)
--
-- Security: Execute permission of this function is granted to public
-- 
print 'Creating function fn_replquotename'
print ''
go
create function system_function_schema.fn_replquotename(
    @string nvarchar(1998)
    ) returns nvarchar(4000)
begin

    declare @resulting_string nvarchar(4000)
    declare @string_len int 
    declare @char nchar(1)
    declare @index int    

    select @resulting_string = null
    if @string is not null
    begin
        select @string_len = len(@string)
        select @index = 1

        select @resulting_string = N'['

        while @index <=  @string_len
        begin
            select @char = substring(@string, @index, 1)

            select @resulting_string = @resulting_string + @char
            if @char = N']'
            begin
                select @resulting_string = @resulting_string + N']'
            end

            select @index = @index + 1
        end
        select @resulting_string = @resulting_string + N']'
    end
    return @resulting_string
end
go

-- 
-- Name: fn_chariswhitespace
-- 
-- Description: This is a very simple function that checks whether a given
--              character is a white-space.
-- 
-- Parameters: @char nchar(1)
-- 
-- Notes:
-- 
-- Returns: bit
--          0 - The given character is not a white-space
--          1 - The given character is a white-space
-- 
-- Security: Execute permission of this function is granted to public
-- 
print 'Creating function fn_chariswhitespace'
print ''
go
create function system_function_schema.fn_chariswhitespace(
    @char nchar(1)
    ) returns bit
begin
    declare @result bit

    if @char in (N' ', nchar(9), nchar(10), nchar(13), N'')
    begin
        select @result = 1
    end
    else
    begin
        select @result = 0
    end
    return @result        
end
go

--
-- Name: fn_generateparameterpattern
--
-- Description: Given the name of a parameter (excluding the leading / or -), 
--              this function will return the pattern for matching the
--              parameter in a case-insensitive manner. For example
--  
--              select fn_generateparameterpattern(N'Ouptut')
-- 
--              will return
--
--              %[-/][Oo][Uu][Tt][Pp][Uu][Tt]%
--
-- Parameters: @parameter nvarchar(200)
--             
-- Notes: The leading / or - should be omitted from @parameter
--
-- Returns: nvarchar(806)
--
-- Security: Execute permission of this function is granted to public 
--
print 'Creating function fn_generateparameterpattern'
print ''
go
create function system_function_schema.fn_generateparameterpattern(
    @parameter nvarchar(200)
    ) returns nvarchar(806)
begin
    declare @pattern          nvarchar(806)
    declare @parameter_length int
    declare @i                int
    declare @c                nvarchar(1)

    select @pattern = N'%[-/]'
    select @i = 1
    select @parameter_length = len(@parameter)
    
    while @i <= @parameter_length
    begin
    select @c = substring(@parameter, @i, 1)        
    select @pattern = @pattern + N'[' + upper(@c collate SQL_Latin1_General_CP1_CS_AS) + lower(@c collate SQL_Latin1_General_CP1_CS_AS) + N']'
        select @i = @i + 1
    end 
    select @pattern = @pattern + '%'
    return @pattern
end
go

--
-- Name: fn_skipparameterargument
--
-- Description: This function basically removes the first non-parameter
--              token from the given command. It is designed to handle
--              square-bracket quoted or double-quoted parameter arguments.
--              Note that all white-spaces trailing the removed argument will 
--              also be removed in the returned command.
--
-- Parameters: @command nvarchar(3200)
-- 
-- Returns: nvarchar(3200)
--
-- Security: Execute permission of this function is granted to public
--              
print 'Creating function fn_skipparameterargument'
print ''
go
create function system_function_schema.fn_skipparameterargument(
    @command nvarchar(3200)
    ) returns nvarchar(3200)
begin
    declare @state int
    declare @i int
    declare @char nvarchar(1)
    declare @command_length int
    declare @state_start int
    declare @state_in_dquote_argument int
    declare @state_seen_matching_dquote int
    declare @state_in_square_bracket_argument int
    declare @state_seen_matching_bracket int
    declare @state_reached_end_of_argument int
    declare @state_in_unquoted_argument int
    declare @state_exit int
    -- Initializations
    select @state_start = 0
    select @state_in_dquote_argument = 1    
    select @state_seen_matching_dquote = 2
    select @state_in_square_bracket_argument = 3
    select @state_seen_matching_bracket = 4
    select @state_reached_end_of_argument = 5
    select @state_in_unquoted_argument = 6
    select @state_exit = 7

    select @i = 1
    select @state = @state_start
    select @command_length = len(@command)  

    while @i <= @command_length
    begin

        select @char = substring(@command,@i,1)
        select @state = 
            case @state 
            when @state_start then
                case 
                when fn_chariswhitespace(@char) = 1 then @state_start   
                when @char in (N'-',N'/') then @state_exit
                when @char in (N'[') then @state_in_square_bracket_argument
                when @char in (N'"') then @state_in_dquote_argument
                else @state_in_unquoted_argument
                end
            when @state_in_dquote_argument then
                case 
                when @char in (N'"') then @state_seen_matching_dquote
                else @state_in_dquote_argument
                end
            when @state_seen_matching_dquote then
                case 
                when @char in (N'"') then @state_in_dquote_argument 
                when fn_chariswhitespace(@char) = 1 then @state_reached_end_of_argument
                else @state_exit
                end
            when @state_in_square_bracket_argument then
                case
                when @char in (N']') then @state_seen_matching_bracket
                else @state_in_square_bracket_argument  
                end
            when @state_seen_matching_bracket then
                case 
                when @char in (N']') then @state_in_square_bracket_argument
                when fn_chariswhitespace(@char) = 1 then @state_reached_end_of_argument
                else @state_exit
                end
            when @state_reached_end_of_argument then
                case 
                when fn_chariswhitespace(@char) = 1 then @state_reached_end_of_argument
                else @state_exit    
                end
            when @state_in_unquoted_argument then
                case
                when fn_chariswhitespace(@char) = 1 then @state_reached_end_of_argument
                else @state_in_unquoted_argument
                end
            else @state         
            end 

        if @state = @state_exit
        begin
            goto done
        end
    select @i = @i + 1
    end -- while
done:
    select @command = substring(@command, @i, @command_length - @i + 1)
    return @command 
end
go  

-- 
-- Name: fn_removeparameterwithargument
-- 
-- Description: This function removes all instances of a parameter and their
--              arguments from a given command line.
--
-- Notes: @parameter must be specified without the leading / or -
--
-- Parameters: @command nvarchar(3200)
--             @parameter nvarchar(200)
--
-- Returns: @nvarchar(3200)
-- 
-- Security: Execute permission of this function is granted to public
--
print 'Creating function fn_reomveparameterwithargument'
print ''
go
create function system_function_schema.fn_removeparameterwithargument(
    @command nvarchar(3200),
    @parameter nvarchar(200)
    ) returns nvarchar(3200)
begin

    declare @pattern nvarchar(806)
    declare @resulting_command nvarchar(3200)
    declare @command_length int
    declare @pattern_start int
    declare @first_iteration bit
    declare @parameter_length int

    select @first_iteration = 1
    select @pattern = fn_generateparameterpattern(@parameter)
    select @parameter_length = len(@parameter) + 1 -- leading - or /
    
    select @resulting_command = N''
    select @pattern_start = patindex(@pattern,@command) 
    while @pattern_start <> 0 and @pattern_start is not NULL
    begin
        select @command_length = len(@command)

        -- Check if the pattern found is properly delimited in the command.
        -- If so, try to skip over the next token. 
        if (@pattern_start = 1 and @first_iteration = 1 or
            (@pattern_start > 1 and fn_chariswhitespace(substring(@command, @pattern_start - 1, 1)) = 1))  and
            (fn_chariswhitespace(substring(@command, @pattern_start + @parameter_length, 1)) = 1)             
        begin
            -- Add everything before the parameter to the resulting command
            select @resulting_command = @resulting_command + rtrim(substring(@command, 1, @pattern_start - 1))

            -- Eat the parameter
            select @command = substring(@command, @pattern_start + @parameter_length, @command_length - @pattern_start - @parameter_length + 1)

            -- Skip over the argument of the parameter
            select @command = fn_skipparameterargument(@command)

            if @resulting_command <> N''
            begin
                select @resulting_command = @resulting_command + N' '
            end
        end  
        else    
        begin
            -- Not a properly delimited parameter so transfer the 
            -- matching substring to the resulting command and
            -- eat the substring in the process
            select @resulting_command = @resulting_command + substring(@command, 1, @pattern_start + @parameter_length - 1)
            select @command = substring(@command, @pattern_start + @parameter_length, @command_length - @pattern_start - @parameter_length + 1)
        end
        select @first_iteration = 0
        select @pattern_start = patindex(@pattern, @command) 
    end 
    select @resulting_command = @resulting_command + @command
    return @resulting_command
end
go

--
-- Name: fn_updateparameterwithargument
--
-- Description: This function updates the argument value of the specified
--              parameter in the given command line. If there are multiple
--              instances of the specified parameter in the command line, 
--              only the first instance will be updated and all subsequent 
--              instances will be removed. If the command line does not 
--              contain the specified parameter in the first place, this
--              function will append the specified parameter and argument 
--              to the command line.
--
-- Notes: Any quoting that is required for the argument should be done
--        before calling this function.
--
-- Parameters: @command nvarchar(3200)
--             @parameter nvarchar(200)
--             @argument nvarchar(1000)
--            
-- Returns: nvarchar(3200)
--
-- Security: Execute permission of this function is granted to public
--
print 'Creating function fn_updateparameterwithargument'
print ''
go
create function system_function_schema.fn_updateparameterwithargument(
    @command nvarchar(3200),
    @parameter nvarchar(200),
    @argument  nvarchar(1000)
    ) returns nvarchar(3200)
begin
    declare @pattern nvarchar(806)
    declare @resulting_command nvarchar(3200)
    declare @command_length int
    declare @pattern_start int
    declare @first_iteration bit
    declare @parameter_length int
    declare @found_parameter bit
    
    select @first_iteration = 1
    select @found_parameter = 0
    select @pattern = fn_generateparameterpattern(@parameter)
    select @parameter_length = len(@parameter) + 1 -- leading - or /

    select @resulting_command = N''
    select @pattern_start = patindex(@pattern,@command)
        
    if @argument is null
    begin
        select @argument = N''
    end

    while @pattern_start <> 0 and @pattern_start is not null
    begin
        select @command_length = len(@command)

        -- Check if the pattern found is properly delimited in the command,
        -- If so, try to change the argument of the parameter with the given
        -- value.
        if (@pattern_start = 1 and @first_iteration = 1 or
            (@pattern_start > 1 and fn_chariswhitespace(substring(@command, @pattern_start - 1, 1)) = 1)) and
            (fn_chariswhitespace(substring(@command, @pattern_start + @parameter_length, 1)) = 1)
        begin

            -- Add everything before the parameter to the resulting command
            select @resulting_command = @resulting_command + rtrim(substring(@command, 1, @pattern_start - 1))

            -- Add back the parameter with the specified argument
            if @resulting_command <> ''
            begin
                select @resulting_command = @resulting_command + N' '
            end
            select @resulting_command = @resulting_command + N'-' + @parameter + N' ' + rtrim(ltrim(@argument)) + ' '

            -- Remove the leading part of the command up to the begining of the
            -- matching pattern
            select @command = substring(@command, @pattern_start, @command_length - @pattern_start + 1)

            -- Remove all traces of the specified parameter from the remaining
            -- command line
            select @command = fn_removeparameterwithargument(@command, @parameter)
            select @found_parameter = 1
        end
        else
        begin
            -- Not a properly delimited parameter so transfer the 
            -- matching substring to the resulting command and
            -- eat the substring in the process
            select @resulting_command = @resulting_command + substring(@command, 1, @pattern_start + @parameter_length - 1)
            select @command = substring(@command, @pattern_start + @parameter_length, @command_length - @pattern_start - @parameter_length + 1)
        end

        select @first_iteration = 0
        select @pattern_start = patindex(@pattern, @command)
    end

    select @resulting_command = @resulting_command + @command

    if @found_parameter = 0
    begin
        select @resulting_command = rtrim(@resulting_command) + N' ' + N'-' +
               @parameter + N' ' + rtrim(ltrim(@argument)) 
    end
    return @resulting_command
end
go

--
-- Name: sp_MSreplcheckoffloadserver
--
-- Description: A simple procedure for checking whether a specified
--              offload server name contains invalid characters.
--
-- Parameter: @offloadserver sysname (mandatory)
--
-- Security: Admin only
--
-- Returns: 0 - The specified offload server name doesn't contain invalid 
--             characters
--         1 - The specified offload server name contains invalid characters
--
print ''
print 'Creating procedure sp_MSreplcheckoffloadserver'
go
create procedure sp_MSreplcheckoffloadserver (
    @offloadserver sysname
    )
as 
begin
    -- @offload_server being null is ok
    -- look for '\'
    if 0 < charindex('\', @offloadserver)
    begin
        raiserror(21368,-1,-1,N'\')
        return 1
    end
    return 0
end
go
exec sp_MS_marksystemobject sp_MSreplcheckoffloadserver
go

--
-- Name: fn_MSrepl_get_unique_name
--
-- Description: Use the prefixes passed in to generate a unique name based on a new GUID
-- which is less than 100 characters (100 is task name limit) as
-- 'prefix1-prefix2-prefix3-prefix4-hex_of_guid'
-- All prefixes are optional.
--
-- Security: To public
--
raiserror('Creating function fn_repluniquename', 0,1)
go

create function system_function_schema.fn_repluniquename (
-- cannot use newid() in a UDF
	@guid uniqueidentifier,
    @prefix1 sysname = NULL,
	@prefix2 sysname = NULL,
	@prefix3 sysname = NULL,
	@prefix4 sysname = NULL
    ) returns nvarchar(100)
as
begin
	declare @name nvarchar(100)
	select @name = N''

	-- Max len is (16 + 1) * 4 + 32 = 100
	if @prefix1 is not null
		select @name = @name + CONVERT(nvarchar(16),@prefix1) + N'-'
	if @prefix2 is not null
		select @name = @name + CONVERT(nvarchar(16),@prefix2) + N'-'
	if @prefix3 is not null
		select @name = @name + CONVERT(nvarchar(16),@prefix3) + N'-'
	if @prefix4 is not null
		select @name = @name + CONVERT(nvarchar(16),@prefix4) + N'-'

	select @name = @name + replace(convert(nvarchar(36), @guid), N'-',N'')
	return @name
end
go

print ''
print 'Creating procedure sp_MSget_file_existence'
go
create procedure sp_MSget_file_existence (
@filename nvarchar(260),
@exists bit = 0 output
)
AS
    SET NOCOUNT ON

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

	select @echo_text = 'file_exists'

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

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

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

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

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

    drop table #text_ret
go
EXEC dbo.sp_MS_marksystemobject sp_MSget_file_existence
GO


raiserror('Creating procedure sp_MSrepl_isdbowner', 0,1)
go
CREATE PROCEDURE sp_MSrepl_isdbowner 
	@dbname nvarchar(255)
AS
BEGIN
	SET NOCOUNT ON
	DECLARE @retcode int
	DECLARE @cmd 	 nvarchar(255)
	DECLARE @isdbowner int

	SELECT @retcode = has_dbaccess(@dbname)
	IF (@retcode IS NULL) OR (@retcode = 0)
	BEGIN
		/* 
		** Either no access or database not found 
		** No need to go further
		*/
		RETURN 0
	END

	SELECT @cmd = 'USE ' + quotename(@dbname) + ' SELECT @isdbowner = is_member(''db_owner'')'
	EXEC sp_executesql @cmd, N'@isdbowner int output', @isdbowner output

	RETURN isnull(@isdbowner, 0)
END
GO

raiserror('Creating procedure sp_resyncmergesubscription', 0,1)
go
CREATE PROCEDURE sp_resyncmergesubscription 
	@publisher			sysname = NULL,
	@publisher_db		sysname = NULL,
	@publication		sysname,
	@subscriber			sysname = NULL,
	@subscriber_db		sysname = NULL,
	@resync_type		int, --0:force convergence, 1: since last successful validation, 2:since a given date
	@resync_date_str	nvarchar(30) = NULL
AS
	declare @retcode 			int
	declare @subid				uniqueidentifier
	declare @pubid				uniqueidentifier
	declare @subscriber_srvid 	int
	declare @resync_gen			int
	declare @resync_date		datetime
	/*
    ** Security Check
    */

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

	if isdate(@resync_date_str)=0 and @resync_type=2
	begin
		raiserror(21370, 16, -1, @resync_date_str)
		return (1)
	end
	if @resync_date_str is not NULL
		select @resync_date=convert(datetime, @resync_date_str)
	else
		select @resync_date = NULl
	
	/*
	** parameter checking for null/not-null; including validity of @resync_type and @resync_date
	*/

	if ((@publisher is NULL and @subscriber is NULL) or
	   (@publisher is not NULL and @subscriber is not NULL) or
	   (@publisher is NULL and @publisher_db is not NULL) or
	   (@subscriber is NULL and @subscriber_db is not NULL) or
	   (@publisher is not NULL and @publisher_db is NULL) or
	   (@subscriber is not NULL and @subscriber_db is NULL))
	   begin
	   		raiserror(21294, 16, -1)
	   		return (1)
	   end

	if @resync_type<0 or @resync_type>2
		begin
			raiserror(21296, 16, -1)
			return (1)
		end

	if @publisher is NULL	
		select @publisher=@@SERVERNAME
	if @publisher_db is NULL
		select @publisher_db=db_name()
	if @subscriber is NULL
		select @subscriber=@@SERVERNAME
	if @subscriber_db is NULL
		select @subscriber_db=db_name()
		
	select @pubid = pubid from sysmergepublications where name=@publication and lower(publisher)=lower(@publisher) and publisher_db=@publisher_db
	if (@pubid is null)
		begin
			RAISERROR (20026, 16, -1, @publication)
			return (1)
		end
	select @subscriber_srvid=srvid from master..sysservers where LOWER(srvname)=LOWER(@subscriber) collate database_default
	select @subid=subid from sysmergesubscriptions where pubid=@pubid and srvid=@subscriber_srvid and db_name=@subscriber_db
	if @resync_type > 0 --since a given date or last validation	
		begin
			if @resync_type = 1	-- last validation time; make sure resync_date is not NULL in this case; 
				begin
					select @resync_date=last_validated from sysmergesubscriptions where subid=@subid
					-- invalid case - there is no prior validation, this call is a non-op.
					if @resync_date is NULL
						begin
							raiserror(21370, 16, -1)
							return (1)
						end
				end
				
			declare @guidnull uniqueidentifier
			set @guidnull= '00000000-0000-0000-0000-000000000000'
			
			exec sp_MSlocalizeinterruptedgenerations
			select @resync_gen=NULL
			select top 1 @resync_gen=generation from MSmerge_genhistory 
				where 	coldate > @resync_date 
						and art_nick in (select nickname from sysmergearticles where pubid=@pubid)
						and guidlocal <> @guidnull
					order by coldate ASC
			-- this is valid case, meaning there is no need to do any resynchronization
			if @resync_gen is NULL
				begin
					return (0)
				end
		end
	else if @resync_type=0
		select @resync_gen=0 -- force convergence case
	update  sysmergesubscriptions  set resync_gen=@resync_gen where subid=@subid
	if @@ERROR<>0
		begin
			raiserror(21298, 16, -1)
			return (1)
		end
Go
EXEC dbo.sp_MS_marksystemobject sp_resyncmergesubscription
GO
grant exec on sp_resyncmergesubscription to public
go



raiserror('Creating procedure sp_MSget_qualified_name', 0,1)
GO
CREATE PROCEDURE sp_MSget_qualified_name (
	@object_id				int,						 
	@qualified_name			nvarchar(512)	output       
)AS
    if object_name(@object_id) is not null
	    select @qualified_name = quotename(user_name(OBJECTPROPERTY(@object_id,'OwnerId'))) collate database_default + 
		    N'.' + quotename(object_name(@object_id)) collate database_default
    else
        select @qualified_name = NULL
GO
exec dbo.sp_MS_marksystemobject sp_MSget_qualified_name
go


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

CREATE PROCEDURE sp_MSdrop_object (
        @object_id int = NULL,
        @object_name sysname = NULL,
        @object_owner sysname = NULL
		)
    AS

    SET NOCOUNT ON

	declare @cmd nvarchar(1000)
	
    if @object_name is not null
    begin
    	declare @owner_id int
    	if @object_owner is null
    		select @owner_id = user_id()
    	else
    		select @owner_id = user_id(@object_owner)
    	select @object_id = id from sysobjects where
    		name = @object_name and
    		uid = @owner_id
   	end

   	if @object_id is not null
   	begin
   		exec dbo.sp_MSget_qualified_name @object_id, @cmd output
   		if objectproperty(@object_id, 'IsTable') = 1
   			select @cmd = 'drop table ' + @cmd
   		else if objectproperty(@object_id, 'IsProcedure') = 1
   			select @cmd = 'drop procedure ' + @cmd
   		else if objectproperty(@object_id, 'IsTrigger') = 1
   			select @cmd = 'drop trigger ' + @cmd
   		else if objectproperty(@object_id, 'IsView') = 1
   			select @cmd = 'drop view ' + @cmd
   	end

   	exec (@cmd)
   	if @@error <> 0
   		return(1)

GO

print ''
print 'Creating procedure sp_isarticlecolbitset'
go

create procedure sp_isarticlecolbitset @colid int, @colbitmap binary(32)
as
declare @word tinyint
declare @mval int
declare @mask  smallint

select @word = convert(tinyint, 16 - floor((@colid-1)/16))
select @mval = power(2, (@colid-1) % 16 )
select @mask = convert( smallint, convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) ) )


if convert( binary(2), substring( convert( nchar(16),@colbitmap), @word, 1 ) ) & @mask = @mask 
begin   
   return 1
end
else
begin
   return 0
end

go

EXEC dbo.sp_MS_marksystemobject sp_isarticlecolbitset
GO

print ''
print 'Creating procedure sp_getarticlepkcolbitmap'
go

create procedure sp_getarticlepkcolbitmap @tabid int, @colbitmap binary(32) output
as
declare @pkindid int
declare @indkey int
declare @colid int
declare @word tinyint
declare @mval    int
declare @mask    binary(2)
declare @wordval binary(2)
declare @objname nvarchar(265)

select @colbitmap = 0x00

if exists( select * from sysobjects where id = @tabid and xtype = 'V' )
begin
	select @pkindid = 1
end
else
begin
	select @pkindid = indid from sysindexes where id = @tabid and status & 2048 <> 0
end

select @indkey = 1
select @objname = QUOTENAME(user_name(OBJECTPROPERTY(@tabid, 'OwnerId'))) collate database_default + N'.' collate database_default + QUOTENAME(object_name( @tabid )) collate database_default 

while @indkey <= 16 and index_col( @objname, @pkindid, @indkey ) is not null
begin
    select @colid = colid from syscolumns where id = @tabid 
           and name = index_col( @objname, @pkindid, @indkey )
    select @word = convert(tinyint, 16 - floor((@colid-1)/16))

    select @mval = power(2, (@colid-1) % 16 )
    select @mask = convert( binary(2), substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) )                                 

    select @wordval = convert( binary(2), substring( convert( nchar(16), @colbitmap ), @word, 1 ) )
    select @wordval = convert( binary(2), convert( smallint, @wordval) | convert( smallint, @mask) )

    select @colbitmap = convert(binary(32), STUFF( convert(nchar(16),@colbitmap), @word, 1, convert( nchar(1),@wordval))) 
      
    select @indkey = @indkey + 1
end
go

EXEC dbo.sp_MS_marksystemobject sp_getarticlepkcolbitmap
GO

raiserror('Creating procedure sp_MSsubst_filter_name', 0,1)
GO
create procedure sp_MSsubst_filter_name 
@srch_string nvarchar(500), 
@rplc_string nvarchar(500), 
@filter_clause nvarchar(4000) output
as

declare @expansion int  -- BYTES data will be expanded/contracted by
declare @subst_offset int -- CHARACTER OFFSET at which to perform string operations

select @expansion = datalength(@rplc_string) - datalength(@srch_string) 
select @subst_offset = 0

-- Note!  procedure is case insensitive

select @subst_offset = charindex( upper(@srch_string), upper(@filter_clause), @subst_offset )
while( @subst_offset <> 0 )
begin
	if datalength( @filter_clause ) + @expansion > 8000
	begin
		-- buffer overflow, return error
		return 1
	end
	else
	begin
		select @filter_clause = stuff( @filter_clause, @subst_offset, datalength( @srch_string ) / 2, @rplc_string )
		select @subst_offset = @subst_offset + @expansion / 2
	end
	select @subst_offset = charindex( upper(@srch_string), upper(@filter_clause), @subst_offset )
end
return 0
go

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

create procedure sp_MSsubst_filter_names 
@owner sysname, 
@table sysname, 
@filter_clause nvarchar(4000) output
as
declare @retcode int
declare @rplc_string nvarchar( 513 )

if @filter_clause is null or @table is null
begin 
	-- error, @filter_clause cannot be null
	return 1
end

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

select @rplc_string = @rplc_string + QUOTENAME(@table)

exec @retcode = sp_MSsubst_filter_name N'<<TABLE>>', @rplc_string, @filter_clause output 
if @retcode <> 0 or @@error <> 0
begin
	return 1
end

return 0

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

CREATE PROCEDURE sp_MSreplcheck_name
	@name			sysname,
	@raise_error	bit = 1
AS
	declare @index	int

	Set nocount on

	-- Name cannot be NULL or empty ("")
	-- Blank identifiers (" ") are allowed
	IF (@name is null OR datalength(@name) = 0)
	begin
		if @raise_error = 1
			raiserror (15004,16,-1)
		return (1)
	end

	-- Check for proscribed characters

	declare @length int
	select @length = datalength( @name ) / 2
	select @index = 1
	while @index < @length
	begin
		if( 0 = unicode( substring( @name, @index, 1 ) ) )
		begin
			if @raise_error = 1
				raiserror(15006,16,-1,@name)
			return (1)
		end

		select @index = @index + 1
	end

	--check for other proscribed characters

	select @index = charindex( N'%', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'*', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'[', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N']', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'|', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N':', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'"', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'?', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	/*
	** Fix 52855 - allow single quote
	**
	select @index = charindex(N'''', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	*/
	select @index = charindex(N'\', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'/', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'<', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	select @index = charindex(N'>', @name)
	if (@index <> 0)
	begin
		if @raise_error = 1
			raiserror(15006,16,-1,@name)
		return (1)
	end
	
	-- return success

	return (0) 
GO
    

exec dbo.sp_MS_marksystemobject sp_MSreplcheck_name
go



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

create procedure sp_MScheckvalidsystables  @validsubs int output
AS
	if not exists (select name from sysobjects where name='sysmergesubscriptions')
		begin
		set @validsubs = 0
		return
		end

	/* Is there a valid non-loopback subscription? */
	if exists (select * from sysmergesubscriptions
		where db_name=db_name() and srvid = (select srvid from master..sysservers where UPPER(srvname) = UPPER(@@servername) collate database_default)
		and subid <> partnerid)
		begin
		set @validsubs = 1
		return
		end
	/* Only possible subscriptions are loopbacks.  If database not enabled for publishing,
	** then they don't indicate a valid publication/subscription. */
	if not exists (select name from master..sysdatabases where
		(category & 4) = 4 and name = db_name() collate database_default)
		begin
		set @validsubs = 0
		return
		end
	/* Database has merge publishing turned on, is probably a publisher.  Look for loopback
	** subscription just to be sure... */
	if exists (select * from sysmergesubscriptions
		where db_name=db_name() and srvid = (select srvid from master..sysservers where UPPER(srvname) = UPPER(@@servername) collate database_default))
		begin
		set @validsubs = 1
		return
		end
		
	/* Must not be valid... */	
	set @validsubs = 0
	return


GO


raiserror('Creating procedure sp_MSdrop_mergesystables', 0,1)
GO
create procedure sp_MSdrop_mergesystables as

	begin tran
	save transaction drop_mergesystables
	if exists (select * from sysobjects
		where name = 'sysmergearticles')
		begin
		drop table sysmergearticles
		end
	if @@error<>0
		goto Error

	if exists (select * from sysobjects
		where name = 'sysmergepublications')
		begin
		drop table sysmergepublications
		end
	if @@error<>0
		goto Error

	if exists (select * from sysobjects
		where name = 'sysmergesubscriptions')
		begin
		drop table sysmergesubscriptions
		end
	if @@error<>0
		goto Error
		
	if exists (select * from sysobjects
		where name = 'MSmerge_contents')
		begin
		drop table MSmerge_contents
		end
	if @@error<>0
		goto Error

	if exists (select * from sysobjects
		where name = 'MSmerge_replinfo')
		begin
		drop table MSmerge_replinfo
		end
	if @@error<>0
		goto Error
		
	if exists (select * from sysobjects
		where name = 'MSmerge_identity_range ')
		begin
		drop table MSmerge_identity_range 
		end
	if @@error<>0
		goto Error


	if exists (select * from sysobjects
		where name = 'MSmerge_tombstone')
		begin
		drop table MSmerge_tombstone
		end
	if @@error<>0
		goto Error
		
	if exists (select * from sysobjects
		where name = 'MSmerge_genhistory')
		begin
		drop table MSmerge_genhistory
		end
	if @@error<>0
		goto Error
		
	if exists (select * from sysobjects
		where name = 'MSmerge_delete_conflicts')
		begin
		drop table MSmerge_delete_conflicts
		end
	if @@error<>0
		goto Error

	if exists (select * from sysobjects
		where name = 'sysmergeschemachange')
		begin
		drop table sysmergeschemachange
		end
	if @@error<>0
		goto Error

	if exists (select * from sysobjects
		where name = 'sysmergesubsetfilters')
		begin
		drop table sysmergesubsetfilters
		end
	if @@error<>0
		goto Error

    if exists (select * from sysobjects
        where name = 'sysmergeschemaarticles')
        begin
        drop table sysmergeschemaarticles
        end
    if @@error<>0
        goto Error
        
    if exists (select * from sysobjects
        where name = 'MSmerge_errorlineage')
        begin
        drop table MSmerge_errorlineage
        end
    if @@error<>0
        goto Error

    if exists (select * from sysobjects
        where name = 'MSrepl_identity_range')
        begin
        drop table MSrepl_identity_range
        end
    if @@error<>0
        goto Error
    
    if exists (select * from sysobjects 
        where name = 'sysmergeextendedarticlesview')
        begin
        drop view sysmergeextendedarticlesview
        end
    if @@error<>0
        goto Error    

    if exists (select * from sysobjects
        where name = 'MSdynamicsnapshotjobs')
        begin
        drop table MSdynamicsnapshotjobs
        end
    if @@error<>0
        goto Error

    if exists (select * from sysobjects
        where name = 'MSmerge_altsyncpartners')
        begin
        drop table MSmerge_altsyncpartners
        end
    if @@error<>0
        goto Error
        
    if exists (select * from sysobjects
        where name = 'MSdynamicsnapshotviews')
        begin
        drop table MSdynamicsnapshotviews
        end
    if @@error<>0
        goto Error

	if exists (select * from master..sysobjects where type='P' and name='sp_MSremovedebuginfrastructure')
	begin
		declare @retval int
		exec @retval= dbo.sp_MSremovedebuginfrastructure
		if @@ERROR <> 0 or @retval <> 0 goto Error
	end
	
	commit transaction	
	return 0
Error:
	RAISERROR (20007, 16, -1)
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION drop_mergesystables
		COMMIT TRANSACTION
	end
	return 1
go

exec dbo.sp_MS_marksystemobject sp_MSdrop_mergesystables
go

raiserror ('Executing procedure dbo.sp_MSdrop_mergesystables.',0,1)
go
exec dbo.sp_MSdrop_mergesystables
go

dump tran master with no_log
go

raiserror('Creating procedure sp_MScreate_mergesystables',0,1)
GO
create procedure sp_MScreate_mergesystables as

	/* This is to make sure that the varbinary columns do not get padded */

	set ANSI_PADDING off

	DECLARE @exist bit 
	DECLARE @validsubs  int
	select @exist = 1
	
	begin tran
	save transaction MScreate_mergesystables

	exec dbo.sp_MScheckvalidsystables  @validsubs  output
	if @validsubs = 0
		exec dbo.sp_MSdrop_mergesystables
		
	if not exists (select * from sysobjects where name = 'sysmergepublications')
		begin

			raiserror('Creating table sysmergepublications',0,1)
			
			create table dbo.sysmergepublications
			(	publisher				sysname NOT NULL default @@servername,
				publisher_db			sysname NOT NULL default db_name(),
				name					sysname				NOT NULL,
				description				nvarchar(255) 		NULL,
				retention				int					NULL,
				publication_type 		tinyint				NULL,
				pubid 					uniqueidentifier 	NOT NULL,
				designmasterid			uniqueidentifier 	NULL,
				parentid				uniqueidentifier 	NULL,
				sync_mode				tinyint				NULL,
				allow_push				int					NULL,
				allow_pull				int					NULL,
				allow_anonymous			int					NULL,
				centralized_conflicts	int					NULL,
				status					tinyint				NULL,
				snapshot_ready			tinyint				NULL,
		        enabled_for_internet    bit                	NOT NULL default 0,
				dynamic_filters			bit					NOT NULL default 0,
                -- portable snapshot support
                snapshot_in_defaultfolder   bit             NOT NULL default 1,
                alt_snapshot_folder         nvarchar(255)   NULL,
                -- Pre/post - snapshot commands
                pre_snapshot_script         nvarchar(255)   NULL,
                post_snapshot_script        nvarchar(255)   NULL,
                -- Snapshot compression
                compress_snapshot           bit             NOT NULL default 0,
                -- Post 7.0 Ftp support
                ftp_address                 sysname         NULL,
                ftp_port                    int             NOT NULL default 21,
                ftp_subdirectory            nvarchar(255)   NULL,
                ftp_login                   sysname         NULL default N'anonymous',
                ftp_password                nvarchar(524)   NULL,
                conflict_retention			int				NULL,
                keep_before_values			int				NULL default 0,
				allow_subscription_copy		bit 			NULL default 0, 	
				allow_synctoalternate		bit 			NULL default 0,
				validate_subscriber_info	nvarchar(500)	NULL,
				ad_guidname					sysname			NULL,
                backward_comp_level			int				not NULL default 10, --7.0 RTM
				max_concurrent_merge		int				not NULL default 0,
                max_concurrent_dynamic_snapshots int        not NULL default 0
			)
			if @@ERROR <> 0
				goto Error
			
			CREATE UNIQUE NONCLUSTERED INDEX nc1sysmergepublications 
				ON sysmergepublications(pubid)
			if @@ERROR <> 0
				goto Error

			exec dbo.sp_MS_marksystemobject sysmergepublications
			if @@ERROR <> 0
				goto Error
			-- grant select on sysmergepublications to public
		end

	if not exists (select * from sysobjects where name = 'MSmerge_errorlineage')
		begin		
			raiserror('Creating table MSmerge_errorlineage',0,1)
			
			create table dbo.MSmerge_errorlineage (
			tablenick		int NOT NULL,
			rowguid			uniqueidentifier NOT NULL,
			lineage			varbinary(255)
			)
			exec dbo.sp_MS_marksystemobject MSmerge_errorlineage
			if @@ERROR <> 0
				goto Error
			create unique clustered index uc1errorlineage on MSmerge_errorlineage(tablenick, rowguid)
			if @@ERROR <> 0
				goto Error
			
			--grant select on MSmerge_errorlineage to public
		end

	-- this table exists at distribution/db and subscriber databse both
	if not exists (select * from sysobjects where name = 'MSrepl_identity_range')
		begin		
			raiserror('Creating table MSrepl_identity_range',0,1)
			
			create table dbo.MSrepl_identity_range (
			objid					int not NULL primary key,
			next_seed				bigint NULL, --resource control
			pub_range				bigint NULL, --publisher range
			range					bigint NULL, -- set by sp_addmergearticle
			max_identity			bigint NULL, --resource control
			threshold				int	NULL,	--in percentage, set by sp_addmergearticle
			current_max				bigint NULL	--max value for current check constraint,set by sp_addmergearticle
			)
			exec dbo.sp_MS_marksystemobject MSrepl_identity_range
			if @@ERROR <> 0
				goto Error

			--grant select on MSrepl_identity_range to public
		end

	if not exists (select * from sysobjects where name = 'sysmergearticles')
		begin
		
			raiserror('Creating table sysmergearticles',0,1)

			
			create table dbo.sysmergearticles (
				name					sysname				NOT NULL,
		        type        			tinyint       	 	NULL,
				objid					int					NOT NULL, 
				sync_objid				int					NOT NULL,
				view_type 				tinyint				NULL,
				artid					uniqueidentifier	NOT NULL,
				description    			nvarchar(255)    	NULL,
				pre_creation_command	tinyint				NULL,
				pubid					uniqueidentifier 	NOT NULL,
				nickname				int					NOT NULL,
				column_tracking			int					NOT NULL,
				status					tinyint				NULL,
				conflict_table			sysname				NULL,
				creation_script			nvarchar(255)		NULL,
				conflict_script			nvarchar(255)		NULL,
				article_resolver		nvarchar(255)		NULL,
				ins_conflict_proc		sysname				NULL,
				insert_proc				sysname				NULL,
				update_proc				sysname				NULL,
				select_proc				sysname				NULL,
		        schema_option 			binary(8) 			NULL,
				destination_object		sysname				NOT NULL,
				destination_owner		sysname				NULL,
				resolver_clsid			nvarchar(50)		NULL,
				subset_filterclause    	nvarchar(1000)  	NULL,
				missing_col_count		int					NULL,
				missing_cols			varbinary(128)		NULL,
				excluded_cols			varbinary(128)		NULL,
				excluded_col_count		int					not NULL default 0,
				columns        			varbinary(128)   	NULL,
				resolver_info			nvarchar(255)		NULL,
				view_sel_proc			nvarchar(290)		NULL,
				gen_cur					int					NULL,
				vertical_partition		int					not NULL default 0,
				identity_support		int					not NULL default 0,
				before_image_objid		int					NULL,
				before_view_objid		int					NULL,
				verify_resolver_signature 		int			NULL,
				allow_interactive_resolver		bit			NOT NULL default 0,
				fast_multicol_updateproc		bit			NOT NULL default 0,
				check_permissions		int					NOT NULL default 0,
				maxversion_at_cleanup	int					NOT NULL default 1,
				published_in_tran_pub	bit					NOT NULL default 0,
				compensate_for_errors	bit					NOT NULL default 1
				
                -- Note: Please update sysmergeextendedarticlesview whenever
                -- there is a schema change in sysmergearticles
			)
		
			if @@error<>0
				goto Error
			else
				begin
					
					create unique clustered index uc1sysmergearticles
						on sysmergearticles(artid, pubid) 
					if @@ERROR <> 0
						goto Error
					
					if not exists (select * from sysindexes where name = 'nc1sysmergearticles')
					begin
						create nonclustered index nc1sysmergearticles on sysmergearticles(nickname) 
						if @@ERROR <> 0
						return 1
					end
				end
			exec dbo.sp_MS_marksystemobject sysmergearticles
			if @@ERROR <> 0
				goto Error
			grant select(nickname,gen_cur,maxversion_at_cleanup) on sysmergearticles to public
			
		end

    if not exists (select * from sysobjects where name = 'sysmergeschemaarticles')
        begin
            
            -- The extended merge articles table is for storing 
            -- schema only article information. 
            -- The current supported schema only articles are
            -- stored procs and views.
            raiserror('Creating table sysmergeschemaarticles',0,1)

            create table dbo.sysmergeschemaarticles 
            (   name                    sysname             NOT NULL,
                type                    tinyint             NULL,
                objid                   int                 NOT NULL,
                artid                   uniqueidentifier    NOT NULL,
                description             nvarchar(255)       NULL,
                pre_creation_command    tinyint             NULL,
                pubid                   uniqueidentifier    NOT NULL,
                status                  tinyint             NULL,
                creation_script         nvarchar(255)       NULL,
                schema_option           binary(8)           NULL,
                destination_object      sysname             NOT NULL,
                destination_owner       sysname             NULL
                -- Note: Please update sysmergeextendedarticlesview whenever
                -- there is a schema change in sysmergeschemaarticles
            )
            
            if @@error<>0
                goto Error
            else
                begin
                    create unique clustered index uc1sysmergeschemaarticles
                        on sysmergeschemaarticles(artid, pubid)
                        if @@ERROR <> 0
                            goto Error
                end

            exec dbo.sp_MS_marksystemobject sysmergeschemaarticles
            if @@ERROR <> 0
                goto Error

        end

    if exists (select * from sysobjects where name = 'sysmergeextendedarticlesview')
    begin
        drop view dbo.sysmergeextendedarticlesview
    end
    exec ('create view dbo.sysmergeextendedarticlesview
               as
           select name, type, objid, sync_objid, view_type, artid, description, pre_creation_command, pubid,
				  nickname, column_tracking, status, conflict_table, creation_script, conflict_script, article_resolver,
				  ins_conflict_proc, insert_proc, update_proc, select_proc, schema_option, destination_object,
				  resolver_clsid, subset_filterclause, missing_col_count, missing_cols, columns, resolver_info,
				  view_sel_proc, gen_cur, excluded_cols, excluded_col_count, vertical_partition, identity_support,
			      destination_owner, before_image_objid, before_view_objid, verify_resolver_signature, 
				  allow_interactive_resolver, fast_multicol_updateproc, check_permissions, maxversion_at_cleanup,
				  published_in_tran_pub, compensate_for_errors
		   from sysmergearticles
	       union all
           select name, type, objid, NULL, NULL, artid, description, pre_creation_command, pubid, 
				  NULL, NULL, status, NULL, creation_script, NULL, NULL, 
				  NULL, NULL, NULL, NULL, schema_option, destination_object, 
				  NULL, NULL, NULL, NULL, NULL, NULL, 
				  NULL, NULL, NULL, NULL, NULL, NULL, 
				  destination_owner, NULL, NULL, NULL, 
				  0, 0, 0, NULL, 
				  0, 1
				  from sysmergeschemaarticles
                  go')            
    if @@error <> 0
        goto Error

    exec dbo.sp_MS_marksystemobject sysmergeextendedarticlesview

	if not exists (select * from sysobjects	where name = 'sysmergesubscriptions')
		begin
		
			raiserror('Creating table sysmergesubscriptions',0,1)

			
			create table dbo.sysmergesubscriptions
			(
				subid     			uniqueidentifier 	NOT NULL,
				partnerid 			uniqueidentifier 	NOT NULL,
				datasource_type		int					NOT NULL,
				datasource_path		nvarchar(255)		NULL,
				srvid	     		int					NOT NULL,
				db_name		  		sysname		 		NOT NULL
				constraint 			unique_pubsrvdb 	unique nonclustered (pubid, srvid, db_name),
				pubid				uniqueidentifier 	NULL,
				status    			tinyint     		NOT NULL,
				subscriber_type		int					NOT NULL,
				subscription_type	int					NOT NULL,
				priority			real				NOT NULL,
				sync_type 			tinyint				NOT NULL,	-- 1 = automatic 2 = no sync
				description			nvarchar(255)		NULL,
				login_name			sysname				NOT NULL,
				last_validated		datetime			NULL,
				subscriber_server	sysname				NULL,
				use_interactive_resolver		bit		NOT NULL default 0,
				publication			sysname			 	NULL,
				distributor			sysname			 	NULL,
				validation_level	int					not NULL default 0,
				resync_gen			int					not NULL default -1,
				attempted_validate	datetime			NULL,
				last_sync_date		datetime			NULL,
				last_sync_status	int					NULL,
				last_sync_summary	sysname				NULL
			)
		
			if @@error<>0
				goto Error
			else
				begin
					create unique clustered index uc1sysmergesubscriptions 
						on sysmergesubscriptions (subid) 
					if @@ERROR<>0
						goto Error

					create index nc2sysmergesubscriptions on sysmergesubscriptions (srvid, db_name)
					if @@ERROR<>0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject sysmergesubscriptions
			if @@ERROR <> 0
				goto Error
			--grant select on sysmergesubscriptions to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_replinfo')
		begin
			raiserror('Creating table MSmerge_replinfo',0,1)
			
			create table dbo.MSmerge_replinfo
			(
				repid     				uniqueidentifier 	NOT NULL,
				replnickname			int					NOT NULL,
				recgen					int     			NULL,
				recguid					uniqueidentifier 	NULL,
				sentgen					int     			NULL,
				sentguid				uniqueidentifier 	NULL,
				schemaversion			int     			NULL,
				schemaguid				uniqueidentifier 	NULL,
				merge_jobid				binary(16)			NULL,
				snapshot_jobid			binary(16)			NULL
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create unique clustered index uc1MSmerge_replinfo
						on MSmerge_replinfo (repid)
					if @@ERROR <> 0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject MSmerge_replinfo
			if @@ERROR <> 0
				goto Error
			--grant select on MSmerge_replinfo to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_tombstone')
		begin
			raiserror('Creating table MSmerge_tombstone',0,1)
			
			create table dbo.MSmerge_tombstone
			(
				rowguid			uniqueidentifier rowguidcol NOT NULL,
				tablenick		int				NOT NULL,
				type			tinyint			NOT NULL,
				lineage			varbinary(249)	NOT NULL,
				generation		int				NOT NULL,
				reason			nvarchar(255)	NOT NULL,
			)

			if @@ERROR <> 0
				goto Error
			else
			begin
				create unique clustered index uc1MSmerge_tombstone
					on MSmerge_tombstone (tablenick DESC, rowguid) 
				if @@ERROR <> 0	goto Error
				
				create index nc2MSmerge_tombstone
					on MSmerge_tombstone (generation) 
				if @@ERROR <> 0	goto Error
			end	
	
			 exec dbo.sp_MS_marksystemobject MSmerge_tombstone
			 if @@ERROR <> 0
				goto Error
			--grant select on MSmerge_tombstone to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_contents')
		begin
			raiserror('Creating table MSmerge_contents',0,1)
			
			create table dbo.MSmerge_contents
			(
				tablenick		int					NOT NULL,
				rowguid			uniqueidentifier rowguidcol   NOT NULL,
				generation		int					NOT NULL,
				partchangegen	int					NULL,
				joinchangegen	int					NULL,
				lineage			varbinary(249)		NOT NULL,
				colv1			varbinary(2048)		NULL,
			)
		
			if @@ERROR <> 0
				goto Error
			else
			begin
				create unique clustered index uc1SycContents on MSmerge_contents(tablenick, rowguid)
				if @@ERROR <> 0 goto Error
				create index nc2MSmerge_contents on MSmerge_contents(generation) 
				if @@ERROR <> 0 goto Error
				create index nc3MSmerge_contents on MSmerge_contents(partchangegen) 
				if @@ERROR <> 0 goto Error
				create index nc4MSmerge_contents on MSmerge_contents(rowguid) 
				if @@ERROR <> 0 goto Error
			end
			exec dbo.sp_MS_marksystemobject MSmerge_contents
			if @@ERROR <> 0
				goto Error
			--grant select on MSmerge_contents to public
			
		end				

	if not exists (select * from sysobjects	where name = 'MSmerge_genhistory')
		begin
			raiserror('Creating table MSmerge_genhistory',0,1)
			
			create table dbo.MSmerge_genhistory
			(
				guidsrc 		uniqueidentifier 	NOT NULL,
				guidlocal 		uniqueidentifier 	NOT NULL,
				pubid			uniqueidentifier 	NULL,
				generation 		int					NOT NULL,
				art_nick		int					NULL,
				nicknames		varbinary(1000)		NOT NULL,
				coldate 		datetime			NOT NULL
			)
					
			if @@ERROR <> 0
				goto Error

			create clustered index c1MSmerge_genhistory on MSmerge_genhistory(generation) 
			if @@ERROR <> 0
				goto Error

			create unique index unc1MSmerge_genhistory on MSmerge_genhistory(guidsrc, pubid) 
			if @@ERROR <> 0
				goto Error

			create  index nc2MSmerge_genhistory on MSmerge_genhistory(guidlocal) 
			if @@ERROR <> 0
				goto Error

			CREATE INDEX nc4MSmerge_genhistory ON MSmerge_genhistory(coldate)		
			if @@ERROR <> 0
				goto Error

			 exec dbo.sp_MS_marksystemobject MSmerge_genhistory
			 if @@ERROR <> 0
				goto Error
			--grant select on MSmerge_genhistory to public
			
		end

	if not exists (select * from sysobjects	where name = 'MSmerge_delete_conflicts')
		begin

			raiserror('Creating table MSmerge_delete_conflicts',0,1)
			
			create table dbo.MSmerge_delete_conflicts
			(
				tablenick			int				NOT NULL,
				rowguid				uniqueidentifier rowguidcol NOT NULL,
				origin_datasource	nvarchar(255)	NULL,
				conflict_type		int NULL,
				reason_code			int NULL,
				reason_text			nvarchar(720) 	NULL,
				pubid				uniqueidentifier NULL,
				create_time			datetime not null default getdate()
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create clustered index uc1MSmerge_delete_conflicts on MSmerge_delete_conflicts(tablenick, rowguid) 
					if @@ERROR <> 0
						goto Error
				end					

			CREATE UNIQUE NONCLUSTERED INDEX nc1MSmerge_delete_conflicts 
					ON MSmerge_delete_conflicts(tablenick, rowguid, origin_datasource)
			if @@ERROR <> 0
						goto Error

			exec dbo.sp_MS_marksystemobject MSmerge_delete_conflicts
			if @@ERROR <> 0
				goto Error
			--grant select on MSmerge_delete_conflicts to public
			
		end

	if not exists (select * from sysobjects	where name = 'sysmergeschemachange')
		begin
		
			raiserror('Creating table sysmergeschemachange',0,1)
			
			create table dbo.sysmergeschemachange
			(
				pubid			uniqueidentifier 	NOT NULL,
				artid			uniqueidentifier 	NULL,
				schemaversion 	int 	   		NOT NULL,
				schemaguid    	uniqueidentifier 	NOT NULL,
				schematype		int		  		NOT NULL,
				schematext		nvarchar(2000) 	NOT NULL
			)
		
			if @@ERROR <> 0
				goto Error
			else
				begin
					create unique clustered index schemachangeversion on sysmergeschemachange(schemaversion, pubid) 
					if @@ERROR <> 0
						goto Error
				end
			exec dbo.sp_MS_marksystemobject sysmergeschemachange
			if @@ERROR <> 0
				goto Error
			--grant select on sysmergeschemachange to public
			
		end

	if not exists (select * from sysobjects where name = 'sysmergesubsetfilters')
		begin
			raiserror('Creating table sysmergesubsetfilters',0,1)

			
			create table dbo.sysmergesubsetfilters (
                filtername              sysname		         NOT NULL,
                join_filterid			int					identity NOT NULL,
				pubid					uniqueidentifier	NOT NULL,
				artid					uniqueidentifier	NOT NULL,
				art_nickname			int					NOT NULL,
				join_articlename		sysname NOT NULL,
				join_nickname 			int					NOT NULL,
				join_unique_key			int					NOT NULL,
				expand_proc				sysname					NULL,
				join_filterclause    	nvarchar(1000)  		NULL
			)
			if @@ERROR <> 0
				goto Error

			CREATE UNIQUE NONCLUSTERED INDEX nc1sysmergesubsetfilters 
				ON sysmergesubsetfilters(join_filterid, pubid)
			if @@ERROR <> 0
				goto Error

			exec dbo.sp_MS_marksystemobject sysmergesubsetfilters
			if @@ERROR <> 0
				goto Error
			--grant select on sysmergesubsetfilters to public
			
		end

	if @@error <> 0
		goto Error

    if not exists (select * from sysobjects where name = 'MSdynamicsnapshotviews')
        begin
            raiserror('Creating table MSdynamicsnapshotviews',0,1)
            
            create table dbo.MSdynamicsnapshotviews (
                dynamic_snapshot_view_name sysname primary key
            )
            if @@ERROR <> 0
                goto Error
            exec dbo.sp_MS_marksystemobject MSdynamicsnapshotviews
        end

    if not exists (select * from sysobjects where name = 'MSdynamicsnapshotjobs')
        begin
            raiserror('Creating table MSdynamicsnapshotjobs',0,1)
        
            create table dbo.MSdynamicsnapshotjobs (
                id int identity, 
                name sysname not null unique,
                pubid uniqueidentifier not null,
                job_id uniqueidentifier not null,
                dynamic_filter_login sysname null,
                dynamic_filter_hostname sysname null,
                dynamic_snapshot_location nvarchar(255) not null
            )
            if @@ERROR <> 0
                goto Error

            exec dbo.sp_MS_marksystemobject MSdynamicsnapshotjobs

            create unique clustered index uciMSdynamicsnapshotjobs on 
                dbo.MSdynamicsnapshotjobs(job_id, pubid)
            
            if @@ERROR <> 0
                goto Error


        end
    
    if @@error <> 0
        goto Error

    if not exists (select * from sysobjects where name = 'MSmerge_altsyncpartners')
        begin
            raiserror('Creating table MSmerge_altsyncpartners',0,1)
        
            create table dbo.MSmerge_altsyncpartners (
                subid 				uniqueidentifier 	not null,
                alternate_subid 	uniqueidentifier 	not null,
                description			nvarchar(255)		NULL

            )
            if @@ERROR <> 0
                goto Error

            exec dbo.sp_MS_marksystemobject MSmerge_altsyncpartners

            create unique clustered index uciMSmerge_altsyncpartners on 
                dbo.MSmerge_altsyncpartners(subid, alternate_subid)
            
            if @@ERROR <> 0
                goto Error


        end
    

	if exists (select * from master..sysobjects where type='P' and name='sp_MScreatedebuginfrastructure')
	begin
		declare @retval int
		exec @retval= dbo.sp_MScreatedebuginfrastructure
		if @@ERROR <> 0 or @retval <> 0 goto Error
	end
	
	commit transaction
	return (0)
Error:
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION MScreate_mergesystables
		COMMIT TRANSACTION
	end
	RAISERROR (20008, 16, -1)
	return (1)
go

exec dbo.sp_MS_marksystemobject sp_MScreate_mergesystables 
go

raiserror('Creating procedure sp_MStestbit',0,1)
go
create procedure sp_MStestbit
			@bm varbinary(128),
			@coltotest smallint
AS
			declare @word smallint
			declare @bit  smallint
			declare @mask binary(2)
			declare @mval int
			declare @oldword binary(2)  

			if @coltotest < 1 return 0

			SELECT @word = 1 + FLOOR((@coltotest -1)/16)

			SELECT @bit = (@coltotest -1) % 16

			SELECT @mval = POWER(2, @bit)
			SELECT @mask = convert( binary(2), unicode( substring( convert( nchar(2), convert( binary(4), @mval ) ), 2, 1 ) ) )
			
			SELECT @oldword = convert( binary(2), SUBSTRING( convert( nvarchar(64),@bm), @word, 1) )
			IF @oldword IS NULL return 0

			return  convert( smallint, @oldword ) & convert( smallint, @mask )
go
exec dbo.sp_MS_marksystemobject sp_MStestbit
go
grant exec on dbo.sp_MStestbit to public
		
raiserror('Creating procedure sp_MSsetbit',0,1)
go
set ansi_padding on
go
create procedure sp_MSsetbit
	@bm varbinary(128) output,
	@coltoadd smallint,
	@toset	int = 1
AS
	declare @bytenum smallint
	declare @bit smallint
	declare @mask tinyint
	declare @newbyte tinyint     
	declare @oldbyte tinyint
			
	SELECT @bytenum = 1 + FLOOR((@coltoadd-1)/8)

	IF @bytenum > 128 return 0

	SELECT @bit = (@coltoadd-1) % 8

	SET @mask = POWER(2, @bit)
	if @toset = 0
		SET @mask = (~@mask % 256)
				
	if @bm is null
		set @bm = 0x0
	while datalength(@bm) < @bytenum
		set @bm = @bm + 0x00 

	SET @oldbyte = SUBSTRING( @bm, @bytenum, 1)
	IF @oldbyte IS NULL SET @oldbyte = 0
	if @toset <> 0			
		SET @newbyte = @oldbyte | @mask
	else
		SET @newbyte = @oldbyte & @mask

	if (@bytenum = 1)
		set @bm = convert(binary(1), @newbyte) + substring(@bm, 2, 127)
	else
		set @bm = substring(@bm, 1, @bytenum - 1) + convert(binary(1), @newbyte) + substring(@bm, @bytenum + 1, 128 - @bytenum)
go
exec dbo.sp_MS_marksystemobject sp_MSsetbit
go
grant exec on dbo.sp_MSsetbit to public

raiserror('Creating procedure sp_MSinsertcontents',0,1)
go
create procedure sp_MSinsertcontents
				@tablenick int,
				@rowguid uniqueidentifier,
	 			@lineage varbinary(249),
	 			@colv1 varbinary(2048)
AS
				/*
				** permission check
				*/
				declare @retcode	int
				declare @objid		int
				declare @owner		sysname
				declare @artid		uniqueidentifier
				declare @guidstr	nvarchar(32)	
				declare @instrigger nvarchar(270)
				
				select @objid = objid, @artid=artid from sysmergearticles where nickname=@tablenick
				select @owner =user_name(uid) from sysobjects where id=@objid

				exec @retcode=sp_MSguidtostr @artid, @guidstr out
					if @retcode<>0 or @@ERROR<>0 return (1)

				set @instrigger = QUOTENAME(@owner) + '.ins_' + @guidstr

				if trigger_nestlevel(object_id(@instrigger)) = 0
				begin
					raiserror(14126, 16, -1)
					return (1) -- current user does not have insert permission to underlying table
				end
			
				insert into MSmerge_contents (tablenick, rowguid, generation, partchangegen, joinchangegen, lineage, colv1)
					values (@tablenick, @rowguid, 0, 0, 0, @lineage, @colv1)
				if @@error <> 0
					begin
					raiserror (20041, 16, -1)
					return (1)
					end			

				delete from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick		 
				if @@error <> 0
					begin
					raiserror (20041, 16, -1)
					return (1)
					end	

go
exec dbo.sp_MS_marksystemobject sp_MSinsertcontents
go

raiserror('Creating procedure sp_MSupdatecontents',0,1)
go
create procedure sp_MSupdatecontents
				 @tablenick int,
				 @rowguid uniqueidentifier,
				 @lineage varbinary(249),
				 @colv1 varbinary(2048),
				 @partchange int = null,
				 @joinchange int = null
AS
			/*
			** permission check
			*/
			declare @retcode	int
			declare @objid		int
			declare @owner		sysname
			declare @artid		uniqueidentifier
			declare @guidstr	nvarchar(32)	
			declare @updtrigger	nvarchar(270)
			
			select @objid = objid, @artid=artid from sysmergearticles where nickname=@tablenick
			select @owner =user_name(uid) from sysobjects where id=@objid
			
			exec @retcode=sp_MSguidtostr @artid, @guidstr out
					if @retcode<>0 or @@ERROR<>0 return (1)
					
				set @updtrigger = QUOTENAME(@owner) + '.upd_' + @guidstr

				if trigger_nestlevel(object_id(@updtrigger)) = 0
				begin
					raiserror(14126, 16, -1)
					return (1) -- current user does not 'update all' permission upon underlying table
				end
			
			update MSmerge_contents set lineage = @lineage, generation = 0, colv1 = @colv1
				where tablenick = @tablenick and rowguid = @rowguid
			if (@@rowcount = 0)
				insert into MSmerge_contents (tablenick, rowguid, generation, joinchangegen, lineage, colv1)
					values (@tablenick, @rowguid, 0, 1, @lineage, @colv1)
			if @@error <> 0
				begin
				raiserror (20041, 16, -1)
				return (1)
				end
			if @partchange = 1
				begin
				update MSmerge_contents set partchangegen = 0, joinchangegen = 0
					where tablenick = @tablenick and rowguid = @rowguid
				if @@error <> 0
					begin
					raiserror (20041, 16, -1)
					return (1)
					end
				end
			else if @joinchange = 1
				begin
				update MSmerge_contents set joinchangegen = 0
					where tablenick = @tablenick and rowguid = @rowguid
				if @@error <> 0
					begin
					raiserror (20041, 16, -1)
					return (1)
					end
				end 
go
exec dbo.sp_MS_marksystemobject sp_MSupdatecontents
go

raiserror(15339, -1, -1, 'sp_MSdeletecontents')
go
create procedure sp_MSdeletecontents
	@tablenick int,
	@rowguid uniqueidentifier
AS
	declare @nick int
	declare @reason nvarchar(255)
	declare @lineage varbinary(255)

	/*
	** permission check
	*/
	declare @retcode	int
	declare @objid		int
	declare @owner		sysname
	declare @artid		uniqueidentifier
	declare @guidstr	nvarchar(32)	
	declare @deltrigger	nvarchar(270)
	declare @oldmaxversion int
	
	select @objid = objid, @artid=artid from sysmergearticles where nickname=@tablenick
	select @owner =user_name(uid) from sysobjects where id=@objid
	
	exec @retcode=sp_MSguidtostr @artid, @guidstr out
		if @retcode<>0 or @@ERROR<>0 return (1)

	set @deltrigger = QUOTENAME(@owner) + '.del_' + @guidstr

	if trigger_nestlevel(object_id(@deltrigger)) = 0
		begin
			raiserror(14126, 16, -1)
			return (1) -- current user does not have 'delete' permission to underlying table
		end

	exec dbo.sp_MSgetreplnick @nickname = @nick out
	if (@@error <> 0) or @nick IS NULL 
        begin
        RAISERROR (14055, 11, -1)
        RETURN(1)
        end                 

	select @oldmaxversion= maxversion_at_cleanup from sysmergearticles where nickname = @tablenick
	select @lineage = lineage from MSmerge_contents (UPDLOCK ROWLOCK index = 1) 
		where tablenick = @tablenick and rowguid = @rowguid
	set @lineage= { fn UPDATELINEAGE(@lineage, @nick, @oldmaxversion+1) }
	select @reason = 'user delete'

	insert into MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason)
		values (@rowguid, @tablenick, 1, @lineage, 0, @reason)
	if @@error <> 0
		begin
		raiserror (20041, 16, -1)
		return (1)
		end
	delete from MSmerge_contents where
		tablenick = @tablenick and rowguid = @rowguid
	if @@error <> 0
		begin
		raiserror (20041, 16, -1)
		return (1)
		end 
go
exec dbo.sp_MS_marksystemobject sp_MSdeletecontents
go		


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

CREATE PROCEDURE sp_MSunmarkifneeded(
@object				sysname,
@pubid				uniqueidentifier,
@pre_command 		int = 0,
@publisher			sysname,
@publisher_db		sysname
)AS
declare @table_in_use	int
declare @retcode 		int

select @table_in_use = 0
--if pre-creation_command is 'drop (1)' or 'truncate (3)', then disallow this deployment if there is already an article using that table.
--other commands like 'delete, truncate, none are fine'

if exists (select * from sysmergearticles where objid=object_id(@object) and pubid in
	(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@publisher) and 
		publisher_db=@publisher_db and pubid<>@pubid))
	OR
	((@pre_command=1 or @pre_command=3) and 
		EXISTS (select * from sysmergearticles where objid=object_id(@object) and pubid <> @pubid and pubid not in
			(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name())))  
begin
	select @table_in_use = 1
	select @table_in_use
	return (0)
end
exec @retcode = sp_MSunmarkreplinfo @object
if @retcode <>0 or @@error<>0
	return (1)
select @table_in_use 
return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSunmarkifneeded
go		
grant exec on dbo.sp_MSunmarkifneeded to public
go

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

CREATE PROCEDURE sp_MSunmarkreplinfo(
	@object				sysname,			/* Name of the table, unqualitied */
	@owner				sysname = NULL,			/* Name of the owner, unqualified */
	@type				smallint = 0        /* default is to unmark, as name implies */
)AS
declare @merge_pub_object_bit int
declare @merge_pub_unmark_bit int
declare @id	int
declare @qualified_name			nvarchar(270)
declare @retcode				int

exec @retcode = sp_MSreplcheck_subscribe
if @@error<>0 or @retcode<>0
    return (1)

if @owner is NULL or @owner=''
	select @owner = user_name(uid) from sysobjects where name=@object
select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object) 


select @id = object_id(@qualified_name)

select @merge_pub_object_bit 	= 128
select @merge_pub_unmark_bit = ~@merge_pub_object_bit

if exists (select name from sysobjects where id = @id) 
	begin
			if @type = 0    /* type = 0, unmark; else mark the bit */
		begin
			BEGIN TRANSACTION
   				exec dbo.sp_replupdateschema @qualified_name
   				update sysobjects set replinfo = replinfo & @merge_pub_unmark_bit where id = @id
   				exec dbo.sp_replupdateschema @qualified_name
	    	COMMIT TRANSACTION
	    end
	    else
	    begin
	    	BEGIN TRANSACTION
	    		exec dbo.sp_replupdateschema @qualified_name
       			update sysobjects set replinfo = replinfo | @merge_pub_object_bit where id = @id
	    		exec dbo.sp_replupdateschema @qualified_name
       		COMMIT TRANSACTION
		end
	end
GO
exec dbo.sp_MS_marksystemobject sp_MSunmarkreplinfo
go
grant execute on dbo.sp_MSunmarkreplinfo to public
go

/*
** This is to have a better name 'sp_MSmarkreplinfo' while keeping the change minimal.
*/
raiserror('Creating procedure sp_MSmarkreplinfo',0,1)
GO
CREATE PROCEDURE sp_MSmarkreplinfo(
	@object				sysname,			/* Name of the table, unqualitied */
	@owner				sysname = NULL		/* Name of the owner, unqualified */
)AS
declare @retcode int

exec @retcode = sp_MSunmarkreplinfo @object, @owner, 1
if @@ERROR<>0 or @retcode<>0
	return (1)
return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSmarkreplinfo
go


raiserror('Creating procedure sp_MSunmarkschemaobject',0,1)
go
CREATE PROCEDURE sp_MSunmarkschemaobject(
    @object           sysname,     
    @owner            sysname = NULL
)AS
begin
set nocount on
declare @schema_obj_bit_mask int
declare @qualified_name nvarchar(520)
declare @id int
declare @retcode int

exec @retcode = sp_MSreplcheck_subscribe
if @@error<>0 or @retcode <>0
    return (1)

select @schema_obj_bit_mask = 0x00000200
select @schema_obj_bit_mask = ~@schema_obj_bit_mask

if (@owner is null or @owner = N'')
begin
    select @owner = user_name()
end
select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object)

select @id = NULL
select @id = object_id(@qualified_name)

if (@id is not null)
begin
    begin transaction
    exec dbo.sp_replupdateschema @qualified_name
    update sysobjects set replinfo = replinfo & @schema_obj_bit_mask
    where id = @id
    exec dbo.sp_replupdateschema @qualified_name
    commit transaction
end
return 0    
end
go
exec dbo.sp_MS_marksystemobject sp_MSunmarkschemaobject
go
grant execute on dbo.sp_MSunmarkschemaobject to public
go

raiserror('Creating procedure sp_MSmarkschemaobject',0,1)
go
CREATE PROCEDURE sp_MSmarkschemaobject(
    @object           sysname,
    @owner            sysname = NULL
)AS
begin
set nocount on
declare @schema_obj_bit_mask int
declare @qualified_name nvarchar(520)
declare @id int
declare @retcode int

exec @retcode = sp_MSreplcheck_subscribe
if @@error<>0 or @retcode<>0
    return (1)

select @schema_obj_bit_mask = 0x00000200

if (@owner is null or @owner = N'')
begin
    select @owner = user_name()
end
select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object)

select @id = NULL
select @id = object_id(@qualified_name)

if (@id is not null)
begin
    begin transaction
    exec dbo.sp_replupdateschema @qualified_name
    update sysobjects set replinfo = replinfo | @schema_obj_bit_mask
    where id = @id
    exec dbo.sp_replupdateschema @qualified_name
    commit transaction
end
return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSmarkschemaobject
go

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

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

select @preexists = 0

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

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

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

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

			return (1)   
			end
		
	end
end

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

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

raiserror('Creating procedure sp_MSgetreplicainfo',0,1)
GO
CREATE PROCEDURE sp_MSgetreplicainfo
	(@publisher			sysname,
	 @publisher_db		sysname,
	 @publication 		sysname,
	 @datasource_type	int = 0, 				/* 0 = SQL Server, 1 = DSN, 2 = Jet */
	 @server_name		sysname	= NULL, 		/* Server Name */
	 @db_name			sysname = NULL, 		/* Database Name */
	 @datasource_path	nvarchar(255) = NULL)	/* Datasource path - JET MDB file path etc */
	 
as
	declare		@srvid				int
	declare		@retcode			int
	declare		@repid 				uniqueidentifier
	declare		@pubid 				uniqueidentifier
	declare		@schemaguid			uniqueidentifier
	declare  	@nickname 			int
	declare 	@subscription_type int
	declare 	@validation_level	int
	declare 	@reptype 			tinyint
	declare 	@priority 			real 
	declare 	@schversion 		int 
	declare 	@status				int
	declare 	@resync_gen			int
	declare  	@partnerid 			uniqueidentifier
	declare 	@sync_type 			tinyint
	declare 	@description 		nvarchar(255)
	declare 	@distributor		sysname
	
    /*
    ** Parameter Check:  @publication.
    ** Make sure that the publication exists.
    */
	if (@publication is null)
		begin
		RAISERROR(14043, 16, -1, '@publication')
		return (1)
		end

	if (@server_name is NULL)
		SET @server_name = @@SERVERNAME

	if (@db_name is NULL)
		set @db_name = db_name()
		
	SELECT @srvid = srvid FROM master..sysservers WHERE UPPER(srvname) = UPPER(@server_name) collate database_default
   	IF @@ERROR <> 0
       	BEGIN
            RAISERROR (14080, 16, -1)
     		RETURN (1)
		END

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

	select @pubid = pubid from sysmergepublications 
		where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
	if (@pubid is null)
		begin
			RAISERROR (20026, 16, -1, @publication)
			return (1)
		end

	if (@datasource_type = 0)
		begin
			SELECT @repid = subid, @priority = priority, @reptype = subscriber_type, 
				@subscription_type = subscription_type , @status = status, 
				@partnerid = partnerid, @sync_type = sync_type, 
				@description = description, @distributor = distributor, 
				@validation_level=validation_level, @resync_gen=resync_gen
				FROM sysmergesubscriptions
				WHERE srvid = @srvid and db_name = @db_name and pubid = @pubid
		END
	ELSE
		BEGIN
			SELECT @repid = subid, @priority = priority, @reptype = subscriber_type, 
				@subscription_type = subscription_type , @status = status, 
				@partnerid = partnerid, @sync_type = sync_type, 
				@description = description,@distributor = distributor, 
					@validation_level=validation_level, @resync_gen=resync_gen
				FROM sysmergesubscriptions
				WHERE srvid = @srvid and pubid = @pubid
		END

	if @repid is NULL
		begin
			RAISERROR(20021, 16, -1)
			return (1)
		end
	select @schversion = schemaversion, @schemaguid = schemaguid from MSmerge_replinfo where repid = @repid
	select @nickname = replnickname from MSmerge_replinfo where repid = @repid
	select @repid, @nickname, @reptype, @subscription_type, @priority, @schversion, @schemaguid,
		@status, @partnerid, @sync_type, @description, @publication, @distributor, @validation_level, @resync_gen
	return (0)
go
exec dbo.sp_MS_marksystemobject sp_MSgetreplicainfo
go
grant execute on dbo.sp_MSgetreplicainfo to public


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

CREATE PROCEDURE sp_MSadd_repl_job
  @name                   nvarchar(200),
  @subsystem              nvarchar(60)  = 'TSQL',
  @server                 sysname  = NULL,
  @username               sysname  = NULL,
  @databasename           sysname  = NULL,
  @enabled                TINYINT      = 0,
  @freqtype               INT          = 2, -- 2 means OnDemand
  @freqinterval           INT          = 1,
  @freqsubtype            INT          = 1,
  @freqsubinterval        INT          = 1,
  @freqrelativeinterval   INT          = 1,
  @freqrecurrencefactor   INT          = 1,
  @activestartdate        INT          = 0,
  @activeenddate          INT          = 0,
  @activestarttimeofday   INT          = 0,
  @activeendtimeofday     INT          = 0,
  @nextrundate            INT          = 0,
  @nextruntime            INT          = 0,
  @runpriority            INT          = 0,
  @emailoperatorname      nvarchar(100) = NULL,
  @retryattempts          INT          = NULL,
  @retrydelay             INT          = 0,
  @command                nvarchar(4000)= NULL,
  @loghistcompletionlevel INT          = 2,
  @emailcompletionlevel   INT          = 0,
  @description            nvarchar(255) = NULL,
  @tagadditionalinfo      nvarchar(96)  = NULL,
  @tagobjectid            INT          = NULL,
  @tagobjecttype          INT          = NULL,
  @cmdexecsuccesscode     INT          = 0,
  @category_name          sysname = NULL, -- New for 7.0
  @failure_detection      BIT           = 0,
  @agent_id               INT           = NULL,
  @job_id BINARY(16) = NULL OUTPUT
AS
BEGIN
  DECLARE   @retval INT
  declare   @step_id int
  declare   @step_name nvarchar(100)
  declare   @step_command nvarchar(1024)
  declare   @on_fail_action tinyint
  declare   @on_success_action tinyint
  declare   @schedule_name nvarchar(100)
  declare   @comments nvarchar(100)

  SET NOCOUNT ON

  SELECT @retval = 1 -- 0 means success, 1 means failure
  set @step_id = 1
  set @on_fail_action = 2   -- Return failure
  set @on_success_action = 1    -- Return success
  set @step_command = NULL

  /*
  ** Set default retries to every minute for 10 minutes.
  **
  */
  if @retryattempts = NULL and @retrydelay = 0
  begin
     select @retryattempts = 10
     select @retrydelay = 1
  end

  BEGIN TRANSACTION
  save tran sp_MSadd_repl_job

    -- Drop the job if it already exists
    IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @name collate database_default)
    begin
        exec @retval = msdb.dbo.sp_delete_job @job_name=@name
        if @@ERROR<>0 or @retval<>0
            goto UNDO
    end

    -- Add the job
    EXECUTE @retval = msdb.dbo.sp_add_job
      @job_name                   = @name,
      @enabled                    = @enabled,
      @start_step_id              = 1,
      @description                = @description,
      @category_name              = @category_name,
      @notify_level_eventlog      = @loghistcompletionlevel,
      @notify_level_email         = @emailcompletionlevel,
      @notify_email_operator_name = @emailoperatorname,
      @job_id = @job_id OUTPUT

    IF (@retval <> 0)
    BEGIN
        GOTO UNDO
    END

    -- Add startup message step
    if @failure_detection = 1
    begin
        select @step_name = 
            case UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS)
                when N'SNAPSHOT' then isnull(formatmessage(21410), N'Message 21410')
                when N'LOGREADER' then isnull(formatmessage(20528), N'Message 20528')
                when N'DISTRIBUTION' then isnull(formatmessage(21411), N'Message 21411')
                when N'MERGE' then isnull(formatmessage(21412), N'Message 21412')
                when N'QUEUEREADER' then isnull(formatmessage(21422), N'Message 21422')
            end 
            ,@comments = isnull(formatmessage(20529), N'Message 20529')

        -- Construct command based on subsystem type
        select @step_command =
            case UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) 
                WHEN 'SNAPSHOT' THEN
                N'sp_MSadd_snapshot_history @perfmon_increment = 0,  @agent_id = ' + 
                    convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
                    @comments = ''' + @comments + ''''
                WHEN 'LOGREADER' THEN
                N'sp_MSadd_logreader_history @perfmon_increment = 0, @agent_id = ' + 
                    convert (nvarchar(10), @agent_id) + N', @runstatus = 1, 
                    @comments = ''' + @comments + ''''
                WHEN 'DISTRIBUTION' THEN
                N'sp_MSadd_distribution_history @perfmon_increment = 0, @agent_id = ' + 
                    convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
                    @comments = ''' + @comments + ''''
                WHEN 'MERGE' THEN
                N'sp_MSadd_merge_history @perfmon_increment = 0, @agent_id = ' + 
                    convert (nvarchar(10),@agent_id) + N', @runstatus = 1,  
                    @comments = ''' + @comments + ''''
                WHEN 'QUEUEREADER' THEN
                N'sp_MSadd_qreader_history @perfmon_increment = 0, @agent_id = ' + 
                    convert (nvarchar(10), @agent_id) + N', @runstatus = 1,  
                    @comments = ''' + @comments + ''''                  
            end
    
        -- Add the job step
        EXECUTE @retval = msdb.dbo.sp_add_jobstep_internal
          @job_id                = @job_id,
          @step_id               = @step_id,
          @step_name             = @step_name,
          @command               = @step_command,
          @cmdexec_success_code  = @cmdexecsuccesscode,
          @on_success_action     = 3,   -- Goto next step
          @on_fail_action        = 3,   -- Goto next step
          @server                = @server,
          @database_name         = @databasename,
          @database_user_name    = @username,
          @os_run_priority       = @runpriority

        IF (@retval <> 0)
        BEGIN
            GOTO UNDO
        END

        set @step_id = @step_id + 1
        set @on_fail_action = 3         -- Goto next step
    end

    -- Add the job step
     select @step_name = isnull(formatmessage(20530), N'Message 20530')
    EXECUTE @retval = msdb.dbo.sp_add_jobstep_internal
    @job_id                = @job_id,
      @step_id               = @step_id,
      @step_name             = @step_name,
      @subsystem             = @subsystem,
      @command               = @command,
      @cmdexec_success_code  = @cmdexecsuccesscode,
      @on_success_action     = @on_success_action,
      @on_fail_action        = @on_fail_action,
      @server                = @server,
      @database_name         = @databasename,
      @database_user_name    = @username,
      @retry_attempts        = @retryattempts,
      @retry_interval        = @retrydelay,
      @os_run_priority       = @runpriority

    IF (@retval <> 0)
    BEGIN
        GOTO UNDO
    END

    -- Add failure message step
    if @failure_detection = 1
    begin
        -- Construct command
        select @step_id = @step_id + 1
                ,@step_name = isnull(formatmessage(20531), N'Message 20531')
                ,@step_command = N'sp_MSdetect_nonlogged_shutdown @subsystem = ''' + @subsystem +  N''', @agent_id = ' + convert (nvarchar(10),   @agent_id) 

        -- Add the job step
        EXECUTE @retval = msdb.dbo.sp_add_jobstep_internal
          @job_id                = @job_id,
          @step_id               = @step_id,
          @step_name             = @step_name,
          @command               = @step_command,
          @cmdexec_success_code  = @cmdexecsuccesscode,
          @on_success_action     = 2,                   -- Always quit with failure
          @server                = @server,
          @database_name         = @databasename,
          @database_user_name    = @username,
          @os_run_priority       = @runpriority

        IF (@retval <> 0)
        BEGIN
            GOTO UNDO
        END
    end

    -- Add the job schedule
    IF (@activestartdate = 0)
      SELECT @activestartdate = NULL
    IF (@activeenddate = 0)
      SELECT @activeenddate = NULL
    
    -- But if @activeenddate is NOT NULL, then @activestartdate cannot be allowed to be NULL either.  Set it to today's date converted to the int format used yyyymmdd

    IF (@activeenddate IS NOT NULL AND @activestartdate IS NULL)
    SELECT @activestartdate=DATEPART(YYYY,getdate()) * 10000 + DATEPART(MM,getdate()) * 100 + DATEPART(DD,getdate())

    -- But never let startdate be > end date
    IF (@activestartdate > @activeenddate)
    SELECT @activestartdate=@activeenddate

    IF (@activestarttimeofday = 0)
      SELECT @activestarttimeofday = NULL
    IF (@activeendtimeofday = 0)
      SELECT @activeendtimeofday = NULL
    IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0
    BEGIN
      select @schedule_name = isnull(formatmessage(20532), N'Message 20532')

      EXECUTE @retval = msdb.dbo.sp_add_jobschedule
        @job_id                 = @job_id,
        @name                   = @schedule_name,
        @enabled                = 1,
        @freq_type              = @freqtype,
        @freq_interval          = @freqinterval,
        @freq_subday_type       = @freqsubtype,
        @freq_subday_interval   = @freqsubinterval,
        @freq_relative_interval = @freqrelativeinterval,
        @freq_recurrence_factor = @freqrecurrencefactor,
        @active_start_date      = @activestartdate,
        @active_end_date        = @activeenddate,
        @active_start_time      = @activestarttimeofday,
        @active_end_time        = @activeendtimeofday

      IF (@retval <> 0)
      BEGIN
        GOTO UNDO
      END
    END

    -- And finally, add the job server
    EXECUTE @retval = msdb.dbo.sp_add_jobserver @job_id = @job_id, @server_name  = '(local)'

    IF (@retval <> 0)
    BEGIN
      GOTO UNDO
    END

  COMMIT TRANSACTION

  -- If this is an autostart LogReader or Distribution or Merge job, add the [new] '-Continuous' paramter to the command
  IF (@freqtype = 0x40) AND ((UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'LOGREADER') OR (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'DISTRIBUTION') OR 
            (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'MERGE') OR (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'QUEUEREADER'))
  BEGIN
    UPDATE msdb.dbo.sysjobsteps
    SET command = command + ' -Continuous'
    WHERE (job_id = @job_id)
      AND ((@failure_detection = 0 and step_id = 1) or (@failure_detection = 1 and step_id = 2))
  END  

  -- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)
  IF (@freqtype = 0x40)
    EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0

  RETURN(0)

UNDO:
    rollback tran sp_MSadd_repl_job
    commit tran
    return(1)

END
go

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

CREATE PROCEDURE sp_MScheck_subscription (
@publication	sysname,  -- 	1 Tran, 2 Merge
@pub_type		int
)AS
declare @merge_pubid	uniqueidentifier
declare @tran_pubid		int
declare @retcode int

-- Security check
exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
if @retcode <> 0 or @@error <> 0
    return 1

if @pub_type = 2
BEGIN
	if not exists (select * from sysobjects where name = 'sysmergepublications')
		begin
			raiserror(20054, 16, -1)
			return (1)
		end
	select @merge_pubid = pubid from sysmergepublications where name=@publication and publisher=@@SERVERNAME and publisher_db=db_name()
	if @merge_pubid is NULL
		begin
			raiserror(20026, 16, -1, @publication)
			return (1)
		end
	if EXISTS (select * from sysmergesubscriptions where pubid=@merge_pubid and subid<>pubid)
		select 1
	else 
		select 0
END
else	-- if not merge, it has to be tran level. For other level, a generic error will be returned
BEGIN
	if not exists (select * from sysobjects where name='syspublications')
		begin
			raiserror(20054, 16, -1)
			return (1)
		end
	select @tran_pubid = pubid from syspublications where name=@publication
	if @tran_pubid is NULL 
		begin
			raiserror(20026, 16, -1, @publication)
			return (1)
		end
	if EXISTS (select * from syssubscriptions where (srvid <> -1) and artid in 
           			(select artid from sysextendedarticlesview where pubid=@tran_pubid))
      	select 1
    else
       	select 0
END
GO

exec dbo.sp_MS_marksystemobject sp_MScheck_subscription
go
grant execute on dbo.sp_MScheck_subscription to public
go

-- system procedure : returns string representing path to shared tools directory for 
-- the current instance as an output parm; if unable to get path, returns 1
raiserror(15339,-1,-1,'sp_MSgettools_path')
GO
CREATE PROCEDURE dbo.sp_MSgettools_path ( @install_path NVARCHAR(260) OUTPUT )
AS
BEGIN
	
	DECLARE @retcode INTEGER
	DECLARE @regkey NVARCHAR(260)
	DECLARE @len_minorversion tinyint

	SET NOCOUNT ON 
	
	SELECT @len_minorversion = 1 -- assume only 10's digit of minor version is significant
	SELECT @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\' + dbo.fn_MSsharedversion(@len_minorversion) + '\Tools\ClientSetup'

	EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 
		@regkey,
		'SQLPath',
		@param = @install_path OUTPUT

	IF ( @retcode <> 0 ) or ( @@ERROR <> 0 ) or ( @install_path IS NULL ) or ( @install_path = '' )
	BEGIN
		RETURN (1)
	END

	RETURN (0)

END
GO

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

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

	DECLARE @install_path nvarchar (255)

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

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

	SELECT @undo_install = 'undo_install'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		END

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

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

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

NO_SCRIPTS:

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

	END
	/* Uninstall replication */
	ELSE
	BEGIN

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

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

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

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

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

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

		*/
	END

	RETURN(0)

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

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

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

CREATE PROCEDURE sp_helpreplicationoption (
@optname		sysname = NULL
)
AS
	DECLARE @optbit bit
	DECLARE @retcode int


	IF @optname IS NOT NULL AND LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('transactional','merge')
	BEGIN
		RAISERROR(21014, 16, -1)
		GOTO FAILURE
	END
	
	SELECT optname, value, major_version, minor_version, revision 
		FROM master..MSreplication_options
		WHERE
			optname = @optname OR
			@optname = NULL

	RETURN(0)

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

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

create procedure sp_MSgetreplnick (
	@server		sysname = NULL,
	@db_name	sysname = NULL,
	@pubid		uniqueidentifier  = NULL,
	@nickname	int output
	)
as
	declare @srvid 			int
	
	if @db_name IS NULL
		select @db_name = db_name()

	/* Use 0 if the Server name is not passed in since it would be the local server */
	if @server IS NULL
		select @srvid = 0
	else			
		select @srvid = max(srvid) from master..sysservers where UPPER(srvname) = UPPER(@server) collate database_default

	if (@pubid IS NOT NULL)
		begin
			select @nickname = max(replnickname) from MSmerge_replinfo 
				where repid in (select subid from sysmergesubscriptions
					where srvid = @srvid and db_name = @db_name and pubid = @pubid)
		end
	else
		begin
			select @nickname = max(replnickname) from MSmerge_replinfo 
				where repid in (select subid from sysmergesubscriptions
						where srvid = @srvid and db_name = @db_name)
		end
go

exec dbo.sp_MS_marksystemobject sp_MSgetreplnick
go
grant execute on dbo.sp_MSgetreplnick to public

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

CREATE PROCEDURE sp_MSreplcheck_publish 
AS
BEGIN
    --
    -- reintroducing the sysadmin check as it is 4 times more efficient
    -- than is_member call and reduces performance overhead in case 
    -- the user has sysadmin privileges
    --
    if (is_srvrolemember('sysadmin') = 1 or is_member('db_owner') = 1)
        return 0
    else
    BEGIN
        RAISERROR (21050, 14, -1)
        RETURN (1)
    END
END
GO


raiserror('Creating procedure sp_MSlocktable', 0,1)
go
CREATE PROCEDURE sp_MSlocktable
@ownername		sysname,
@tablename		sysname
AS
	declare @retcode			int
	declare @procname			sysname
	declare @objid 				int
	declare @qualified_name		nvarchar(270)
	select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
	select @objid = object_id(@qualified_name)
	if @objid is NULL
		select @objid = id from sysobjects where name=@tablename
	if @objid is null
		return (1)
	
	exec @retcode = dbo.sp_MSrepl_PAL_rolecheck @objid = @objid 
	if (@retcode <> 0 or @@error <> 0)
	    return 1
	
	select @procname = select_proc from sysmergearticles where objid = @objid and select_proc is not NULL
	exec @retcode = @procname @type = 7
	IF @@ERROR<>0 or @retcode<>0 RETURN (1)

--  exec ('select count(*) from ' + @ownername + '.' + @tablename + ' (tablock holdlock) where 1 = 2')
go
exec dbo.sp_MS_marksystemobject sp_MSlocktable
go
grant execute on dbo.sp_MSlocktable to public
go

raiserror('Creating procedure sp_MSenumcolumns', 0,1)
go
CREATE PROCEDURE sp_MSenumcolumns
	@pubid uniqueidentifier,
	@artid uniqueidentifier
AS
	declare @retcode			int
	declare @procname			sysname
	
	select @procname = select_proc from sysmergearticles where pubid = @pubid and artid = @artid
	exec @retcode = @procname @type =6

go
exec dbo.sp_MS_marksystemobject sp_MSenumcolumns
go
grant execute on dbo.sp_MSenumcolumns to public
go

/*
** Get pubid through connection_ID and check permission of this publication
*/

raiserror('Creating procedure sp_MSsetaccesslist', 0,1)
go
CREATE PROCEDURE sp_MSsetaccesslist
@publication 	sysname,
@publisher 		sysname,
@publisher_db	sysname
AS

-- we don't need to do anything here since we are using role based security
    return 0
go
exec dbo.sp_MS_marksystemobject sp_MSsetaccesslist
go
grant execute on dbo.sp_MSsetaccesslist to public
go
			
--
-- Name: sp_MSreplcheck_pull
--
-- Description: This proc is called publication PAL security check
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure  
--
raiserror('Creating procedure sp_MSreplcheck_pull', 0,1)
go

create procedure sp_MSreplcheck_pull 
(
    @publication sysname,
    @raise_fatal_error bit = 1,
    @pubid uniqueidentifier = NULL,
    @given_login sysname = NULL
)
as
begin
    declare @login sysname
                ,@login_time datetime

    --
    -- initialize
    --
    if (@given_login = N'')
        select @given_login = null
    --
    -- Special processing if explicit login was not provided
    --
    if @given_login is null 
    begin
        --
        -- explict login not provided
        -- sysadmin or db_owner have access
        --
        if (is_srvrolemember('sysadmin') = 1 or is_member('db_owner') = 1)
            return (0)
        --
        -- If spid with publication in the cache, return success.
        --
        select @login_time = login_time from master..sysprocesses where spid = @@spid
        if exists (select login_time 
            from tempdb.dbo.MSpublisher_access 
            where spid = @@spid 
                and login_time = @login_time
                and db_id = db_id() 
                and publication = @publication)
        return (0)
    end
    --
    -- Get the current login
    -- NOTE: why is user_name() not being used
    --
    select @login = suser_sname(suser_sid())
    --
    -- Special processing if explicit login was provided
    --
    if ((@given_login is not null) and (@login <> @given_login))
    begin
        --
        -- To determine whether another login has access to a publication
        -- requires user to be db_owner in the publishing database
        --
        if is_member('db_owner') <> 1
            return (1)
        select @login = @given_login
    end
    --
    -- If we have reached here - means - need to get the publication access
    -- information from distribution db
    --
    declare @has_access bit
                ,@distribdb sysname
                ,@distproc nvarchar (300)
                ,@retcode int
                ,@dist_rpcname sysname
                ,@database sysname

    --
    -- initialize RPC information
    --
    select @database = db_name()
    EXEC @retcode = dbo.sp_helpdistributor 	@rpcsrvname = @dist_rpcname OUTPUT,
                                       	@distribdb   = @distribdb   OUTPUT
    IF @retcode <> 0 or @@error <> 0
    BEGIN
         RAISERROR (14071, 16, -1)
         return (1)
    END
    IF @retcode <> 0 OR @distribdb IS NULL OR @dist_rpcname IS NULL
    BEGIN
        RAISERROR (14071, 16, -1)
        return(1)
    END
    --
    -- Invoke call on distribution db
    --
    SELECT @distproc = RTRIM(@dist_rpcname) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSpublication_access'
    EXEC @retcode = @distproc
                @publisher = @@SERVERNAME,
                @publisher_db = @database,
                @publication = @publication,
                @operation = 'check',
                @login = @login,
                @has_access = @has_access output
    IF @@error <> 0 OR @retcode <> 0
        return (1)
    --
    -- Check access information
    --
    if @has_access = 0
    begin
        -- We don't have access if we reach here, return error
        IF @raise_fatal_error = 1
            RAISERROR (21049, 14, -1, @login, @publication)
        ELSE
            RAISERROR (21049, 10, -1, @login, @publication)
        return(1)
    end
    --
    -- If explicit login is being used - do not cache
    --
    if (@given_login is not null)
        return (0)
    --
    -- If we are here - means - need to add access information to the cache.
    -- Clear the cache to keep it small.
    --
    exec @retcode = dbo.sp_MSflush_access_cache
    if @retcode <> 0 or @@error <> 0
        return (1)
    --
    -- insert entry for this publication access
    --
    insert tempdb.dbo.MSpublisher_access
        (spid, db_id, publication, login_time, pubid) values
        (@@spid, db_id(), @publication, @login_time, @pubid)
    if @@error <> 0
        return (1)
    --
    -- all done
    --
    return (0)
end
GO
exec dbo.sp_MS_marksystemobject sp_MSreplcheck_pull
go
grant execute on dbo.sp_MSreplcheck_pull to public
go

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

CREATE PROCEDURE sp_MSreplcheck_connection
@publication sysname = NULL,
@artid uniqueidentifier = NULL,
@repid uniqueidentifier = NULL,
@pubid uniqueidentifier = NULL,
@objid int				= NULL,
@tablenick int = NULL,
@is_init bit = 0
AS
	-- sysadmin or db_owner have access
	if is_member('db_owner') = 1 
		return 0

	declare @retcode int
	declare @cached_id uniqueidentifier

	-- Need login_time to uniquely identify a connection.
	declare @login_time datetime
	select @login_time = login_time from master..sysprocesses where spid = @@spid

	select @cached_id = pubid from tempdb.dbo.MSpublisher_access where 
		spid = @@spid and
		login_time = @login_time

	-- If spid with publication in the cache, return success.
	if @cached_id is null
	begin
		-- This stored procedure might be called by common sprocs at
		-- both the publisher and the subscriber by the merge agent
		-- The merge agent will call this sp with @is_init = 1 before
		-- any other calls to the publisher. All the other calls will
		-- set @is_init to 0.

		-- it is not a problem if the entry is not found in the cache and 
		-- is_init is set to 0. We should not fail here and instead call
		-- replcheck_pull to make get the cache entry back.
		exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication,
			@pubid = @pubid
		if @retcode <> 0 or @@error <> 0
			begin
				return (1)
			end
	end
	else
	begin
		if @pubid is not null
		begin
			if @pubid <> @cached_id
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end

		end
		else if @tablenick is not null
		begin
			if not exists (select * from sysmergearticles where pubid = @cached_id and 
				nickname = @tablenick)
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end
		end
		else if @artid is not null
		begin
			if not exists (select * from sysmergearticles where pubid = @cached_id and 
				artid = @artid)
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end
		end
		else if @objid is not null
		begin
			if not exists (select * from sysmergearticles where pubid = @cached_id and 
				objid=@objid)
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end
		end
		
		else if @publication is not null
		begin
			if not exists (select * from sysmergepublications where pubid = @cached_id and 
				name = @publication)
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end
		end
		else if @repid is not null
		begin
			if not exists (select * from sysmergesubscriptions where pubid = @cached_id and 
				subid = @repid)
			begin
				RAISERROR (14126, 11, -1)
				return (1)
			end
		end
	end
GO
exec dbo.sp_MS_marksystemobject sp_MSreplcheck_connection
go
grant execute on dbo.sp_MSreplcheck_connection to public
go

raiserror('Creating procedure sp_MSrepl_PAL_rolecheck', 0,1)
go
CREATE PROCEDURE sp_MSrepl_PAL_rolecheck
@publication sysname = NULL,
@artid uniqueidentifier = NULL,
@repid uniqueidentifier = NULL,
@pubid uniqueidentifier = NULL,
@objid int				= NULL,
@tablenick int = NULL
AS
	-- sysadmin or db_owner have access
	if is_member('db_owner') = 1 
		return 0

    if (@pubid is not NULL)
    begin
    	if (1 <> {fn ISPALUSER(@pubid)})
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if (@publication is not NULL)
    begin
    	if not exists (select * from dbo.sysmergepublications where name = @publication and (1 = {fn ISPALUSER(pubid)}))
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if (@artid is not NULL)
    begin
    	if not exists (select * from dbo.sysmergearticles where artid = @artid and (1 = {fn ISPALUSER(pubid)}))
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if (@repid is not NULL)
    begin
    	if not exists (select * from dbo.sysmergesubscriptions where subid = @repid and (1 = {fn ISPALUSER(pubid)}))
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if ((@tablenick is not NULL) and (@tablenick <> 0))
    begin
    	if not exists (select * from dbo.sysmergearticles where nickname = @tablenick and (1 = {fn ISPALUSER(pubid)}))
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if (@objid is not NULL)
    begin
    	if not exists (select * from dbo.sysmergearticles where objid = @objid and (1 = {fn ISPALUSER(pubid)}))
		begin
			RAISERROR (14126, 11, -1)
			return (1)
		end
    end
    else if not exists(select * from dbo.sysmergepublications where (1 = {fn ISPALUSER(pubid)}))
	begin
		RAISERROR (14126, 11, -1)
		return (1)
	end

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


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

create procedure sp_MSreplcheck_qv
as
begin

	set nocount on 
		
	declare @qv_replication varchar(10)
	declare @qv_engine varchar(10)
	declare @qv_value_replication integer
	declare @qv_value_engine integer

	select @qv_replication = '2745196162', @qv_engine = '845129433'

	exec @qv_value_replication = master.dbo.sp_MSinstance_qv @qv_replication 	
	if @@ERROR <> 0 
		select @qv_value_replication = 1

	exec @qv_value_engine = master.dbo.sp_MSinstance_qv @qv_engine
	if @@ERROR <> 0
		select @qv_value_engine = 1

	-- magic number 1 assumes least common setting on all failure states
	select isnull( @qv_value_replication, 1 ) as VALUE_REPLICATION, isnull( @qv_value_engine, 1 ) as VALUE_ENGINE


end
go

exec dbo.sp_MS_marksystemobject sp_MSreplcheck_qv
go	

grant execute on dbo.sp_MSreplcheck_qv to public
go

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

create procedure sp_reinitmergepullsubscription
	@publisher		sysname  = 'all',
	@publisher_db	sysname  = 'all',
	@publication	sysname  = 'all',
	@upload_first	nvarchar(5) = 'FALSE'
AS
	declare @schemaversion			int
	declare @schematype				smallint
	declare @schemaguid				uniqueidentifier
	declare @pubname				sysname
	declare @publisher_name			sysname
	declare @retcode				int
	declare @pubdb					sysname
    declare @pubid					uniqueidentifier
    declare @subid					uniqueidentifier
    declare @artid					uniqueidentifier

    
	/*
	** Security check - Need to be a dbo to call this proc
	*/
	exec @retcode = dbo.sp_MSreplcheck_subscribe
    if @@error<>0 or @retcode<>0
        return (1)
    
	/*
	** Replace 'all' with '%'
	*/
	set nocount on
	if LOWER(@publication) = 'all'
		SELECT @publication = '%'

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

	if LOWER(@publisher_db) = 'all'
		SELECT @publisher_db = '%'
	select @retcode = 0
	/*
	** At subscriber side, we need to qualify the publication with server name and database name
	*/
    IF NOT EXISTS (SELECT * FROM sysmergepublications WHERE name LIKE @publication 
    	and ((@publisher = N'%') or (UPPER(publisher) = UPPER(@publisher))) 
    	and ((@publisher_db = N'%') or (publisher_db = @publisher_db)) )
    	
        BEGIN
        IF @publication = '%'
                RAISERROR (14008, 11, -1)
        ELSE
                RAISERROR (20026, 11, -1, @publication)
        RETURN (1)
        END

	if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS) not in ('true', 'false')
	begin
		raiserror(14148, 16, -1, '@upload_first')
		return (1)
	end
	Declare SYN_CUR CURSOR LOCAL FAST_FORWARD FOR 
		select subs.subid, pubs.name, pubs.publisher, pubs.publisher_db
			from sysmergepublications pubs, sysmergesubscriptions subs
				where pubs.name LIKE  @publication
					AND ((@publisher = '%') OR (UPPER(pubs.publisher) = UPPER(@publisher)))
                                        AND ((@publisher_db = N'%') OR (pubs.publisher_db = @publisher_db))
					AND pubs.pubid=subs.pubid
					AND subs.pubid<>subs.subid
	FOR READ ONLY
	open SYN_CUR
	fetch SYN_CUR into @subid, @pubname, @publisher_name, @pubdb
	while (@@fetch_status<>-1)
	BEGIN	
		
		-- do not update schemaversion if the initial snapshot has never been applied.
		update MSmerge_replinfo set schemaversion=-1, recgen = NULL, recguid=NULL, 
			sentgen=NULL, sentguid = NULL where repid=@subid and schemaversion is not null

		if (@@rowcount <> 0)
		begin
			if LOWER(@upload_first collate SQL_Latin1_General_CP1_CS_AS)='true'
				update sysmergesubscriptions set status=5 where subid=@subid
			else
				exec @retcode=sp_MSCleanupForPullReinit @publication=@pubname,
											  @publisher=@publisher_name,
											  @publisher_db=@pubdb
			if @retcode<>0 or @@ERROR<>0
			begin
				return (1)
			end
		end

		fetch next from SYN_CUR into @subid, @pubname, @publisher_name, @pubdb	
			-- so that it won't be treated as a new susbscription	
	END
	close SYN_CUR
	deallocate SYN_CUR
	-- Forget that publisher ever sent us any generations.  They must be resent.
	-- Publication cleanup will remove the genhistory rows.

	if @publication = '%'
		-- get them all
		update MSmerge_replinfo set recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
	else
		begin
		select @pubid = pubid from sysmergepublications where name = @publication
		update MSmerge_replinfo set recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL
			where repid in (select subid from sysmergesubscriptions where pubid = @pubid)
		end
GO

exec dbo.sp_MS_marksystemobject sp_reinitmergepullsubscription
go	
grant execute on dbo.sp_reinitmergepullsubscription to public
go
raiserror('Creating procedure sp_MSreplcheck_subscribe', 0,1)
go

CREATE PROCEDURE sp_MSreplcheck_subscribe
AS
BEGIN
    --
    -- reintroducing the sysadmin check as it is 4 times more efficient
    -- than is_member call and reduces performance overhead in case 
    -- the user has sysadmin privileges
    --
    if (is_srvrolemember('sysadmin') = 1 or is_member('db_owner') = 1)
        return 0
    else
    BEGIN
        RAISERROR (21050, 14, -1)
        RETURN (1)
    END
END
GO

raiserror('Creating procedure sp_MSreplicationcompatlevel', 0,1)
GO
create procedure sp_MSreplicationcompatlevel
@dbname 			sysname,
@cmptlevel			float(8)
As
	declare		@is_distdb	smallint

	select @is_distdb = 0

	IF EXISTS (select * from msdb..sysobjects where name='MSdistributiondbs')
		begin
			IF EXISTS (SELECT * FROM msdb..MSdistributiondbs where name=@dbname)
				select @is_distdb = 1
		end
		
	/*
	** Parameter check
	** @dbname
	*/
	IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE
		name = @dbname collate database_default)
	BEGIN
		RAISERROR(15010, 16, -1, @dbname)
		RETURN(2)
	END

	select @dbname = QUOTENAME(@dbname)

	/*
	** Parameter check. NOTE
	** @cmptlevel
	*/
	IF @cmptlevel<6.0
	BEGIN
    	RAISERROR(20060,16,-1)
		RETURN(2)
	END

	/*
	** If cmptlevel is lower than 7.0, special attention should be paid. 
	** If current database is a distribution database or is involed in merge
	** replication, then it can not be set to a level lower than 7.0.
	*/
	
	create table #tmp (any_merge smallint NOT NULL)
	insert into #tmp exec ('select count(*) from ' + @dbname + '..sysobjects where name=' + '''sysmergesubscriptions''' )
	if (exists(select any_merge from #tmp where any_merge>0) OR @is_distdb = 1) 
				AND (@cmptlevel<7.0) 
		begin
			drop table #tmp
			return 1
		end
	else 
		begin
			drop table #tmp
			return 0
		end
go

exec dbo.sp_MS_marksystemobject sp_MSreplicationcompatlevel
go


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

create procedure sp_MShelp_identity_property
			@tablename	sysname,
			@ownername	sysname = NULL
AS
declare @qualified_name		nvarchar(270)
declare @objid				int
declare @retcode			int
declare @proc				nvarchar(300)
declare @distributor		sysname
declare @distribdb			sysname
declare @publisher			sysname
declare @publisherdb		sysname
declare @pub_range			bigint
declare @sub_range			bigint
declare @threshold			int
declare @artid				int
declare @next_seed			bigint
declare @current_max		bigint
declare @replicated_already	bit
declare @auto_identity_support int
declare @identity_incr		int 
declare	@current_identity	bigint
declare @max_identity		bigint	
declare @xprec				int
declare @xtype				int
declare @republishing		bit
declare @length				int

select @replicated_already = 0
select @auto_identity_support = NULL

select @republishing = 0

select @pub_range	= NULL
select @sub_range	= NULL
select @threshold	= NULL
select @next_seed	= NULL
select @current_max	= NULL

if @ownername is not NULL
begin
	select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename)
	select @objid = object_id(@qualified_name)
end
else
begin
	select @qualified_name = QUOTENAME(@tablename)
	select @objid = id from sysobjects where name=@tablename
end
if @objid is NULL
begin
	raiserror(14027, 16, -1, @tablename)
	return (1)
end

if OBJECTPROPERTY(@objid, 'tablehasidentity') <> 1
	begin
		raiserror(21194, 16, -1)
		return (1)
	end

select @xtype=xtype, @xprec=xprec, @length=length from syscolumns where id=@objid and columnproperty(id, name, 'IsIdentity')=1

select @max_identity = case @xtype 
					 when 52 then power((convert(bigint,2)), 8*2 -1) - 1 --smallint 
					 when 48 then power((convert(bigint,2)), 8 - 1) - 1 		 --tinyint
					 when 56 then power((convert(bigint,2)), 8*4 - 1) - 1 		 --int
					 when 127 then power((convert(bigint,2)), 62) -1 + power((convert(bigint,2)), 62) 		 --bigint
						else power((convert(bigint,2)), 62) - 1 + power((convert(bigint,2)), 62)  			 --bigint;.
					end

if (@xtype=108 or @xtype=106) and @xprec<18
	select @max_identity = power((convert(bigint,10)), (@xprec+1)) - 1

select @identity_incr = IDENT_INCR(@qualified_name)
select @current_identity =  ident_current(@qualified_name)

if exists (select * from sysobjects where name='sysmergearticles')
	begin
		if exists (select * from sysmergearticles where objid=@objid)
			begin
				select @replicated_already = 1
				select @auto_identity_support = identity_support from sysmergearticles where objid=@objid
				if not exists (select * from sysmergearticles where objid=@objid and pubid in
					(select pubid from sysmergepublications where publisher_db=db_name() 
						and LOWER(publisher)=LOWER(@@SERVERNAME)))
					select @republishing = 1
			end
	end	

if exists (select * from sysobjects where name='sysarticles')
	begin
		if exists (select * from sysarticles where objid=@objid)
			begin
				select @replicated_already = 1
				select @artid = artid from sysarticles where objid=@objid
				select @auto_identity_support = identity_support from sysarticleupdates where artid=@artid
			end
	end

if @auto_identity_support is NOT NULL and @auto_identity_support=1
begin
	if @republishing = 0
	begin
		select @pub_range	= 0
		select @sub_range	= 0
		select @threshold	= 0
		select @next_seed	= 0
		select @current_max	= 0
		select @publisher=@@SERVERNAME
		select @publisherdb=db_name()

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

		IF @distribdb is null
			BEGIN
				RAISERROR (14071, 16, -1)
				RETURN (1)
			END
									 
		SELECT @proc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_pub_identity'
		exec @retcode = @proc 	@publisher=@publisher, 
						@publisher_db=@publisherdb,  
						@tablename=@tablename,
						@current_max=@current_max OUTPUT,
						@pub_range=@pub_range OUTPUT,
						@range = @sub_range OUTPUT,
						@threshold=@threshold OUTPUT,
						@next_seed = @next_seed OUTPUT
		if @retcode<>0 or @@ERROR<>0
			return (1)

		-- Tran pub range is not stored at the distributor
		if @pub_range = 0
		begin
			if object_id('MSpub_identity_range') is not null
			begin
				select @pub_range = pub_range from MSpub_identity_range where
					objid = @objid 
			end
		end
	end
	else
	begin
		select @next_seed=next_seed, @max_identity=max_identity, @pub_range=(max_identity-next_seed)*2/10, 
				@sub_range=(max_identity-next_seed)/10,
				@threshold=80 from MSrepl_identity_range where objid=@objid
	end
end
SELECT 'replicated' = @replicated_already, 
	   'auto_identity_support' = @auto_identity_support, 
	   'identity_incremental' = @identity_incr, 
	   'current_identity' = @current_identity,
	   'next_starting_seed' = @next_seed, 
	   'max_identity' = @max_identity, 
	   'publisher_range' = ABS(@pub_range), 
	   'subscriber_range' = ABS(@sub_range), 
	   'threshold' = @threshold,
	   'in_repulishing' = @republishing
GO
exec dbo.sp_MS_marksystemobject sp_MShelp_identity_property
go
grant execute on dbo.sp_MShelp_identity_property to public
GO

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

create procedure sp_MSgenreplnickname
			@srcguid	uniqueidentifier,	/* Source Guid */
			@repnick	int	output	/* nickname */
	as
	declare @binguid binary(16)
	declare	@nickname		int
	set @binguid = convert(binary(16), @srcguid)
	select @nickname = convert(int, convert(binary(4),substring( convert(nchar(8),@binguid), 1, 2)))
	while exists (select replnickname from MSmerge_replinfo where replnickname = @nickname) or
			(@nickname > 0 and @nickname <= 256)
	begin
		select @nickname = @nickname + 1
	end
	select @repnick = @nickname
go

exec dbo.sp_MS_marksystemobject sp_MSgenreplnickname
go
grant execute on dbo.sp_MSgenreplnickname to public

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

CREATE PROCEDURE sp_MSmergesubscribedb(
	@value sysname
	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @retcode 				int
	

    /*
    ** Security Check
    */

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


	/*
	** Initialization
	*/


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

	IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		BEGIN		
			execute @retcode = dbo.sp_MScreate_mergesystables
			if @@ERROR <> 0 or @retcode <> 0
				begin
					return (1)
				end
		END
	
	-- We assume we will do nothing about disabling a subscriber
	
GO

exec dbo.sp_MS_marksystemobject sp_MSmergesubscribedb
go

grant execute on dbo.sp_MSmergesubscribedb to public
go 

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

CREATE PROCEDURE sp_MSenumallsubscriptions(
@subscription_type	nvarchar(5) = 'push', 
@subscriber_db		sysname='%'
)AS

	set nocount on
	declare @current_db		sysname
	declare @retcode		int
	declare @proc			nvarchar(200)
	declare @db_status		int

	create table #MSenumallsubscriptions (
						publisher			sysname collate database_default not null,
						publisher_db		sysname collate database_default not null,
						publication			sysname collate database_default null,
						replication_type	int not NULL,
						subscription_type	int not NULL,
						last_updated		datetime null,
						subscriber_db		sysname collate database_default not null,
						update_mode			smallint null,
						last_sync_status	int null,
						last_sync_summary	sysname collate database_default null,
						last_sync_time		datetime null
						)

	declare #cur_db cursor local FAST_FORWARD FOR select DISTINCT name, status
		FROM master.dbo.sysdatabases where ((@subscriber_db = N'%' collate database_default) or (name = @subscriber_db collate database_default)) and
			has_dbaccess(name) = 1
	open #cur_db
	fetch #cur_db into @current_db, @db_status
	while (@@fetch_status <> -1)
	begin
		/*
		 * we only return subscriptions in db which is not in loading (0x20), suspect(0x100),
		 * offline(0x200), in recovering(0x80), shutdown(0x40000), not recovered(0x40)
		 */
		if (@db_status & 0x403e0) = 0
			begin
				select @proc = QUOTENAME(@current_db) + '.' + 'dbo.sp_MSenumsubscriptions ' 
				insert into #MSenumallsubscriptions exec @retcode = @proc  @subscription_type
				if @@ERROR<>0 or @retcode<>0
					begin
						close #cur_db
						deallocate #cur_db
						return (1)
					end
			end
		fetch next from #cur_db into @current_db, @db_status
	end
    select  distinct 'publisher'				= publisher,
            'publishing database'	= publisher_db,
            'publication'			= publication,
            'replication type'		= replication_type,
            'subscription type'     = subscription_type,
			'last updating time'	= convert(nvarchar(12), last_updated, 112) + 
                                          substring(convert(nvarchar(24), last_updated, 121), 11,13),
			'subscribing database'  = subscriber_db,
			'update_mode'           = update_mode,
			'last sync status'		= last_sync_status,
			'last sync summary'		= last_sync_summary,
			'last sync time'		= convert(nvarchar(12), last_sync_time, 112) + 
				substring(convert(nvarchar(24), last_sync_time, 121), 11,13)
	from #MSenumallsubscriptions
	--drop table #MSenumallsubscriptions
	close #cur_db
	deallocate #cur_db
	return (0)
Go
grant execute on dbo.sp_MSenumallsubscriptions to public
go 
exec dbo.sp_MS_marksystemobject sp_MSenumallsubscriptions
GO

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

CREATE PROCEDURE sp_MSenumsubscriptions(
@subscription_type	nvarchar(5) = 'push',
@publisher		sysname = '%',
@publisher_db 	sysname = '%'
)AS

	set nocount on
	declare @dbname		sysname
	declare @category 	int
	declare @proc			nvarchar(200)
	declare @retcode	int
	declare @cur_db		sysname
	declare @type_value	int

	select @type_value = 100
	
	if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='push'
		select @type_value = 0
	else
		if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='pull'
			select @type_value = 1
		else
			if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS)='both'
				select @type_value = 2

	select @cur_db = db_name()
	
	create table #MSenumpushsubscriptions (
						publisher			sysname collate database_default not null,
						publisher_db		sysname collate database_default not null,
						publication			sysname collate database_default null,
						replication_type	int not NULL,
						subscription_type	int not NULL,
						last_updated		datetime null,
						subscriber_db		sysname collate database_default not null,
						update_mode			smallint null,
						last_sync_status	int null,
						last_sync_summary	sysname collate database_default null,
						last_sync_time		datetime null
						)

	if exists (select * from sysobjects where name='sysmergesubscriptions')
	begin
		-- return all subscriptions that this database is a subscriber to
		-- suppress all subscriptions that originate from this database.
		insert into #MSenumpushsubscriptions select p.publisher, p.publisher_db, p.name, 2, 
			s.subscription_type, s.last_sync_date, s.db_name, 
			NULL, s.last_sync_status, s.last_sync_summary, s.last_sync_date
			from sysmergepublications p, sysmergesubscriptions s
			where p.pubid = s.pubid 
			and (s.subscription_type=@type_value OR @type_value=2) 
			and s.pubid <> s.subid 
			and ((@publisher = N'%') or (p.publisher = @publisher))
           	and ((@publisher_db = N'%') or ( p.publisher_db = @publisher_db))
			and s.db_name = @cur_db
			and p.pubid not in 
				(select pubid from sysmergepublications pubs where 
					lower(pubs.publisher) = LOWER(@@servername) AND
					pubs.publisher_db = @cur_db)
	end

	if exists (select * from sysobjects where name='MSreplication_subscriptions')
	begin
		if  exists (select * from sysobjects where name='MSsubscription_properties') and
			exists (select * from sysobjects where name='MSsubscription_agents ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				case isnull(p.publication_type,0) when 0 then 0 else 1 end,
				s.subscription_type,
				s.time, @cur_db, 
				-- NOTE: For Queued case: we will always return 2/3 for the 4/5 case
				-- since we overload update_mode based on queue_type
				case when isnull(a.update_mode,0) = 4 then 2
				when isnull(a.update_mode,0) = 5 then 3
				else isnull(a.update_mode,0)
				end,
				a.last_sync_status,
				a.last_sync_summary,
				a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_agents a with (NOLOCK) 
					on (UPPER(s.publisher) = UPPER(a.publisher) and 
						s.publisher_db = a.publisher_db and 
						((s.publication = a.publication and 
						s.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and s.independent_agent = 0)) and
						s.subscription_type = a.subscription_type)
				left outer join MSsubscription_properties p with (NOLOCK)
					on (UPPER(s.publisher) = UPPER(p.publisher) and 
						s.publisher_db = p.publisher_db and 
						s.publication = p.publication and
						-- don't use property table for push. 
						s.subscription_type <> 0) 
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
		-- Property table does not exists.
		else if exists (select * from sysobjects where name='MSsubscription_agents ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				-- Property table does not exists. Say transactional.
				0,
				s.subscription_type,
				s.time, @cur_db, 
				-- NOTE: For Queued case: we will always return 2/3 for the 4/5 case
				-- since we overload update_mode based on queue_type
				case when isnull(a.update_mode,0) = 4 then 2
				when isnull(a.update_mode,0) = 5 then 3
				else isnull(a.update_mode,0)
				end,
				a.last_sync_status,
				a.last_sync_summary,
				a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_agents a with (NOLOCK) 
					on (UPPER(s.publisher) = UPPER(a.publisher) and 
						s.publisher_db = a.publisher_db and 
						((s.publication = a.publication and 
						s.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and s.independent_agent = 0)) and
						s.subscription_type = a.subscription_type)
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 			
		end
		-- Agents table does not exists.
		else if exists (select * from sysobjects where name='MSsubscription_properties ') 
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				case isnull(p.publication_type,0) when 0 then 0 else 1 end,
				s.subscription_type,
				s.time, @cur_db, 
				s.update_mode,
				NULL, --a.last_sync_status,
				NULL, --a.last_sync_summary,
				NULL  --a.last_sync_time	
				from MSreplication_subscriptions s with (NOLOCK) 
				left outer join MSsubscription_properties p with (NOLOCK)
					on (UPPER(s.publisher) = UPPER(p.publisher) and 
						s.publisher_db = p.publisher_db and 
						s.publication = p.publication and
						-- don't use property table for push. 
						s.subscription_type <> 0) 
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
		-- Both table does not exists
		else
		begin
			-- update_mode in MSreplication_subscriptions table is not reliable.
			insert into #MSenumpushsubscriptions select s.publisher, s.publisher_db, s.publication,
				0,
				s.subscription_type,
				s.time, @cur_db, 
				s.update_mode,
				NULL, -- a.last_sync_status,
				NULL, -- a.last_sync_summary
				NULL  -- a.last_sync_time
				from MSreplication_subscriptions s with (NOLOCK)
				where
					((@publisher = N'%') OR (UPPER(s.publisher) = UPPER(@publisher))) AND
					((@publisher_db = N'%') or ( s.publisher_db = @publisher_db)) and
					((s.subscription_type = 0 and @type_value = 0) or
					-- For pull, return both pull and anonymous
					(s.subscription_type <> 0 and @type_value = 1) or
					@type_value = 2) 
		end
	
	end
	select * from #MSenumpushsubscriptions
	--drop table #MSenumpushsubscriptions
	return (0)
GO

grant execute on dbo.sp_MSenumsubscriptions to public
go 
exec dbo.sp_MS_marksystemobject sp_MSenumsubscriptions
GO

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

CREATE PROCEDURE sp_MSenumallpublications(
@publisherdb sysname = '%', 
@replication_type tinyint = null, -- by default return all types of publication
@agent_login sysname = NULL,
@security_check bit = 1, -- Security check by default so that things depending on security 
                        -- filtering will not break immediately
@vendor_name sysname = NULL,	-- Use vender name to filter the result of third party publications.
@publication sysname = NULL
)
as
BEGIN
	set nocount on
	declare @dbname 		sysname
	declare @trans 			tinyint
	declare @merge 			tinyint
	declare @3rdparty		tinyint
	declare @retcode		int
	DECLARE @dist_rpcname	sysname
	declare @distribdb		sysname
	declare @login			sysname
	declare @proc			nvarchar(255)
	declare @distbit		int
	declare @is_user_admin	bit
	declare @same_as_user	bit

	-- UI: If the distributor is not installed, return empty result
    if not exists (SELECT * FROM master.dbo.sysservers
              WHERE  srvstatus & 8 <> 0)
		return (0)

    -- UI: Win95 subscriber will send in null agent_login
    -- Assume the agent login to be the current login if it is NT login
    if @security_check = 1 and @agent_login is null
        and not exists (select * from master.dbo.syslogins where
            sid = suser_sid() and 
            isntname = 0)
        select @agent_login = suser_sname(suser_sid())

	/* Initializations */
	select @trans = 1 
	select @merge = 2
	select @3rdparty = 0
	select @login = suser_sname(suser_sid())
    SELECT @distbit = 16
	select @is_user_admin = 0
	select @same_as_user = 0

	-- Get publication list
	create table #pubdbs (publisher_db sysname collate database_default not null, replication_type int NOT NULL)
	create table #MSenumpublications 
			(publisher_db sysname collate database_default not null, publication sysname collate database_default not null, replication_type tinyint NOT NULL, 
			immediate_sync bit NOT NULL, allow_pull bit NOT NULL, allow_anonymous bit NOT NULL, 
			enabled_for_internet bit NOT NULL, repl_freq tinyint NOT NULL, immediate_sync_ready bit NOT NULL, 
			allow_sync_tran bit NOT NULL, independent_agent bit NOT NULL, is_db_owner int NOT NULL, 
			thirdparty_flag bit NOT NULL, vendor_name sysname collate database_default null, publisher sysname collate database_default null, 
			description nvarchar(255) collate database_default null, distribution_db sysname collate database_default null, 
			allow_queued_tran bit not null, allow_dts bit not null, thirdparty_options int null,
			queue_type int null, dynamic_filters bit not null default 0)
	create table #admin_publications (publisher_db sysname collate database_default not null, 
		publication sysname collate database_default not null)
	create table #agent_publications (publisher_db sysname collate database_default not null,
		publication sysname collate database_default not null)

	/* Return everything if @replication_type is not in (@3rdparty, @trans, @merge) */
	if not @replication_type in (@3rdparty, @trans, @merge)
		select @replication_type = null

	if @replication_type = @trans or @replication_type is null
		insert into #pubdbs select name, @trans from master.dbo.sysdatabases where 
			((@publisherdb = N'%') or ( name = @publisherdb collate database_default)) and category & 1 <> 0 and 
			has_dbaccess(name) = 1
	if @replication_type = @merge or @replication_type is null
		insert into #pubdbs select name, @merge from master.dbo.sysdatabases where 
			((@publisherdb = N'%') or ( name = @publisherdb collate database_default)) and category & 4 <> 0 and 
			has_dbaccess(name) = 1
	if @replication_type = @3rdparty
		insert into #pubdbs select name, @3rdparty from master.dbo.sysdatabases where 
			((@publisherdb = N'%') or ( name = @publisherdb collate database_default)) and category & @distbit <> 0 and 
			has_dbaccess(name) = 1

	declare hCForEachDb CURSOR LOCAL FAST_FORWARD FOR select publisher_db, replication_type from  #pubdbs
	FOR READ ONLY
	open hCForEachDb
	fetch hCForEachDb into @dbname, @replication_type
	/* Loop for each database */
	while (@@fetch_status >= 0) 
	begin
		if (@replication_type) = @trans
			select @proc = quotename(@dbname) + '.dbo.sp_MSenumtranpublications'
		else if (@replication_type) = @merge
			select @proc = quotename(@dbname) + '.dbo.sp_MSenummergepublications'
		else if (@replication_type) = @3rdparty
			select @proc = quotename(@dbname) + '.dbo.sp_MSenum3rdpartypublications'
		if (@replication_type) = @3rdparty
			insert into #MSenumpublications exec @retcode = @proc @vendor_name, @publication
		else
			insert into #MSenumpublications exec @retcode = @proc @publication

		if @@ERROR <> 0 or @retcode <> 0
			return (1)
		fetch hCForEachDb into @dbname, @replication_type
	end /* while FETCH_SUCCESS */

	-- Prepare for filtering.
	IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = 'MSdistpublishers' and xtype = 'U') -- this is the distributor, check if publisher too
		if not exists (select * from msdb.dbo.MSdistpublishers where upper(name) = upper(@@SERVERNAME) collate database_default) -- not publisher
			select @security_check = 0 	-- no need to go through security check for none-publisher 
							-- since it won't have any publication other than third party ones.
							
    IF (@security_check <> 0)
    BEGIN	
        EXEC @retcode = dbo.sp_helpdistributor 	@rpcsrvname = @dist_rpcname OUTPUT,
                                           	@distribdb   = @distribdb   OUTPUT

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

        IF @distribdb is null
        BEGIN
            RAISERROR (14071, 16, -1)
            RETURN (1)
        END

        SELECT @proc = RTRIM(@dist_rpcname) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSpublication_access'

		-- Optimization
		if is_srvrolemember('sysadmin') = 1
			select @is_user_admin = 1
		else
			insert into #admin_publications EXEC @retcode = @proc
				 @publisher = @@SERVERNAME,
				 @operation = 'get_publications',
				 @login = @login

		if suser_sid(@agent_login) = suser_sid()
			select @same_as_user = 1
		else
			insert into #agent_publications EXEC @retcode = @proc
				@publisher = @@SERVERNAME,
				@operation = 'get_publications',
				@login = @agent_login
		
    END -- IF (@security_check <> 0) 

	-- commit open tran in case 
	-- insert into exec failed.
	while(@@trancount <> 0) commit tran

	select pub.publisher_db, pub.publication, pub.replication_type, 
			pub.immediate_sync, pub.allow_pull, pub.allow_anonymous, 
			pub.enabled_for_internet, pub.repl_freq, pub.immediate_sync_ready, 
			pub.allow_sync_tran, pub.independent_agent, N'agent_access' = case 
				when 
					(@same_as_user = 1 or
					exists (select * from #agent_publications agent where
					agent.publisher_db = pub.publisher_db and
					agent.publication = pub.publication))
					then convert(bit,1)
				else convert(bit,0)
				end,
			pub.thirdparty_flag,
			pub.vendor_name, pub.publisher, pub.description, pub.distribution_db, 
			allow_queued_tran, allow_dts, pub.thirdparty_options, pub.queue_type, pub.dynamic_filters
	 from #MSenumpublications pub where exists (select * from #admin_publications admin where
		pub.publisher_db = admin.publisher_db and
		pub.publication = admin.publication) or
        @security_check = 0 or
		pub.is_db_owner = 1 or
		@is_user_admin = 1
	 order by pub.publication, pub.publisher_db

	return (0)
END
go

grant execute on dbo.sp_MSenumallpublications to public
go 

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

CREATE PROCEDURE sp_MSenumtranpublications (
@publication sysname
)
as
BEGIN
	set nocount on
	select db_name(), name, 1, immediate_sync, allow_pull, allow_anonymous, 
		enabled_for_internet, repl_freq, immediate_sync_ready, 
		allow_sync_tran, independent_agent, is_member('db_owner'),
		0, -- thirdparty
		'Microsoft SQL Server', @@servername, description,
		convert(sysname, null),
        allow_queued_tran,
        allow_dts
		,convert(int,null) -- thirdparty_options
		,queue_type
        ,0 -- dynamic_filters
		from syspublications pubs
		where exists (select * from sysextendedarticlesview art where pubs.pubid = art.pubid) 
			and status <> 0
			and (pubs.name = @publication or @publication is null)
END
go

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

CREATE PROCEDURE sp_MSenummergepublications (
@publication sysname
)
as
BEGIN
	declare @publisher			sysname
	declare @publisher_db		sysname

	select @publisher=@@SERVERNAME
	select @publisher_db=db_name()
	
	set nocount on
	select db_name(), name, 2, 1, allow_pull, allow_anonymous, enabled_for_internet, 0, snapshot_ready, 0, 1, is_member('db_owner'),
		0, --thirdparty
		'Microsoft SQL Server', publisher, description,
		convert(sysname, null),
        convert(bit,0), --allow_queued_tran
        convert(bit,0) --allow_dts
		,convert(int, null) -- thirdparty_options
		,convert(int, null) -- queue_type
        ,dynamic_filters 
		from 
		sysmergepublications p where status <> 0 
		and LOWER(publisher)=LOWER(@publisher) 
		and publisher_db=@publisher_db
		and (p.name = @publication or @publication is null)

END
go

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

CREATE PROCEDURE sp_MSenum3rdpartypublications (
	@vendor_name sysname,
	@publication sysname
)
as
BEGIN
	set nocount on
	select pubs.publisher_db, publication, 
		case when publication_type <> 2 then 1
		else 2
		end,  --replication_type, 1 tran, 2 merge ; pub type 0 tran 1 snapshot, 2 merge
		immediate_sync, allow_pull, allow_anonymous, 
		0,	--enabled_for_internet,
		case when publication_type = 0 then 0
		else 1
		end,  --repl_freq, 
		1,	--immediate_sync_ready, always return 1 so that UI will not warn
		0,	-- allow_sync_tran, 
		independent_agent, 
		is_member('db_owner'),
		1, --thirdparty
		pubs.vendor_name,
		srv.srvname,
		pubs.description,
		db_name(),
        convert(bit,0), --allow_queued_tran
        convert(bit,0) --allow_dts
		,thirdparty_options
		,convert(int, null) -- queue_type
        ,0 -- dynamic_filters
		from MSpublications pubs, master..sysservers srv
		where exists (select * from MSarticles art where 
				pubs.publication_id = art.publication_id)  and
			thirdparty_flag <> 0 and
			publisher_id = srvid and
			(@vendor_name <> 'others' and vendor_name = @vendor_name or 
			 @vendor_name  = 'others' and (vendor_name is null or vendor_name = '') or
			 @vendor_name is null ) and
			 (pubs.publication = @publication or @publication is null)
END
go


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

CREATE PROCEDURE sp_MSenumthirdpartypublicationvendornames(
@within_db bit = 0
)

as
	set nocount on
	if @within_db = 0
	begin
		declare @dbname 		sysname
		declare @retcode		int
		declare @distbit		int
		declare @proc			nvarchar(300)

		--init
		SELECT @distbit = 16

		-- Get publication list
		create table #pubdbs (publisher_db sysname collate database_default not null)

		insert into #pubdbs select name from master..sysdatabases where 
			category & @distbit <> 0 and 
			has_dbaccess(name) = 1

		create table #MSenumpublications 
				(vendor_name sysname collate database_default not null)

		declare hCForEachDb CURSOR LOCAL FAST_FORWARD FOR select publisher_db from  #pubdbs
		FOR READ ONLY
		open hCForEachDb
		fetch hCForEachDb into @dbname
		/* Loop for each database */
		while (@@fetch_status >= 0) 
		begin
			select @proc = quotename(@dbname) + 
				'.dbo.sp_MSenumthirdpartypublicationvendornames'
			insert into #MSenumpublications exec @retcode = @proc 1
			if @@ERROR <> 0 or @retcode <> 0
				return (1)
			fetch hCForEachDb into @dbname
		end /* while FETCH_SUCCESS */
	end
	else
	begin
		select distinct vendor_name from MSpublications where thirdparty_flag = 1 and
			vendor_name is not null and vendor_name <> ''
	end

	select distinct vendor_name from #MSenumpublications  order by vendor_name

	return (0)
go

grant execute on dbo.sp_MSenumthirdpartypublicationvendornames to public
go 

dump tran master with no_log
GO

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

CREATE PROCEDURE sp_reinitpullsubscription (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname = 'all'   					/* publication name */
    )AS

	SET NOCOUNT ON
    
	declare @subscription_type int	
	declare @sync_type tinyint
	/*
    ** Security Check
    */
	
  	declare @retcode 	int  
	EXEC @retcode = dbo.sp_MSreplcheck_subscribe
	IF @@ERROR <> 0 or @retcode <> 0
		RETURN(1)

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

    IF @publisher = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher

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

    /*
    ** Parameter Check: @publisher_db
    */

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

    IF @publisher_db = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher_db

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

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

    IF LOWER(@publication) = 'all'
		select @publication = '%'
	ELSE
	BEGIN
		EXECUTE @retcode = dbo.sp_validname @publication

		IF @@ERROR <> 0 OR @retcode <> 0
		RETURN (1)
	END
		
    IF NOT EXISTS (SELECT * FROM  MSreplication_subscriptions 
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
					  publication like @publication )
	BEGIN
			RAISERROR(14135, 11, -1,  @publisher, @publisher_db, @publication)
			RETURN(1)
	END
		
	select @sync_type = immediate_sync 
		from MSreplication_subscriptions
    	WHERE UPPER(publisher) = UPPER(@publisher) AND publisher_db  = @publisher_db AND publication like @publication 

	IF @sync_type = 0
	BEGIN
		raiserror(21059, 16, -1)
		return (1)
	END
		
	UPDATE MSreplication_subscriptions set 
		transaction_timestamp = 0x00
		WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
					  publication like @publication 
	if @@ERROR<>0 
		RETURN (1)

	-- Reset the attach state so that the distribution agent will not adjust attach state.
	if @publication <> '%'
	begin
		select @subscription_type = subscription_type from MSreplication_subscriptions
			WHERE UPPER(publisher) = UPPER(@publisher) AND
						  publisher_db  = @publisher_db AND
						  publication = @publication and
						  -- Don't do this for push
						  subscription_type <> 0
		if @subscription_type is not null
		begin
			exec @retcode = dbo.sp_MSreset_attach_state 
				@publisher = @publisher,
				@publisher_db = @publisher_db,
				@publication = @publication,
				@subscription_type = @subscription_type
			if @retcode <> 0 or @@error <> 0
				return (1)
		end
	end
GO

grant execute on dbo.sp_reinitpullsubscription to public
go
    
raiserror('Creating procedure sp_addpullsubscription', 0,1)
go

CREATE PROCEDURE sp_addpullsubscription (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,    /* publication name */
	@independent_agent nvarchar(5) = 'true',  /* true or false */
	@subscription_type nvarchar(9) = 'anonymous',     /* subscription_type, pull or anonymous */
	@description nvarchar(100) = NULL,
	-- SyncTran
	@update_mode          nvarchar(15) = 'read only', -- 'sync tran', 'queued tran', 'failover'
	@immediate_sync		bit = 1
) AS
BEGIN

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @retcode int
    DECLARE @subscription_type_id int   /* 1 = pull, 2 = anonymous */
	DECLARE @independent_agent_id bit
	-- SyncTran
	DECLARE @update_mode_id     tinyint 

	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
	begin
		raiserror(21211, 16, -1)
		return 1
	end

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

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

    /*
    ** Initializations.
    */

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

    IF @publisher = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher

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

    /*
    ** Parameter Check: @publisher_db
    */

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

    IF @publisher_db = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END

    EXECUTE @retcode = dbo.sp_validname @publisher_db

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

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

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

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

    IF LOWER(@independent_agent collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @independent_agent_id = 1
    ELSE SELECT @independent_agent_id = 0
    /*
    ** Parameter Check:  @subscription_type
    ** The @status value can be:
    **
    **      type_id            type
    **      ======            ========
	**			 0			  push
    **           1            pull
    **           2            anonymous
	**
	**	Note: @subscription_type = push is only used by distribution agents
    */
	
    IF @subscription_type IS NULL OR LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull','anonymous')
    BEGIN
        RAISERROR (20016, 16, -1)
        RETURN (1)
    END


    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'pull'    
		SELECT @subscription_type_id = 1
    ELSE IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'anonymous'  
		SELECT @subscription_type_id = 2
	ELSE
		SELECT @subscription_type_id = 0

	IF @independent_agent_id = 0 AND @subscription_type_id = 2
	BEGIN
		RAISERROR (21026, 16, -1)
		RETURN (1)
	END

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

	-- Anonymous subscriptions should not be allowed to 
	-- subscribe with 'synctran option'	
    IF LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) in ('sync tran', 'queued tran', 'failover') and
        @subscription_type_id = 2 
    begin					  
       	RAISERROR (21057, 16, -1)
		RETURN (1)
	end

	select @update_mode_id = 
	case
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'sync tran' then 1
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'queued tran' then 4
		when LOWER(@update_mode collate SQL_Latin1_General_CP1_CS_AS) = 'failover' then 5
		else 0
    end


	begin tran
    save TRAN addpullsubscription
	
    /* 
	** Check to see if MSreplication_subscriptions and MSsubscription_properties 
	** tables exists.
	** If not, create it.
	*/

	exec @retcode = dbo.sp_MScreate_sub_tables
		@tran_sub_table = 1,
		@property_table = 1
	IF @@ERROR <> 0 or @retcode <> 0
		goto UNDO
	
	/*
    ** Check to make sure that the subscription does not already exist
    */
	declare @sub_type int
	select @sub_type = subscription_type from MSreplication_subscriptions 
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
					  publication = @publication

	-- It is not allowed to subscribe to the same publication twice even with
	-- differnet subscription type. 
	-- Raise special error for push
	if @sub_type is not null
		if @sub_type = 0
		begin
			raiserror (20594, 16, -1)
			GOTO UNDO			
		end
		else
		begin
			RAISERROR (14058, 16, -1)
			GOTO UNDO
		end
  
    /*
    ** Add the subscription
    */

    INSERT MSreplication_subscriptions  (publisher,
                                    publisher_db,
                                    publication,
									independent_agent,
                                    subscription_type,
                                    distribution_agent,
									description,
									time,
									transaction_timestamp,
									-- SyncTran
									update_mode,
									immediate_sync)
       VALUES (@publisher,
                   @publisher_db,
                   @publication,
				   @independent_agent_id,    
                   @subscription_type_id,
                   NULL,
				   @description,
				   getdate(),
				   0,
				   -- SyncTran
				   @update_mode_id,
				   @immediate_sync
				   )
    IF @@ERROR <> 0
    BEGIN
       RAISERROR (14057, 16, -1)
       GOTO UNDO
    END

    COMMIT TRAN

	RETURN (0)

UNDO:
    IF @@TRANCOUNT > 0
	begin
        ROLLBACK TRAN addpullsubscription
        COMMIT TRAN   
	end
	return 1
END
go
 
raiserror('Creating procedure sp_MSupdatesharedagentproperties', 0,1)
go

CREATE PROCEDURE sp_MSupdatesharedagentproperties (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @property    sysname,
    @strvalue    nvarchar(256) = NULL,
    @intvalue    int = NULL,
    @subscription_type int     
    )
AS


    -- Note publisher/publisher_db/publication uniquely identifies 
    -- a subscription in MSreplication_subscriptions 
    CREATE TABLE #subscriptions
    (
        publication sysname collate database_default
    )

    -- Compute the list of affected subscriptions
    INSERT INTO #subscriptions SELECT publication FROM
    MSreplication_subscriptions WHERE UPPER(publisher) = UPPER(@publisher)
    AND publisher_db = @publisher_db AND publication <> @publication
    AND independent_agent = 0 AND subscription_type = @subscription_type

    IF (SELECT COUNT(*) FROM #subscriptions) > 0
    BEGIN 

        IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor'
        BEGIN
            UPDATE MSsubscription_properties SET distributor = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_security_mode'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_security_mode = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_login'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_login = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_password'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'distributor_password'
        BEGIN
            UPDATE MSsubscription_properties SET distributor_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_address'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_address = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_port'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_port = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_login'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_login = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'ftp_password'
        BEGIN
            UPDATE MSsubscription_properties SET ftp_password = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'alt_snapshot_folder'
        BEGIN
            UPDATE MSsubscription_properties SET alt_snapshot_folder = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'working_directory'
        BEGIN
            UPDATE MSsubscription_properties SET working_directory = @strvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'use_ftp'
        BEGIN
            UPDATE MSsubscription_properties SET use_ftp = @intvalue 
             WHERE UPPER(publisher) = UPPER(@publisher)  
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)   
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'offload_agent'
        BEGIN
            UPDATE MSsubscription_properties SET offload_agent = @intvalue
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)
        END
        ELSE IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = N'offload_server'
        BEGIN
            UPDATE MSsubscription_properties SET offload_server = @strvalue
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication in (SELECT publication FROM #subscriptions)
        END
    END

    DROP TABLE #subscriptions

    IF @@ERROR <> 0
        RETURN 1
    ELSE
        RETURN 0
GO 

/* Create  sp_replicationdboption */
raiserror('Creating procedure sp_replicationdboption', 0,1)
GO

CREATE PROCEDURE sp_replicationdboption (
      @dbname    sysname,
      @optname   sysname,
      @value     sysname,
      @ignore_distributor bit = 0,
	  @from_scripting bit = 0
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    
    declare @alert_name     sysname
    declare @alert_id       int
    declare @command        nvarchar(255)
    declare @description    nvarchar(500)
    declare @category_name  sysname
    declare @agentname      sysname
    DECLARE @retcode        int
    DECLARE @optbit         int
    DECLARE @optbit_value   int /* Desired value with the optbit mask */
    DECLARE @proc           nvarchar(255)
		, @category int

    /*
    ** Initialization
    */

    /*
    ** Parameter check
    ** @dbname
    */
    SELECT @category = category FROM master.dbo.sysdatabases WHERE
        name = @dbname collate database_default
	if @category is null
    BEGIN
        RAISERROR(15010, 16, -1, @dbname)
        RETURN(1)
    END

    /*
    ** Parameter check
    ** @type
    */
    IF @optname is null or LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('publish',
        'merge publish',
		'subscribe', -- Used by sp_dboption for backward compatibility only.
		'sync with backup',
		'max cmds in tran'
		)
    BEGIN
        RAISERROR(14138,16,-1,@optname)
        RETURN(1)
    END

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

    /*
    ** Security Check
    */
	-- This proc is not granted to public. Only other system proc or sysadmin can use this
	-- sp_dboption will call this and it has its own security check,

    /*
    **  If we're in a transaction, disallow this since it might make recovery
    **  impossible.
    **
    */
    IF @@trancount > 0 
    BEGIN
        RAISERROR(15002,16,-1,'sp_replicationdboption')
        RETURN(1)
    END
    
    IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'publish'
        BEGIN
            SELECT @optbit = 1
            SELECT @proc = QUOTENAME(@dbname) + '.dbo.sp_MSpublishdb'
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish'
        BEGIN
            SELECT @optbit = 4
            SELECT @proc = QUOTENAME(@dbname) + '.dbo.sp_MSmergepublishdb'
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'subscribe'
        BEGIN
            SELECT @optbit = 2
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'sync with backup'
        BEGIN
            SELECT @optbit = 32
        END
    ELSE IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'max cmds in tran'
        BEGIN
            SELECT @optbit = 64
        END

    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        SELECT @optbit_value = @optbit
    ELSE
        SELECT @optbit_value = 0

          
    /*
    ** Check if the option is set as required already
    */
	if (@category & @optbit) = @optbit_value 
	BEGIN
		if @optbit_value = 64 -- setting 'max cmds in tran' to the same, do nothing
			RETURN (0)
        if LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
            RAISERROR (14035, 10, -1, @optname, @dbname)        
        else
            RAISERROR (14037, 10, -1, @optname, @dbname)
        RETURN (1)
    END

	-- If turning on 'sync with backup', make sure 'publish' or 'dist' is turned on already.
	if  @optbit_value = 32 and (@category & 1 = 0 and @category & 16 = 0)
	begin
		raiserror(20019, 16, -1, 'sync with backup')
		return (1)
	end
	if  @optbit_value = 64 and (@category & 16 = 0)
	begin
		raiserror(20019, 16, -1, 'max cmds in tran')
		return (1)
	end

	-- We do not allow turning on sync with backup mode at publishing db if the db is
	-- in simple recovery mode
	if  @optbit_value = 32 and @category & 1 <> 0 and 
		databasepropertyex(@dbname, 'recovery') = 'SIMPLE'
	begin
		raiserror(20622, 16, -1, 'sync with backup')
		return (1)
	end
	
	-- If turning off 'publish', turn off 'sync with backup' as well if the database
	-- is not a distribution database.
	if @optbit = 1 and @optbit_value = 0 and @category & 32 <> 0 and @category & 16 = 0
	begin
		EXEC @retcode =  dbo.sp_replicationdboption   
			@dbname = @dbname,
			@optname = 'sync with backup',
			@value = 'false',
			@ignore_distributor = @ignore_distributor,
			@from_scripting = @from_scripting
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			GOTO UNDO
		END
	end

	-- if turning on 'sync with backup' a distribution database, initialize the backup lsns 
	-- to nulls, this should be done before the category bit is set.
	declare @backup_proc nvarchar(1000)
	if @optbit_value = 32 and @category & 16 <> 0
	begin
        SELECT @backup_proc = QUOTENAME(@dbname) + 
			'.dbo.sp_MSrepl_init_backup_lsns'
		exec @retcode = @backup_proc
        if @@error <> 0 or @retcode <> 0
            goto UNDO
	end

    /*
    ** Prepare the required option
    */
	if @proc is not null
	begin
		EXEC @retcode = @proc @value = @value,
			@ignore_distributor = @ignore_distributor
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			GOTO UNDO
		END
	end


    /*
    ** Preparation succeeded. 
    ** Toggle the category bit in master..sysdatabases
    */
    UPDATE master..sysdatabases SET category = category ^ @optbit
    WHERE name = @dbname
    IF @@ERROR <> 0 
    BEGIN
        GOTO UNDO
    END


    declare @num_mergedb int
    select @num_mergedb = null
    if lower(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish'
    begin
        if lower(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        begin            
            -- Set the 'startup' option for sp_MScleanupmergepublisher if the
            -- database is enabled for merge replication.  
            exec ('use master 
                   exec dbo.sp_procoption ''sp_MScleanupmergepublisher'', ''startup'', ''true''')
        end
        else
        begin
            -- Reset the 'startup' option for sp_MScleanupmergepublisher if
            -- this is the last database that has its 'merge publish' option 
            -- disabled
            select @num_mergedb = count(*) from master..sysdatabases 
             where (category & 4) <> 0
            if @num_mergedb = 0
            begin
                exec ('use master 
                       exec dbo.sp_procoption ''sp_MScleanupmergepublisher'', ''startup'', ''false''')
            end
        end
    end
    

	-- Get expired subscription cleanup agent name
    set @agentname = formatmessage(20569)  

    IF ((LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish') or (LOWER(@optname) = 'publish')) and (LOWER(@value) = 'true')
    BEGIN
        IF NOT EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
						UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
            BEGIN
                SELECT @command =  'EXEC dbo.sp_expired_subscription_cleanup'
            
                set @description = formatmessage(20542)
    
                select @category_name = name FROM msdb.dbo.syscategories where category_id = 17   
                
                EXECUTE @retcode = msdb.dbo.sp_MSadd_repl_job @agentname,
                @subsystem = 'TSQL',
                @server = @@SERVERNAME,
                @databasename = @dbname,
                @description = @description,
                @freqtype = 4,        -- daily
                @activestarttimeofday=010000,   -- from 01:00:00 am
                @command = @command,
                @enabled = 1,
                @retryattempts = 0,
                @loghistcompletionlevel = 0,
                @category_name = @category_name
            
                IF @@ERROR <> 0 or @retcode <> 0
                    BEGIN
                         return (1)
                    END
            END

		-- Expired subscription cleanup alert            
        select @category_name = name FROM msdb.dbo.syscategories where category_id = 20
        set @alert_name = formatmessage(20538)  
        set @alert_id = 14157 -- corresponding to formatmessage(20538)
        if not exists (select * from msdb.dbo.sysalerts where message_id = @alert_id)
        begin
            exec @retcode = msdb.dbo.sp_add_alert @enabled = 0, @name = @alert_name, @category_name = @category_name, @message_id = 14157
            if @@error <> 0 or @retcode <> 0
                goto UNDO
        end
    END

    IF ((LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge publish') or (LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'publish')) and (LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'false')
    BEGIN
            IF (EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and 
							UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))) 
                and (NOT exists (select name from master..sysdatabases where category & 4 =4 ))
                and (NOT exists (select name from master..sysdatabases where category & 1 =1))
        BEGIN
            EXEC @retcode = msdb.dbo.sp_delete_job  @job_name = @agentname
            IF @@ERROR <> 0 or @retcode <> 0
                return (1)            
        END
        
        set @alert_id = 14157 -- cleanup  alert
        set @alert_name = formatmessage(20569)
        if exists (select * from msdb.dbo.sysalerts where message_id=@alert_id)
            and (NOT exists (select name from master..sysdatabases where category & 4 =4 ))
                and (NOT exists (select name from master..sysdatabases where category & 1 =1))
        begin
            select @alert_name=name from msdb.dbo.sysalerts where message_id=@alert_id
            exec @retcode = msdb.dbo.sp_delete_alert @alert_name
            if @@error <> 0 or @retcode <> 0
                return (1)            
        end
    END
    
    /*
    **  ??? 
    ** CHECKPOINT the database that was changed. Make the change
    ** effective immediatly
    */
    CHECKPOINT
    IF @@ERROR <> 0 
    BEGIN
        RETURN(1)
    END

    RETURN(0)

UNDO:
    -- Create system table is not allowed in a multi-statement transactions.
    -- Drop the tables here
    IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        EXEC dbo.sp_replicationdboption 
          @dbname    = @dbname,
          @optname   = @optname,
          @value     = 'false',
          @ignore_distributor = @ignore_distributor

    return(1)   
GO
 
raiserror('Creating procedure sp_MSfixupdistributorinfo', 0,1)
go

CREATE PROCEDURE sp_MSfixupdistributorinfo (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @distributor sysname,
    @subscription_type int
    )
AS
    DECLARE @local_distributor sysname
    DECLARE @retcode INT

    -- If @distributor = @publisher
    -- we just assume that these values are unspecified 
    -- and so we inherit these values from other shared subscriptions
    -- if possible
    IF @distributor = @publisher
    BEGIN
        SELECT TOP 1 @local_distributor = sp.distributor
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs  
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
                      
        IF @@ROWCOUNT > 0
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
            distributor = @local_distributor
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'distributor',
           @strvalue = @distributor,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
                                    
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupdistributorsecurity (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
	@distributor_security_mode int, -- default 0 -- standard
	@distributor_login sysname, -- default 'sa'
	@distributor_password nvarchar(524), -- default null
    @subscription_type int
    )
AS
    DECLARE @local_distributor_security_mode int
    DECLARE @local_distributor_login sysname 
    DECLARE @local_distributor_password nvarchar(524) 
    DECLARE @retcode INT


    IF @distributor_security_mode = 0 AND @distributor_login = 'sa' 
       AND (@distributor_password IS NULL OR 
            @distributor_password = N'') 
    BEGIN
        -- Parameters are unspecifed, try to inherit values from
        -- shared susbcriptions
        SELECT TOP 1 @local_distributor_security_mode = distributor_security_mode,
                     @local_distributor_login = distributor_login,
                     @local_distributor_password = distributor_password
                     FROM MSsubscription_properties sp
                     JOIN MSreplication_subscriptions rs  
                       ON UPPER(sp.publisher) = UPPER(rs.publisher)
                      AND sp.publisher_db = rs.publisher_db
                      AND rs.subscription_type = @subscription_type
                      AND rs.independent_agent = 0
                    WHERE UPPER(sp.publisher) = UPPER(@publisher)
                      AND sp.publisher_db = @publisher_db
                      AND sp.publication <> @publication
        IF @@ROWCOUNT > 0              
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
           distributor_security_mode = @local_distributor_security_mode,
           distributor_login = @local_distributor_login,
           distributor_password = @local_distributor_password
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'distributor_security_mode',
           @intvalue = @distributor_security_mode,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
                                    
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'distributor_login',
           @strvalue = @distributor_login,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure

        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'distributor_password',
           @strvalue = @distributor_password,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupftpinfo (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
	@ftp_address sysname,         -- default null
	@ftp_port int,                -- default null
	@ftp_login sysname,           -- default null
	@ftp_password nvarchar(524),  -- default null
    @subscription_type int,
    @force_null bit 
    )
AS
    DECLARE @local_ftp_address sysname
    DECLARE @local_ftp_port sysname 
    DECLARE @local_ftp_login sysname
    DECLARE @local_ftp_password nvarchar(524)
    DECLARE @retcode INT

    IF @ftp_address IS NULL AND @ftp_port IS NULL AND
       @ftp_login IS NULL AND @ftp_password IS NULL AND
       @force_null = 0
    BEGIN
        -- Parameters are unspecifed, try to inherit values from
        -- shared susbcriptions
        SELECT TOP 1 @local_ftp_address = ftp_address,
                     @local_ftp_port = ftp_port,
                     @local_ftp_login = ftp_login,
                     @local_ftp_password = ftp_password
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs  
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
        IF @@ROWCOUNT > 0              
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
            ftp_address = @local_ftp_address,
            ftp_port = @local_ftp_port,
            ftp_login = @local_ftp_login,
            ftp_password = @local_ftp_password
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'ftp_address',
           @strvalue = @ftp_address,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
                                    
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'ftp_port',
           @intvalue = @ftp_port,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure

        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'ftp_login',
           @strvalue = @ftp_login,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'ftp_password',
           @strvalue = @ftp_password,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupaltsnapshotfolder (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @alt_snapshot_folder nvarchar(255), -- default null
    @subscription_type int,
    @force_null bit 
    )
AS

    DECLARE @local_alt_snapshot_folder sysname 
    DECLARE @retcode INT

    IF @alt_snapshot_folder IS NULL AND @force_null = 0
    BEGIN
        -- Parameter is unspecifed, try to inherit value from
        -- shared susbcriptions
        SELECT TOP 1 @local_alt_snapshot_folder = alt_snapshot_folder
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs  
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
        IF @@ROWCOUNT > 0           
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
            alt_snapshot_folder = @local_alt_snapshot_folder
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'alt_snapshot_folder',
           @strvalue = @alt_snapshot_folder,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure                                    
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupworkingdirectory (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @working_directory nvarchar(255), -- default null
    @subscription_type int
    )
AS

    DECLARE @local_working_directory sysname 
    DECLARE @retcode INT

    IF @working_directory IS NULL
    BEGIN
        -- Parameter is unspecifed, try to inherit value from
        -- shared susbcriptions
        SELECT TOP 1 @local_working_directory = working_directory
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs  
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
        IF @@ROWCOUNT > 0           
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
            working_directory = @local_working_directory
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'working_directory',
           @strvalue = @working_directory,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure                                    
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupuseftp (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @use_ftp bit, -- default null
    @subscription_type int,
    @force_zero bit
    )
AS

    DECLARE @local_use_ftp bit
    DECLARE @retcode INT

    IF @use_ftp = 0 AND @force_zero = 0
    BEGIN
        -- Parameter is unspecifed, try to inherit value from
        -- shared susbcriptions
        SELECT TOP 1 @local_use_ftp = use_ftp
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs  
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
        IF @@ROWCOUNT > 0           
        BEGIN
           -- Inherit the values from other shared subscriptions
           UPDATE MSsubscription_properties SET 
            use_ftp = @local_use_ftp
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END  
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties 
           @publisher = @publisher,
           @publisher_db = @publisher_db,
           @publication = @publication,
           @property = N'use_ftp',
           @intvalue = @use_ftp,
           @subscription_type = @subscription_type
        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure                                    
    END

    RETURN 0

FixupFailure:
    RETURN 1
 
GO

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

CREATE PROCEDURE sp_MSfixupagentoffloadinfo (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,
    @distributor sysname,
    @offload_agent bit, -- default 0
    @offload_server sysname, -- default null
    @subscription_type int
    )
AS
    DECLARE @local_offload_agent bit
    DECLARE @local_offload_server sysname
    DECLARE @retcode INT

    IF @offload_agent = 0 AND 
        @offload_server is null
    BEGIN
        -- Parameters are assumed to be be unspecified, try to inherit values 
        -- from shared subscriptions
        SELECT TOP 1 @local_offload_agent = offload_agent,
                     @local_offload_server = offload_server
          FROM MSsubscription_properties sp
          JOIN MSreplication_subscriptions rs
            ON UPPER(sp.publisher) = UPPER(rs.publisher)
           AND sp.publisher_db = rs.publisher_db
           AND rs.subscription_type = @subscription_type
           AND rs.independent_agent = 0
         WHERE UPPER(sp.publisher) = UPPER(@publisher)
           AND sp.publisher_db = @publisher_db
           AND sp.publication <> @publication
        IF @@ROWCOUNT > 0
        BEGIN
            -- Inherit the values from other shared subscriptions
            UPDATE MSsubscription_properties SET
             offload_agent = @local_offload_agent,
             offload_server = @local_offload_server
            WHERE UPPER(publisher) = UPPER(@publisher)
              AND publisher_db = @publisher_db
              AND publication = @publication
        END
    END
    ELSE
    BEGIN
        EXEC @retcode = sp_MSupdatesharedagentproperties
            @publisher = @publisher,
            @publisher_db = @publisher_db,
            @publication = @publication,
            @property = N'offload_agent',
            @intvalue = @offload_agent,
            @subscription_type = @subscription_type

        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO FixupFailure
        
        EXEC @retcode = sp_MSupdatesharedagentproperties
            @publisher = @publisher,
            @publisher_db = @publisher_db,
            @publication = @publication,
            @property = N'offload_server',
            @strvalue = @offload_server,
            @subscription_type = @subscription_type
    END
             
    RETURN 0

FixupFailure:
    RETURN 1

GO

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

CREATE PROCEDURE sp_MSfixupsharedagentproperties (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,         /* publication name */
    @distributor sysname,       -- default @publisher
	@distributor_security_mode int, -- default 0 -- standard
	@distributor_login sysname, -- default 'sa'
	@distributor_password nvarchar(524), -- default null
	@ftp_address sysname,       -- default null
	@ftp_port int,              -- default null
	@ftp_login sysname,         -- default null
	@ftp_password nvarchar(524),      -- default null
    @alt_snapshot_folder nvarchar(255), -- default null
    @working_directory   nvarchar(255), -- default null
    @use_ftp bit,               -- default 0
    @offload_agent bit,         -- default 0
    @offload_server sysname     -- default @distributor
    )
AS
    DECLARE @subscription_type int
    DECLARE @retcode int
    DECLARE @force_ftp_null bit
    DECLARE @force_alt_snapshot_folder_null bit

    IF @alt_snapshot_folder IS NOT NULL AND @alt_snapshot_folder <> N''
        SELECT @force_ftp_null = 1 
    ELSE
        SELECT @force_ftp_null = 0 

    IF (@use_ftp = 1)  OR (@ftp_address IS NOT NULL AND @ftp_address <> N'')
        SELECT @force_alt_snapshot_folder_null = 1 
    ELSE
        SELECT @force_alt_snapshot_folder_null = 0 
        
    SELECT @subscription_type = subscription_type
      FROM MSreplication_subscriptions 
     WHERE UPPER(publisher) = UPPER(@publisher)
       AND publisher_db = @publisher_db
       AND publication = @publication
    -- No need to fix up the publisher security properties 
    -- because they are defined on a per subscription 
    -- basis for SyncTran

    EXEC @retcode = sp_MSfixupdistributorinfo
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @distributor = @distributor,
        @subscription_type = @subscription_type

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

    EXEC @retcode = sp_MSfixupdistributorsecurity 
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @distributor_login = @distributor_login,
        @distributor_password = @distributor_password,
        @distributor_security_mode = @distributor_security_mode,                            
        @subscription_type = @subscription_type

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

/* Ignore ftp_address, ftp_port, ftp_login, ftp_password on post 7.0 server
    EXEC @retcode = sp_MSfixupftpinfo
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @ftp_address = @ftp_address,
        @ftp_port = @ftp_port,
        @ftp_login = @ftp_login,
        @ftp_password = @ftp_password,
        @subscription_type = @subscription_type,
        @force_null = @force_ftp_null

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure
*/
    EXEC @retcode = sp_MSfixupaltsnapshotfolder
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @alt_snapshot_folder = @alt_snapshot_folder,
        @subscription_type = @subscription_type,
        @force_null = @force_alt_snapshot_folder_null

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

    EXEC @retcode = sp_MSfixupworkingdirectory
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @working_directory = @working_directory,
        @subscription_type = @subscription_type

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

    EXEC @retcode = sp_MSfixupuseftp
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @use_ftp = @use_ftp,
        @subscription_type = @subscription_type,
        @force_zero = @force_ftp_null

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

    EXEC @retcode = sp_MSfixupagentoffloadinfo
        @publisher = @publisher,
        @publisher_db = @publisher_db,
        @publication = @publication,
        @distributor = @distributor,
        @offload_agent = @offload_agent,
        @offload_server = @offload_server,
        @subscription_type = @subscription_type

    IF @@ERROR <> 0 OR @retcode <> 0
        GOTO FixupFailure

    RETURN 0

FixupFailure:

    RETURN 1

GO

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

CREATE PROCEDURE sp_addpullsubscription_agent (
    @publisher sysname,
    @publisher_db sysname,
    @publication sysname,         /* publication name */
    @subscriber sysname = NULL,
    @subscriber_db sysname = NULL,
    @subscriber_security_mode       int = NULL,                     /* 0 standard; 1 integrated */
    @subscriber_login               sysname = NULL,
    @subscriber_password            sysname = NULL,
    @distributor sysname = @publisher,
    @distribution_db sysname = NULL,
    @distributor_security_mode int = 0,
    @distributor_login sysname = 'sa',
    @distributor_password sysname = NULL,
    @optional_command_line nvarchar(4000) = '',
    @frequency_type  int = 2 ,  /* 2== OnDemand */
    @frequency_interval int = 1, 
    @frequency_relative_interval int = 1, 
    @frequency_recurrence_factor int = 1, 
    @frequency_subday int = 1, 
    @frequency_subday_interval int = 1 ,
    @active_start_time_of_day int = 0, 
    @active_end_time_of_day int = 0,         
    @active_start_date int = 0, 
    @active_end_date int =0,
    @distribution_jobid binary(16) = NULL OUTPUT,
    @encrypted_distributor_password bit = 0,
    @enabled_for_syncmgr nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
    @ftp_address sysname = NULL,
    @ftp_port int = NULL,
    @ftp_login sysname = NULL,
    @ftp_password sysname = NULL,
    @alt_snapshot_folder  nvarchar(255) = NULL,
    @working_directory    nvarchar(255) = NULL,
    @use_ftp              nvarchar(5) = 'false',
    @publication_type     tinyint = 0,-- 0 - Transactional, 1 - Snapshot, 2 - Merge
    @dts_package_name sysname  = NULL,  /* value will be sent and validated at distributor */                                  
    @dts_package_password  sysname = NULL,
    @dts_package_location nvarchar(12) = N'subscriber',
    @reserved nvarchar(100) = N'', -- Not default to null because null problems in conditional expressions.
    @offloadagent          nvarchar(5) = 'false',
    @offloadserver         sysname = NULL,
    @job_name              sysname = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    DECLARE @command nvarchar(4000)
    DECLARE @retcode int
    DECLARE @subscription_type_id int   /* 1 = pull, 2 = anonymous */
    DECLARE @independent_agent_id bit
    DECLARE @distribution_agent nvarchar(100) 
    DECLARE @category_name sysname
    DECLARE @platform_nt binary
    DECLARE @subscriber_enc_password nvarchar(524)
    DECLARE @distributor_enc_password   nvarchar(524)
    DECLARE @use_ftp_bit bit
    DECLARE @offload_agent_bit bit
    
    select @platform_nt = 0x1

    /*
    ** Security Check
    */

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

    /*
    ** Initializations.
    */

    -- Set null @optional_command_line to empty string to avoid string concat problem
    if @optional_command_line is null
        set @optional_command_line = ''
    else
        set @optional_command_line = N' ' + LTRIM( RTRIM(@optional_command_line) ) + N' '

    IF @distributor_password = N''
        select @distributor_password = NULL

    IF @ftp_password = N''
        select @ftp_password = NULL

    IF @dts_package_password = N''
        select @dts_package_password = NULL

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

    EXECUTE @retcode = dbo.sp_validname @publisher

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

    /*
    ** Parameter Check: @publisher_db
    */

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

    EXECUTE @retcode = dbo.sp_validname @publisher_db

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

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

    EXECUTE @retcode = dbo.sp_validname @publication

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

    /*
    ** Parameter Check: @subscriber and @subscriber_db
    */

    if @subscriber IS NULL or rtrim(@subscriber) = ''
        SELECT @subscriber = @@SERVERNAME

    if @subscriber_db IS NULL or rtrim(@subscriber_db) = ''
        SELECT @subscriber_db = DB_NAME()
    
    EXECUTE @retcode = dbo.sp_validname @subscriber
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
    
    EXECUTE @retcode = dbo.sp_validname @subscriber_db
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)

    /* 
    ** Check to see if MSreplictaion_subscriptions table exists.
    ** If so, copy it into the temp table
    */
    IF  NOT EXISTS (SELECT * FROM sysobjects WHERE 
        type = 'U' AND
        name = 'MSreplication_subscriptions')
    BEGIN
        RAISERROR (20017, 16, -1)
        RETURN (1)
    END 
    
    /*
    ** Check to make sure that the subscription does exist
    */
    IF NOT EXISTS (SELECT * FROM  MSreplication_subscriptions
                WHERE UPPER(publisher) = UPPER(@publisher) AND
                      publisher_db  = @publisher_db AND
                      publication = @publication)
    BEGIN
        RAISERROR (20017, 16, -1)
        RETURN (1)
    END
    
    declare @update_mode_id int
    SELECT  @distribution_agent = NULL
    SELECT  @independent_agent_id = independent_agent, 
            @subscription_type_id = subscription_type,
            @distribution_agent = distribution_agent,
            @update_mode_id = update_mode
        FROM  MSreplication_subscriptions
        WHERE UPPER(publisher) = UPPER(@publisher) AND
              publisher_db  = @publisher_db AND
              publication = @publication
    /* Distribution agent for push subscriptions is at distributor side */
    IF @subscription_type_id = 0
    BEGIN
        RAISERROR (21001, 16, -1)
        RETURN (1)
    END

    IF @distribution_agent IS NOT NULL
    BEGIN
        RAISERROR (21002, 11, -1, @distribution_agent)
        RETURN (1)
    END

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

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

    if (@subscription_type_id <> 0)
    begin
        if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
        begin
            raiserror(21344, 16, -1, '@subscriber_login')
            return (1)
        end
    end
    
    if (@distributor_security_mode = 0) and (@distributor_login IS NULL or rtrim(@distributor_login) = '')
    begin
        raiserror(3217, 16, -1, '@distributor_login')
        return (1)
    end

    IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
    begin
        exec @retcode = sp_MScreate_sub_tables @property_table = 1
        if @retcode <> 0 or @@error <> 0
        return (1)
    end

    /* 
    ** Parameter check: @alt_snapshot_folder 
    ** @alt_snapshot_folder and @use_ftp are mutually exclusive    
    */

    IF @alt_snapshot_folder <> N'' AND @alt_snapshot_folder IS NOT NULL
       AND LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = N'true'
    BEGIN
        RAISERROR(21146, 16, -1)
        RETURN (1)
    END

    /* 
    ** Parameter check: @use_ftp
    ** Must be 'true' or 'false'
    */
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@use_ftp')
        RETURN (1)
    END
    
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        SELECT @use_ftp_bit = 1
    END
    ELSE
    BEGIN
        SELECT @use_ftp_bit = 0
    END


    /*
    ** Parameter check: @publication_type
    ** Must be 0 - Transactional or 1 - Snapshot
    */
    IF @publication_type NOT IN (0, 1)
    BEGIN
        RAISERROR (20033, 16, -1)
        RETURN (1)
    END

    /*
    ** Parameter Check: @dts_package_location
    ** Valid values:
    ** distributor
    ** subscriber
    **
    */
    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('distributor', 'subscriber')
    BEGIN
        RAISERROR(21179, 16, -1)    
        RETURN (1)
    END

    declare @dts_package_location_id int

    IF LOWER(@dts_package_location collate SQL_Latin1_General_CP1_CS_AS) = 'distributor'
        SELECT @dts_package_location_id = 0
    ELSE 
        SELECT @dts_package_location_id = 1

    -- Have to be a push, non updatable  subscription to set DTS package name
    if @dts_package_name is not null
    begin
        if  @update_mode_id != 0
        begin
            RAISERROR(21180, 16, -1)    
            RETURN (1)
        end
    end
    
    -- Copy the passwords to new value before attempting to encrypt
    set @distributor_enc_password = @distributor_password
    IF (@encrypted_distributor_password = 0)
        -- Encrypt the password
        BEGIN
            EXEC @retcode = master.dbo.xp_repl_encrypt @distributor_enc_password OUTPUT
            IF @@error <> 0 OR @retcode <> 0
                return 1
        END
	
    declare @dts_package_enc_password nvarchar(524)
    set @dts_package_enc_password = @dts_package_password

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

    /*
    ** Parameter Check: @offloadserver
    ** 1. If @offloadagent = 'true' then @offloadserver cannot be null.
    ** 2. Similar to the push case, we don't allow "remote" activation
    **    of agent on the local machine.
    */
    SELECT @offloadagent = LOWER(@offloadagent collate SQL_Latin1_General_CP1_CS_AS)
    IF @offloadagent NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@offloadagent')
        RETURN (1)
    END

    IF @offloadagent = 'true'
    BEGIN
        SELECT @offload_agent_bit = 1
    END
    ELSE
    BEGIN
        SELECT @offload_agent_bit = 0
    END

    IF @offload_agent_bit = 1 AND (@offloadserver is NULL or
                               @offloadserver = N'')
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN (1)
    END
    
    IF UPPER(@offloadserver) = UPPER(@@SERVERNAME) AND
       @offload_agent_bit = 1
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END

    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode <> 0 OR @@ERROR <> 0
        RETURN (1)

    /*
    ** Construct unique name
    */
    if @subscriber is NULL select @subscriber = ''
    if @subscriber_db is NULL select @subscriber_db = ''
    
    declare @job_existing bit
    if @job_name is null
    begin
        select @job_existing = 0
        SELECT @job_name = CONVERT(nvarchar(18),@publisher ) + '-' + CONVERT(nvarchar(18),@publisher_db) + '-' + 
                        CONVERT(nvarchar(18),@publication) + '-' + CONVERT(nvarchar(18),@subscriber) + '-' +
                        CONVERT(nvarchar(18),@subscriber_db) + '-' + CONVERT(nvarchar(36),newid())
    end
    else
        select @job_existing = 1

    -- Get property values.
    if @reserved = 'no_change_to_properties'
    begin
        -- Get the distributor value. It will be used in agent command line.
        select @distributor = distributor, 
            @enabled_for_syncmgr = case enabled_for_syncmgr
                when 0 then 'false'
                when 1 then 'true'
                end
        from MSsubscription_properties where
            UPPER(publisher) = UPPER(@publisher)
            and publisher_db =  @publisher_db
            and publication = @publication              
    end

    BEGIN TRAN

    /*
    ** If the publication is independent agent type or it is the first
    ** subscription on the non independent agent publications.
    */

    IF @independent_agent_id = 1 OR 
        NOT EXISTS (SELECT * FROM MSreplication_subscriptions WHERE
                            UPPER(@publisher) = UPPER(publisher) and
                            @publisher_db = publisher_db and
                            agent_id IS NOT NULL and
                            independent_agent = 0)
    BEGIN
        if @job_existing = 0
        begin
            /* Construct agent command */
            SELECT @command = '-Publisher ' + @publisher + ' '
            SELECT @command = @command + '-PublisherDB ' + QUOTENAME(@publisher_db) + ' '
            IF @independent_agent_id = 1
                SELECT @command = @command + '-Publication ' + QUOTENAME(@publication) + ' '

            SELECT @command = @command + '-Distributor ' + QUOTENAME(@distributor)  + ' '

            /*
            Use -Xdatabase to save command line space
            We can not use -Xserver for distribution because SQLExec will validate the server
            to be in sysservers.

            SELECT @command = @command + '-DistributionDB ' + QUOTENAME(@distribution_db)  + ' '
            */
            
            SELECT @command = @command + '-SubscriptionType ' + convert(nvarchar(10),@subscription_type_id)  + ' '
            SELECT @command = @command + '-Subscriber ' + QUOTENAME(@subscriber)  + ' '
        
            select @command = @command + '-SubscriberSecurityMode ' + 
                convert(nvarchar(10),@subscriber_security_mode) + ' '
            if @subscriber_login is not NULL
                select @command = @command + '-SubscriberLogin ' + quotename(@subscriber_login) + ' '
            if @subscriber_password is not NULL
            begin
                set @subscriber_enc_password = @subscriber_password
                exec @retcode = master.dbo.xp_repl_encrypt @subscriber_enc_password OUTPUT
                select @command = @command + '-SubscriberEncryptedPassword ' + quotename(@subscriber_enc_password) + ' '
            end

            SELECT @command = @command + '-SubscriberDB ' + QUOTENAME(@subscriber_db) + ' '

                    
            if @dts_package_name is not null
              select @command = @command + '-UseDTS '

            if @offload_agent_bit = 1 
                select @command = @command + N'-Offload ' + @offloadserver + N' '

            /* 
            ** make sure the command line is not truncated
            */
            /* Use datalength because len doesn't count the last space in @command */
            IF (datalength(@command) + datalength(@optional_command_line)) > 8000
            BEGIN
                RAISERROR(20018, 16, -1)
                RETURN(1)
            END

            SELECT @command = @command + @optional_command_line

            -- Get Distribution category name (assumes category_id = 10)
            select @category_name = name FROM msdb.dbo.syscategories where category_id = 10

            EXEC @retcode = dbo.sp_MSadd_repl_job
                    @name = @job_name,
                    @subsystem = 'Distribution',
                    @server = @@SERVERNAME,
                    @databasename = @distribution_db,
                    @enabled = 1,
                    @freqtype = @frequency_type,
                    @freqinterval = @frequency_interval,
                    @freqsubtype = @frequency_subday,
                    @freqsubinterval = @frequency_subday_interval,
                    @freqrelativeinterval = @frequency_relative_interval,
                    @freqrecurrencefactor = @frequency_recurrence_factor,
                    @activestartdate = @active_start_date,
                    @activeenddate = @active_end_date,
                    @activestarttimeofday = @active_start_time_of_day,
                    @activeendtimeofday = @active_end_time_of_day,
                    @command = @command,
                    @category_name = @category_name,
                    @retryattempts = 10,
                    @retrydelay = 1,
                    @job_id = @distribution_jobid OUTPUT

            IF @@ERROR <> 0 or @retcode <> 0
            BEGIN
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN   
                RETURN(1)
            END
        end
        else
        begin
            select @distribution_jobid = job_id from msdb..sysjobs_view where 
                name = @job_name collate database_default and
                UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
            if @distribution_jobid IS NULL
            begin
                -- Message from msdb.dbo.sp_verify_job_identifiers
                RAISERROR(14262, -1, -1, 'Job', @job_name)          
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN   
                RETURN(1)
            end
        end
    END

    if @reserved <> 'no_change_to_properties' and (@subscription_type_id = 1) OR (@subscription_type_id = 2)
    BEGIN
        IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
              and publisher_db =  @publisher_db
              and publication = @publication) 
        BEGIN
            -- Publication type:
            -- 0  transactional
            -- 1  snapshot
            -- 2  merge (not allowed)

            INSERT INTO MSsubscription_properties 
            (publisher, publisher_db, publication, publication_type, 
             publisher_login,publisher_password, publisher_security_mode, 
             distributor, distributor_login, distributor_password, 
             distributor_security_mode, ftp_address, ftp_port, ftp_login, 
             ftp_password, alt_snapshot_folder, working_directory, use_ftp,
             dts_package_name, dts_package_password, dts_package_location, 
             offload_agent, offload_server, dynamic_snapshot_location)
            values (@publisher, @publisher_db, @publication, @publication_type, NULL, NULL, 1, 
                @distributor, @distributor_login, @distributor_enc_password, 
                @distributor_security_mode, null, null, null,
                null, @alt_snapshot_folder, @working_directory, @use_ftp_bit,
                @dts_package_name, @dts_package_enc_password, 
                @dts_package_location_id, @offload_agent_bit, @offloadserver, null)

            IF @@ERROR <> 0 
            BEGIN
                IF @@TRANCOUNT = 1
                    ROLLBACK TRAN
                ELSE
                    COMMIT TRAN           
                RETURN(1)
            END
        END
        ELSE
        BEGIN
            update MSsubscription_properties set
                distributor = @distributor,
                distributor_login = @distributor_login,
                distributor_password = @distributor_enc_password,
                distributor_security_mode = @distributor_security_mode,
                dts_package_name = @dts_package_name,
                dts_package_password = @dts_package_enc_password,
                dts_package_location = @dts_package_location_id
                where UPPER(publisher) = UPPER(@publisher)
                    and publisher_db =  @publisher_db
                    and publication = @publication
        END


        -- For dependent subscriptions we need to fix up all the
        -- shared properties  
        IF @independent_agent_id = 0 
        BEGIN

            EXEC @retcode = sp_MSfixupsharedagentproperties
                   @publisher = @publisher,
                   @publisher_db = @publisher_db,
                   @publication = @publication,
                   @distributor = @distributor,
                   @distributor_security_mode = @distributor_security_mode,
                   @distributor_login = @distributor_login,
                   @distributor_password = @distributor_enc_password,
                   @ftp_address = @ftp_address,
                   @ftp_port = @ftp_port,
                   @ftp_login = @ftp_login,
                   @ftp_password = @ftp_password,
                   @alt_snapshot_folder = @alt_snapshot_folder,
                   @working_directory = @working_directory,
                   @use_ftp = @use_ftp_bit,
                   @offload_agent = @offload_agent_bit,
                   @offload_server = @offloadserver
                    
            IF @retcode <> 0 OR @@ERROR <> 0
            BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
            END
        END

        IF @@ERROR <> 0 
        BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
        END
    END


    /* If we do not have independent agents , i.e. independent_agent=0, but there is
    already a row for that publisher and that publisher database with a NOT null 
    distribution_agent_id, then set the @distribution_jobid to that id.  Note that if
    there are no rows returned, the value of the variable does not change, which is what we want.
    There should never be more than one row ever returned for this query - but will use TOP 1
    to insist that is the case.
    */
    
    IF @independent_agent_id = 0
    BEGIN
        SELECT DISTINCT @distribution_jobid=agent_id, @job_name = distribution_agent 
          FROM MSreplication_subscriptions
         WHERE UPPER(publisher) = UPPER(@publisher) 
           AND publisher_db =  @publisher_db
           AND agent_id IS NOT NULL AND independent_agent=0
    
    END

    UPDATE MSreplication_subscriptions 
       SET distribution_agent = @job_name,
           agent_id = @distribution_jobid
     WHERE UPPER(publisher) = UPPER(@publisher) 
       AND publisher_db =  @publisher_db 
       AND publication =  @publication 
       AND (subscription_type = 1 /* pull*/ OR subscription_type = 2) /*anonymous*/

    IF @@ERROR <> 0 
    BEGIN
        IF @@TRANCOUNT = 1
            ROLLBACK TRAN
        ELSE
            COMMIT TRAN           
        RETURN(1)
    END 

    /* Conditional support for MobileSync */
    if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        /* Call sp_MSregistersubscription so that the subscription can be synchronized via MobileSync etc. */
        declare @subscription_id uniqueidentifier
        declare @failover_mode_id int
        set @subscription_id = convert(uniqueidentifier, @distribution_jobid)

        if @update_mode_id in (3,5) 
            select @failover_mode_id = 1
        else if @update_mode_id in (2,4)
            select @failover_mode_id = 2
        else
            select @failover_mode_id = 0
            
        exec @retcode = dbo.sp_MSregistersubscription @replication_type = 1,
                                    @publisher = @publisher,
                                    @publisher_db = @publisher_db,
                                    @publication = @publication,
                                    @subscriber = @subscriber,
                                    @subscriber_db = @subscriber_db,
                                    @subscriber_security_mode = @subscriber_security_mode,
                                    @subscriber_login = @subscriber_login,
                                    @subscriber_password = @subscriber_password,
                                    @distributor = @distributor,
                                    @subscription_id = @subscription_id,
                                    @independent_agent = @independent_agent_id,
                                    @subscription_type = @subscription_type_id,
                                    @failover_mode = @failover_mode_id
        IF @@ERROR <> 0 or @retcode <> 0
        BEGIN
            IF @@TRANCOUNT = 1
                ROLLBACK TRAN
            ELSE
                COMMIT TRAN           
            RETURN(1)
        END
    END

    COMMIT TRAN
    RETURN(0)
GO






raiserror('Creating procedure sp_helpsubscription_properties
', 0,1)
go
CREATE PROCEDURE sp_helpsubscription_properties
        @publisher sysname = '%', 
        @publisher_db sysname = '%', 
        @publication sysname = '%', 
        @publication_type int = NULL
    AS

    SET NOCOUNT ON
    DECLARE @retcode int

    /*
    ** Security Check
    */

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

    /*
    ** The logic is added here for the case where MSsubscription_properties table does not exist
    ** or relevant entry is not added because sp_addmergepullsubscription_agent or sp_addsubscription_agent
    ** is not called.
    */
    IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
    begin
        return (0)
    end

    IF (@publisher IS NULL) OR (@publisher = '')
        select @publisher = '%'
    IF (@publisher_db IS NULL) OR (@publisher_db = '')
        select @publisher_db = '%'
    IF (@publication IS NULL) OR (@publication = '')
        select @publication = '%'

    IF @publication_type IS NOT NULL
    BEGIN
        SELECT publisher, publisher_db, publication, publication_type, publisher_login,
               publisher_password, publisher_security_mode, distributor, distributor_login,
               distributor_password, distributor_security_mode, 'ftp_address' = null, 'ftp_port' = 0,
               'ftp_login' = null, 'ftp_password' = null, alt_snapshot_folder, working_directory, use_ftp,
			   dts_package_name, dts_package_password, dts_package_location, 
               offload_agent, offload_server, dynamic_snapshot_location 
          FROM MSsubscription_properties
         WHERE ((@publisher = N'%') OR (UPPER(publisher) = UPPER(@publisher)))
           AND ((@publisher_db = N'%') or ( publisher_db = @publisher_db))
           AND publication LIKE @publication
           AND publication_type = @publication_type
    END
    ELSE
    BEGIN
        SELECT publisher, publisher_db, publication, publication_type, publisher_login,
               publisher_password, publisher_security_mode, distributor, distributor_login,
               distributor_password, distributor_security_mode, 'ftp_address' = null, 'ftp_port' = 0,
               'ftp_login' = null, 'ftp_password' = null, alt_snapshot_folder, working_directory, use_ftp,
			   dts_package_name, dts_package_password, dts_package_location,
               offload_agent, offload_server, dynamic_snapshot_location
          FROM MSsubscription_properties
         WHERE ((@publisher = N'%') OR (UPPER(publisher) = UPPER(@publisher)))
           AND ((@publisher_db = N'%') or ( publisher_db = @publisher_db))
           AND publication LIKE @publication
    END

    RETURN (0)
GO

EXEC dbo.sp_MS_marksystemobject sp_helpsubscription_properties
GO

raiserror('Creating procedure sp_change_subscription_properties', 0,1)
go
CREATE PROCEDURE sp_change_subscription_properties
        @publisher sysname, 
		@publisher_db sysname, 
		@publication sysname, 
		@property sysname,
		@value nvarchar(1000),
        @publication_type int = NULL
    AS
    SET NOCOUNT ON

	DECLARE @command nvarchar(2000)
	DECLARE @column_to_update nvarchar(64)
	DECLARE @value_string nvarchar(255)
    DECLARE @independent_agent bit
	DECLARE @retcode int
    DECLARE @subscription_type int
    DECLARE @intvalue int
    DECLARE @value_bit bit
    DECLARE @offload_agent bit
    DECLARE @offload_server sysname 
    DECLARE @dbname sysname
    DECLARE @local_publication sysname
    DECLARE @agentid binary(16)
    DECLARE @local_publisher sysname
    DECLARE @cursor_opened bit 
    DECLARE @cursor_allocated bit
    DECLARE @agenttype nvarchar(20)
    DECLARE @commandline nvarchar(3200)

    SELECT @cursor_opened = 0
    SELECT @cursor_allocated = 0
    SELECT @retcode = 0    
	/*
    ** Security Check
    */

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

	IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
	begin
		raiserror(14027, 16, -1, 'The subscription properties table ''MSsubscription_properties''')
		return (1)
	end
	
	if (@publisher is null)
	begin
		raiserror(14043, 16, -1, '@publisher')
		return (1)
	end

	if(@publisher_db is null)
	begin
		raiserror(14043, 16, -1, '@publisher_db')
		return (1)
	end
	
	if (@publication is null) or (@publication = '')
	begin
		select @publication = '%'
	end


    -- Expand '%' into individual subscriptions using a cursor
    IF @publication = N'%'
    BEGIN

        BEGIN TRANSACTION subscription_properties_exp
        DECLARE hsubprop CURSOR LOCAL FAST_FORWARD FOR
            SELECT publication 
              FROM MSreplication_subscriptions
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               -- NOTE:  publication like '%' is implicit
        IF @@ERROR <> 0
            GOTO ExpFailure
        SELECT @cursor_allocated = 1
    
        OPEN hsubprop
        IF @@ERROR <> 0
            GOTO ExpFailure    
        SELECT @cursor_opened = 1

        FETCH hsubprop INTO @local_publication
        WHILE (@@FETCH_STATUS <> 0)
        BEGIN
                            
            EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @local_publication,
                @property = @property,
                @value = @value,
                @publication_type = @publication_type
            IF @retcode <> 0 OR @@ERROR <> 0
                GOTO ExpFailure
            FETCH hsubprop INTO @local_publication
        END

        CLOSE hsubprop
        DEALLOCATE hsubprop
        COMMIT TRANSACTION subscription_properties_exp
        IF @@ERROR <> 0
            GOTO ExpFailure

        RETURN (0)
ExpFailure:

        IF @cursor_opened = 1
            CLOSE hsubprop
        IF @cursor_allocated = 1
            DEALLOCATE hsubprop
        ROLLBACK TRANSACTION subscription_properties_exp        
        RETURN (1)
    END    

    -- Check for existence of the specified pull subscription
    SELECT @agentid = NULL
    SELECT @local_publisher = NULL
    SELECT @dbname = DB_NAME()

    IF @publication_type IN (0,1) OR @publication_type IS NULL
    BEGIN
        IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('MSreplication_subscriptions'))
        BEGIN
            SELECT @local_publisher = publisher, 
                   @agentid = agent_id
              FROM MSreplication_subscriptions
             WHERE UPPER(publisher) = UPPER(@publisher)
               AND publisher_db = @publisher_db
               AND publication = @publication 
        END

    END

    IF @publication_type = 2 OR (@publication_type IS NULL AND
        @local_publisher IS NULL)
    BEGIN
        IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('sysmergepublications'))
        BEGIN

            SELECT @local_publisher = mp.publisher,
                   @agentid = mr.merge_jobid
              FROM sysmergepublications mp
            INNER JOIN sysmergesubscriptions ms
                ON mp.pubid = ms.pubid 
               AND UPPER(mp.publisher) = UPPER(@publisher) 
               AND mp.publisher_db = @publisher_db
               AND mp.name = @publication 
               AND ms.db_name = @dbname
               AND UPPER(ms.subscriber_server) = UPPER(@@SERVERNAME)
            INNER JOIN MSmerge_replinfo mr
                ON ms.subid = mr.repid
        END
    END 

    IF @local_publisher IS NULL
    BEGIN
        RAISERROR(21226, 16, -1, @dbname)
        RETURN (1)
    END

    SELECT @offload_agent = NULL
    SELECT @offload_server = NULL
    SELECT @offload_agent = offload_agent, 
           @offload_server = offload_server,
           @publication_type = publication_type             
      FROM MSsubscription_properties 
     WHERE UPPER(publisher) = UPPER(@publisher)
       AND publisher_db = @publisher_db
       AND publication = @publication
    
    -- If the subscription does not have a corresponding entry in MSsubscription_properties, 
    -- the subscription is probably created by the ActiveX control. In this case there isn't much
    -- we can do about it so we just return 0.
    IF @offload_agent IS NULL
    BEGIN
        RETURN (0)
    END      
    
	IF (@property IS NULL)
	begin
		raiserror(14043, 16, -1, '@property')
		return (1)
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_login')
		select @column_to_update = 'publisher_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_password')
	begin
		select @column_to_update = 'publisher_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode')
		select @column_to_update = 'publisher_security_mode'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor')
		select @column_to_update = 'distributor'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_login')
		select @column_to_update = 'distributor_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_password')
	begin
		select @column_to_update = 'distributor_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_security_mode')
		select @column_to_update = 'distributor_security_mode'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_address')
		select @column_to_update = 'ftp_address'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_port')
		select @column_to_update = 'ftp_port'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_login')
		select @column_to_update = 'ftp_login'
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'ftp_password')
		select @column_to_update = 'ftp_password'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'alt_snapshot_folder')
    BEGIN
        select @column_to_update = 'alt_snapshot_folder'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'working_directory')
    BEGIN
        select @column_to_update = 'working_directory'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_ftp')
        select @column_to_update = 'use_ftp'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_name')
        select @column_to_update = 'dts_package_name'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_password')
	begin
        select @column_to_update = 'dts_package_password'
		EXEC @retcode = master.dbo.xp_repl_encrypt @value OUTPUT
		IF @@error <> 0 OR @retcode <> 0
			return 1
	end
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_location')
        select @column_to_update = 'dts_package_location'
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_agent')
    BEGIN
        select @column_to_update = 'offload_agent'
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_server')
    BEGIN
        select @column_to_update = 'offload_server'
        exec @retcode = sp_MSreplcheckoffloadserver @value
        if @retcode <> 0 or @@error <> 0
                return(1)
    END
    ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = N'dynamic_snapshot_location') and @publication_type = 2
    BEGIN
        select @column_to_update = N'dynamic_snapshot_location'
    END
	ELSE
	BEGIN
		raiserror (3217, 16, -1, '@property')
		return(1)
	END

    IF @column_to_update in ('use_ftp', 'offload_agent')
    BEGIN
        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'true'
        BEGIN
            SELECT @value_bit = 1
        END
        ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'false'
        BEGIN
            SELECT @value_bit = 0
        END
        ELSE
        BEGIN 
            RAISERROR(14137, 16, -1)
        END
    END

	IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distributor_security_mode') OR (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode') 
	BEGIN
		IF NOT ( @value = 0 or @value = 1 or (@value = 2 and lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'publisher_security_mode' )) 
		BEGIN
			raiserror(3217, 16, -1, '@value')
			return(1)
		END
        select @value_string = convert(nvarchar(1), @value)
	END
	ELSE IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'dts_package_location')
	BEGIN
		IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'distributor' 
			select @value_string = '0'
		ELSE IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = N'subscriber' 
			select @value_string = '1'
		ELSE 
		begin
			raiserror(20587, 16, -1, 'dts_package_location', 'sp_change_subscription_properties')
			return(1)
		end

	END
	ELSE
    BEGIN
        IF @value IS NULL
        BEGIN
            select @value_string = 'null'
        END
        ELSE
        BEGIN
		    select @value_string = 'N' + quotename(rtrim(@value),'''')
        END
	END    

    -- Ignore ftp_address, ftp_port, ftp_login, ftp_password on post 7.0 servers
    IF (@column_to_update IN (N'ftp_address', N'ftp_port', N'ftp_login', N'ftp_password'))
    BEGIN
        RETURN (0)
    END

    -- If the 'offload_agent' property is 1, 'offload_server' property must not be
    -- null or empty. Make sure that this is the case
    IF (@column_to_update = N'offload_agent' AND 
        @value_bit = 1 AND 
        (@offload_server IS NULL OR @offload_server = N''))
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN(1)
    END

    -- If we are enabling agent offload for this pull subscription, 
    -- we should make sure that the offload server is different from
    -- the Subscriber's server name
    IF (@column_to_update = N'offload_agent' AND
        @value_bit = 1 AND UPPER(@offload_server) = UPPER(@@SERVERNAME)) OR
       (@column_to_update = N'offload_server' AND
        @offload_agent = 1 AND 
        UPPER(@value) = UPPER(@@SERVERNAME))
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END
    
BEGIN TRANSACTION subscription_properties	
	IF (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_ftp')
    begin
		update MSsubscription_properties set use_ftp = @value_bit where 
			UPPER(publisher) = UPPER(@publisher) and 
			publisher_db = @publisher_db and
			publication = @publication 
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    end
    else if (lower(@property collate SQL_Latin1_General_CP1_CS_AS) = 'offload_agent')
    begin
        update MSsubscription_properties set offload_agent = @value_bit where
            UPPER(publisher) = UPPER(@publisher) and
            publisher_db = @publisher_db and
            publication = @publication
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        -- Call helper procedure to add or remove the '-Offload' parameter 
        -- from the agent's command line in msdb. By now, we should 
        -- have the publication type and the agent jodid.

        -- Don't do anything if the offload_agent property hasn't been changed
        IF @offload_agent <> @value_bit
        BEGIN
            IF @publication_type IN (0,1)    
            BEGIN
                SELECT @agenttype = N'distribution'
            END
            ELSE
            BEGIN
                SELECT @agenttype = N'merge'
            END    

            -- Add or remove the Offload parameter based on the new value
            -- of the offload_agent property 
            IF @value_bit = 0
            BEGIN
                EXEC @retcode = sp_MSremoveoffloadparameter
                        @job_id = @agentid,
                        @agenttype = @agenttype

                IF @@ERROR <> 0 OR @retcode <> 0
                    GOTO Failure 
            END
            ELSE
            BEGIN
                EXEC @retcode = sp_MSaddoffloadparameter 
                        @job_id = @agentid,
                        @offloadserver = @offload_server,
                        @agenttype = @agenttype

                IF @@ERROR <> 0 OR @retcode <> 0
                    GOTO Failure 
            END
        END
    end
    else if lower(@property collate SQL_Latin1_General_CP1_CS_AS) = N'dynamic_snapshot_location'
    begin
        select @value = rtrim(ltrim(@value))

        update MSsubscription_properties 
           set dynamic_snapshot_location = @value
         where upper(publisher) = upper(@publisher) 
           and publisher_db = @publisher_db 
           and publication = @publication
        if @@error <> 0 or @retcode <> 0
            goto Failure

        -- Call helper functions to add/update or remove the -DynamicSnapshotLocationParameter
        if @value is null or @value = N''
        begin
            update msdb.dbo.sysjobsteps 
               set command = fn_removeparameterwithargument(command, N'DynamicSnapshotLocation') collate database_default
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge'
        end
        else
        begin

            select @commandline = command 
              from msdb.dbo.sysjobsteps
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge'

            select @commandline = fn_updateparameterwithargument(@commandline, N'DynamicSnapshotLocation', fn_replquotename(@value)) collate database_default

            -- Need to remove existing alternate snapshot folder parameters
            -- and file transfer type parameters

            select @commandline = fn_removeparameterwithargument(@commandline, N'FileTransferType') collate database_default
            
            select @commandline = fn_removeparameterwithargument(@commandline, N'AltSnapshotFolder') collate database_default

            update msdb.dbo.sysjobsteps
               set command = @commandline
             where job_id = @agentid
               and lower(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'merge' 

        end
    end
    else    
	begin
		-- Password is encrypted. Must prefix every string with N' 
		-- otherwise, the chars will be convert to '???'
		select @command = N'update MSsubscription_properties set ' + @column_to_update + '= ' + @value_string
				+ ' where UPPER(publisher) = UPPER(' + quotename(@publisher,'''') 
				+ ') and publisher_db = ' + quotename(@publisher_db, '''')
				+ ' and publication = ' + quotename(@publication,'''')
		EXEC (@command)
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
	end


    -- If the offload_server property is chnaged, we have to modify the agent's
    -- command line if the agent has already been enabled for remote activation 		
    IF @column_to_update = N'offload_server' AND @offload_agent = 1
    BEGIN
        IF @publication_type IN (0,1)
        BEGIN
            SELECT @agenttype = N'distribution'
        END
        ELSE
        BEGIN
            SELECT @agenttype = N'merge'
        END

        EXEC @retcode = sp_MSaddoffloadparameter
            @job_id = @agentid,
            @offloadserver = @value,
            @agenttype = @agenttype        
        IF @retcode <> 0 OR @@ERROR <> 0
            GOTO Failure
    END

    IF (@publication_type = 0 or @publication_type = 1) AND @publication <> N'%' AND
        @column_to_update IN ('distributor',
                              'distributor_login',
                              'distributor_password',
                              'distributor_security_mode',
                              'ftp_address',
                              'ftp_port',
                              'ftp_login',
                              'ftp_password',
                              'alt_snapshot_folder',
                              'working_dir',
                              'use_ftp',
                              'offload_agent',
                              'offload_server')
    BEGIN
        SELECT @subscription_type = subscription_type
          FROM MSreplication_subscriptions
         WHERE UPPER(publisher) = UPPER(@publisher)
           AND publisher_db = @publisher_db
           AND publication = @publication
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        -- Update the property for all shared subscriptions
        IF @column_to_update IN ('distributor_security_mode', 
                                 'ftp_port')
        BEGIN
            SELECT @intvalue = CONVERT(int, @value)
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @intvalue = @intvalue,
                    @subscription_type = @subscription_type
        END
        ELSE IF @column_to_update IN ('use_ftp', 'offload_agent')
        BEGIN
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @intvalue = @value_bit,
                    @subscription_type = @subscription_type
        END
        ELSE 
        BEGIN
            EXEC @retcode = sp_MSupdatesharedagentproperties 
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = @column_to_update,
                    @strvalue = @value,
                    @subscription_type = @subscription_type
        END  
    
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    -- Ftp and alternate snapshot folder are mutually 
    -- exclusive options but instead of raising an error
    -- when both of them are non-null, nullify the other 
    -- property when either one of them is set to non-null
    -- value since properties can only be set one at a time

    -- 'dynamic_snapshot_location' should also be added to the
    -- list of mutually exclusive properties


    IF (@column_to_update = 'ftp_address') AND (@value <> N''
       AND @value IS NOT NULL)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    IF (@column_to_update = 'use_ftp') AND (@value_bit = 1)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        IF @publication_type = 2
        BEGIN
            EXEC @retcode = sp_change_subscription_properties
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = 'dynamic_snapshot_location',
                    @value = NULL
            IF @@error <> 0 OR @retcode <> 0
                GOTO Failure
        END
    END

    IF (@column_to_update = 'alt_snapshot_folder') AND (@value <> N''
       AND @value IS NOT NULL)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'ftp_address',
                @value = NULL

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties 
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'use_ftp',
                @value = 'false'

        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        IF @publication_type = 2
        BEGIN
            EXEC @retcode = sp_change_subscription_properties
                    @publisher = @publisher,
                    @publisher_db = @publisher_db,
                    @publication = @publication,
                    @property = 'dynamic_snapshot_location',
                    @value = NULL
            IF @@error <> 0 OR @retcode <> 0
                GOTO Failure
        END
    END


    IF (@column_to_update = 'dynamic_snapshot_location') AND (@value <> N''
        AND @value IS NOT NULL)
    BEGIN

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'ftp_address',
                @value = NULL
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'use_ftp',
                @value = 'false'
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'alt_snapshot_folder',
                @value = NULL
            
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure

    END


    -- Turn off the offload agent bit if the 
    -- the new value of offload server happens to be null
    -- or empty
    IF (@column_to_update = 'offload_server' AND 
        (@value IS NULL OR @value = N'') AND
        @offload_agent = 1)
    BEGIN
        EXEC @retcode = sp_change_subscription_properties
                @publisher = @publisher,
                @publisher_db = @publisher_db,
                @publication = @publication,
                @property = 'offload_agent',
                @value = 'false'
        IF @@error <> 0 OR @retcode <> 0
            GOTO Failure
    END

    IF @@error <> 0 OR @retcode <> 0
        GOTO Failure

    COMMIT TRANSACTION subscription_properties
    RETURN (0)
            
Failure:        
    ROLLBACK TRANSACTION subscription_properties
    RETURN (1)
GO
EXEC dbo.sp_MS_marksystemobject sp_change_subscription_properties
GO
grant execute on dbo.sp_change_subscription_properties to public

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

CREATE PROCEDURE sp_MSget_pullsubsagent_owner (
    @publisher    sysname,
    @publisher_db sysname,
    @publication  sysname,   /* publication name */
    @owner_sid    varbinary(85) OUTPUT 
    ) AS

    declare @job_id uniqueidentifier
    set nocount on

    select @owner_sid = null
        

    if exists (select * from sysobjects 
               where type = 'U' and 
                     name = 'MSreplication_subscriptions')
    begin 
        -- Get the job_id corresponding to the publication
        select @job_id = agent_id
        from MSreplication_subscriptions
        where upper(@publisher) = upper(publisher) and
            @publisher_db = publisher_db and
            @publication = publication 

        -- Using the job_id in MSsubscription properties to get the owner_sid 
        -- in msdb..sysjobs    
        select @owner_sid = owner_sid
        from  msdb..sysjobs
        where @job_id = job_id
    end            
go 

exec dbo.sp_MS_marksystemobject 'sp_MSget_pullsubsagent_owner'

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

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

    SET NOCOUNT ON

    /*
    ** Declarations.
    */


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

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

    /*
    ** Security Check
    */

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    begin tran
    save TRAN droppullsubscription

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


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

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

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

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

    END

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

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

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

        IF @@ERROR <> 0 
            GOTO UNDO

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

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

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

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

    return 1
go
exec sp_MS_marksystemobject 'dbo.sp_droppullsubscription'

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

CREATE PROCEDURE sp_helppullsubscription (
    @publisher sysname = '%',
    @publisher_db sysname = '%',
    @publication sysname = '%',
	@show_push nvarchar(5) = 'false'
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */


    DECLARE @command nvarchar(255)
    DECLARE @name nvarchar(255)
	DECLARE @retcode int
	DECLARE @show_push_bit bit
	DECLARE @push int
	declare @subscriber			sysname
	declare @subscriber_db		sysname
	declare @publisher_local	sysname
	declare @publisher_db_local	sysname
	declare @publication_local	sysname
	declare @subscription_name 	nvarchar(1000)
	declare @regkey				nvarchar(1000)
	declare @syncmgr_keyexist				int
	declare @helpsubscriptioncursor_open	int


	SELECT @push = 0

	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
		-- The database is attached from a subscription copy file without using
		-- sp_attachsubscription. Return nothing
		return 0

    /*
    ** Security Check
    */

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

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

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

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

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

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

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


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

	IF LOWER(@show_push collate SQL_Latin1_General_CP1_CS_AS) = 'false'				
		SELECT @show_push_bit = 0	
    IF LOWER(@show_push collate SQL_Latin1_General_CP1_CS_AS) = 'true'	
		SELECT @show_push_bit = 1


	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSreplication_subscriptions')
		RETURN (0)

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
		RETURN (0)

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_agents')
		RETURN (0)

				
    /*
    ** Get the result
	**
	** Note: have to return meta data
    */
	    SELECT  'publisher'				= rs.publisher,
            'publisher database'	= rs.publisher_db,
            'publication'			= rs.publication,
			'independent_agent'		= rs.independent_agent,
            'subscription type'     = rs.subscription_type,
            'distribution agent'	= distribution_agent,
			'publication description'   = description,
			'last updating time'		= convert(nvarchar(12), time, 112) + 
                                          substring(convert(nvarchar(24), time, 121), 11,13),
			'subscription_name'	  	= rs.publisher + ':' + rs.publisher_db + ':' + rs.publication,
			'last transaction timestamp' = transaction_timestamp,
			-- SyncTran
			-- For Queued case, we will return 2/3 for values 4/5 so that
			-- SQL-DMO does not have to deal with the overloaded values of update_mode
			'update_mode'         = case 	when rs.update_mode = 4 then 2
											when rs.update_mode = 5 then 3
											else rs.update_mode
									end,
			'distribution agent job_id' = agent_id,
			'enabled for syncmgr' = enabled_for_syncmgr,
    		'subscription guid' = subscription_guid,
			'subid ' = subid,
			'immediate_sync' = immediate_sync,
	        'publisher_login' = publisher_login,
            'publisher_password' = publisher_password,
            'publisher_security_mode' = publisher_security_mode,
            'distributor' = distributor,
            'distributor_login' = distributor_login,
            'distributor_password' = distributor_password,
            'distributor_security_mode' = distributor_security_mode,
            'ftp_address' = ftp_address,
            'ftp_port' = ftp_port,
            'ftp_login' = ftp_login,
            'ftp_password' = ftp_password,
            'alt_snapshot_folder' = alt_snapshot_folder,
            'working_directory' = working_directory,
            'use_ftp' = use_ftp,
            'publication_type' = publication_type,
			'dts_package_name' = dts_package_name,
			'dts_package_location' = dts_package_location,
            'offload_agent' = offload_agent,
            'offload_server' = offload_server,
			a.last_sync_status, 
			a.last_sync_summary,
			'last_sync_time' = convert(nvarchar(12), a.last_sync_time, 112) + 
				substring(convert(nvarchar(24), a.last_sync_time, 121), 11,13)
       from MSreplication_subscriptions rs
       left outer join MSsubscription_properties sp 
                    on (UPPER(rs.publisher) = UPPER(sp.publisher) and rs.publisher_db = sp.publisher_db and rs.publication = sp.publication) 
       left outer join MSsubscription_agents a
                    on (UPPER(rs.publisher) = UPPER(a.publisher) and 
						rs.publisher_db = a.publisher_db and 
						((rs.publication = a.publication and 
						rs.independent_agent = 1 and
						a.publication <> N'ALL') or
						(a.publication = N'ALL' and rs.independent_agent = 0)) and
						rs.subscription_type = a.subscription_type)
                where ((@publisher = N'%') OR (UPPER(rs.publisher) = UPPER(@publisher))) AND
                      ((@publisher_db = N'%') OR (rs.publisher_db = @publisher_db)) AND
                      ((@publication = N'ALL' AND rs.independent_agent = 0) OR rs.publication LIKE @publication) AND
					  (rs.subscription_type <> @push OR
					   @show_push_bit = 1)
        ORDER BY rs.publisher, rs.publisher_db, rs.publication  
GO


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

create procedure sp_MStable_has_unique_index @tabid int
as
begin

	/* 
	** Returns id of unique index, if it exists, else 0
	*/
	declare @indid int

	if (ObjectProperty(@tabid, 'IsTable') = 1) and (ObjectProperty(@tabid, 'TableHasIndex') = 1)
	begin
        -- First get the primary index id. 
		select @indid = i.indid from sysindexes i where 
            -- get the primary key index
            (i.status & 2048) <> 0
			and i.id = @tabid

        if @indid is null
        begin
            -- Get the first unique index
		    select top 1 @indid = i.indid from sysindexes i where 
                (i.status & 2) <> 0
			    and i.id = @tabid
                order by i.indid asc
        end
		if @indid is null select @indid = 0
	end
	else
		select @indid = 0

	return @indid
end
go

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

CREATE PROCEDURE sp_MSchange_retention (@pubid uniqueidentifier, @value nvarchar(255))
as
	declare @re_pubid			uniqueidentifier 
	declare @artid				uniqueidentifier
	declare @schemaversion      int 
    declare @schemaguid         uniqueidentifier
    declare @schematype         int
    declare @schematext         nvarchar(2000)
	declare @retcode			int

    -- Security check
	if  1 <> {fn ISPALUSER(@pubid)}  
	begin
		raiserror(15247,-1,-1)
		return 1
	end

	begin TRAN	
		update sysmergepublications set retention = convert(int, @value) where pubid = @pubid
		if @@ERROR<>0
			goto UNDO
			
		declare #change_retention CURSOR LOCAL FAST_FORWARD fast_forward for 
			select pubid from sysmergearticles 
				where pubid<>@pubid and 
					  nickname in (select nickname from sysmergearticles where pubid=@pubid) and
					  pubid in (select pubid from dbo.sysmergepublications 
					  				where upper(publisher) collate database_default = upper(@@servername) collate database_default and
					  					  publisher_db = db_name())
					  
		open #change_retention
		fetch #change_retention into @re_pubid
		while (@@fetch_status <> -1)
		BEGIN
			update sysmergepublications set retention = convert(int, @value) where pubid = @re_pubid
			if @@ERROR<>0
				goto UNDO
			set @schematype = 9 /* change retention */
			set @artid = newid()
	        select @schematext = 'exec dbo.sp_MSchange_retention '+ '''' + convert(nchar(36),@re_pubid) + '''' + ',' + '''' + @value + ''''          
			select @schemaversion = schemaversion from sysmergeschemachange
			if (@schemaversion is NULL)
				set @schemaversion = 1
			else
				select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
			set @schemaguid = newid()
			exec @retcode=sp_MSinsertschemachange @re_pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
			if @@ERROR<>0 or @retcode<>0 
				goto UNDO
			fetch #change_retention into @re_pubid
		END
		close #change_retention
		deallocate #change_retention
	COMMIT TRAN
	return (0)
UNDO:
	if @@TRANCOUNT = 1
		ROLLBACK TRAN
	else
		COMMIT TRAN
	return(1)
GO
exec dbo.sp_MS_marksystemobject sp_MSchange_retention 
go
grant execute on dbo.sp_MSchange_retention to public


raiserror('Creating procedure sp_MSchange_priority', 0,1)
GO
-- @value has to be unicode too.

CREATE PROCEDURE sp_MSchange_priority (@subid uniqueidentifier, @value nvarchar(255))
as
    declare @retcode int
    exec @retcode = dbo.sp_MSreplcheck_subscribe
    if @retcode <> 0 or @@error <> 0
        return 1
        
	update sysmergesubscriptions set priority = convert(real, @value)
	       where subid = @subid
go
exec dbo.sp_MS_marksystemobject sp_MSchange_priority 
go
grant execute on dbo.sp_MSchange_priority to public

raiserror('Creating procedure sp_expired_subscription_cleanup', 0,1)
GO
 
CREATE PROCEDURE sp_expired_subscription_cleanup
AS
declare @retcode 		int
declare @publisher_db	sysname
declare @category		int
declare @proc_name		nvarchar(200)
declare @distributor 	sysname
declare @distribdb		sysname
declare @distproc		nvarchar(300)
/*
** Security Check
*/
	EXEC @retcode = dbo.sp_MSreplcheck_publish
	IF @@ERROR <> 0 or @retcode <> 0
		return (1)
	/*
	** Get distribution server information for remote RPC call.
	*/

EXECUTE @retcode = sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
     @distribdb   = @distribdb OUTPUT
IF @@ERROR <> 0 or @retcode <> 0
    BEGIN
        RAISERROR (20036, 16, -1)
        return (1)
    END
	
		
DECLARE DC CURSOR LOCAL FAST_FORWARD for select DISTINCT name, category from master..sysdatabases 
	where (category & 4) = 4 or (category & 1 = 1)
	for read only
	open DC
	fetch DC into @publisher_db, @category
	WHILE (@@fetch_status <> -1)
	BEGIN
		if (@category & 4 = 4)
			begin
				select @proc_name = @publisher_db + '.dbo.sp_MSdrop_expired_mergesubscription'
				exec @retcode = @proc_name
				if @retcode<>0 or @@ERROR<>0
					goto DONE
			end
		if (@category & 1 = 1)
			begin
				select @proc_name = @publisher_db + '.dbo.sp_MSdrop_expired_subscription'
				exec @retcode = @proc_name
				if @retcode<>0 or @@ERROR<>0
					goto DONE
			end	
	fetch DC into @publisher_db, @category
	END

	/*
	** sp_MScleanup_agent_entry in distribution database is called to periodically remove obselete
	** entries in MSmerge_agents, which may be caused by the following reasons:
	**  1. publishing database is externally removed; therefore cleanup agent can not do its job
	**  2. Entries for anonymous merge subscriptions
	*/
	SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '..sp_MScleanup_agent_entry'
	exec @retcode = @distproc 
	if @@ERROR<>0 or @retcode<>0
	BEGIN
		close DC
		deallocate DC
    	return (1)
    END

DONE:
	close DC
	deallocate DC
GO

go
exec dbo.sp_MS_marksystemobject sp_expired_subscription_cleanup
go
grant execute on dbo.sp_expired_subscription_cleanup to public


raiserror('Creating procedure sp_addmergepullsubscription', 0,1)
GO
 
CREATE PROCEDURE sp_addmergepullsubscription (
	@publication 				sysname,	      			/* Publication name */
	@publisher					sysname = @@SERVERNAME,  	/* Publisher server */
	@publisher_db				sysname = NULL,  			/* Publication database */
	@subscriber_type 			nvarchar(15) = 'local',			/* Subscriber type */ 
	@subscription_priority 		real 		= NULL,				/* Subscription priority */
    @sync_type 					nvarchar(15) = 'automatic', /* subscription sync type */
	@description 				nvarchar(255) = NULL			  
 	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @retcode				int
    declare	@subscriber_db			sysname
    declare @subnickname			int
    declare @subscriber_srvid		int 
    declare @publisher_srvid		int 
    declare @priority 				real
    declare @subid	 				uniqueidentifier
    declare @subscriber_typeid 		smallint
    declare @subscription_type	 	smallint
    declare @command 				nvarchar(255)
    declare @inactive				tinyint 
	declare @global 				tinyint		/* subscriber type is global */
	declare @push 					tinyint		/* subscription type is push */
	 
    declare @sync_typeid 			tinyint
	declare @nosync 				tinyint		
	declare @automatic				tinyint			 
	declare @pubid					uniqueidentifier			 
	declare @partnerid				uniqueidentifier			 
    declare @parentid               uniqueidentifier

	/*
    ** Initializations.
    */

    SET @nosync 			= 2       /* Const: synchronization type 'none' */
    SET @automatic 			= 1       /* Const: synchronization type 'automatic' */
	SET @inactive 			= 0
    SET @global 			= 1
	SET @push 				= 0   


	set @pubid 				= newid()
	set @partnerid			= @pubid
	
	set @parentid			= '00000000-0000-0000-0000-000000000000'
	 
	/* 
	** Check if replication components are installed on this server
	*/
	exec @retcode = dbo.sp_MS_replication_installed
	if (@retcode <> 1)
	begin
		return (1)
	end

    /*
    ** Security Check.
    */

	EXEC @retcode = dbo.sp_MSreplcheck_subscribe
	if @@ERROR <> 0 or @retcode <> 0
		return(1)

	/*
	**	Check to see if merge system tables exist. Create them unless they already
	**  exist.
	*/
	IF not exists (select name from sysobjects where name='sysmergesubscriptions')
		BEGIN
			execute @retcode = dbo.sp_MScreate_mergesystables
				if @@ERROR <> 0 or @retcode <> 0
					begin
						return (1)
					end
		END	

	if UPPER(@publisher) = UPPER(@@SERVERNAME) and @publisher_db = db_name()
		begin
			raiserror(21126, 16, -1)
			return (1)
		end

	if exists (select pubid from sysmergepublications where UPPER(publisher) = UPPER(@@SERVERNAME) and publisher_db=db_name()) and @subscriber_type in ('local', 'anonymous')
		begin
            declare @dbname sysname
            select @dbname = DB_NAME()
    	    raiserror(21258, 16, -1, @dbname)
			return (1)
		end
	/* 
	** When adding a pull subscription, if a push subscription for that publication already exists, 
	** we will raise error and fail
	*/
	IF EXISTS (select name from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db)
	BEGIN
		select @pubid=pubid from sysmergepublications 
			where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
		IF EXISTS (select subid from sysmergesubscriptions where pubid=@pubid and subid<>@pubid and subscription_type=0)
			begin
				RAISERROR (21317, 16, -1, @publication)
				return (1)
			end
		ELSE
			begin
				IF EXISTS (select status from sysmergesubscriptions where pubid=@pubid and status =	2)
					begin
						select @subid = subid from sysmergesubscriptions where pubid=@pubid and subid<>pubid
						delete sysmergesubscriptions where pubid=@pubid
						delete MSmerge_replinfo where repid = @subid
					end
				ELSE 
					begin
						RAISERROR (14058, 16, -1)
						return (1)
					end
			end
	END

	set @partnerid = @pubid
     
  	/*
    ** Assign parameter values appropriately for the local server database
	*/
	set @subscriber_db = DB_NAME()
	select @subscriber_srvid = 0

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

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

    EXECUTE @retcode = dbo.sp_validname @publisher
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
	/*
	** Validate that the publisher is a valid server
	*/
	select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
    IF @publisher_srvid IS NULL
		BEGIN
		    EXECUTE @retcode = dbo.sp_addserver @publisher
	        IF @@error <> 0 OR @retcode <> 0
    			BEGIN
		    		RAISERROR (14010, 16, -1)
			       	RETURN (1)
	            END
	        ELSE
	        	select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) collate database_default
		END


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

    IF LOWER(@publisher_db) = 'all'
    BEGIN
        RAISERROR (14136, 16, -1)
        RETURN (1)
    END
	
	/*
	** Check to see if the publication name is already used in the subscription 
	** database - This is the case where we are resubscribing to the same publication.
	** Execute dbo.sp_MSpublicationcleanup to cleanup all all the defunct rows
	
	** if exists (select * from sysmergepublications where name = @publication)
	** begin
	**	exec @retcode = dbo.sp_MSpublicationcleanup 
	**    IF @@ERROR <> 0 OR @retcode <> 0
	**    	BEGIN
	**			RAISERROR (20025, 16, -1, @publication)
	**	    	RETURN (1)
	**		END				    	
	** end
	*/

    /*
    ** Parameter Check: @subscriber_type.
    ** Set subscriber_typeid based on the @subscriber_type specified.
    **
    **   subscriber_type     subscriber_type
    **   =================    ===============
    **             1     		global
    **             2     		local
    **             3     		anonymous
    **             NO support for republisher for B 3
    */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('local', 'global', 'anonymous')
        BEGIN
		  	RAISERROR (20023, 16, -1)
			RETURN (1)
        END

	set @subscription_type = 1 /* pull by default */
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('global')
        set @subscriber_typeid = 1
    else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local')
        set @subscriber_typeid = 2
	else if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('anonymous')       
		begin
			/* For anonymous subscribers set subscription type appropriately */
	        set @subscriber_typeid = 3
	        set @subscription_type = 2
		end	        

	/* 
	** Assign priority appropriately - choose 0.99 times the minimum priority
	** of the global replicas.
	*/
	if (@subscription_priority > 100.0 or @subscription_priority < 0.0)
		set @subscription_priority = NULL		
	if (@subscription_priority IS NULL)
		begin
			select @priority = 0.99 * min(priority) from sysmergesubscriptions where subscriber_type  = 1 /* global/loopback */
			if (@priority IS NOT NULL)
				select @subscription_priority = @priority
			if (@subscription_priority IS NULL) 
				select @subscription_priority = 0.0
		end
	/*
	** For local and anonymous subscriptions the priority is 0.0
	*/
    if LOWER(@subscriber_type collate SQL_Latin1_General_CP1_CS_AS) IN ('local', 'anonymous')
		select @subscription_priority = 0.0

	/*
 	** If the subscription already exists, don't add it.
	
 	** if EXISTS (select db_name, srvid
 	**		FROM sysmergesubscriptions
    ** 		WHERE db_name = @subscriber_db
    ** 		AND srvid = @subscriber_srvid                	       
    **    	AND pubid = @pubid)
	**	BEGIN
	**		RAISERROR (14058, 16, -1)
	**		RETURN (1)
 	**	END
	*/

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


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


   IF LOWER(@sync_type collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
   BEGIN
		SET @sync_typeid = @automatic
   END
   ELSE
   BEGIN
        SET @sync_typeid = @nosync
   END


	/*
	** UNDONE: Validate that the publisher is of type 'republisher'
	*/

	begin tran
    save TRAN addmergepullsubscription
		
		/* Generate a guid for the Subscriber ID */
		set @subid = newid()

		/* Look for existing nickname from any other subscription */
		exec dbo.sp_MSgetreplnick NULL, NULL , NULL,  @subnickname out
		if (@@error <> 0) 
	        begin
            goto FAILURE
	        end                 


		/* Generate a new replica nickname from the @subid */
		if (@subnickname is null)
			EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output

	
		/* 
		** Check to see if MSsubscription_properties table exists.
		** If not, create it.
		*/
		exec @retcode = dbo.sp_MScreate_sub_tables
			@tran_sub_table = 0,
			@property_table = 1,
			@sqlqueue_table = 0

		IF @@ERROR <> 0 or @retcode <> 0
			goto FAILURE

		/*
		** The subscription doesn't exist, so let's add it to sysmergesubscriptions 
		*/
		INSERT sysmergesubscriptions (subid, partnerid, datasource_type, srvid, db_name, 
				pubid, status, subscriber_type, subscription_type, priority, sync_type, 
				description, login_name, subscriber_server, publication)
					VALUES (@subid,
							@partnerid,
							0,
		    				@subscriber_srvid,
		    				@subscriber_db,
		    				@pubid,
		    				@inactive,
		    				@subscriber_typeid,
							@subscription_type, 	/* for a pull/anon subscription */
		    				@subscription_priority,
		    				@sync_typeid,
		    				@description,
		    				suser_sname(suser_sid()),
		    				@@servername,
		    				@publication)			
		if @@ERROR <> 0
			BEGIN
				GOTO FAILURE
			END

		/* Add a self-subscribed subscription to represent the publication */
			
		insert sysmergepublications(publisher, publisher_db, pubid, name, parentid) 
			values(@publisher, @publisher_db, @pubid, @publication, @parentid)
		if @@ERROR <> 0
			begin
				goto FAILURE
			end
		insert sysmergesubscriptions(subid, partnerid, datasource_type, srvid, db_name, 
				pubid, subscriber_type, subscription_type, status, priority, sync_type, description, login_name, subscriber_server, publication, distributor)
			values (@pubid, @pubid, 0, @publisher_srvid, @publisher_db, 
				@pubid, @global, @push, @inactive, 100.0, @sync_typeid, @description, suser_sname(suser_sid()), @publisher, @publication, @publisher)  
						
		if @@ERROR <> 0
			begin
				goto FAILURE
			end
					
		/*
		**  Add row for subscription in MSmerge_replinfo.
		*/
		insert MSmerge_replinfo(repid, replnickname)
				values (@subid, @subnickname)
		if @@ERROR <> 0
			BEGIN
				GOTO FAILURE
			END

    COMMIT TRAN
	return (0)

FAILURE:
	RAISERROR (14057, 16, -1)
	if @@trancount > 0
	begin
		ROLLBACK TRANSACTION addmergepullsubscription
		COMMIT TRANSACTION
	end
	RETURN (1)

go
exec dbo.sp_MS_marksystemobject sp_addmergepullsubscription 
go

grant execute on dbo.sp_addmergepullsubscription to public
go
 
raiserror('Creating procedure sp_changemergepullsubscription', 0,1)
GO

CREATE PROCEDURE sp_changemergepullsubscription (
	@publication 		sysname = '%',	/* Publication name */
	@publisher			sysname = '%',  /* Publisher server */
	@publisher_db		sysname = '%', 	/* Publication database */
    @property 			sysname = NULL, /* The property to change */
    @value 				nvarchar(255) = NULL	/* The new property value */
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @subscriber_srvid	 	int
    declare @publisher_srvid	 	int
	declare @retcode 				int
	declare	@pubid 					uniqueidentifier
	declare	@subid 					uniqueidentifier
	declare	@partnerid 				uniqueidentifier
    declare @sync_typeid 			tinyint
    declare @nosync 				tinyint
    declare @automatic 				tinyint
     
    declare @artid					uniqueidentifier
	declare @subscriber				sysname
	declare @subscriber_db			sysname
    declare @schematype				int
	declare @schemaversion			int
	declare @schemaguid				uniqueidentifier
    declare @db_name				sysname
    declare @subscriber_type		int
    declare @schematext				nvarchar(2000)
	declare @use_interactive_bit	bit
	declare @use_interactive_int	int
	declare @enabled_for_syncmgr	int
	declare @regkey					nvarchar(1000)
	declare @snapshot_ready			int
    /*
    ** Initializations.
    */
    SET @subscriber 	= @@SERVERNAME
    SET @subscriber_db	= DB_NAME()
    SET @nosync 		= 2     /* Const: synchronization type 'none' */
    SET @automatic 		= 1     /* Const: synchronization type 'automatic' */

	select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
    IF @subscriber_srvid IS NULL
		BEGIN
		   RAISERROR (14010, 16, -1)
		   RETURN (1)     
		END

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


	/*
	**	Check to see if current database is enabled for subscribing
	*/
	IF not exists (select name from sysobjects where name='sysmergesubscriptions')
		BEGIN
        	RAISERROR (14055, 16, -1)
	    	RETURN (1)
		END

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

    IF @property IS NULL
        BEGIN
            CREATE TABLE #tab1 (properties sysname collate database_default not null)
            INSERT INTO #tab1 VALUES ('sync_type')
            INSERT INTO #tab1 VALUES ('priority')
            INSERT INTO #tab1 VALUES ('description') 
            INSERT INTO #tab1 VALUES ('use_interactive_resolver') 			
            -- Properties delegated to sp_change_subscription_properties
            INSERT INTO #tab1 VALUES ('publisher_login')
            INSERT INTO #tab1 VALUES ('publisher_password')
            INSERT INTO #tab1 VALUES ('publisher_security_mode')
            INSERT INTO #tab1 VALUES ('distributor')
            INSERT INTO #tab1 VALUES ('distributor_login')
            INSERT INTO #tab1 VALUES ('distributor_password')
            INSERT INTO #tab1 VALUES ('distributor_security_mode')
            INSERT INTO #tab1 VALUES ('ftp_address')
            INSERT INTO #tab1 VALUES ('ftp_port')
            INSERT INTO #tab1 VALUES ('ftp_login')
            INSERT INTO #tab1 VALUES ('ftp_password')
            INSERT INTO #tab1 VALUES ('alt_snapshot_folder')
            INSERT INTO #tab1 VALUES ('working_directory')
            INSERT INTO #tab1 VALUES ('use_ftp')
            INSERT INTO #tab1 VALUES ('offload_agent')
            INSERT INTO #tab1 VALUES ('offload_server')
            INSERT INTO #tab1 VALUES ('dynamic_snapshot_location')
            select * FROM #tab1
            RETURN (0)
        END

    /*
    ** Parameter Check:  @publisher.
    ** Check to make sure we have a valid publisher.
    ** Should make sure that @publisher is non-null before using it to check whether @publication is valid
    */
    IF @publisher IS NULL
        BEGIN
            RAISERROR (14043, 16, -1, '@publisher')
            RETURN (1)
        END

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

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

    select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
    IF @pubid IS NULL
        BEGIN
            RAISERROR (20026, 11, -1, @publication)
            RETURN (1)
        END

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

    /*
    ** Check to see if you have a local / global subscription on this publication
    */
    set @subid = NULL
	select @subid = subs1.subid, 
    @pubid = pubs.pubid, /* identified from publication name */
	@subscriber_type=subs1.subscriber_type,
    	@partnerid = subs2.subid from
		sysmergesubscriptions 	subs1,
	  	sysmergesubscriptions 	subs2,
		sysmergepublications 	pubs
		where subs1.srvid = @subscriber_srvid
			and subs1.db_name = @subscriber_db
			and subs2.srvid = @publisher_srvid
			and subs2.db_name = @publisher_db
			and subs1.pubid = subs2.subid
			and subs2.pubid = pubs.pubid
			and pubs.name = @publication
			and UPPER(pubs.publisher)=UPPER(@publisher)
			and pubs.publisher_db = @publisher_db

	if @subid IS NULL 
     	begin
            RAISERROR (14050, 11, -1)
            RETURN(1)
		end     			

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

	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
                               ('sync_type', 
                                'priority', 
                                'description',
                                'publisher_login',
                                'publisher_password',
                                'publisher_security_mode',
                                'distributor',
                                'distributor_login',
                                'distributor_password',
                                'distributor_security_mode',
                                'ftp_address',
                                'ftp_port',
                                'ftp_login',
                                'ftp_password',
                                'alt_snapshot_folder',
                                'working_directory',
                                'use_ftp',
                                'use_interactive_resolver',
                                'offload_agent',
                                'offload_server',
                                'dynamic_snapshot_location')
        BEGIN
            RAISERROR (21348, 16, -1, @property)
            RETURN (1)
        END

    /*
    ** Change the property.
    */
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'sync_type'
        BEGIN

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

            IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('automatic', 'none')
                BEGIN
                    RAISERROR (14052, 16, -1)
                    RETURN (1)
                END

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

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'automatic'
		        SET @sync_typeid = @automatic
	        ELSE
		        SET @sync_typeid = @nosync

            /*
            ** Update the subscription with the new sync_type.
            */

            UPDATE sysmergesubscriptions
               	SET sync_type = @sync_typeid
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END

        END
        
	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'description'
        BEGIN
		UPDATE sysmergesubscriptions
               	SET description = @value
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1) 
              
                    RETURN (1)
                END

        END

	IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'use_interactive_resolver'
        BEGIN

            /* Check to make sure that we have a true/false. */

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

            /* Determine the bit value. */

	        IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
		        SET @use_interactive_bit = 1
	        ELSE
		        SET @use_interactive_bit = 0
	
			/* Update the subscription with the new 'use_interactive' value. */

            UPDATE sysmergesubscriptions
               	SET use_interactive_resolver = @use_interactive_bit
             	WHERE subid = @subid
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END
			/* If the subscription is enable for Sync Manager, then update the reg value */
			exec sp_MSsubscription_enabled_for_syncmgr
				@publisher, @publisher_db, @publication, @subscriber, @subscriber_db, 
				@enabled_for_syncmgr OUT, @regkey OUT
            IF @@ERROR <> 0
                BEGIN
                    RAISERROR (14053, 16, -1)
                    RETURN (1)
                END
			if @enabled_for_syncmgr = 1
				begin
			        select @use_interactive_int = convert(int, @use_interactive_bit)
					EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
			                               @regkey,
			                               'UseInteractiveResolver',
			                               'REG_DWORD',
			                                @use_interactive_int
					if @retcode <> 0 OR @@ERROR <> 0
		                BEGIN
		                    RAISERROR (14053, 16, -1)
		                    RETURN (1)
		                END
				end

        END
        

     
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'priority'
    BEGIN

		select @db_name = db_name from sysmergesubscriptions
        	where (pubid=@pubid) and (subid=@pubid)
        IF @db_name <> db_name()
	        BEGIN
    	    	RAISERROR (20047, 16, -1)
        	    RETURN (1)
	        END

	    /* Only the original publisher can change priority of a global subscriptions */

    	IF @subscriber_type<>1  
    	    BEGIN
        	    RAISERROR (20044, 16, -1)  /* Local subscriber does not have priority*/
	            RETURN (1)
    	    END

		 
		BEGIN TRANSACTION
		save tran sp_changemergepullsubscription
        	exec dbo.sp_MSchange_priority @subid,  @value
            select @snapshot_ready=snapshot_ready from sysmergepublications where pubid = @pubid
	    	/* Insert the sp_MSchange_priority schema change only if the publication's snapshot is ready */
			if (@snapshot_ready > 0)
			begin
		     	select @schemaversion = schemaversion from sysmergeschemachange
				if (@schemaversion is NULL)
				set @schemaversion = 1
				else
					select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
				set @schemaguid = newid()
				set @artid = newid()
				set @schematype = 8 /* change priority */
				select @schematext = 'exec dbo.sp_MSchange_priority '+ '''' + convert(nchar(36),@subid) + '''' + ',' + '''' + @value + '''' 
			 	exec dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
                if @@ERROR <> 0 goto Rollback_tran
			end		 	
		COMMIT TRANSACTION

	END
	
    IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) IN 
                           ('publisher_login',
                            'publisher_password',
                            'publisher_security_mode',
                            'distributor',
                            'distributor_login',
                            'distributor_password',
                            'distributor_security_mode',
                            'ftp_address',
                            'ftp_port',
                            'ftp_login',
                            'ftp_password',
                            'alt_snapshot_folder',
                            'working_directory',
                            'use_ftp',
                            'offload_agent',
                            'offload_server',
                            'dynamic_snapshot_location')
    BEGIN
        EXEC @retcode = sp_change_subscription_properties @publisher = @publisher,
                                                          @publisher_db = @publisher_db,
                                                          @publication = @publication,
                                                          @property = @property,
                                                          @value = @value,
                                                          @publication_type = 2
        IF @retcode <> 0
            RETURN 1
    END


    /*
    ** Return succeed.
    */

    RAISERROR (14054, 10, -1)
    RETURN (0)
Rollback_tran:
	rollback tran sp_changemergepullsubscription
	commit tran
	return(1)
go

exec dbo.sp_MS_marksystemobject sp_changemergepullsubscription 
go

grant execute on dbo.sp_changemergepullsubscription to public
go


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

CREATE PROCEDURE sp_helpmergepullsubscription(
	@publication 		sysname = '%',		/* Publication name */
	@publisher			sysname = '%',  	/* Publisher server */
	@publisher_db		sysname = '%',  	/* Publication database */
	@subscription_type	nvarchar(10) = 'pull'	/* Show only pull subscriptions */
	)AS
	
    SET NOCOUNT ON

    /*
    ** Declarations.
    */

    declare @retcode 			int
    declare @srvid	 			int
	declare	@pubid 				uniqueidentifier
	declare	@subid 				uniqueidentifier
	declare	@partnerid 			uniqueidentifier
    declare @cursor_open		int
	declare @subscriber			sysname
	declare @subscriber_db		sysname
    declare @subscription_set 	nvarchar(10)
	declare @publisher_local	sysname
	declare @publisher_db_local	sysname
	declare @publication_local	sysname
	declare @subscription_name 	nvarchar(1000)
	declare @regkey				nvarchar(1000)
	declare @syncmgr_keyexist				int
	declare @helpsubscriptioncursor_open	int
	

    /*
    ** Initializations.
    */
	set @cursor_open 			= 0					

	select @publisher_db = RTRIM(@publisher_db)
	select @publication = RTRIM(@publication)
	
	-- For attach
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
		-- The database is attached from a subscription copy file without using
		-- sp_attachsubscription. Return nothing
		return 0

	/*
	**	Calling sp_help* is all right whether current database is enabled for pub/sub or not
	*/

	IF not exists (select * from sysobjects where name='sysmergesubscriptions')
		RETURN (0)

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

	set @subscriber = @@SERVERNAME	 
	set @subscriber_db = DB_NAME()
 
    /*
    ** Parameter Check: @publisher
    ** Check to make sure that the publisher is defined
    */
    IF @publisher <> '%' AND @publisher IS NOT NULL
    BEGIN
		EXECUTE @retcode = dbo.sp_validname @publisher

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

	/*
    ** Parameter Check: @subscription_type.
    ** Set subscription_typeid based on the @subscription_type specified.
    **
    **   subscription_type    subscription_type
    **   =================    ===============
    **             0     		push
    **             1     		pull
    **			  0,1			both
    */
    if LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('push', 'pull', 'both')
        BEGIN
		  	RAISERROR (14128, 16, -1)
			RETURN (1)
        END
    IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'both'
        set @subscription_set = '(0, 1)'
    else IF LOWER(@subscription_type collate SQL_Latin1_General_CP1_CS_AS) = 'push'
        set @subscription_set = '(0)'
    else 
        set @subscription_set = '(1,2)'   -- including pull subscription and pull/anonymous subscription

	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
		RETURN (0)

    /*
    ** Get subscriptions
    */
	
	create table #helpmergepullsubscription
				(
					publication				sysname		collate database_default not null,
					publisher				sysname		collate database_default not null,
					publisher_db			sysname		collate database_default not null,
					subscriber				sysname		collate database_default not null,
					subscriber_db		 	sysname		collate database_default not null,
					status    				int     	NOT NULL,
					subscriber_type 		int		    NOT NULL,
					subscription_type 		int		    NOT NULL,
					priority				float(8)	NOT NULL,
					sync_type				tinyint		NOT NULL,
					description				nvarchar(255) 	collate database_default null,
					merge_jobid				binary(16)		NULL,
					enabled_for_syncmgr		int				NULL,
					last_updated	        nvarchar(26) 	collate database_default null,
                    use_interactive_resolver 	int			NULL,
                    subid					uniqueidentifier	not NULL,
                    last_sync_status		int				NULL,
                    last_sync_summary		sysname			collate database_default null
				)

    IF @publisher IS NULL and @publisher_db IS NULL
	    BEGIN
	    	select @subid = subid from sysmergesubscriptions where subid = partnerid
	    	set @partnerid = @subid
			-- show the loopback subscription
		    insert into #helpmergepullsubscription 
				select pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
					subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
					subs1.sync_type, subs1.description, replinfo.merge_jobid, 0, 
					convert(nvarchar(12), subs1.last_sync_date, 112) + substring(convert(nvarchar(24), subs1.last_sync_date, 121), 11,13), 
					subs1.use_interactive_resolver, @subid, subs1.last_sync_status, subs1.last_sync_summary
		    	FROM  	sysmergesubscriptions 	subs1,
		    		  	sysmergesubscriptions 	subs2,
		    		  	MSmerge_replinfo	 	replinfo,
	        			master.dbo.sysservers 	servers1,
	        			master.dbo.sysservers 	servers2,
						sysmergepublications 	pubs
				where subs1.subid = @subid
					and subs2.subid = @partnerid
					and pubs.pubid = subs1.pubid
					and servers1.srvid = subs1.srvid
					and servers2.srvid = subs2.srvid
					and subs1.subid = subs1.partnerid 
					and replinfo.repid = subs1.subid 
	    	
	    END
	else
		begin
			declare #cursor cursor local FAST_FORWARD FOR select DISTINCT sub.subid, sub.partnerid 
	        	FROM sysmergesubscriptions 	sub,
	    	    sysmergesubscriptions 		sub1, 
	            master.dbo.sysservers		ss,  
	            master.dbo.sysservers		ss1, 
	            sysmergepublications 		pub 
	         	WHERE ((@subscriber = N'%') OR (UPPER(ss.srvname) = UPPER(@subscriber) collate database_default)) 
					AND ((@publisher = N'%') OR (UPPER(ss1.srvname) = UPPER(@publisher) collate database_default)) 
					AND sub1.srvid = ss1.srvid 
	           		AND sub.srvid = ss.srvid  
	           		AND pub.name LIKE  @publication  
	           		AND sub.pubid = pub.pubid 
                                AND ((@subscriber_db = N'%') OR (sub.db_name = @subscriber_db collate database_default))
                                AND ((@publisher_db = N'%') OR (sub1.db_name = @publisher_db collate database_default))
					AND sub1.pubid = pub.pubid 
					AND (sub.subscription_type=1 or sub.subscription_type=2) 
				FOR READ ONLY

			open #cursor
			select @cursor_open = 1					
			fetch next from #cursor into @subid, @partnerid
			while (@@fetch_status <> -1)
				begin
				    insert into #helpmergepullsubscription 
						select pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, 
							subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, 
							subs1.sync_type, subs1.description, replinfo.merge_jobid, 0, 
							convert(nvarchar(12), subs1.last_sync_date, 112) + substring(convert(nvarchar(24), subs1.last_sync_date, 121), 11,13), 
							subs1.use_interactive_resolver, @subid, subs1.last_sync_status, subs1.last_sync_summary
				    	FROM  	sysmergesubscriptions 	subs1,
				    		  	sysmergesubscriptions 	subs2,
				    		  	MSmerge_replinfo	 	replinfo,
			        			master.dbo.sysservers	servers1,
			        			master.dbo.sysservers	servers2,
								sysmergepublications 	pubs
						where subs1.subid = @subid
							and subs2.subid = @partnerid
							and pubs.pubid = subs1.pubid
							and servers1.srvid = subs1.srvid
							and servers2.srvid = subs2.srvid
							and @subid <> @partnerid -- do not show the loopback subscription
							and replinfo.repid = subs1.subid 
		
					if @@ERROR <> 0
						begin
							set @retcode = 1
							goto DONE
						end					
				fetch next from #cursor into @subid, @partnerid
			end
		end
		declare #helpsubscriptioncursor CURSOR LOCAL FAST_FORWARD FOR 
			select DISTINCT publisher, publisher_db, publication
       			FROM #helpmergepullsubscription
				FOR READ ONLY
		create table #syncmgr_keyexist (syncmgr_keyexist int)
		open #helpsubscriptioncursor
		select @helpsubscriptioncursor_open = 1					
		fetch next from #helpsubscriptioncursor into @publisher_local, @publisher_db_local, @publication_local
		while (@@fetch_status <> -1)
		begin
			set @subscription_name = @publisher_local + ':' + @publisher_db_local + ':' + @publication_local + ':' + @subscriber + ':' + @subscriber_db
			/* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */
			set @subscription_name = REPLACE(@subscription_name,'\','/')
			set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
			insert into #syncmgr_keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @regkey
			select @syncmgr_keyexist = syncmgr_keyexist from #syncmgr_keyexist
			update #helpmergepullsubscription set enabled_for_syncmgr = @syncmgr_keyexist 
				where UPPER(publisher) = UPPER(@publisher_local)
					and publisher_db = @publisher_db_local
					and publication = @publication_local
			fetch next from #helpsubscriptioncursor into @publisher_local, @publisher_db_local, @publication_local
		end

	select 'subscription_name'= hs.publisher + ':' + hs.publisher_db + ':' + hs.publication collate database_default, hs.publication, hs.publisher,
            hs.publisher_db, hs.subscriber, hs.subscriber_db, hs.status, hs.subscriber_type, hs.subscription_type,
            hs.priority, hs.sync_type, hs.description, hs.merge_jobid, hs.enabled_for_syncmgr, hs.last_updated, sp.publisher_login,
            sp.publisher_password, sp.publisher_security_mode, sp.distributor, sp.distributor_login, 
            sp.distributor_password, sp.distributor_security_mode, 'ftp_address' = null, 'ftp_port' = 0, 
            'ftp_login' = null, 'ftp_password' = null, sp.alt_snapshot_folder, sp.working_directory, sp.use_ftp, 
            sp.offload_agent, sp.offload_server, hs.use_interactive_resolver, hs.subid, 
            sp.dynamic_snapshot_location, hs.last_sync_status, hs.last_sync_summary
				from #helpmergepullsubscription hs
     left outer join MSsubscription_properties sp
                  on hs.publisher = sp.publisher collate database_default
                 and hs.publisher_db = sp.publisher_db collate database_default
                 and hs.publication = sp.publication collate database_default
			order by hs.publisher, hs.publisher_db, hs.publication, hs.subscriber, hs.subscriber_db
    	 
	select @retcode = 0
DONE:
	if (@cursor_open = 1)
		begin
			close #cursor
			deallocate #cursor
		end			
	--drop table #helpmergepullsubscription

	return @retcode	
go
exec dbo.sp_MS_marksystemobject sp_helpmergepullsubscription
go

grant execute on dbo.sp_helpmergepullsubscription to public
go

raiserror('Creating procedure sp_addmergepullsubscription_agent', 0,1)
GO
CREATE PROCEDURE sp_addmergepullsubscription_agent (
	@name							sysname = NULL,
	@publisher						sysname,  						/* Publisher server */
	@publisher_db					sysname,  						/* Publisher database */
	@publication 					sysname,	      				/* Publication name */
	@publisher_security_mode		int = 1,
	@publisher_login				sysname = NULL,
	@publisher_password				sysname = NULL,
	@publisher_encrypted_password	bit = 0,
	@subscriber						sysname = NULL,
	@subscriber_db					sysname = NULL,
	@subscriber_security_mode		int = NULL,						/* 0 standard; 1 integrated */
	@subscriber_login				sysname = NULL,
	@subscriber_password			sysname = NULL,
	@distributor					sysname = @@SERVERNAME,
	@distributor_security_mode		int = 0,						/* 0 standard; 1 integrated */
	@distributor_login				sysname = 'sa',
	@distributor_password			sysname = NULL,
	@encrypted_password				bit = 0,			/* distributor password encrypted or not */
    @frequency_type  				int = NULL,
    @frequency_interval 			int = NULL,				
    @frequency_relative_interval 	int = NULL, 
    @frequency_recurrence_factor 	int = NULL, 
	@frequency_subday 				int = NULL,
    @frequency_subday_interval 		int = NULL,	   
    @active_start_time_of_day 		int = NULL, 
    @active_end_time_of_day 		int = NULL,         
    @active_start_date 				int = NULL, 
    @active_end_date 				int = NULL,
	@optional_command_line 			nvarchar(255) = '',			/* Optional command line arguments */
    @merge_jobid					binary(16) = NULL OUTPUT,
    @enabled_for_syncmgr 			nvarchar(5) = 'false', /* Enabled for SYNCMGR: true or false */
	@ftp_address 					sysname = NULL,
	@ftp_port 						int = NULL,
	@ftp_login 						sysname = NULL,
	@ftp_password 					sysname = NULL,
    @alt_snapshot_folder  			nvarchar(255) = NULL,
    @working_directory    			nvarchar(255) = NULL,
    @use_ftp              			nvarchar(5) = 'false',
	@reserved 						nvarchar(100) = N'', -- Not default to null because null problems in conditional expressions.
	@use_interactive_resolver   	nvarchar(5) = 'false',
    @offloadagent         			nvarchar(5) = 'false',
    @offloadserver        			sysname = null,
	-- Used by DMO scripting
	@job_name						sysname = NULL,
    @dynamic_snapshot_location      nvarchar(260) = NULL
    ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    declare @command 				nvarchar(4000)
    declare @retcode 				int
	declare @database				sysname
	declare @repid					uniqueidentifier
	declare @pubid					uniqueidentifier
    declare @subscriber_srvid		int 
    declare @publisher_srvid		int 
	declare @name_id				nvarchar(50)
	declare @subscriber_typeid		int
	declare @subscription_type_id	int
	declare @category_name			sysname
	declare @platform_nt			binary
	DECLARE @subscriber_enc_password 	nvarchar(524)
	DECLARE @publisher_enc_password 	nvarchar(524)
	DECLARE @distributor_enc_password 	nvarchar(524)
    DECLARE @use_ftp_bit            	bit
	declare @use_interactive_bit		bit
    DECLARE @offload_agent_bit      	bit

	select @platform_nt = 0x1

    SELECT @use_ftp_bit = 0

	/* Security check */
	EXEC @retcode = dbo.sp_MSreplcheck_subscribe
	if @@ERROR <> 0 or @retcode <> 0
		return(1)
		
	-- For attach check
	if exists (select * from sysobjects where name = 'MSrepl_restore_stage')
	begin
		raiserror(21211, 16, -1)
		return 1
	end

	-- Set null @optional_command_line to empty string to avoid string concat problem
	if @optional_command_line is null
		set @optional_command_line = ''
        else
                set @optional_command_line = N' ' + LTRIM( RTRIM(@optional_command_line) ) + N' '

	IF @distributor_password = N''
		select @distributor_password = NULL

	IF @publisher_password = N''
		select @publisher_password = NULL

	IF @ftp_password = N''
		select @ftp_password = NULL

	/*
	** Parameter Check: @subscriber and @subscriber_db
	*/

	if @subscriber IS NULL or rtrim(@subscriber) = ''
		SELECT @subscriber = @@SERVERNAME

	if @subscriber_db IS NULL or rtrim(@subscriber_db) = ''
		SELECT @subscriber_db = DB_NAME()
	
	EXECUTE @retcode = dbo.sp_validname @subscriber
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)
	
    EXECUTE @retcode = dbo.sp_validname @subscriber_db
    IF @@ERROR <> 0 OR @retcode <> 0
       RETURN (1)

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

    /* 
    ** Parameter check: @alt_snapshot_folder 
    ** @alt_snapshot_folder and @use_ftp are mutually exclusive    
    ** @dynamic_snapshot_location is incompatible with both 
    ** @alt_snapshot_folder and @use_ftp
    */

    IF @alt_snapshot_folder <> N'' AND @alt_snapshot_folder IS NOT NULL
    BEGIN
        IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = N'true'
        BEGIN
            RAISERROR(21146, 16, -1)
            RETURN (1)
        END
        IF @dynamic_snapshot_location <> N'' AND @dynamic_snapshot_location IS NOT NULL
        BEGIN
            RAISERROR(21341, 16, -1)
            RETURN (1)
        END
    END

   	/*
    ** Parameter Check: @use_interactive_resolver  
    */
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
        BEGIN
            RAISERROR (14148, 16, -1, '@use_interactive_resolver')
            RETURN (1)
        END
    if LOWER(@use_interactive_resolver collate SQL_Latin1_General_CP1_CS_AS) = 'true'
        set @use_interactive_bit = 1
    else 
        set @use_interactive_bit = 0

    /* 
    ** Parameter check: @use_ftp
    ** Must be 'true' or 'false'
    */
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@use_ftp')
        RETURN (1)
    END
    
    IF LOWER(@use_ftp collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
        /*
        ** Ftp file transfer is incompatible with @dynamic_snapshot_location
        */
        IF @dynamic_snapshot_location <> N'' AND @dynamic_snapshot_location IS NOT NULL
        BEGIN
            RAISERROR (21342, 16, -1)
            RETURN (1)
        END

        SELECT @use_ftp_bit = 1

    END
    ELSE
    BEGIN
        SELECT @use_ftp_bit = 0
    END

    /*
    ** Parameter Check: @offloadserver
    ** If @offloadagent = 'true' then @offloadserver cannot be null
    */
    SELECT @offloadagent = LOWER(@offloadagent collate SQL_Latin1_General_CP1_CS_AS)
    IF @offloadagent NOT IN ('true', 'false')
    BEGIN
        RAISERROR (14148, 16, -1, '@offloadagent')
        RETURN (1)
    END

    IF @offloadagent = 'true'
    BEGIN
        SELECT @offload_agent_bit = 1
    END
    ELSE
    BEGIN
        SELECT @offload_agent_bit = 0
    END

    IF @offload_agent_bit = 1 AND (@offloadserver IS NULL or
                               @offloadserver = N'')
    BEGIN
        RAISERROR(21215, 16, -1)
        RETURN (1)
    END

    IF UPPER(@offloadserver) = UPPER(@@SERVERNAME) AND
       @offload_agent_bit = 1
    BEGIN
        RAISERROR(21227, 16, -1)
        RETURN (1)
    END

    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode <> 0 OR @@ERROR <> 0
        RETURN (1)

    -- Make sure that there are no leading or trailing blanks
    -- in the dynamic snapshot location
    select @dynamic_snapshot_location = rtrim(ltrim(@dynamic_snapshot_location))

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

	select @subscription_type_id = 1 /* pull agent only */
	/*
	** Set Default schedule values if NULL is specified
	** The default are not implemented during parmeter defintion because this procedure
	** is can be called from sp_addmergesubscription.
	*/
	if @frequency_type is NULL
		set @frequency_type = 4		/* Daily */
	if @frequency_interval is NULL
		set @frequency_interval = 1
	if @frequency_relative_interval is NULL
		set @frequency_relative_interval = 1
	if @frequency_recurrence_factor is NULL
		set @frequency_recurrence_factor = 0
	if @frequency_subday is NULL
		set @frequency_subday = 8	/* Hour */
    if @frequency_subday_interval is NULL
		set @frequency_subday_interval = 1
    if @active_start_time_of_day is NULL
		set @active_start_time_of_day = 0
    if @active_end_time_of_day is NULL
		set @active_end_time_of_day = 235959
    if @active_start_date is NULL
		set @active_start_date = 0
    if @active_end_date is NULL
		set @active_end_date = 99991231

	select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@@SERVERNAME) collate database_default
    IF @subscriber_srvid IS NULL
		BEGIN
		   RAISERROR (14010, 16, -1)
		   RETURN (1)     
		END
			
	select @pubid = pubid from sysmergepublications 
		where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db
	IF @pubid is NULL
		begin
			RAISERROR (20026, 16, -1, @publication)
			RETURN (1)
		end
			
	select @repid = subid, @subscriber_typeid = subscriber_type from sysmergesubscriptions
			where srvid = @subscriber_srvid and pubid<>subid and pubid = @pubid and db_name = @subscriber_db

	if @subscriber_typeid = 3 set @subscription_type_id = 2 /* This corresponds to anonymous subscription */

	if (@subscription_type_id <> 0)
	begin
		if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
		begin
			raiserror(3217, 16, -1, '@subscriber_login')
			return (1)
		end
	end

	if (@distributor_security_mode = 0) and (@distributor_login IS NULL or rtrim(@distributor_login) = '')
	begin
		raiserror(3217, 16, -1, '@distributor_login')
		return (1)
	end

	if (@publisher_security_mode = 0) and (@publisher_login IS NULL or rtrim(@publisher_login) = '')
	begin
		raiserror(3217, 16, -1, '@publisher_login')
		return (1)
	end

	IF NOT EXISTS (select * from sysobjects where name = 'MSsubscription_properties' and type = 'U')
	begin
		raiserror(14027, 16, -1, 'The subscription properties table ''MSsubscription_properties''')
		return (1)
	end
	
	declare @job_existing bit
	-- For scripting
	if @job_name is null
		select @job_existing = 0
	else
	begin
		select @job_existing = 1
		select @name = @job_name
	end

	/*
    ** Construct unique task name if @name = NULL
	*/
	IF @name IS NULL
		begin
			 SELECT @name = CONVERT(nvarchar(23),@publisher ) + '-' + CONVERT(nvarchar(23),@publisher_db) + '-' + 
						CONVERT(nvarchar(23),@publication) + '-' + CONVERT(nvarchar(23),@subscriber) + '-' +
						CONVERT(nvarchar(23), @subscriber_db) + '- 0'
		end
	else
	begin
		/*
		** validate name
		*/
		exec @retcode = dbo.sp_MSreplcheck_name @name
		if @@ERROR <> 0 or @retcode <> 0
			return(1)

	end

	-- Get property values.
	if @reserved = 'no_change_to_properties'
	begin
		-- Get the distributor value. It will be used in agent command line.
		select @distributor = distributor, 
			@enabled_for_syncmgr = case enabled_for_syncmgr
				when 0 then 'false'
				when 1 then	'true'
				end
			from MSsubscription_properties where
			UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
	end

	begin tran
	save tran sp_addpullsub_agent

	if @job_existing = 0
	begin
		/* Construct task command */
		select @command = '-Publisher ' + QUOTENAME(@publisher) + ' -PublisherDB ' + QUOTENAME(@publisher_db) + ' '
		select @command = @command + '-Publication ' + QUOTENAME(@publication) + ' '
		select @command = @command + '-Subscriber ' + QUOTENAME(@@SERVERNAME)  + ' '
		select @command = @command + '-SubscriberDB ' + QUOTENAME(db_name()) + ' '
		SELECT @command = @command + '-SubscriptionType ' + convert(nvarchar(10), @subscription_type_id)  + ' '
		
		select @command = @command + '-SubscriberSecurityMode ' + 
			convert(nvarchar(10),@subscriber_security_mode) + ' '
		if @subscriber_login is not NULL
			select @command = @command + '-SubscriberLogin ' + quotename(@subscriber_login) + ' '
		if @subscriber_password is not NULL
		begin
			set @subscriber_enc_password = @subscriber_password
			exec @retcode = master.dbo.xp_repl_encrypt @subscriber_enc_password OUTPUT
			select @command = @command + '-SubscriberEncryptedPassword ' + quotename(@subscriber_enc_password) + ' '
		end
		
		select @command = @command + @optional_command_line
		select @command = @command + ' -Distributor ' + QUOTENAME(@distributor) + ' '

		if @offload_agent_bit = 1
			select @command = @command + N'-Offload ' + @offloadserver + N' '
		
        select @dynamic_snapshot_location = rtrim(ltrim(@dynamic_snapshot_location))
        if @dynamic_snapshot_location is not null and 
           @dynamic_snapshot_location <> N''
            select @command = @command + N'-DynamicSnapshotLocation ' + fn_replquotename(@dynamic_snapshot_location) collate database_default + N' '

		select @database = db_name()

		-- Get Merge category name (assumes category_id = 14)
		select @category_name = name FROM msdb.dbo.syscategories where category_id = 14

		EXEC @retcode = dbo.sp_MSadd_repl_job
				@name = @name,
				@subsystem = 'Merge',
				@server = @@SERVERNAME,
				@databasename = @database,
				@enabled = 1,
				@freqtype = @frequency_type,
				@freqinterval = @frequency_interval,
				@freqsubtype = @frequency_subday,
				@freqsubinterval = @frequency_subday_interval,
				@freqrelativeinterval = @frequency_relative_interval,
				@freqrecurrencefactor = @frequency_recurrence_factor,
				@activestartdate = @active_start_date,
				@activeenddate = @active_end_date,
				@activestarttimeofday = @active_start_time_of_day,
				@activeendtimeofday = @active_end_time_of_day,
				@command = @command,
				@retryattempts = 10,
				@retrydelay = 1,
				@category_name = @category_name,
				@job_id = @merge_jobid OUTPUT

		if @@ERROR <> 0 or @retcode <> 0 goto Rollback_tran
	end
	else
	begin
		select @merge_jobid = job_id from msdb..sysjobs_view where 
			name = @name collate database_default and
			UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
		if @merge_jobid IS NULL
		begin
			-- Message from msdb.dbo.sp_verify_job_identifiers
			RAISERROR(14262, -1, -1, 'Job', @name)          
			goto Rollback_tran
		end
	end


	if @reserved <> 'attach_subscription' and (@subscription_type_id = 1) OR (@subscription_type_id = 2)
	begin
		IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication) 
		BEGIN
			
			-- Copy the passwords to new value before attempting to encrypt
			set @distributor_enc_password = @distributor_password
			set @publisher_enc_password = @publisher_password

			IF (@encrypted_password = 0)
			-- Encrypt the password
			BEGIN
				EXEC @retcode = master.dbo.xp_repl_encrypt @distributor_enc_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0 goto Rollback_tran
			END
	
			IF (@publisher_encrypted_password = 0)
			-- Encrypt the password
			BEGIN
				EXEC @retcode = master.dbo.xp_repl_encrypt @publisher_enc_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0 goto Rollback_tran
			END
	
			INSERT INTO MSsubscription_properties 
			(publisher, publisher_db, publication, publication_type, 
			 publisher_login,publisher_password, publisher_security_mode, 
			 distributor, distributor_login, distributor_password, 
			 distributor_security_mode, ftp_address, ftp_port, ftp_login, 
			 ftp_password, alt_snapshot_folder, working_directory, use_ftp,
             offload_agent, offload_server, dynamic_snapshot_location)
			values 
			(@publisher, @publisher_db, @publication, 2, @publisher_login, 
			 @publisher_enc_password, @publisher_security_mode, @distributor, 
			 @distributor_login, @distributor_enc_password, 
			 @distributor_security_mode, null, null, null,
			 null, @alt_snapshot_folder, @working_directory, @use_ftp_bit,
             @offload_agent_bit, @offloadserver, @dynamic_snapshot_location)
		END
	end

		
	/* Update merge joibd for this pull subscription */
	UPDATE MSmerge_replinfo set merge_jobid = @merge_jobid WHERE repid = @repid

	/* Update the distributor column in sysmergesubscriptions */
	UPDATE sysmergesubscriptions set 
			use_interactive_resolver = @use_interactive_bit,
			distributor = @distributor 
				WHERE subid = @repid
	
	/* Conditional support for MobileSync */
    if LOWER(@enabled_for_syncmgr collate SQL_Latin1_General_CP1_CS_AS) = 'true'
    BEGIN
		/* Call sp_MSregistersubscription so that the subscription can be synchronized via MobileSync etc. */
		exec @retcode = dbo.sp_MSregistersubscription @replication_type = 2,
									@publisher = @publisher,
									@publisher_security_mode = @publisher_security_mode,
									@publisher_login = @publisher_login,
									@publisher_password = @publisher_password,
									@publisher_db = @publisher_db,
									@publication = @publication,
								    @subscriber = @subscriber,
								    @subscriber_db = @subscriber_db,
									@subscriber_security_mode = @subscriber_security_mode,
									@subscriber_login = @subscriber_login,
									@subscriber_password = @subscriber_password,
									@distributor = @distributor,
									@distributor_security_mode = @distributor_security_mode,
									@distributor_login = @distributor_login,
									@distributor_password = @distributor_password,
								    @subscription_id = @repid,
									@subscription_type = @subscription_type_id,
									@use_interactive_resolver = @use_interactive_bit

		IF @@ERROR <> 0 or @retcode <> 0 goto Rollback_tran
	END

commit tran
	RETURN (0)
Rollback_tran:
	rollback tran sp_addpullsub_agent
	commit tran
	return(1)
GO

exec dbo.sp_MS_marksystemobject sp_addmergepullsubscription_agent
go

raiserror('Creating procedure sp_MSget_mergepullsubsagent_owner', 0,1)
GO
CREATE PROCEDURE sp_MSget_mergepullsubsagent_owner(
	@publication 		sysname = NULL,	      		/* Publication name */
	@publisher			sysname = NULL,  			/* Publisher server */
	@publisher_db		sysname = NULL,  			/* Publication database */
    @owner_sid          varbinary(85) OUTPUT
	)AS
    
    declare @srvid  int
    declare @pubid  uniqueidentifier 
    declare @subid  uniqueidentifier
    declare @job_id uniqueidentifier
    set nocount on

    select @owner_sid = NULL

    if exists (select * from sysobjects 
               where type = 'U' and
                     name = 'sysmergesubscriptions')
        -- Get the server id of the current server (subscriber)
    begin
        -- Get the srvid of the current subscriber database 
        select @srvid = srvid 
        from master.dbo.sysservers      
        where upper(@@servername) = upper(srvname) collate database_default

        -- Get the pubid from sysmergepublications using @publisher, 
        -- @publisher_db, @publication 
        select @pubid = pubid
        from sysmergepublications
        where @publication = name

        -- Get the subid from sysmergesubscriptions using @pubid and @srvid
        select @subid = subid
        from sysmergesubscriptions
        where @pubid = pubid and
              @srvid = srvid and
              pubid <> subid 

        -- Get the merge_jobid from MSreplication_info using @subid
        select @job_id = merge_jobid
        from MSmerge_replinfo
        where @subid = repid

        -- Finally, get the owner_sid from msdb..sysjobs using @job_id
        select @owner_sid = owner_sid
        from msdb..sysjobs 
        where @job_id = job_id
    end
go

exec dbo.sp_MS_marksystemobject 'sp_MSget_mergepullsubsagent_owner'

raiserror('Creating procedure sp_dropmergepullsubscription', 0,1)
GO
CREATE PROCEDURE sp_dropmergepullsubscription(
    @publication        sysname = NULL,             /* Publication name */
    @publisher          sysname = NULL,             /* Publisher server */
    @publisher_db       sysname = NULL,             /* Publication database */
    @reserved           bit = 0
    )AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

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


    select @close_cursor_at_commit = 0
    select @implicit_transaction = 0

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

    COMMIT TRAN

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

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

    RETURN(0)       

FAILURE:
    RAISERROR (14056, 16, -1)
    if @@trancount > 0
    begin
        ROLLBACK TRANSACTION dropmergepullsubscription
        COMMIT TRANSACTION
    end
    /*
    ** Set back original settings
    */  
    IF @reserved = 0
    BEGIN
        IF @implicit_transaction <>0 
            SET IMPLICIT_TRANSACTIONS ON
        IF @close_cursor_at_commit <>0 
            SET CURSOR_CLOSE_ON_COMMIT ON
    END
    return 1
go
exec dbo.sp_MS_marksystemobject sp_dropmergepullsubscription
go

grant execute on dbo.sp_dropmergepullsubscription to public
go

-- synctran supporting sprocs
raiserror('Creating procedure sp_MSreplraiserror', 0,1)
go

create proc sp_MSreplraiserror @errorid int, @param1 sysname = null, @param2 sysname= null
as
    if @errorid = 20508 raiserror (20508, 16, 1)
    else if @errorid = 20509 raiserror (20509, 16, 1)
    else if @errorid = 20510 raiserror (20510, 16, 1)
    else if @errorid = 20511 raiserror (20511, 16, 1)
    else if @errorid = 20512 raiserror (20512, 16, 1)
    else if @errorid = 20515 raiserror (20515, 16, 1)
    else if @errorid = 20516 raiserror (20516, 16, 1)
    else if @errorid = 20517 raiserror (20517, 16, 1)
    else if @errorid = 20518 raiserror (20518, 16, 1)
    else if @errorid = 20519 raiserror (20519, 16, 1)
    else if @errorid = 20520 raiserror (20520, 16, 1)
    else if @errorid = 21034 raiserror (21034, 16, 1)
    else if @errorid = 21052 raiserror (21052, 16, 1)
    else if @errorid = 21054 raiserror (21054, 16, 1)
    else if @errorid = 21064 raiserror (21064, 16, 1)
    else if @errorid = 21161 raiserror (21161, 16, 1)
    else if @errorid = 20598 raiserror (20598, 16, 1)
go
exec dbo.sp_MS_marksystemobject sp_MSreplraiserror
go

--
-- Name: sp_check_sync_trigger
--
-- Description: This SP is used by insert sync trigger on subscriber to check the trigger nesting level. 
-- The SP returns 1 if the trigger nestlevel is > 0. Else it returns 0.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 = there is a nesting in the synctran trigger, 0 = no nesting
--  -1 = Error
--
-- Security: Public procedure - Internal security check. 
--
raiserror('Creating procedure sp_check_sync_trigger', 0,1)
go
create proc sp_check_sync_trigger
(
    @trigger_procid int
    ,@trigger_op char(10) OUTPUT
    ,@owner sysname = null
)
as
begin
    declare @trigid int
    --
    -- Security check
    -- Make sure this proc is infact being called from the given object(trigger)
    -- 
    if (trigger_nestlevel(@trigger_procid) = 0)
    begin
        raiserror(14126, 16, 2)
        return -1
    end
    --
    -- Security check: the caller of this SP has to be one of the 
    -- predefined replication triggers defined in the db
    --
    if not exists (select so.id from (dbo.MSreplication_objects as ro join dbo.sysobjects as so
        on ro.object_name = so.name)
        where so.id = @trigger_procid and ro.object_type = 'T' 
        and (@owner is null or user_name(so.uid) = @owner))
    begin
        raiserror(14126, 16, 3)
        return -1
    end
    --
    -- process
    --
    select @trigger_op = NULL
    select @trigid = so1.id from sysobjects so1, sysobjects so2 where
    so1.type = N'TR' and so1.name like N'trg_MSsync_ins_%' and so1.parent_obj = so2.parent_obj
    and so2.id = @trigger_procid
	
    -- if nestlevel of insert trigger on same table > 0 then bail

    if trigger_nestlevel( @trigid ) > 0
         return 1
    else
        return 0
end
go
exec dbo.sp_MS_marksystemobject sp_check_sync_trigger
go

--
-- Name: sp_check_for_sync_trigger
--
-- Description: This procedure determines if sync tran trigger is 
-- being called in the context of an updatable subscription. This 
-- stored procedure is executed at the Subscriber on the subscription database.
-- Used by user triggers to handle updating trigger in consistent way
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does not need any check. 
--
raiserror('Creating procedure sp_check_for_sync_trigger', 0,1)
go
create proc sp_check_for_sync_trigger 
(
    @tabid int, 
    @trigger_op char(10) = NULL OUTPUT
)
as
begin
    declare @ins_trigid int
            ,@upd_trigid int
            ,@del_trigid int
            ,@retcode int

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

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

raiserror('Creating procedure sp_MSpad_command', 0,1)
go
create proc sp_MSpad_command (
	@cmd     nvarchar(4000) output,
	@indent  int = 0)  -- indent for command buffer (for pretty formatting
as
BEGIN
	declare
		@cnt int
		,@num_tabs int
		,@num_spaces int

	select @cmd = N''
	select @num_tabs = @indent / 4
	select @num_spaces = @indent % 4

	select @cnt = 0
	while (@cnt < @num_tabs)
	begin
		select @cmd = @cmd + N'	'
		select @cnt = @cnt + 1
	end

	select @cnt = 0
	while (@cnt < @num_spaces)
	begin
		select @cmd = @cmd + N' '
		select @cnt = @cnt + 1
	end
END
go

raiserror('Creating procedure sp_MSflush_command', 0,1)
go
create proc sp_MSflush_command
    @cmd     nvarchar(4000) output,
	@force   int,     -- 0 = flush if necesssary, 1 = flush always
	@indent  int = 0  -- indent for command buffer (for pretty formatting
as
-- debug
--    if len(@cmd) >= 4000
--	begin
--	    raiserror("buffer overflow!", 16, 1)
--		select @cmd
--	end
-- debug

    if @force = 1 or len( @cmd ) > 3000
	begin
        insert into #proctext(procedure_text) values( @cmd )
        select @cmd = N''
		if @indent > 0 
		    exec dbo.sp_MSpad_command @cmd output, @indent
    end
go



raiserror('Creating procedure sp_MSget_colinfo', 0,1)
go
create proc sp_MSget_colinfo 
    @objid int,
    @colid int, 
	@columns binary(32), 
	@bGetTextImageInfo tinyint = 0, -- boolean for returning text/image info
	@colname sysname output, 
	@ccoltype sysname = null output
as
	declare @isset        int

    if @columns is not NULL
	    -- this code path for synctran procs
	    exec @isset = dbo.sp_isarticlecolbitset @colid, @columns
	else
	    -- this code path for synctran triggers
		select @isset = 1

    if @isset != 0 
    begin
	    select @colname = c.name, @ccoltype= t.name from syscolumns c, systypes t
	    where id = @objid and colid = @colid and c.xtype = t.xusertype
		-- when checking replicated columns, text/image datatypes cannot be declared or used locally
	    if (@bGetTextImageInfo = 0) and (@ccoltype in (N'text',N'ntext',N'image'))
		    return 1
	end
	else
	begin
        select @colname = null, @ccoltype = null
		return 1
	end

	return 0
go

--
-- Name: sp_MSget_col_position
--
-- Description: 
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Internal procedure - exec permission not granted explicitly. 
--
raiserror('Creating procedure sp_MSget_col_position ', 0,1)
go
create procedure sp_MSget_col_position (
    @objid int,
	@columns binary(32), -- should be NULL if processing trigger generation
	@key     sysname, 
	@colpos  sysname = NULL output,
	@art_col int = NULL output,
	@get_num_col bit = 0,
	@num_col  int = NULL output,
	@this_col int = null output,
	@skipcomputedcol bit = 0
)
as
BEGIN  
	declare @colname      sysname
			,@ccoltype     sysname
			,@rc           int
			,@iscomputed int
	
	select @num_col = 0
	--
	-- Use a cursor to walk through the columns
	--
	DECLARE #hCColid CURSOR LOCAL FAST_FORWARD FOR 
		select colid, name, iscomputed from syscolumns where id = @objid order by colid asc
	OPEN #hCColid
	FETCH #hCColid INTO @this_col, @colname, @iscomputed
	WHILE (@@fetch_status <> -1)
	begin
		if @columns is NULL
		begin
			--
			-- processing updating trigger generation on subscriber.
			-- all columns are to be processed
			--
			select @rc = 1
		end
		else
		begin
			--
			-- processing updating procedure generation on publisher.
			-- only replicated columns are to be processed
			--
			exec @rc = dbo.sp_isarticlecolbitset @this_col, @columns
		end
		--
		-- skip computed columns if needed
		--
		if @rc = 1
		begin
		    if (@skipcomputedcol = 1 and @iscomputed = 1)
		        select @rc = 0
		end
		--
		-- check if name matches
		--
		if @rc = 1
		begin
			select @num_col = @num_col + 1
			-- If @get_num_col is 1, we just need the number of columns in the partition.
			if (@get_num_col != 1) and (@colname = @key)
			begin
				select @colpos = 'c' + convert(varchar(4), @this_col)
						,@art_col = @num_col
				break
			end
		end
		--
		-- Get next row
		--
		FETCH #hCColid INTO @this_col, @colname, @iscomputed
	end
	close #hCColid
	deallocate #hCColid
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_MSget_col_position
go

raiserror('Creating procedure sp_MSget_map_position ', 0,1)
go
create procedure sp_MSget_map_position 
    @primary_key_bitmap varbinary(4000) = null,
	@index int,
	@colpos  sysname = NULL output,
	@art_col int = NULL output
as
  
	declare @this_col int
	declare @num_keys int
	declare @num_cols int
	
	select @this_col = 1
	select @num_keys = 0
	select @num_cols = datalength(@primary_key_bitmap) * 8

	select @colpos = null
	select @art_col = null

	while @this_col <= @num_cols
	begin
		if (substring(@primary_key_bitmap, 1 + (@this_col-1) / 8 , 1) &
			power(2, (@this_col-1) % 8 )) <> 0
		begin
			select @num_keys = @num_keys + 1
			if @num_keys = @index
			begin
				select @art_col = @this_col
				select @colpos = 'c' + convert(sysname, @this_col)				
				break
			end
		end
		select @this_col = @this_col + 1
	end
go

exec dbo.sp_MS_marksystemobject sp_MSget_map_position
go

raiserror('Creating procedure sp_MSget_type', 0,1)
go
create proc sp_MSget_type 
    @tabid int, 
	@colid int, 
	@colname sysname output, 
	@typestring nvarchar(4000) output
as
    declare @ccolchar       nvarchar(5)
    declare @coltype        tinyint
    declare @prec           smallint
    declare @scale          int
    declare @ccoltype       sysname
	declare @xtype          int

    select @colname = c.name, @xtype = c.xtype, @prec = c.prec, @scale = c.scale,
	    @ccoltype = t.name
    from syscolumns c, systypes t
    where c.id = @tabid and c.colid = @colid and 
	    c.xtype = t.xusertype
	 
	select @typestring = @ccoltype

	-- datatypes requiring precision (nchar, nvarchar, binary, varbinary)
	-- format: @var <dt> (prec)
	if @ccoltype in (N'char',N'nchar', N'varchar', N'nvarchar', N'binary', N'varbinary') 
	    select @typestring = @typestring + N'(' + rtrim(convert(nchar(10),@prec)) + N')'

	-- datatypes requiring precision & scale (numeric & decimal)
	-- format: @var <dt> (prec, scale)
	else if @ccoltype in (N'numeric', N'decimal') 
	    select @typestring = @typestring + N'(' + rtrim(convert(nchar(10),ColumnProperty(@tabid, @colname, 'PRECISION'))) + N',' + 
		    rtrim(convert(nchar(10),@scale)) + N')'
	
	-- text/image datatypes cannot be declared or used locally
	else if @ccoltype in (N'text',N'ntext',N'image')
	    select  @typestring = NULL
go

raiserror('Creating procedure sp_MSscript_where_clause', 0,1)
go
create procedure sp_MSscript_where_clause (
	@objid		  int,
	@columns      binary(32), 
	@clause_type  varchar(15) = 'pk_new', -- 'new pk', 'old pk', 'upd version', 'upd rc', 'trg pk', 'qcft_comp', 'new_pk_q', 'subwins_check'
	@ts_col       sysname = NULL,
	@indent       int = 0,
	@op_type      char(3) = NULL, -- 'ins', 'del', 'upd'
	@primary_key_bitmap varbinary(4000) = null )
as
BEGIN
	declare	@cmd			nvarchar(4000)
			,@colname		sysname
			,@ccoltype		sysname
			,@spacer		nvarchar(20)
			,@indkey		int
			,@indid			int
			,@key			sysname
			,@rc			int
			,@this_col		int
			,@art_col		int
			,@src_cols		int
			,@total_col		int
			,@col			sysname
			,@qualname		nvarchar(512)
			,@curparam		nvarchar(20)
			,@retcode		int
			,@fcreatedcolmap	bit
	declare @colmap table (relativeorder int identity(1,1), colid int)

	select @spacer = N' '
		,@cmd = N''
		,@indkey = 1
		,@indid = 0
		,@fcreatedcolmap = 0
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	select @src_cols = max(colid)
			,@total_col = count(colid)
		from syscolumns where id = @objid
	exec dbo.sp_MSpad_command @cmd output, @indent
	if (@clause_type = 'qcft_comp')
		select @cmd = @cmd + N' '' where '
	else
		select @cmd = @cmd + N'where'
	exec dbo.sp_MSflush_command @cmd output, 1, @indent

	if @clause_type in ('new pk','old pk','upd version','trg pk','version pk','qcft_comp','new_pk_q','subwins_check')
	begin
		if @primary_key_bitmap is null
		begin
			exec @indid = dbo.sp_MStable_has_unique_index @objid
			if @indid is null
			begin
				raiserror('Debug: Cannot find unique index', 16, -1)
				return (1)
			end
		end

		--
		-- check if column Id match relative column order
		-- for specific trigger operations
		--
		if ((@total_col < @src_cols) and (@clause_type = 'trg pk') and 
			(@columns is null) and (@primary_key_bitmap is not null))
		begin
			--
			-- this table may have altered columns, so when we need to 
			-- set a mapping for using the bitmaps properly as the bitmap
			-- always refers relative column order
			--
			insert into @colmap (colid)
				select colid from syscolumns where id = @objid order by colid
			if (@@error != 0)
			begin
				raiserror('Could not create column mapping', 16, -1)
				return (1)
			end
			select @fcreatedcolmap = 1
		end
		
		while (1=1)
		begin
			--
			-- get the column position
			--
	        	if @primary_key_bitmap is null 
	        	begin
		             	select @key = index_col(@qualname, @indid, @indkey)
		             	if @key is null
		             		break
		             	--exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, @this_col output
		             	exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, NULL, 0, NULL, @this_col output
	        	end
	        	else
	        	begin
	        		exec dbo.sp_MSget_map_position @primary_key_bitmap, @indkey, @col output, @this_col output
	        		if @this_col is null
	        			break

				--
				-- set the actual column id for this relative order in the PK bitmap if necessary
				--
				if (@fcreatedcolmap = 1)
				begin
					select @this_col = colid
						,@col = 'c' + convert(sysname, colid) 
					from @colmap 
					where relativeorder = @this_col 
				end
	        	end

			--
			-- Get column name
			--
			exec @retcode = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @key output, @ccoltype output
			if (@retcode = 1)
			begin
				--
				-- this column not used for replication
				-- continue
				--
				select @indkey = @indkey + 1
				continue
			end
		
			if @clause_type = 'new pk'
			begin
			    if ColumnProperty(@objid, @key, 'IsIdentity') = 1
			        select @cmd = @cmd + @spacer + quotename(@key) + N' = @@identity'
			    else
			        select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col

			    select @spacer = ' and '
			end
			else if @clause_type in ('upd version', 'subwins_check')
			begin
			    select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
			    select @spacer = ' and '
			end
			else if @clause_type = 'version pk'
			begin
			    select @cmd = @cmd + @spacer + @qualname + '.' + quotename(@key) + N' = inserted.' + quotename(@key)
			    select @spacer = ' and
	'
			end
			else if @clause_type in ('trg pk', 'old pk')
			begin				
				if @op_type = 'ins'
					select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
				else
					-- The vars correspoding to pk were set in sp_MSscript
					-- _pkvar_assignment.
					select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col 
				select @spacer = ' and
	'
			end
			else if (@clause_type = 'qcft_comp')
			begin
				--
				-- Conflict compensation generation
				-- This is a special case - we generate
				-- and exec string for the WHERE clause
				--
				if (@op_type = 'ins')
					select @curparam = N'@' + @col
				else if (@op_type = 'del')
					select @curparam = N'@' + @col + N'_old'
				else
					select @curparam = N'ISNULL(@' + @col + N', @' + @col + N'_old)'
				
				select @cmd = @cmd + @spacer + quotename(@key)
				
				if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
					select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
					select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
					select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
					select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
					select @cmd = @cmd + N' = '' + master.dbo.fn_varbintohexstr(' + @curparam + N') collate database_default ' 
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
					select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
					select @cmd = @cmd + N' = '' + CONVERT(nvarchar(60),' + @curparam + N', 2) '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
					select @cmd = @cmd + N' = '' + CONVERT(nvarchar(40),' + @curparam + N', 2) '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
					select @cmd = @cmd + N' = '' + '''''''' + CAST(' + @curparam + N' as nvarchar(40)) + '''''''' '
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
					select @cmd = @cmd + N' = '' + '''''''' + CONVERT(nvarchar(40), ' + @curparam + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @curparam + N', 114) + '''''''' '	
				else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
					select @cmd = @cmd + N' = '' + master.dbo.fn_sqlvarbasetostr(' + @curparam + N' ) collate database_default '
				else
					select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
				
				select @spacer = ' + '' and  '
			end
			else if @clause_type = 'new_pk_q'
			begin
				--
				-- new value of primary key, ignore identity
				-- used for scripting in synctran procs
				--
				select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col
				select @spacer = ' and '
			end
			select @indkey = @indkey + 1

			-- flush command if necessary
			exec dbo.sp_MSflush_command @cmd output, 1, @indent
		end -- end of while loop
	    
		-- add version col as necessary
		if ((@clause_type in ('upd version','subwins_check')) and (@ts_col is not null))
		begin
			--
			-- @ts_col is version col actually.
			-- check for special cases for queued processing
			--
			exec dbo.sp_MSget_col_position @objid, @columns, @ts_col, @col output
			if (@clause_type = 'subwins_check')
				select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col
			else
				select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col + N'_old'

			--
			-- save off command fragment
			--
			exec dbo.sp_MSflush_command @cmd output, 1, @indent
		end
	end -- end of if clause_type
	-- 'upd rc' is used for column value conflict detection. It is no longer used.
	else if @clause_type = 'upd rc'
	begin
		select @this_col = 1, @art_col = 1
		while @this_col <= @src_cols
		begin
			exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
			if @rc = 0
			begin
				select @cmd = @cmd +  @spacer + '(' + @colname + N' = @c' + convert(varchar(4), @this_col) + N'_old or (' 
				select @cmd = @cmd + @colname + ' is null and @c' + convert(varchar(4), @this_col) + N'_old is null)) '
				select @spacer = N' and 
	'
				exec dbo.sp_MSflush_command @cmd output, 0, @indent
			end
			exec dbo.sp_MSflush_command @cmd output, 1, @indent
			select @this_col = @this_col + 1
		end

		-- save off cmd fragment
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
	end
	
END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_where_clause
GO

raiserror('Creating procedure sp_MSscript_params', 0,1)
go
create procedure sp_MSscript_params (
    @objid   int,
	@columns binary(32),
	@postfix nvarchar(8) = NULL,
	@bOutParams tinyint = 0, -- boolean indicating wether or not to declare timestamp/identity params as output params
	@outvars nvarchar(4000) = NULL output)
as
BEGIN
    declare @cmd          nvarchar(4000)
	declare @colname      sysname
	declare @typestring   nvarchar(4000)
	declare @spacer       nvarchar(1)
	declare @spacer2      nvarchar(1)
	declare @this_col     int
	declare @art_col      int
	declare @isset        int
	declare @pkcolumns    binary(32)
	declare @ispkcol      int

    select @spacer = N' '		
	select @spacer2 = N' '
	select @art_col = 1
	select @outvars = null
	select @cmd = N'	'

	exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output

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

	OPEN hCColid

	FETCH hCColid INTO @this_col

	WHILE (@@fetch_status <> -1)
    begin

	    if @columns is not null
            exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
		else
		    select @isset = 1

		exec @ispkcol = dbo.sp_isarticlecolbitset @this_col, @pkcolumns

        if @isset != 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and (iscomputed<>1 or @ispkcol<>0)) 
        begin
            exec dbo.sp_MSget_type @objid, @this_col, @colname output, @typestring OUTPUT
            if (@typestring IS NOT NULL)
			begin
				if @postfix is null
				    select @cmd = @cmd + @spacer + N'@c' + convert(varchar(4), @this_col) + N' ' + @typestring 
                else
				    -- old vars
				    select @cmd = @cmd + @spacer + N'@c' + convert(varchar(4), @this_col) + @postfix + N' ' + @typestring

                -- new vars of type timestamp and identity are declared as output params
                if @bOutParams = 1 and (@typestring = N'timestamp' or ColumnProperty(@objid, @colname, 'IsIdentity') = 1)
				begin
				    select @cmd = @cmd + N' output'
				    select @outvars = isnull(@outvars, N'') + @spacer2 + N'@c' + convert(varchar(4), @this_col) + N' = ' + @colname 
					select @spacer2 = N','
				end
				
				select @spacer = N','
			end
            select @art_col = @art_col + 1

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

END
go

--
-- proc to generate the other param declarations and
-- initial proc declarations and assignments for
-- synctran/queued updating procs
--
raiserror('Creating procedure sp_MSscript_procbodystart', 0,1)
go
create procedure sp_MSscript_procbodystart (
	@queued_pub		bit = 0
	,@identity_insert bit = 0
)
as
BEGIN
	declare @cmd          nvarchar(4000)

	--
	-- script the initial declarations and assignments
	--
	select @cmd = N'	,@execution_mode tinyint = 0)
AS
BEGIN
	set nocount on
	declare	@retcode int
		, @rowcount int
		, @error int
		, @reinit int
		, @cmd nvarchar(4000)'
	exec dbo.sp_MSflush_command @cmd output, 1

	select @cmd = N'
	declare	@immediate tinyint '
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N' 
		, @QFirstPass tinyint
		, @QPubWins tinyint
		, @QSubWins tinyint
		, @QReinit tinyint
		, @cftcase int
'
	end
	insert into #proctext(procedure_text) values(@cmd)
	--
	-- script identity specific local variables
	--
	if (@identity_insert = 1)
	begin
		select @cmd = N'
		,@iderror int'
		insert into #proctext(procedure_text) values(@cmd)
	end
	--
	-- script initialization of variables
	--
	select @cmd = N' 
	select @immediate = 0 '
	if (@queued_pub = 1)
	begin
		select @cmd = @cmd + N' 	
		, @QFirstPass = 1
		, @QPubWins  = 2
		, @QSubWins = 3
		, @QReinit = 4
'
	end	
	insert into #proctext(procedure_text) values(@cmd)
	--
	-- script initialization of identity specific local variables
	--
	if (@identity_insert = 1)
	begin
		select @cmd = N'
		,@iderror = 0'
		insert into #proctext(procedure_text) values(@cmd)
	end

	return 0
END
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_procbodystart
GO


raiserror('Creating procedure sp_MSscript_begintrig1', 0,1)
go
create procedure sp_MSscript_begintrig1 (
	@trigname sysname
	,@objid int
	,@procname sysname
	,@filter_clause nvarchar(4000)
	,@op_type char(3) = 'ins' -- ins, upd, del
	,@fisqueued bit = 0 -- 1 = Queued subscription
)
as
BEGIN
	declare @cmd       nvarchar(4000)
			,@start     int
			,@sub_len   int
			,@subtableowner sysname
			,@qualname  nvarchar(512)

	select @subtableowner = user_name(objectproperty(@objid, N'OwnerId'))
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT

	-- construct trigger name
	select @cmd = N'create trigger ' + QUOTENAME(@trigname) + N' on ' + @qualname + N' for '
	select @cmd = case
					when (@op_type = 'ins') then @cmd + N'insert '
					when (@op_type = 'upd') then @cmd + N'update '
					when (@op_type = 'del') then @cmd + N'delete '
				end
	select @cmd = @cmd + N'not for replication
as
'
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- declare common local variables
	--
	--		,@update_mode char(40)
	--		,@failover_mode char(10)
	--
	insert into #proctext(procedure_text) values (N'
	declare 	@rc int
		,@retcode int
		,@connect_string nvarchar(2000)
		,@rpc_proc nvarchar(4000)
		,@rpc_types nvarchar(4000)
		,@update_mode_id int
		,@bitmap varbinary(4000)
		,@version_guid uniqueidentifier
		,@trigger_op char(10) ')

		--
		-- queued specific declarations
		--
	insert into #proctext(procedure_text) values (N'
		,@failover_mode_id int
		,@queue_server sysname
		,@queue_id sysname
		,@tran_id varchar(255)
		,@subscriber sysname
		,@subscriber_db sysname 
		,@partial_cmd bit
		,@start_offset int
		,@end_offset int
		,@vb_buffer varbinary(8000)
		,@vb_bufferlen int		
		')

	-- script variables used to retrieve data from inserted table
	if @op_type in ('ins', 'upd')
	begin
		insert into #proctext(procedure_text) values(N'
	declare ')
	        exec dbo.sp_MSscript_params @objid, null, null, 0, null
	end
	insert into #proctext(procedure_text) values(N'
	declare ')
	exec dbo.sp_MSscript_params @objid, null, '_old',  0, null

	-- Set @rc, @subscriber and @subscriber_db
	-- Optimization. Return immediately if no row changed
	select @cmd = N'

	select @rc = @@ROWCOUNT, @subscriber = @@SERVERNAME, @subscriber_db = db_name() 
	if @rc = 0 
		return 
	set nocount on '
	insert into #proctext(procedure_text) values(@cmd)
		
	-- set column update bitmap for update trigger
	if @op_type in ('upd')
	begin
		declare 	@num_bytes		int
				,@i_byte			int
				,@i_bit			tinyint
				,@len_before nvarchar(10)
				,@len_after nvarchar(10)
				,@index1 nvarchar(10)
				,@index2 nvarchar(10)
				,@this_col 		int
				,@max_col			int
				,@total_col		int

		--
		-- check if the subscriber table was altered for column changes
		--
		select @max_col = max(colid)
				,@total_col = count(colid)
			from syscolumns where id = @objid
		if (@total_col = @max_col)
		begin
			--
			-- actual colid and relative column order are same
			--
			insert into #proctext(procedure_text) values(N'
	select @bitmap = columns_updated() 
	')
		end
		else
		begin
			--
			-- we need to convert the columns_updated bitmap to 
			-- a bitmap that contains relative column information
			--
			select @cmd = N'
	select @bitmap = fn_repladjustcolumnmap( ' + cast(@objid as sysname) + N', ' +
				cast(@total_col as sysname) + N', columns_updated())'
			insert into #proctext(procedure_text) values(@cmd)
			select @cmd = N'				
	if (@bitmap is null) 
	begin
		raiserror(''fn_repladjustcolumnmap could not create column mapping'', 16, 1)
		goto FAILURE
	end
	'
			insert into #proctext(procedure_text) values(@cmd)
		end

	        --
	        -- Mark the version bit in the bitmap as updated.
	        --
	        select @cmd = N'
	' + '-- set the bit for msrepl_tran_version'
		insert into #proctext(procedure_text) values(@cmd)

		-- get actual column id
		exec dbo.sp_MSget_col_position @objid, null, 'msrepl_tran_version', @this_col = @this_col output
		if (@total_col < @max_col)
		begin
			--
			-- this table has altered columns, create a mapping between
			-- relative column position and actual column id
			--
			declare @colmap table (relativeorder int identity(1,1), colid int)
			insert into @colmap (colid)
				select colid from syscolumns where id = @objid order by colid
			if (@@error != 0)
			begin
				raiserror('Could not create column mapping', 16, -1)
				return (1)
			end

			--
			-- get the relative column position for msrepl_tran_version
			--
			select @this_col = relativeorder from @colmap where colid = @this_col 
		end
	
		select @num_bytes = @total_col / 8 + 1
			,@i_byte = 1 + (@this_col-1) / 8
			,@i_bit  = power(2, (@this_col-1) % 8 )

		select @len_before = convert(nvarchar(10), @i_byte -1)
			,@index1 = convert(nvarchar(10), @i_byte)
			,@index2 = convert(nvarchar(10), @i_byte + 1)
			,@len_after = convert(nvarchar(10), @num_bytes - @i_byte)

		select @cmd = N'
	select @bitmap = substring(@bitmap, 1, ' + @len_before + 
            ') + (convert(binary(1), substring(@bitmap, ' + @index1 + 
            ', 1) | convert(tinyint,' + convert(nvarchar(10), @i_bit) + 
            '))) + substring(@bitmap, ' + @index2 + 
            ', ' + @len_after + 
            ') '
		exec dbo.sp_MSflush_command @cmd, 1
	end

	select @cmd = N'
	select @version_guid = newid() '
	insert into #proctext(procedure_text) values(@cmd) 

	-- Partition check statement
	if @filter_clause IS NOT NULL
	begin
		declare @retcode int
		exec @retcode = sp_MSsubst_filter_names NULL, N'inserted', @filter_clause output
		if @retcode <> 0 or @@error <> 0
			return 1	    
				
		select @cmd = N'
	if exists (select * from inserted where not ('
		insert into #proctext(procedure_text) values(@cmd) 
		    
		-- break filter_clause into chunks of 255
		select @start = 1
		while @start < len(@filter_clause)
		begin
			if len(@filter_clause) < 255
				select @sub_len = len(@filter_clause)
			else
				select @sub_len = 255
			select @cmd = substring(@filter_clause, @start, @sub_len)
			exec dbo.sp_MSflush_command @cmd output, 1
			select @start = @start + @sub_len
		end
				
		select @cmd = N'))
	 begin 
	     exec sp_MSreplraiserror 21034
	     goto FAILURE 
	 end '
		insert into #proctext(procedure_text) values(@cmd) 
	end

	-- trigger nesting checks
	if @op_type in ('upd')
	begin
		select @cmd = N'
	' + '-- trigger nesting check
	' + '-- error = -1, nested call = 1, not a nested call = 0
	exec @retcode = dbo.sp_check_sync_trigger @@procid, @trigger_op OUTPUT, N'''
	+ master.dbo.fn_MSgensqescstr(@subtableowner) collate database_default + ''' 
	if (@retcode = -1)
		goto FAILURE 
	if (@retcode = 1)
		return '
		insert into #proctext(procedure_text) values(@cmd) 
	end
END
go

raiserror('Creating procedure sp_MSscript_begintrig2', 0,1)
go
create procedure sp_MSscript_begintrig2 (
	@publisher sysname
	,@publisher_db sysname
	,@publication sysname
	,@objid int
	,@op_type char(3) = 'ins' -- ins, upd, del
	,@agent_id int
	,@fisqueued bit = 0 -- 1 = Queued subscription
)
as
BEGIN
	declare @cmd nvarchar(4000)
			,@queue_server sysname
			,@subtableowner sysname

	select @subtableowner = user_name(objectproperty(@objid, N'OwnerId'))

	if @op_type = 'ins' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerInsertOrder'') != 1	
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21128, 16, 1, @trigname)
		goto FAILURE
	end ')
	end
	else if @op_type = 'upd' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerUpdateOrder'') != 1	
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21129, 16, 1, @trigname)
		goto FAILURE
	end ')
	end
	else if @op_type = 'del' 
	begin
		insert into #proctext(procedure_text) values(N'
	if Objectproperty(@@procid,''TriggerDeleteOrder'') != 1
	begin
		declare @trigname sysname
		select @trigname = object_name(@@procid)

		raiserror (21130, 16, 1, @trigname)
		goto FAILURE
	end ')
	end

	--
	-- scripting for debug messages
	--
	select @cmd = N'
	select @update_mode_id = update_mode 
	from dbo.MSsubscription_agents where id = ' + convert(nvarchar(10), @agent_id) + N' '
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- continue with scripting
	--
	select @cmd = N'
	' + N'--
	' + N'-- initialize and validate based on update mode
	' + N'--
	if @update_mode_id = 1
	begin
		exec @retcode = dbo.sp_MSget_publisher_rpc @@procid, @connect_string output, N'''
        	+ master.dbo.fn_MSgensqescstr(@subtableowner) collate database_default + ''' 
		if @retcode <>0 or @@error <> 0 goto FAILURE
	end'
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- continue with scripting
	--
	if (@fisqueued = 1)
	begin
		--
		-- Queued specific scripting
		--
		select @cmd = N'
	else if @update_mode_id in (2,4)
	begin
		select @queue_server = queue_server, @queue_id = queue_id from dbo.MSsubscription_agents where id = ' + convert(nvarchar(10), @agent_id) + N'
		if (@queue_id is NULL) 
			goto FAILURE
	end'
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- continue with scripting
		--
		select @cmd = N'
	else if @update_mode_id in (3,5)
	begin
		select @queue_server = queue_server, @queue_id = queue_id from dbo.MSsubscription_agents 
			where id = ' + convert(nvarchar(10), @agent_id) + N' and failover_mode = 1 '
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- continue with scripting
		--
		select @cmd = N'
		if (@queue_id is NULL)
		begin
			exec @retcode = dbo.sp_MSget_publisher_rpc @@procid, @connect_string output, N'''
                	+ master.dbo.fn_MSgensqescstr(@subtableowner) collate database_default + ''' 
			if @retcode <>0 or @@error <> 0 
				goto FAILURE
		end
	end'
		insert into #proctext(procedure_text) values (@cmd)
	end
	
	--
	-- continue with scripting
	--
	select @cmd = N'
	else if @update_mode_id = 0
	begin
		raiserror (''read only mode - no updates allowed'', 16, 1)
		goto FAILURE
	end
	else
	begin
		raiserror(''invalid update mode %d'', 16, 1, @update_mode_id)
		goto FAILURE
	end '
	insert into #proctext(procedure_text) values (@cmd)

	if (@fisqueued = 1)
	begin		
		select @cmd = N'
	' + N'--
	' + N'-- set queue prefix for MSMQ cases
	' + N'--
	if (@update_mode_id in (2,3))
	begin
		select @queue_id = N''DIRECT=OS:'' + @queue_server + N''\PRIVATE$\'' + @queue_id 
	end'
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- Get failover mode scripting
		--
	    select @cmd = N'
	' + N'--
	' + N'-- get failover mode
	' + N'--
	if @update_mode_id in (3,5)
	begin
		select @failover_mode_id = failover_mode
		from dbo.MSsubscription_agents where id = '
		+ convert(nvarchar(10), @agent_id) + ' and update_mode in (3,5)
	end'
		insert into #proctext(procedure_text) values (@cmd)
    end
    
    --
	-- Start the distributed tran and get the transaction id as we may use
	-- it for queue sends
	--
    select @cmd = N'
	' + N'--
	' + N'-- begin tran or dist tran based on update mode
	' + N'--
	if (@update_mode_id in (4,5))
		BEGIN TRAN
	else
		BEGIN DISTRIBUTED TRAN
	'
	insert into #proctext(procedure_text) values (@cmd)
		
	if (@fisqueued = 1)
	begin
		select @cmd = N'
	' + N'--
	' + N'-- save the transaction token for later use
	' + N'--
	exec sp_getbindtoken @out_token = @tran_id OUTPUT , @for_xp_flag = 1 '
		insert into #proctext(procedure_text) values (@cmd)
	end

	--
	-- all done with scripting
	--
	return 0
END
go

raiserror('Creating procedure sp_MSscript_endtrig', 0,1)
go
create proc sp_MSscript_endtrig
as
BEGIN
	declare @cmd nvarchar(4000)

	select @cmd = N'
	if (@@trancount > 0)
		commit tran
	return 

FAILURE:
	if (@@trancount > 0)
	begin
		exec sp_MSreplraiserror 20512
		rollback tran
	end '
	insert into #proctext(procedure_text) values(@cmd)
END
go

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

create procedure sp_MSscript_trigger_variables
(
	@objid int,
	@prefix char(1) = null, -- null or '@'
	@postfix varchar(4) = null,
	@indent int = 0,
	@spacer nvarchar(1) = N' ', 
	@bOutput_params tinyint = 0,  -- declare output params if necessary
	@identity_col sysname = null,
	@ts_col sysname = null,
	@include_type bit = 0,
	@set_nulls	bit = 0,
	@op_type char(3) = 'ins', -- 'ins, 'upd', 'del'
	@is_new		bit = 0,
	@primary_key_bitmap varbinary(4000) = NULL,
	@no_output bit = 0
)
as
begin
	declare @cmd          nvarchar(4000)
			,@colname      sysname
			,@ccoltype     sysname
			,@src_cols     int
			,@this_col     int
			,@total_col		int
			,@indkey			int
			,@fcreatedcolmap	bit
			,@rc           int
			,@column		  nvarchar(4000)
	declare @colmap table (relativeorder int identity(1,1), colid int)

	-- script cursor select variables
	select @cmd = N''
			,@indkey = 1
			,@fcreatedcolmap = 0
	select @src_cols = max(colid)
			,@total_col = count(colid)
		from syscolumns where id = @objid
	exec dbo.sp_MSpad_command @cmd output, @indent

	--
	-- check if column Id match relative column order
	-- for trigger scripting
	--
	if (@total_col < @src_cols)
	begin
		--
		-- this table may have altered columns, so when we need to 
		-- set a mapping for using the bitmaps properly as the bitmap
		-- always refers relative column order
		--
		insert into @colmap (colid)
			select colid from syscolumns where id = @objid order by colid
		if (@@error != 0)
		begin
			raiserror('Could not create column mapping', 16, -1)
			return (1)
		end
		select @fcreatedcolmap = 1
	end

	while (@indkey <= @total_col)
	begin
		--
		-- set the actual column id for this relative order in the bitmap if necessary
		--
		if (@fcreatedcolmap = 1)
		begin
			select @this_col = colid from @colmap 
				where relativeorder = @indkey 
		end
		else
		begin
			select @this_col = @indkey
		end

		--
		-- Get column name
		-- Don't include timestamp or computed columns        
		--
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, null, 0, @colname output, @ccoltype output
		if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1 and xtype <> 189)
		begin
			if @prefix is null
			begin
			
				if (@set_nulls = 1)
				begin
					-- Optimization:
					-- Get null or actual column name
					-- Note: the output is quoted.
					exec dbo.sp_MSget_synctran_column 
						@ts_col = @ts_col,
						@op_type = @op_type, -- 'ins, 'upd', 'del'
						@is_new = @is_new,
						@primary_key_bitmap = @primary_key_bitmap,
						@colname = @colname,
						@this_col = @this_col,
						@column = @column output,
						@from_proc = 0, 
						@coltype = @ccoltype, 
						@type = NULL,
						@art_col = @indkey
					select @cmd = @cmd + @spacer + @column + isnull(@postfix, N'')
				end
				else
				begin
					-- set null is false
					select @cmd = @cmd + @spacer + N'[' + @colname + isnull(@postfix, N'') + N']'
				end
			end
			else
			begin
				-- prefix was specified
				select @cmd = @cmd + @spacer + isnull(@prefix, N'') 
					+ N'c' + RTRIM(convert(nvarchar(4), @this_col)) + isnull(@postfix, N'')
			end

			if (@include_type = 1)
			begin
				declare @typestring nvarchar(100)
				exec dbo.sp_MSget_type @objid, @this_col, @colname output, @typestring OUTPUT
				select @cmd = @cmd +  N' ' + @typestring 
			end

			-- new vars of type timestamp and identity are declared as output params
			if (@bOutput_params = 1 and (@ccoltype = N'timestamp' or ColumnProperty(@objid, @colname, 'IsIdentity') = 1))
				or (@colname = @identity_col or @colname = @ts_col)
			begin
				-- YWU: Do this to avoid output in cursor declaration statement.
				-- The right thing seems to be set output only when bOutput_params is set
				-- but it seems not the way this sp is called.
				if @set_nulls = 0 and @no_output = 0
					select @cmd = @cmd + N' output'
			end

			select @spacer = N','
		end -- if rc=0 and exists ...
		
		exec dbo.sp_MSflush_command @cmd output, 0, @indent
		select @indkey = @indkey + 1
	end -- while () loop

	exec dbo.sp_MSflush_command @cmd output, 1, @indent
	insert into #proctext(procedure_text) values(N'
') 

end
go

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

create procedure sp_MSscript_trigger_assignment (
	@objid int
	,@postfix char(4) = null
	,@indent int = 0
	,@ts_col sysname
	,@op_type char(3) -- 'ins, 'upd', 'del'
	,@is_new	bit
	,@primary_key_bitmap varbinary(4000) = null
)
as
BEGIN
	declare @cmd          nvarchar(4000)
			,@colname      sysname
			,@spacer       nvarchar(1)
			,@ccoltype     sysname
			,@src_cols     int
			,@this_col     int
			,@total_col		int
			,@indkey			int
			,@fcreatedcolmap	bit
			,@rc           int
			,@column		  nvarchar(4000)
	declare @colmap table (relativeorder int identity(1,1), colid int)

	-- initialize
	select @spacer = N' '
			,@indkey = 1
			,@fcreatedcolmap = 0
	select @src_cols = max(colid)
			,@total_col = count(colid)
		from syscolumns where id = @objid
	exec dbo.sp_MSpad_command @cmd output, @indent

	--
	-- check if column Id match relative column order
	-- for trigger scripting
	--
	if (@total_col < @src_cols)
	begin
		--
		-- this table may have altered columns, so when we need to 
		-- set a mapping for using the bitmaps properly as the bitmap
		-- always refers relative column order
		--
		insert into @colmap (colid)
			select colid from syscolumns where id = @objid order by colid
		if (@@error != 0)
		begin
			raiserror('Could not create column mapping', 16, -1)
			return (1)
		end
		select @fcreatedcolmap = 1
	end

	while (@indkey <= @total_col)
	begin
		--
		-- set the actual column id for this relative order in the bitmap if necessary
		--
		if (@fcreatedcolmap = 1)
		begin
			select @this_col = colid from @colmap 
				where relativeorder = @indkey 
		end
		else
		begin
			select @this_col = @indkey
		end

		--
		-- Get column name
		--
		exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, null, 0, @colname output, @ccoltype output
		if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and @this_col=colid and iscomputed<>1)
		begin
			-- Optimization:
			-- Get null or actual column name
			-- Note: the output is quoted.
			exec dbo.sp_MSget_synctran_column 
				@ts_col = @ts_col,
				@op_type = @op_type, -- 'ins, 'upd', 'del'
				@is_new = @is_new,
				@primary_key_bitmap = @primary_key_bitmap,
				@colname = @colname,
				@this_col = @this_col,
				@column = @column output,
				@from_proc = 0, 
				@coltype = NULL, 
				@type = NULL,
				@art_col = @indkey

			select @cmd = @cmd + @spacer + N'@c' + 
				convert(sysname, @this_col) + isnull(@postfix, N'') + 
				N' = ' + @column  
				
			select @spacer = N','
		end
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
		select @indkey = @indkey + 1
	end
	exec dbo.sp_MSflush_command @cmd output, 1, @indent

END
go

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

create procedure sp_MSscript_trigger_fetch_statement (
    @objid   int, 
    @op_type char(3) = 'ins',
    @indent   int = 0
)
as
BEGIN
	declare @cmd          nvarchar(4000)

	-- script fetch statements
	if @op_type in ('ins', 'upd')
	begin
		exec dbo.sp_MSpad_command @cmd output, @indent
		select @cmd = @cmd + N'fetch next from rpl_ins_cursor into 
'
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
		exec dbo.sp_MSscript_trigger_variables @objid, '@', null, @indent, ' '
	end

	if @op_type in ('ins')
	begin
		exec dbo.sp_MSpad_command @cmd output, @indent
		select @cmd = @cmd + N'fetch next from rpl_ins2_cursor into 
'
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
		exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @indent, ' '
	end

	if @op_type in ('upd', 'del')
	begin
		exec dbo.sp_MSpad_command @cmd output, @indent
		select @cmd = @cmd + N'fetch next from rpl_del_cursor into 
'
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
		exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @indent, ' '
	end
END
go

raiserror('Creating procedure sp_MSscript_trigger_exec_rpc ', 0,1)
go
create procedure sp_MSscript_trigger_exec_rpc (
	@publisher   sysname,
	@publisherdb sysname,
	@publication sysname,
	@procname   sysname,
	@proc_owner sysname,
	@cftproc	sysname,
	@objid       int, 
	@op_type     char(3) = 'ins', 
	@indent      int = 0,
	@identity_col sysname = null,
	@ts_col       sysname = null,
	@primary_key_bitmap   varbinary(4000),
	@pubversion int
)
as
BEGIN
	declare @cmd nvarchar(4000)
			,@min_identity int
			,@max_identity int
			,@fisqueued bit
			,@varindent int
			,@object_owner sysname

	--
	-- validate @op_type
	--
	if (@op_type) not in ('ins', 'upd', 'del')
		return 1	
	select @fisqueued = case when (@cftproc is NULL) then 0 else 1 end
	--
	-- Set version guid param and column first.
	--
	if @op_type in ('upd')
	begin
		exec dbo.sp_MSscript_trigger_version_updates @objid, 'msrepl_tran_version', @indent,
			@primary_key_bitmap
	end

	--
	-- continue scripting
	--
	select @cmd = N'
		if (@update_mode_id = 1) or (@update_mode_id in (3, 5) and @failover_mode_id = 0)
		begin 
			' + N'-- 
			' + N'-- immediate mode - check if publisher is local
			' + N'-- 
			if @connect_string is null 
			begin '
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- prepare the proc invocation
	-- 1st two variables are subscriber server name and database name for cycle detection
	--
	select @cmd = N'
				select @rpc_proc = N''' + quotename(@publisher) collate database_default + N'.' + 
					quotename(master.dbo.fn_MSgensqescstr(@publisherdb)) collate database_default + N'.' + 
					quotename(master.dbo.fn_MSgensqescstr(@proc_owner)) collate database_default + N'.' + 
					quotename(master.dbo.fn_MSgensqescstr(@procname)) collate database_default + N''' 
				exec @retcode = @rpc_proc @subscriber, @subscriber_db,
			'
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- script the trigger variables
	--
    select @min_identity = @@identity
    if @op_type in ('ins', 'upd')
        exec dbo.sp_MSscript_trigger_variables @objid, '@', N'', @indent, N'', 0,  @identity_col, @ts_col

    if @op_type = 'upd'
	begin
        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @indent, ',', 0, null, null
		insert into #proctext(procedure_text) values (N'
						,@bitmap')
	end

    else if @op_type = 'del'
        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @indent, ' ', 0, null, null

    select @max_identity = @@identity
	
	--
	-- continue scripting
	--
	select @cmd = N'
				if (@@error != 0 or @retcode != 0)
				begin 
					if (@retcode = -2)
						exec sp_MSreplraiserror 21064
					else if @retcode = 5
						exec sp_MSreplraiserror 20515
					else
						exec sp_MSreplraiserror 21054
					goto FAILURE 
				end
			end
			else
			begin'
	insert into #proctext(procedure_text) values (@cmd)
    
	--
	-- prepare the RPC invocation
	--
	select @cmd = N'
				select @rpc_proc = N''
				declare @retcode int 
				exec @retcode = '' + N'
	select @cmd = @cmd + quotename('OpenDataSource(''SQLOLEDB'',N' ,'''') 
	select @cmd = @cmd + '+ '''''''' + replace(@connect_string, '''''''', '''''''''''''''') + N'''''''' + '
	select @cmd = @cmd + 'N'').'' + N''' 
	select @cmd = @cmd + quotename(master.dbo.fn_MSgensqescstr(@publisherdb)) collate database_default + '.'
	select @cmd = @cmd + quotename(master.dbo.fn_MSgensqescstr(@proc_owner)) collate database_default + '.'
	select @cmd = @cmd + quotename(master.dbo.fn_MSgensqescstr(@procname)) collate database_default + ''' + quotename(@subscriber) collate database_default + '','' + quotename(@subscriber_db) collate database_default + '', '' + 
				'''
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- script the trigger variables
	--
	select @varindent = @indent + 4
    if @op_type in ('ins', 'upd')
        exec dbo.sp_MSscript_trigger_variables @objid, '@', N'', 0, N'', 0,  @identity_col, @ts_col

    if @op_type = 'upd'
	begin
        exec dbo.sp_MSscript_trigger_variables @objid, '@', 'o', @varindent, ',', 0, null, null
		insert into #proctext(procedure_text) values (N'
						,@bitmap')
	end
    else if @op_type = 'del'
        exec dbo.sp_MSscript_trigger_variables @objid, '@', 'o', 0, ' ', 0, null, null

    --
    -- Must raise error right before exiting the dynamic exec so that it will be picked up.
    --
	select @cmd = N'
		'' + '' if (@@error != 0 or @retcode != 0) 
		begin 
			if (@retcode = -2) 
				exec sp_MSreplraiserror 21064 
			else if @retcode = 5 
				exec sp_MSreplraiserror 20515
			else 
				exec sp_MSreplraiserror 21054 
		end''
		'
	insert into #proctext(procedure_text) values (@cmd)

	--
	-- Get parameter datatypes
	--
    insert into #proctext(procedure_text) values (N'
				select @rpc_types = ''')
    if @op_type in ('ins', 'upd')
        exec dbo.sp_MSscript_trigger_variables @objid, '@', N'' , 0, N'', 0,  @identity_col, @ts_col, 1
    if @op_type = 'upd'
        exec dbo.sp_MSscript_trigger_variables @objid, '@', 'o', @varindent, ',', 0, null, null, 1
    else if @op_type = 'del'
        exec dbo.sp_MSscript_trigger_variables @objid, '@', 'o', 0, ' ', 0, null, null, 1
    
	exec dbo.sp_MSpad_command @cmd output, @indent
	select @cmd = @cmd + N''''
    insert into #proctext(procedure_text) values (@cmd)

    if @op_type = 'upd'
	begin
		insert into #proctext(procedure_text) values (N'
				select @rpc_types = @rpc_types + '', @bitmap varbinary(4000)'' ')
	end

	--
	-- make rpc call
	--
    insert into #proctext(procedure_text) values (N'
				exec @retcode = dbo.sp_executesql @rpc_proc, @rpc_types, 
')

	--
	-- Get parameters again
	--
    insert into #proctext(procedure_text) select procedure_text from #proctext
    where c1 > @min_identity and c1 <= @max_identity
    order by c1 asc

	--
	-- continue scripting
	--
	select @cmd = N'
				if @@error != 0 
					goto FAILURE
			end
		end '
	insert into #proctext(procedure_text) values (@cmd)

	if (@fisqueued = 1)
	begin
		declare @artidstring sysname
			,@qversion int
			,@foldqueuestyle bit

		--
		-- Check the publisher version
		--
		if (@pubversion = 1)
		begin
			--
			-- Publisher is PreSP3
			-- Use the new style of parameter passing - Queue version 1
			--
			select @foldqueuestyle = 1
		end
		else if (@pubversion > 1)
		begin
			--
			-- Publisher is SP3 or later
			-- get the article id as string
			-- Use the new style of parameter passing - Queue version 2
			--
			select @artidstring = cast(artid as sysname)
			from (dbo.MSsubscription_articles as a join dbo.MSsubscription_agents as b
					on a.agent_id = b.id)
			where UPPER(b.publisher) = UPPER(@publisher)
				and b.publisher_db = @publisherdb
				and b.publication = @publication
				and a.dest_table = object_name(@objid)
			select @foldqueuestyle = 0
		end
		else
		begin
			--
			-- bad publisher version
			--
			return 1
		end
		--
		-- Are we going old style - for backwards compatibility for SQL Queue
		-- For MSMQ we use a newer clsid for queue version and will
		-- use whatever is assigned to the queue during its creation
		-- A newer publisher will imply a newer distributor and we are
		-- okay.
		--
		if (@foldqueuestyle = 1)
		begin
			--
			-- Update the version on the sql queue to v1 if necessary
			--
			update dbo.MSsubscription_agents
			set queue_id = 'mssqlqueue'
			where UPPER(publisher) = UPPER(@publisher)
				and publisher_db = @publisherdb
				and publication = @publication
				and update_mode in (4,5)
				and queue_id != 'mssqlqueue'
		end
		else
		begin
			--
			-- Update the version on the sql queue to v2 if necessary
			--
			update dbo.MSsubscription_agents
			set queue_id = 'mssqlqueuev2'
			where UPPER(publisher) = UPPER(@publisher)
				and publisher_db = @publisherdb
				and publication = @publication
				and update_mode in (4,5)
				and queue_id != 'mssqlqueuev2'
		end
		--
		-- continue scripting
		--
		select @cmd = N'
		else
		begin
			' + N'--
			' + N'-- handle queued cases
			' + N'-- 
			if (@update_mode_id in (2,3))
			begin'
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- MSMQ based write
		--
		if (@foldqueuestyle = 1)
		begin
			--
			-- old style scripting - non secure
			--
			select @cmd = N'
				exec @retcode = master.dbo.sp_replsendtoqueue @queue_id, @tran_id, N' + 
				quotename(@publication, '''') + N', N' +	
				quotename(@cftproc, '''') + N', N' +
				quotename(@proc_owner, '''')	+ N', N' + 
				quotename(@procname, '''') + N', @subscriber, @subscriber_db, 
'
		end
		else
		begin
			--
			-- new style scripting - secure
			--
			select @cmd = N'
				exec @retcode = master.dbo.sp_replsendtoqueue @queue_id, @tran_id, N' + 
				quotename(@publication, '''') + N', N' +	
				quotename(@artidstring, '''') + N', N' +
				quotename(@op_type, '''')	+ N', N' + 
				quotename(@procname, '''') + N', @subscriber, @subscriber_db, 
'
		end
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- script the trigger variables
		--
		select @varindent = @indent + 8
	    select @min_identity = @@identity
	    if @op_type in ('ins', 'upd')
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', N'', @varindent, N'', 0,  @identity_col, @ts_col,
				@no_output = 1

	    if @op_type = 'upd'
		begin
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @varindent, ',', 0, null, null,
				@no_output = 1

			insert into #proctext(procedure_text) values (N'
					,@bitmap')
		end

	    else if @op_type = 'del'
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @varindent, ' ', 0, null, null,
				@no_output = 1

	    select @max_identity = @@identity

		--
		-- SQL Queued case
		-- we loop here if the command length exceeds queue message length and
		-- break the command into partial cmds and send it in more than one 
		-- queue message
		--
	    select @cmd = N'
			end
			else if (@update_mode_id in (4,5))
			begin
				select @partial_cmd = 1, @start_offset = 0, @end_offset = 0
				while (@partial_cmd != 0)
				begin'
		insert into #proctext(procedure_text) values (@cmd)

		if (@foldqueuestyle = 1)
		begin
			--
			-- old style scripting - non secure
			--
			select @cmd = N'
					exec @retcode = master.dbo.sp_replwritetovarbin @start_offset, @end_offset output, @vb_buffer output, @vb_bufferlen output, N' + 
				quotename(@publisher, '''') + N', N' +
				quotename(@publisherdb, '''') + N', N' +	
				quotename(@publication, '''')	+ N', @tran_id, N' +	
				quotename(@cftproc, '''')	+ N', N' +
				quotename(@proc_owner, '''') + N', N' + 
				quotename(@procname, '''') + N', @subscriber, @subscriber_db, 
'
		end
		else
		begin
			--
			-- new style scripting - secure
			--
			select @cmd = N'
					exec @retcode = master.dbo.sp_replwritetovarbin @start_offset, @end_offset output, @vb_buffer output, @vb_bufferlen output, N' + 
				quotename(@publisher, '''') + N', N' +	
				quotename(@publisherdb, '''') + N', N' +	
				quotename(@publication, '''')	+ N', @tran_id, N' +	
				quotename(@artidstring, '''')	+ N', N' +
				quotename(@op_type, '''') + N', N' + 
				quotename(@procname, '''') + N', @subscriber, @subscriber_db, 
'
		end
		insert into #proctext(procedure_text) values (@cmd)

		--
		-- script the trigger variables
		--
	    select @min_identity = @@identity
	    if @op_type in ('ins', 'upd')
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', N'', @varindent, N'', 0,  @identity_col, @ts_col,
				@no_output = 1

	    if @op_type = 'upd'
		begin
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @varindent, ',', 0, null, null,
				@no_output = 1

			insert into #proctext(procedure_text) values (N'
					,@bitmap')
		end

	    else if @op_type = 'del'
	        exec dbo.sp_MSscript_trigger_variables @objid, '@', '_old', @varindent, ' ', 0, null, null,
				@no_output = 1

	    select @max_identity = @@identity

		--
		-- continue scripting
		--
		select @cmd = N'
					if @@error != 0 or @retcode != 0 
					begin 
						exec sp_MSreplraiserror 21052
						goto FAILURE 
					end'
		insert into #proctext(procedure_text) values(@cmd)

		--
		-- handle partial messages
		--
		select @object_owner = user_name(ObjectProperty(@objid, 'ownerid'))
		select @cmd = N'
					select @partial_cmd = case when (@end_offset > 0) then 1 else 0 end			
					exec @retcode = sp_MSsendtosqlqueue @@procid, N' + 
						quotename(@publisher, '''') + N', N' + 
						quotename(@publisherdb, '''') + N', N' + 
						quotename(@publication, '''') + N', N' +
						quotename(@object_owner, '''') +
						N', @tran_id, @vb_buffer, @vb_bufferlen, 1, @partial_cmd '
		insert into #proctext(procedure_text) values(@cmd)

		--
		-- continue scripting
		--
		select @cmd = N'
					if @@error != 0 or @retcode != 0 
					begin 
						exec sp_MSreplraiserror 21052
						goto FAILURE 
					end
					select @start_offset = @end_offset
				end
			end'
		insert into #proctext(procedure_text) values(@cmd)

		--
	    -- continue scripting
	    --
		select @cmd = N'
			if @@error <>0 or @retcode <> 0 
			begin 
				exec sp_MSreplraiserror 21052
				goto FAILURE 
			end
		end
	'
		insert into #proctext(procedure_text) values(@cmd)
	end
	
	--
	-- all done
	--
	return 0
END
go

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

create procedure sp_MSscript_trigger_update_checks(
    @objid int,
    @identity_col sysname,
    @ts_col       sysname,
    @op_type varchar(3) = 'ins', -- 'ins', 'upd'
    @indent int = 0
)
as
BEGIN
    declare @cmd          nvarchar(4000)
    declare @colname      sysname
    declare @ccoltype     sysname
    declare @src_cols     int
    declare @this_col     int
    declare @rc           int
    declare @qualname     nvarchar(512)
    declare @indid        int
    declare @key          sysname
    declare @indkey       int

/*
    if @op_type = 'pk'
    begin
		select @indkey = 1
		exec sp_MSget_qualified_name @objid, @qualname OUTPUT
        exec @indid = dbo.sp_MStable_has_unique_index @objid
        if @indid > 0
  	    begin
	        exec dbo.sp_MSpad_command @cmd output, @indent
	        while @indkey < 16 and index_col(@qualname, @indid, @indkey) is not null
            begin
                select @key = index_col(@qualname, @indid, @indkey)
                select @cmd = N'if update(' + @key + N')
'
                exec dbo.sp_MSflush_command @cmd output, 1, @indent
                insert into #proctext(procedure_text) values(N'begin
     exec sp_MSreplraiserror 20517
     goto FAILURE
 end 

')
                select @indkey = @indkey + 1
            end
        end
    end
    else
    begin
 */
    -- Image cols
    select @src_cols = max(colid) from syscolumns where id = @objid
    select @this_col = 1
	exec dbo.sp_MSpad_command @cmd output, @indent
   
        while @this_col <= @src_cols
        begin
            exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, null, 1, @colname output, @ccoltype output
            if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and @this_col=colid and iscomputed<>1)
            begin
                if @ccoltype in ('text','ntext','image')
                begin
    		    if @op_type = 'ins'
                    begin
                        select @cmd = N'if update(' +  quotename(@colname) + ') 
'
                        exec dbo.sp_MSflush_command @cmd output, 1, 0
                        insert into #proctext(procedure_text) values(N'    exec sp_MSreplraiserror 20508
')
                    end
                    else if @op_type = 'upd'
                    begin
                        select @cmd = N'if update(' +  quotename(@colname) + ') 
' 
                        exec dbo.sp_MSflush_command @cmd output, 1, 0
                        insert into #proctext(procedure_text) values(N'begin
     exec sp_MSreplraiserror 20509
     goto FAILURE 
 end

')
                    end
                end
            end
            select @this_col = @this_col + 1
        end
 --   end

    -- identity col
    if @op_type = 'upd' and @identity_col is not null
    begin
        select @cmd = N'if update(' +  quotename(@identity_col) + N') 
'
        exec dbo.sp_MSflush_command @cmd, 1
        insert into #proctext(procedure_text) values(N'begin
     exec sp_MSreplraiserror 20510
     goto FAILURE
 end

')
    end
 
    -- timestamp col
    if @op_type = 'upd' and @ts_col is not null
	begin
        select @cmd = N'if update(' +  quotename(@ts_col) + N') 
'
        exec dbo.sp_MSflush_command @cmd, 1
        insert into #proctext(procedure_text) values(N'begin
     exec sp_MSreplraiserror 20511
     goto FAILURE
 end

')
	end
END
go	

raiserror('Creating procedure sp_MSscript_trigger_updates', 0,1)
go
create procedure sp_MSscript_trigger_updates
    @identity_col sysname,
	@ts_col       sysname,
	@op_type      char(3) = 'ins', -- 'ins', 'del'
	@objid        int,
	@indent       int = 0,
	@primary_key_bitmap varbinary(4000) = null
as
    declare @cmd nvarchar(4000)
	declare @col sysname
	declare @qualname nvarchar(512)

	if @op_type = 'upd'
	begin
		-- Script out pk var assigment that used in sp_MSscript_where_clause
		exec dbo.sp_MSscript_pkvar_assignment @objid, NULL, 1, @identity_col, @ts_col, 
			@primary_key_bitmap

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

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

    if @ts_col is not null and OBJECTPROPERTY(@objid, 'tablehastimestamp') <> 1
	begin
	    insert into #proctext(procedure_text) values(N' 
')
	    exec dbo.sp_MSpad_command @cmd output, @indent
		exec dbo.sp_MSget_col_position @objid, null, @ts_col, @col output
		select @cmd = @cmd + N'update ' + @qualname + N' set ' + @ts_col + N' = @' + @col
		exec dbo.sp_MSflush_command @cmd, 1

		exec dbo.sp_MSscript_where_clause @objid, null, 'trg pk', null, @indent, @op_type, @primary_key_bitmap
	end

   -- Reset to publisher's identity value if it is not an identity at the subscriber
   if @op_type = 'ins' and @identity_col is not null and OBJECTPROPERTY(@objid, 'tablehasidentity') <> 1
	begin
	    insert into #proctext(procedure_text) values(N' 
')
	    exec dbo.sp_MSpad_command @cmd output, @indent
		exec dbo.sp_MSget_col_position @objid, null, @identity_col, @col output
		select @cmd = @cmd + N'update ' + @qualname + N' set ' + @identity_col + N' = @' + @col
		exec dbo.sp_MSflush_command @cmd, 1

		exec dbo.sp_MSscript_where_clause @objid, null, 'trg pk', null, @indent, @op_type, @primary_key_bitmap
	end
go

raiserror('Creating procedure sp_MSscript_trigger_version_updates', 0,1)
go
create procedure sp_MSscript_trigger_version_updates
	@objid        int,
    @version_col  sysname,
	@indent       int = 0,
	@primary_key_bitmap   varbinary(4000)
as
    declare @cmd nvarchar(4000)
	declare @col sysname
	declare @qualname nvarchar(512)

	-- Script out pk var assigment that used in sp_MSscript_where_clause
	exec dbo.sp_MSscript_pkvar_assignment @objid, NULL, 1, null, null, @primary_key_bitmap

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

	exec dbo.sp_MSget_col_position @objid, null, @version_col, @col output

    -- Assign the param corresponding to version col to new guid
	exec dbo.sp_MSpad_command @cmd output, @indent
	select @cmd = @cmd + N'set @' + @col + N' = @version_guid ' 
    exec dbo.sp_MSflush_command @cmd, 1
	insert into #proctext(procedure_text) values(N' 
')

    exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	exec dbo.sp_MSpad_command @cmd output, @indent
    select @cmd = N'update ' + @qualname + N' set ' + @version_col + N' = @' + @col
	exec dbo.sp_MSflush_command @cmd, 1
    exec dbo.sp_MSscript_where_clause @objid, null, 'trg pk', null, @indent, 'upd', @primary_key_bitmap
go

raiserror('Creating procedure sp_MSscript_singlerow_trigger', 0,1)
go
create procedure sp_MSscript_singlerow_trigger (
    @objid        int,
    @publisher    sysname,
    @publisher_db sysname,
    @publication  sysname,
    @procname     sysname,
    @proc_owner	  sysname,
    @cftproc	  sysname,
    @identity_col  sysname,
    @ts_col        sysname,
    @op_type char(3) = 'ins', -- 'ins, 'upd', 'del'
    @primary_key_bitmap varbinary(4000) = NULL,
    @pubversion int
)
as
BEGIN
	declare @colname      sysname
			,@spacer       nvarchar(1)
			,@ccoltype     sysname
			,@this_col     int
			,@rc           int
			,@cmd			nvarchar(4000)

	--
	-- script update checks
	--
	if @op_type in ('ins', 'upd')
	    exec dbo.sp_MSscript_trigger_update_checks @objid, @identity_col, @ts_col, @op_type, 0

	--
	-- continue scripting
	--
	select @cmd = N' 
	' + N'--
	' + N'-- Are we doing single or multi row trigger update 
	' + N'--
	if (@rc = 1)
	begin 
		' + N'--
		' + N'-- single row trigger update
		' + N'-- '
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- script the trigger assignments
	--
	if @op_type in ('ins', 'upd')
	begin
		select @cmd = N'
		select 
'
		insert into #proctext(procedure_text) values(@cmd)
		exec dbo.sp_MSscript_trigger_assignment @objid, null, 8, @ts_col, @op_type, 1, @primary_key_bitmap
		select @cmd = N'
		from inserted '
		insert into #proctext(procedure_text) values(@cmd)    
	end

	if @op_type in ('ins')
	begin
		select @cmd = N'
		select 
'
		insert into #proctext(procedure_text) values(@cmd)
		exec dbo.sp_MSscript_trigger_assignment @objid, '_old', 8, @ts_col, @op_type, 0, @primary_key_bitmap
		select @cmd = N'
		from inserted '
		insert into #proctext(procedure_text) values(@cmd)    
	end
	else if @op_type in ('upd', 'del')
	begin
		select @cmd = N'
		select 
'
		insert into #proctext(procedure_text) values(@cmd)
		exec dbo.sp_MSscript_trigger_assignment @objid, '_old', 8, @ts_col, @op_type, 0, @primary_key_bitmap
		select @cmd = N'
		from deleted '
		insert into #proctext(procedure_text) values(@cmd)    
	end

	--
	-- script the execution logic
	--
	exec dbo.sp_MSscript_trigger_exec_rpc @publisher, @publisher_db, @publication, @procname, @proc_owner, 
				@cftproc, @objid, @op_type, 12, @identity_col, @ts_col, @primary_key_bitmap, @pubversion
	        
	--
	-- script any updates to be done
	--
	if @op_type in ('ins', 'upd')
		exec dbo.sp_MSscript_trigger_updates @identity_col, @ts_col, @op_type, @objid, 8, @primary_key_bitmap

	--
	-- script the end (for single row change)
	-- 
	select @cmd = N'
	end -- end of single row trigger update '
	insert into #proctext(procedure_text) values(@cmd)

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

raiserror('Creating procedure sp_MSscript_multirow_trigger', 0,1)
go
create procedure sp_MSscript_multirow_trigger (
	@objid        int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname,
	@procname     sysname,
	@proc_owner	  sysname,
	@cftproc	  sysname,
	@identity_col  sysname,
	@ts_col        sysname,
	@op_type char(3) = 'ins', -- 'ins, 'upd', 'del'
	@primary_key_bitmap varbinary(4000) = NULL,
	@pubversion int
)
as
BEGIN

    declare @cmd          nvarchar(4000)

	--
	-- start scripting
	--
	select @cmd = N'
	else
	begin 
		' + N'--
		' + N'-- start of multirow row trigger update 
		' + N'-- '
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- setup cursor over inserted table for ins & upd triggers
	--
	if @op_type in ('ins', 'upd')
	begin
		select @cmd = N'
		declare rpl_ins_cursor CURSOR LOCAL FAST_FORWARD FOR select 
'
		insert into #proctext(procedure_text) values(@cmd)

		exec dbo.sp_MSscript_trigger_variables @objid, null, null, 8, ' ',
			0,@identity_col, @ts_col,0, 1, @op_type, 1, @primary_key_bitmap

		select @cmd = N'
		from inserted for read only
		open rpl_ins_cursor 
'
		insert into #proctext(procedure_text) values(@cmd)
	end

	if @op_type in ('ins')
	begin
		select @cmd = N'
		declare rpl_ins2_cursor CURSOR LOCAL FAST_FORWARD FOR select 
'
		insert into #proctext(procedure_text) values(@cmd)

		exec dbo.sp_MSscript_trigger_variables @objid, null, null, 8, ' '

		select @cmd = N'
		from inserted for read only
		open rpl_ins2_cursor 
'
		insert into #proctext(procedure_text) values(@cmd)
	end

	--
	-- setup cursor over deleted table for  upd & del triggers
	--
	if @op_type in ('upd', 'del')
	begin
		select @cmd = N'
		declare rpl_del_cursor CURSOR LOCAL FAST_FORWARD FOR select 
'
		insert into #proctext(procedure_text) values(@cmd)

		exec dbo.sp_MSscript_trigger_variables @objid, null, null, 8, ' ', 
			0,@identity_col, @ts_col,0, 1,  @op_type, 0, @primary_key_bitmap

		select @cmd = N'
		from deleted for read only
		open rpl_del_cursor 
'
		insert into #proctext(procedure_text) values(@cmd)
	end

	--
	-- script fetch statement
	--
	exec dbo.sp_MSscript_trigger_fetch_statement @objid, @op_type, 8

	--
	-- start the fetch loop
	--
	select @cmd = N'
		while (@@fetch_status != -1)
		begin '
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- script the execution logic
	--
	exec dbo.sp_MSscript_trigger_exec_rpc @publisher, @publisher_db, @publication, @procname, @proc_owner, 
			@cftproc, @objid, @op_type, 16, @identity_col, @ts_col, @primary_key_bitmap, @pubversion

	--
	-- script any updates to be done
	--
	if @op_type in ('ins', 'upd')
		exec dbo.sp_MSscript_trigger_updates @identity_col, @ts_col, @op_type, @objid, 8, @primary_key_bitmap

	--
	-- do the next fetch
	--
	insert into #proctext(procedure_text) values(N'
')
	exec dbo.sp_MSscript_trigger_fetch_statement @objid, @op_type, 12

	--
	-- release the cursors
	--
	select @cmd = N'
		end  -- cursor while loop'
	insert into #proctext(procedure_text) values(@cmd)

	if @op_type in ('ins', 'upd')
	begin
		select @cmd = N'
		close rpl_ins_cursor
		deallocate rpl_ins_cursor '
		insert into #proctext(procedure_text) values(@cmd)
	end

	if @op_type = 'ins'
	begin
		select @cmd = N'
		close rpl_ins2_cursor
		deallocate rpl_ins2_cursor '
		insert into #proctext(procedure_text) values(@cmd)
	end

	if @op_type in ('upd', 'del')
	begin
		select @cmd = N'
		close rpl_del_cursor
		deallocate rpl_del_cursor '
		insert into #proctext(procedure_text) values(@cmd)		
	end

	--
	-- script the end (for single row change)
	-- 
	select @cmd = N'
	end -- end of multi row trigger update '
	insert into #proctext(procedure_text) values(@cmd)

	--
	-- all done
	--
	return 0

END
go

--
-- Name: sp_MSscript_sync_ins_trig
--
-- Description: This proc is used during the scripting of publisher synctran trigger 
-- used by updating subscribers. This SP generates the script for INSERT synctran 
-- trigger.It is executed on subscriber during the subscription initialization phase.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_MSscript_sync_ins_trig', 0,1)
go
create procedure sp_MSscript_sync_ins_trig (
	@objid		  int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname,
	@trigname     sysname,
	@procname     sysname,
	@proc_owner   sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000),
	@pubversion int = 1
)
as
BEGIN
	declare @colname      sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

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

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

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

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

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

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

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

    -- script end of trigger
	exec dbo.sp_MSscript_endtrig 

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

--
-- Name: sp_MSscript_sync_upd_trig
--
-- Description: This proc is used during the scripting of publisher synctran trigger 
-- used by updating subscribers. This SP generates the script for UPDATE synctran 
-- trigger.It is executed on subscriber during the subscription initialization phase.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_MSscript_sync_upd_trig', 0,1)
go
create procedure sp_MSscript_sync_upd_trig (
	@objid        int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname, 
	@trigname     sysname,
	@procname     sysname,
	@proc_owner   sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000),
	@pubversion int = 1)
as
BEGIN
	declare @colname      sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

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

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

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

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

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

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

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

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

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

--
-- Name: sp_MSscript_sync_del_trig
--
-- Description: This proc is used during the scripting of publisher synctran trigger used by updating subscribers. 
-- This SP generates the script for DELETE synctran trigger.It is executed on subscriber during the 
-- subscription initialization phase.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_MSscript_sync_del_trig', 0,1)
go
create procedure sp_MSscript_sync_del_trig (
	@objid        int,
	@publisher    sysname,
	@publisher_db sysname,
	@publication  sysname, 
	@trigname     sysname,
	@procname     sysname,
	@proc_owner	  sysname,
	@cftproc	  sysname,
	@agent_id	  int, 
	@identity_col sysname = NULL,
	@ts_col       sysname = NULL,
	@filter_clause nvarchar(4000),
	@primary_key_bitmap  varbinary(4000),
	@pubversion int = 1
)
as
BEGIN
	declare @colname sysname
			,@cmd          nvarchar(4000)
			,@ins_cmd      nvarchar(4000)
			,@columns      binary(32)
			,@outvars      nvarchar(4000)
			,@rc           int
			,@qualname     nvarchar(512)
			,@fisqueued	   bit

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

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

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

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

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

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

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

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

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

	-- script end of trigger
	exec dbo.sp_MSscript_endtrig 

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

raiserror('Creating procedure sp_MSget_synctran_column', 0,1)
go
create procedure sp_MSget_synctran_column
(
	@ts_col sysname,
	@op_type char(3), -- 'ins, 'upd', 'del'
	@is_new	bit,
	@primary_key_bitmap varbinary(4000) = null,
	@colname sysname,
	@this_col int, -- position in source object
	@column nvarchar(4000) output,
	@from_proc bit = 0,
	@coltype sysname = NULL,
	@type	varchar(10) = NULL,
	@art_col int = NULL -- position in the partition.
)
as
begin
	declare @bytestr      nvarchar(10)
			,@bitstr       nvarchar(10)
			,@typed_null	  nvarchar(255)

	--
	-- if @art_col is not NULL then it means one of the following:
	-- 1) If we are scripting for triggers - then it means the subscriber
	-- 	table (destination table) was altered and column id do not match
	-- 	relative column order(as specified in PK bitmap or columns_updated()).
	--	The @art_col will represent the relative column order in the bitmap
	--	and @this_col will represent the actual column id
	--
	-- 2) If we are scripting for synctran procedures on publisher - then 
	--	@art_col represents the relative index of the column that is being
	--	replicated and @this_col represents the actual column id of the column
	--
	-- if @art_col is NULL - then we will set it to the value of @this_col
	--
	if (@art_col is NULL)
		select @art_col = @this_col
		
	select @typed_null = case when (@coltype is null) then N'NULL'
					else N'convert(' + @coltype + N', NULL)' end

	-- Optimization:
	-- If the column value is not needed, we set the corresponding
	-- param to null to reduce the network traffic. Here is the rule:

	-- For new values in update trigger,
	--	Set the param to column value or null depending on whether or
	--  or the column is updated.
	-- For old values 
	--	if ts col is replicated and the current column is not the ts col
	--	and the column is not in primary key, set the param to null
	-- For other cases
	--	set the param to column values.

	-- Called by proc
	if @type = 'pk_var'
	begin
		select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
		select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

		select @column = N'case substring(@bitmap,' 
			+ @bytestr + N',1) & ' + @bitstr +  
			N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @this_col ) + 
			N' else ' + N'@c'+ convert( nvarchar, @this_col )  + N'_old end'
	end
	else if (@from_proc = 1)
	begin
		select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
		select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )

		select @column = N'case substring(@bitmap,' 
			+ @bytestr + N',1) & ' + @bitstr +  
			N' when ' + @bitstr + N' then ' + N'@c'+ convert( nvarchar, @this_col ) + 
			N' else [' + @colname + N'] end'
	end
	-- Called in trigger,
	else if (@is_new = 1) and (@op_type = 'upd')
	begin
		-- @bitmap is set using columns_updated() at the beginning
		-- of the trigger.
		select @bytestr = convert( nvarchar, 1 + (@art_col-1) / 8 )
		select @bitstr =  convert( nvarchar, power(2, (@art_col-1) % 8 ) )
		
		select @column = N'case substring(@bitmap,' + @bytestr + N',1) & ' + @bitstr +  
			N' when ' + @bitstr + N' then [' + @colname + N'] ' + 
			N' else ' + @typed_null 
			+' end'
	end
	else if ((@is_new = 0) and 
		(@ts_col is not null and @colname not in (@ts_col, N'msrepl_tran_version')) and
		(@primary_key_bitmap is not null and 
		(substring(@primary_key_bitmap, 1 + (@art_col-1) / 8 , 1) & power(2, (@art_col-1) % 8 )) = 0))
		select @column =  @typed_null
	else 
		select @column = N'[' + @colname  + N'] '
	
	-- Add a new line
	select @column = @column + N'
	'
end
go

--
-- Name: sp_addqueued_artinfo
--
-- Description: This procedure is invoked by distribution agent to populate MSsubscription_articles 
-- with all the necessary article meta data for queued publications. This article meta data is later 
-- used for conflict viewing (de-centralized). Invoked on subscriber.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_addqueued_artinfo', 0,1)
go
CREATE PROCEDURE sp_addqueued_artinfo (
	@artid				int
	,@article			sysname
	,@publisher 		sysname
	,@publisher_db		sysname
	,@publication		sysname
	,@dest_table		sysname
	,@owner				sysname
	,@cft_table			sysname
	,@columns			binary(32))
AS
BEGIN
	set nocount on
	declare 	@agent_id int
				,@update_mode int
				,@retcode int

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

CREATE PROCEDURE sp_addsynctriggers (
	@sub_table       sysname,			-- table name 
	@sub_table_owner sysname,			-- table owner
	@publisher      sysname,            -- publishing server name
	@publisher_db   sysname,            -- publishing database name. If NULL then same as current db
	@publication	sysname,			-- publication name.
	@ins_proc       sysname,
	@upd_proc       sysname,
	@del_proc       sysname,
	@cftproc		sysname,
	@proc_owner		sysname,
	@identity_col   sysname = 'NULL', 
	@ts_col         sysname = 'NULL',
	@filter_clause  nvarchar(4000) = 'NULL',
	@primary_key_bitmap  varbinary(4000),
	@identity_support bit = 0,
	@independent_agent bit = 0
	,@distributor	sysname				-- distribution server name
	,@pubversion int = 1	-- 1 = when this call is generated by pre SP3 publishers, 2 = SP3 or later
)
AS
BEGIN
    set nocount on

    declare @db						sysname
                ,@trigname				sysname
                ,@ins_trig				sysname
                ,@upd_trig				sysname
                ,@del_trig				sysname
                ,@qual_ins_trig			nvarchar(540)
                ,@qual_upd_trig			nvarchar(540)
                ,@qual_del_trig			nvarchar(540)
                ,@dbname				sysname
                ,@ccols					int
                ,@cnt					int
                ,@retcode				int
                ,@cmd					nvarchar(4000)
                ,@merge_pub_object_bit	int
                ,@synctran_bit			int
                ,@object_id				int
                ,@bitmap_str				varchar(8000)
                ,@constraint_name		sysname
                ,@quoted_name			nvarchar(540)
                ,@qualname				nvarchar(540)
                ,@loctrancount 			int

    select 	@merge_pub_object_bit 	= 128
                ,@synctran_bit			= 256

    --  Security Check
    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
    IF @@ERROR <> 0 or @retcode <> 0
        RETURN(1)
    --
    -- validate @pubversion
    --
    if (@pubversion is null)
        select @pubversion = 1
    if (@pubversion not in (1,2))
        return 1

    -- Dist Agent executes this sproc with 'implicit transasctions on'.
    -- We take care of our own transactions boundaries to get out of tran 
    set implicit_transactions off
    select @loctrancount = @@trancount
    while @@trancount > 0 commit tran

    -- check valid server and database setting
    -- 1. nested trigger have to be on
    if exists (select * from master..sysconfigures where config = 115 and value = 0)
    begin
        raiserror(21081, 16, 1)
        return (1)
    end

    -- 2. db option: recursive trigger have to be off
    if DATABASEPROPERTY(db_name(), N'IsRecursiveTriggersEnabled') <> 0
    begin
        raiserror(21082, 16, 1)
        return (1)
    end	
	
    -- 2. db compatibility level have to be 7.0
    if exists (select * from master..sysdatabases where dbid = db_id() and 
    cmptlevel < 70)
    begin
        raiserror(21083, 16, 1)
        return (1)
    end	

    if lower(@sub_table_owner) = N'null'
        select @qualname = QUOTENAME(@sub_table)		
    else
        select @qualname = QUOTENAME(@sub_table_owner) + N'.' + QUOTENAME(@sub_table)

    -- Verify that table exists 
    select @object_id = object_id (@qualname)
    if @object_id is null
    begin
        raiserror(20507, 16, 1, @qualname, 'sp_addsynctriggers')
        return (1)
    end

    -- Add default to timestamp, identity and version guid column
    if OBJECTPROPERTY(@object_id, 'tablehastimestamp') <> 1
    begin
        select @constraint_name = 'MSrepl_synctran_ts_default_' + convert(nvarchar(10), @object_id)
        select @quoted_name = quotename(@ts_col)
        if @ts_col is not null and @ts_col not in ('null','NULL') and not exists
        (select * from sysobjects where name = @constraint_name)
        begin
            exec ('alter table ' + @qualname + 
                ' add constraint ' + @constraint_name + 
                ' default 0 for ' + @quoted_name )
            if @@ERROR<>0 return 1
        end
    end
	
    if OBJECTPROPERTY(@object_id, 'tablehasidentity') <> 1
    begin
	    select @constraint_name = 'MSrepl_synctran_identity_default_' + convert(nvarchar(10), @object_id)
	    select @quoted_name = quotename(@identity_col)
	    if @identity_col is not null and @identity_col not in ('null','NULL') and not exists
		    (select * from sysobjects where name = @constraint_name)
	    begin
		    exec ('alter table ' + @qualname + 
			    ' add constraint ' + @constraint_name + 
			    ' default 0 for ' + @quoted_name )
		    if @@ERROR<>0 return 1
	    end
    end

    -- The default constraint is transfered with snapshot already for native publication.
    -- Need to detect to see if default constraint already there.
    select @quoted_name = 'msrepl_tran_version'
    declare @colid int
    select @colid = colid from syscolumns where 
        id = @object_id and
        name = @quoted_name
    if not exists (select * from sysconstraints where
        id = @object_id and 
        colid = @colid and
        status & 5 = 5) -- default
    begin 
        select @constraint_name = 'MSrepl_tran_version_default_' + convert(nvarchar(10), @object_id)
        exec ('alter table ' + @qualname + 
            ' add constraint ' + @constraint_name + 
            ' default newid() for ' + @quoted_name )
        if @@ERROR<>0 return 1
    end

    --
    -- determine if we should pass @cftproc to scripting of synctran trigger
    -- Check if the subscription needs scripting for queued replication. 
    -- For publishers that are pre 80SP3 - cftproc should not be null
    -- that takes care of it. For publisher that 80SP3 or later - we need
    -- to validate the article information
    --
    -- Check the version of the publisher
    --
    if ((@pubversion = 2) and not (@cftproc is null or lower(@cftproc) = 'null'))
    begin
        --
        -- Publisher is 80SP3 or later
        -- @cftproc should exist and article information should exist
        -- for this subscription
        --
        if not exists (select artid 
			from (dbo.MSsubscription_articles as a join dbo.MSsubscription_agents as b
					on a.agent_id = b.id)
			where UPPER(b.publisher) = UPPER(@publisher)
				and b.publisher_db = @publisher_db
				and b.publication = @publication
				and a.dest_table = object_name(@object_id))
	begin
	    --
	    -- There is no article information
	    -- disable queued specific scripting 
	    --
	    select @cftproc = 'null'
	end
    end
    
	-- If MSsubscription_properties table does not exists, create one.
	if (LOWER(@cftproc) = 'null')
	begin
		exec @retcode = dbo.sp_MScreate_sub_tables
			@tran_sub_table = 0,
			@property_table = 1,
			@sqlqueue_table = 0
	end
	else
	begin
		exec @retcode = dbo.sp_MScreate_sub_tables
			@tran_sub_table = 0,
			@property_table = 1,
			@sqlqueue_table = 1
	end
	IF @@ERROR <> 0 or @retcode <> 0
		RETURN(1)

	-- If no entry in MSsubscription_properties for this publication, add one.
	IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication) 
	BEGIN
		-- Use status rpc for local publisher
		declare @security_mode int
		declare @login sysname
		if UPPER(@@servername) = UPPER(@publisher)
		begin
			select @security_mode = 2
		end
		else
		begin
			select @security_mode = 0
			select @login = 'sa'
		end

		exec @retcode = dbo.sp_link_publication
			@publisher = @publisher,
			@publisher_db = @publisher_db,
			@publication = @publication,
			@security_mode = @security_mode,
			@login = @login,
			@password = NULL,
			@distributor = @distributor
		IF @@ERROR <> 0 or @retcode <> 0
			RETURN(1)
	END
	  
    if exists (select * from sysobjects where 
		replinfo & @merge_pub_object_bit <> 0 and
		id = @object_id)
	begin
        raiserror(21063, 16, 1, @qualname)
        return (1)
	end
	
    -- Get agent_id
    declare @agent_id int

	-- First try to get the agent id initialized by the distribution agent
	declare @login_time datetime
	select @login_time = login_time from master..sysprocesses where spid = @@spid

	select @agent_id = id from MSsubscription_agents where
		spid = @@spid and
		login_time = @login_time

	-- If row not found, the current call is not from a distribution agent. Uses
	-- are creating trigger manually using the script generated by
	-- sp_script_synctran_triggers.
	-- Get the row using the publication name. However, it is possible that there are
	-- more than one qualifed rows with different subscription_type, for example
	-- pull and push subscriptions to share agent publications or subscriptions that has
	-- not been cleaned up.
	if @agent_id is null
	begin
		declare @num_dup_rows int
		select @agent_id = avg(id), @num_dup_rows = count(*) from MSsubscription_agents where
			publisher = @publisher and
			publisher_db = @publisher_db and
			publication = case @independent_agent 
				when 0 then N'ALL'
				else @publication
				end and
			-- We know the subscription must be updateble. This
			-- is to reduce the chance of dup rows.
			update_mode <> 0

		if @num_dup_rows > 1
		begin
			-- Raise subscription already exist error
			-- This should rarely happen.
			RAISERROR (14058, 16, -1)
			return(1)
		end

		if @agent_id is null
		begin
			raiserror(20588, 16, -1)
			return(1)
		end
	end


	/*
	**	Create system table MSreplication_objects if it does not exist
	*/
	IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND name = 'MSreplication_objects')
		BEGIN
			CREATE TABLE dbo.MSreplication_objects
			(
			publisher sysname NULL,
			publisher_db sysname NULL,
       		publication sysname NULL, 
			object_name	sysname NOT NULL,
			object_type	char(2) NOT NULL
			)
			IF @@ERROR <> 0
				begin
					rollback transaction 
					return (1)
				end
			
			CREATE UNIQUE CLUSTERED INDEX ucMSreplication_objects ON dbo.MSreplication_objects(object_name)
			EXEC dbo.sp_MS_marksystemobject 'dbo.MSreplication_objects'
		END


	-- Drop all replication triggers on the source object
	-- We should drop all because we don't support updatable subscriptions to 
	-- multiple publications on same dest table.
	declare object_cursor CURSOR LOCAL FAST_FORWARD for 
		select o.object_name, so.id from MSreplication_objects o, sysobjects so where
			o.object_name = so.name and
			so.parent_obj = @object_id and
			o.object_type = 'T'

	declare @old_id int 
	declare @old_name sysname

	OPEN object_cursor
    FETCH object_cursor INTO @old_name, @old_id
 	WHILE (@@fetch_status <> -1)
	BEGIN
        -- Cleanup identity range table
        declare @parent_obj int
        select @parent_obj = 0
		select @parent_obj = parent_obj from sysobjects where id = @old_id
        if exists (select * from sysobjects where name = 'MSsub_identity_range')
            delete MSsub_identity_range where objid = @parent_obj

        -- Drop the trigger
        exec @retcode = dbo.sp_MSdrop_object 
			@object_id = @old_id
		if @retcode <> 0 or @@error <> 0
			goto UNDO
		delete from MSreplication_objects where object_name=@old_name
		FETCH object_cursor INTO @old_name, @old_id
	END
    CLOSE object_cursor
    DEALLOCATE object_cursor

	-- Generate trigger names
        select @trigname = RTRIM(SUBSTRING(@sub_table,1,110))
	select @ins_trig = N'trg_MSsync_ins_' + @trigname 
	select @upd_trig = N'trg_MSsync_upd_' + @trigname 
	select @del_trig = N'trg_MSsync_del_' + @trigname 

	-- check uniqueness of names and revert to ugly guid-based name if friendly name already exists
	if exists (select name from sysobjects where name in (@ins_trig, @upd_trig, @del_trig))
        begin
            declare @guid_name nvarchar(36)
            select @guid_name =  convert (nvarchar(36), newid())
		select @ins_trig = 'trg_MSsync_ins_' + @guid_name
		select @upd_trig = 'trg_MSsync_upd_' + @guid_name
		select @del_trig = 'trg_MSsync_del_' + @guid_name
        end

	-- Get qual names
	if lower(@sub_table_owner) = N'null'
	begin
		select @qual_ins_trig = @ins_trig
		select @qual_upd_trig = @upd_trig
		select @qual_del_trig = @del_trig
	end
	else
	begin
		select @qual_ins_trig = QUOTENAME(@sub_table_owner) + N'.' + @ins_trig
		select @qual_upd_trig = QUOTENAME(@sub_table_owner) + N'.' + @upd_trig
		select @qual_del_trig = QUOTENAME(@sub_table_owner) + N'.' + @del_trig
	end

	exec @retcode = master..xp_varbintohexstr @primary_key_bitmap, @bitmap_str output
	if @retcode <> 0 or @@error <> 0
		return 1

/*
	exec ('if exists (select * from sysobjects where name = N''' + @ins_trig + N''' and xtype = N''TR'')
        drop trigger ' + @ins_trig)
    exec ('if exists (select * from sysobjects where name = N''' + @upd_trig + N''' and xtype = N''TR'')
        drop trigger ' + @upd_trig)
    exec ('if exists (select * from sysobjects where name = N''' + @del_trig + N''' and xtype = N''TR'')
        drop trigger ' + @del_trig)

*/
    -- We are now going to create triggers, so start a transaction
    begin tran
        -- Call out to individual create trigger routines
	    select @dbname = db_name()
	    select @cmd = 'sp_MSscript_sync_ins_trig ' + 
		    convert( nvarchar, @object_id )  + ', N' + 
			quotename(@publisher, '''')     + ', N' + 
			quotename(@publisher_db, '''')  + ', N' + 
			quotename(@publication, '''')   + ', N' + 
		    quotename(@ins_trig, '''')      + ', N' + 
			quotename(@ins_proc, '''')      + ', N' + 
			quotename(@proc_owner, '''')	+ ', N' + 
			quotename(@cftproc, '''')       + ', ' + 
			convert(nvarchar(10), @agent_id) + ', N' + 
			quotename(@identity_col, '''') + ', N' + 
			quotename(@ts_col, '''')        
		if @filter_clause in ('NULL', 'null')
		    select @cmd = @cmd + ', null' 
		else 
            select @cmd = @cmd + ', N''' + replace (@filter_clause,'''','''''')  + ''''
									
            -- Set primary key bitmap and pubversion
            select @cmd = @cmd + ', ' + @bitmap_str +  ', ' + cast(@pubversion as nvarchar(10))

	    exec @retcode = master..xp_execresultset @cmd, @dbname
		IF @@ERROR <> 0 or @retcode <> 0
			goto UNDO
	    select @cmd = 'sp_MSscript_sync_upd_trig ' + 
		    convert( nvarchar, @object_id )  + ', N' + 
			quotename(@publisher, '''')     + ', N' + 
			quotename(@publisher_db, '''')  + ', N' + 
			quotename(@publication, '''')   + ', N' + 
		    quotename(@upd_trig, '''')      + ', N' + 
			quotename(@upd_proc, '''')      + ', N' + 
			quotename(@proc_owner, '''')	+ ', N' + 
			quotename(@cftproc, '''')       + ', ' + 
			convert(nvarchar(10), @agent_id)  + ', N' + 
			quotename(@identity_col, '''')  + ', N' + 
			quotename(@ts_col, '''')        
		if @filter_clause in ('NULL', 'null')
		    select @cmd = @cmd + ', null' 
		else 
            select @cmd = @cmd + ', N''' + replace (@filter_clause,'''','''''')  + ''''
									
            -- Set primary key bitmap and pubversion
            select @cmd = @cmd + ', ' + @bitmap_str +  ', ' + cast(@pubversion as nvarchar(10))

		exec @retcode = master..xp_execresultset @cmd, @dbname
		IF @@ERROR <> 0 or @retcode <> 0
			goto UNDO

	    select @cmd = 'sp_MSscript_sync_del_trig ' + 
		    convert( nvarchar, @object_id )  + ', N' + 
			quotename(@publisher, '''')     + ', N' + 
			quotename(@publisher_db, '''')  + ', N' + 
			quotename(@publication, '''')   + ', N' + 
		    quotename(@del_trig, '''')      + ', N' + 
			quotename(@del_proc, '''')      + ', N' + 
			quotename(@proc_owner, '''')	+ ', N' + 
			quotename(@cftproc, '''')       + ', ' + 
			convert(nvarchar(10), @agent_id) + ', N' + 
			quotename(@identity_col, '''')  + ', N' + 
			quotename(@ts_col, '''')        
		if @filter_clause in ('NULL', 'null')
		    select @cmd = @cmd + ', null' 
		else 
            select @cmd = @cmd + ', N''' + replace (@filter_clause,'''','''''')  + ''''			

            -- Set primary key bitmap and pubversion
            select @cmd = @cmd + ', ' + @bitmap_str +  ', ' + cast(@pubversion as nvarchar(10))

	    exec @retcode = master..xp_execresultset @cmd, @dbname
		IF @@ERROR <> 0 or @retcode <> 0
			goto UNDO

		-- Drop old entries before insert. The triggers with those names
		-- are created as above.
		delete MSreplication_objects where object_name = @ins_trig
		IF @@ERROR <> 0
			goto UNDO
		delete MSreplication_objects where object_name = @upd_trig
		IF @@ERROR <> 0
			goto UNDO
		delete MSreplication_objects where object_name = @del_trig
		IF @@ERROR <> 0
			goto UNDO

		-- Mark procedures as system procs so they don't show up in the UI
		exec dbo.sp_MS_marksystemobject @qual_ins_trig
		IF @@ERROR <> 0
			goto UNDO

		insert into MSreplication_objects(publisher, publisher_db, publication, object_name, object_type)
					values(@publisher, @publisher_db, @publication, @ins_trig, 'T')
		IF @@ERROR <> 0
			goto UNDO

		exec dbo.sp_MS_marksystemobject @qual_upd_trig
		IF @@ERROR <> 0
			goto UNDO
				
		insert into MSreplication_objects(publisher, publisher_db, publication, object_name, object_type)
					values(@publisher, @publisher_db, @publication, @upd_trig, 'T')
		IF @@ERROR <> 0
			goto UNDO

		exec dbo.sp_MS_marksystemobject @qual_del_trig
		IF @@ERROR <> 0
			goto UNDO

		insert into MSreplication_objects(publisher, publisher_db, publication, object_name, object_type)
					values(@publisher, @publisher_db, @publication, @del_trig, 'T')
		IF @@ERROR <> 0
			goto UNDO

		-- Mark the table for warnings in BCP
		update sysobjects set replinfo = replinfo | @synctran_bit where
			id = @object_id
		IF @@ERROR <> 0
			goto UNDO

		-- Set up identity range table
		if @identity_support <> 0
		begin
			if not exists (select * from sysobjects where name = 'MSsub_identity_range')
			begin
				create table dbo.MSsub_identity_range (
					objid int not null,
					range bigint not null,
					last_seed bigint not null,
					threshold int not null)
				IF @@ERROR <> 0
					goto UNDO
			
				CREATE UNIQUE CLUSTERED INDEX ucMSsub_identity_range ON dbo.MSsub_identity_range (objid)
				
				EXEC dbo.sp_MS_marksystemobject 'MSsub_identity_range'
				IF @@ERROR <> 0
					goto UNDO
			end
			if not exists (select * from MSsub_identity_range where objid = @object_id)
			begin
				-- add zero at the beginning.
				insert into MSsub_identity_range (objid, range, last_seed, threshold) values
					(@object_id, 0, 0, 0)
				IF @@ERROR <> 0
					goto UNDO
			end
		end

	-- commit tran
	commit tran

	-- Set trigger firing order for insert
	exec dbo.sp_settriggerorder @qual_ins_trig,'first','insert'
	exec dbo.sp_settriggerorder @qual_upd_trig,'first','update'
	exec dbo.sp_settriggerorder @qual_del_trig,'first','delete'
	
    -- Ignore errors.
    exec dbo.sp_MSsub_cleanup_orphans

	-- restore the trancount if necessary
	if (@loctrancount > 0)
	begin
		while (@@trancount < @loctrancount)
			begin tran
	end

	return (0)
UNDO:
	if @@trancount <> 0
		rollback tran
	return(1)
END
go

--
-- Name: sp_setreplfailovermode
--
-- Description: This SP is invoked on the subscriber to toggle the failover 
-- mode for immediate updating with failover to queued subscriptions.
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_setreplfailovermode', 0,1)
go
create procedure sp_setreplfailovermode (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,
	@failover_mode nvarchar (10), 
	@override tinyint = 0)
as
begin
	set nocount on
	declare	@failover_mode_id tinyint, 
			@current_failover_mode_id bit,
			@retcode int,
			@queue_id sysname,
			@fqueue_empty int,
			@update_mode int,
			@queue_server sysname

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

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

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

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

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

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

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

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

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

	-- All done
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_setreplfailovermode
go

--
-- Name: sp_helpreplfailovermode
--
-- Description: This SP is used by Queued replication user and 
-- Replication UI to find out the failover state of a given queued subscription. 
-- Invoked on the subscriber
--
-- Parameter: Refer to the comments in the create procedure statement
--
-- Returns: 1 or 0   0 = success
--
-- Security: Public procedure - does subscribe security check. 
--
raiserror('Creating procedure sp_helpreplfailovermode', 0,1)
go
create procedure sp_helpreplfailovermode (
	@publisher sysname,
	@publisher_db sysname,
	@publication sysname,
	@failover_mode_id tinyint = 0 output,
	@failover_mode nvarchar(10) = NULL output)
as
BEGIN
	declare	@subfound bit
			,@retcode int

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

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

			select @failover_mode_id = 0
		end
	end

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

	--
	-- all done
	--
	return 0
END
go
exec dbo.sp_MS_marksystemobject sp_helpreplfailovermode
go

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

CREATE PROCEDURE sp_helpreplicationdboption (
	@dbname sysname = '%', @type sysname = 'replication allowed'
)
AS
BEGIN
	SET NOCOUNT ON

	/*
	** Declarations.
	*/

	DECLARE @retcode int
			,@typebit int
			,@distbit int -- bit to distinguish distribution databases
			,@dbowner bit
			,@dbreadonly bit
			,@replication_db sysname

	SELECT @distbit = 16
			,@dbowner = 0
			,@dbreadonly = 0

	-- don't do security check.

	if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'publish%')
		select @typebit = 1
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'subscribe%')
		select @typebit = 2
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'merge publish%')
		select @typebit = 4
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'merge subscribe%')
		select @typebit = 8
	else if (lower(@type collate SQL_Latin1_General_CP1_CS_AS) like 'replication allowed%')
		select @typebit = 0
	else        
	begin
		raiserror(14091,-1,-1)
		return 1
	end

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

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

	/*
	** Show databases with this option enabled.
	*/
	CREATE TABLE #replicationdbs (name sysname collate database_default not null, id int identity NOT NULL, transpublish bit not null, mergepublish bit not null, dbowner bit not null, dbreadonly bit not null)
	if @typebit <> 0
	begin
		INSERT INTO #replicationdbs (name, transpublish, mergepublish, dbowner, dbreadonly)
			SELECT name, 
				case when (category & 1) <> 0 then 1 else 0 end,
				case when (category & 4) <> 0 then 1 else 0 end,
				@dbowner,
				DATABASEPROPERTY(name, N'IsReadOnly')
			FROM master.dbo.sysdatabases
			WHERE ((@dbname = N'%') OR (name = @dbname collate database_default))
				AND (category & @typebit) <> 0 
				AND (HAS_DBACCESS ( name ) = 1)

		DECLARE hCdboinfo CURSOR LOCAL FAST_FORWARD FOR
			SELECT name FROM #replicationdbs
			FOR READ ONLY
		OPEN hCdboinfo
		FETCH hCdboinfo INTO @replication_db
		WHILE (@@fetch_status <> -1)
		BEGIN
			EXEC @retcode = sp_MSrepl_isdbowner @replication_db
			IF (@retcode IS NOT NULL) AND (@retcode <> 0)
			BEGIN
				UPDATE #replicationdbs set dbowner = 1 where name = @replication_db
			END
			FETCH hCdboinfo INTO @replication_db
		END
		CLOSE hCdboinfo
		DEALLOCATE hCdboinfo
	end            
	else
	begin
		DECLARE @db_category int

		/* Filter out distribution databases */
		DECLARE hC  CURSOR LOCAL FAST_FORWARD FOR 
			SELECT name, category, DATABASEPROPERTY(name, N'IsReadOnly')
			FROM master.dbo.sysdatabases 
			WHERE ((@dbname = N'%') OR (name = @dbname collate database_default)) 
				AND (category & @distbit) = 0 
				AND (HAS_DBACCESS ( name ) = 1)
			FOR READ ONLY
		OPEN hC
		FETCH hC INTO @replication_db, @db_category, @dbreadonly
		WHILE (@@fetch_status <> -1)
		BEGIN
			if @replication_db NOT IN ('master','model','tempdb','msdb','MSSQLWeb')
			BEGIN
				EXEC @retcode = sp_MSrepl_isdbowner @replication_db
				IF (@retcode IS NOT NULL) AND (@retcode <> 0)
				BEGIN
					SELECT @dbowner = 1
				END
				ELSE
				BEGIN
					SELECT @dbowner = 0
				END
				INSERT INTO #replicationdbs (name, transpublish, mergepublish, dbowner, dbreadonly) 
				VALUES (@replication_db,
						case when (@db_category & 1) <> 0 then 1 else 0 end,
						case when (@db_category & 4) <> 0 then 1 else 0 end,
						@dbowner, @dbreadonly)
			END
			FETCH hC INTO @replication_db, @db_category, @dbreadonly
		END
		CLOSE hC
		DEALLOCATE hC
	end
	SELECT * FROM #replicationdbs
	-- DROP TABLE #replicationdbs
END
go

raiserror('Creating procedure sp_MScheck_agent_instance', 0,1)
GO
CREATE PROCEDURE sp_MScheck_agent_instance
@application_name sysname,
@agent_type int = NULL

as
	declare @count_pro int
	set nocount on
	select @count_pro = count(*) from master..sysprocesses where 
		program_name = @application_name collate database_default
	-- type 3 is for 7.0 distribution agent backward compatibility.
	if @agent_type = 3
	begin
		-- The distribution agent will before connecting to the publisher with unique 
		-- application name
		if @count_pro > 0
			raiserror (21036, 16, -1, 'distribution')
	end
	-- 10 is 7.5 version of the distribution agent.
	else if @agent_type = 10
	begin
		-- The distribution agent will connecting to the publisher with unique 
		-- application name and then check.
		if @count_pro > 1
			raiserror (21036, 16, -1, 'distribution')
	end
	else if @agent_type = 4
	begin
		-- The merge agent will connect to the publisher with unique application name
		-- then call this procedure
		if @count_pro > 1 
			raiserror (21036, 16, -1, 'merge')
	end
	else if @agent_type = 1
	begin
		-- The snapshot agent will connect to the distributiondb with unique application name
		-- then call this procedure
		if @count_pro > 2 
			raiserror (21036, 16, -1, 'snapshot')
	end
	else if @agent_type = 2
	begin
		-- The logreader agent will connect to the distributiondb with unique application name
		-- then call this procedure
		if @count_pro > 1 
			raiserror (21036, 16, -1, 'logreader')
	end
	else if @agent_type = 9
	begin
		-- The queuereader agent will connect to the distributiondb with unique application name
		-- then call this procedure
		if @count_pro > 1 
			raiserror (21036, 16, -1, 'queuereader')
	end
go

CREATE PROCEDURE sp_MSBumpupCompLevel(
@pubid				uniqueidentifier,
@new_level			int
)
as

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

	/* always bump UP, not Down in any case */
	update sysmergepublications set backward_comp_level = @new_level where pubid=@pubid and backward_comp_level < @new_level
	if @@ERROR<>0
		return (1)
	return (0)
GO
exec dbo.sp_MS_marksystemobject sp_MSBumpupCompLevel
go


CREATE PROCEDURE sp_MSCleanupForPullReinit (
	@publication 		sysname,
	@publisher_db		sysname,
	@publisher     		sysname = @@servername
	) AS
	declare @pubid 		uniqueidentifier
	declare @artid 		uniqueidentifier
	declare @retcode	smallint

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

	/* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)	

	begin transaction
	save tran cleanupforreinit
	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_genhistory where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergesubsetfilters where pubid=@pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergeschemachange where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_contents where tablenick in (select nickname from sysmergearticles where pubid=@pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_tombstone where tablenick in (select nickname from sysmergearticles where pubid=@pubid)
	if @@ERROR<>0 
		goto Error
	update MSmerge_replinfo set recgen = NULL, recguid = NULL, sentgen = NULL, sentguid = NULL 
			where repid in ( select subid from sysmergesubscriptions where pubid = @pubid)
	if @@ERROR<>0 
		goto Error

	commit tran 
	return (0)

Error:
	rollback tran cleanupforreinit
	commit tran 
	return (1)
GO
exec dbo.sp_MS_marksystemobject sp_MSCleanupForPullReinit
go

grant execute on dbo.sp_MSCleanupForPullReinit to public
go


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

CREATE PROCEDURE sp_MSpublicationcleanup (
	@publication 		sysname,
	@publisher_db		sysname,
	@publisher	       	sysname = @@servername
	) AS
	declare @pubid 		uniqueidentifier
	declare @artid 		uniqueidentifier
	declare @retcode	smallint
    declare @objectname sysname
    declare @objectowner sysname

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

    /* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db = @publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)

	/* 
	** If we are deleting the last publication in the database, ie there are articles in
	** sysmergearticles with a different pubid then the one being dropped
	** then remove all the rows in MSmerge_genhistory, MSmerge_contents and MSmerge_tombstone 
	** use a truncate table in order to make the operation non logged and hence efficient
	*/
	if not exists (select * from sysmergearticles where pubid <> @pubid)
		begin
			truncate table MSmerge_genhistory
			truncate table MSmerge_contents
			truncate table MSmerge_tombstone
		end

	begin transaction
	save tran MSpublicationcleanup
	/* Clean up the articles for this publication, and delete the row */
	select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
	while @artid is not null
		begin
		if not exists (select * from sysmergearticles WHERE artid = @artid and pubid <> @pubid)
			begin
				exec @retcode=sp_MSarticlecleanup @pubid, @artid
				if @retcode<>0 or @@ERROR<>0 
					goto Error
			end
		delete from sysmergearticles where artid = @artid and pubid = @pubid
		if @@ERROR<>0 
			goto Error
		set @artid = NULL
		select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
		end
		
    /* Unmark all schema articles in this publication */
    if exists (select * from sysobjects where name = 'sysmergeschemaarticles')
    begin
        declare hschemaarticle_cur cursor local fast_forward for
            select destination_object, destination_owner from sysmergeschemaarticles where
            pubid = @pubid 
        for read only
        open hschemaarticle_cur
        fetch hschemaarticle_cur into @objectname, @objectowner
        while (@@fetch_status<>-1)
        begin
                exec  sp_MSunmarkschemaobject @objectname, @objectowner    
				if @retcode<>0 or @@ERROR<>0 
					goto Error
                fetch hschemaarticle_cur into @objectname, @objectowner
        end
        close hschemaarticle_cur
        deallocate hschemaarticle_cur

        /* Delete all schema article rows for this publication*/
        delete from sysmergeschemaarticles where pubid = @pubid
		if @@ERROR<>0 
			goto Error
    end
    
	/* Now clean up any traces in other system tables */

	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_genhistory where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from MSmerge_replinfo where repid in (select subid from sysmergesubscriptions where pubid = @pubid and status <> 2)
	if @@ERROR<>0 
		goto Error
    delete from sysmergesubsetfilters where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergesubscriptions where pubid = @pubid and status <> 2
	if @@ERROR<>0 
		goto Error
	delete from sysmergepublications where pubid = @pubid
	if @@ERROR<>0 
		goto Error
	delete from sysmergeschemachange where pubid = @pubid
	if @@ERROR<>0 
		goto Error

	commit tran 
	
	return (0)

Error:
	rollback tran MSpublicationcleanup
	commit tran 
	return (1)
GO
exec dbo.sp_MS_marksystemobject sp_MSpublicationcleanup
go

grant execute on dbo.sp_MSpublicationcleanup to public
go

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

create procedure sp_cleanupdbreplication
AS
set nocount on

declare @pubid			uniqueidentifier
declare @artid			uniqueidentifier
declare @retcode		int

exec @retcode = sp_MSreplcheck_publish
if (@retcode <> 0 or @@error <> 0)
    return 1
    
if not exists (select name from sysobjects where name='sysmergesubscriptions')
	return (0)
declare #RemoveReplication CURSOR LOCAL FAST_FORWARD for 
	select pubid from sysmergepublications 
open #RemoveReplication
fetch #RemoveReplication into @pubid
while (@@fetch_status<>-1)
begin
	/* Clean up the articles for this publication, and delete the row */
	select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
	while @artid is not null
		begin
		if not exists (select * from sysmergearticles WHERE artid = @artid and pubid <> @pubid)
			begin
				exec @retcode=sp_MSarticlecleanup @pubid, @artid
				if @retcode<>0 or @@ERROR<>0 
				begin
					close #RemoveReplication
					deallocate #RemoveReplication
					return (1)
				end
			end
		delete from sysmergearticles where artid = @artid and pubid = @pubid
		set @artid = NULL
		select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
		end
	fetch #RemoveReplication into @pubid
end
close #RemoveReplication
deallocate #RemoveReplication
		
/* Now clean up any traces in other system tables */
	
delete from MSmerge_genhistory 
delete from MSmerge_replinfo
delete from sysmergesubsetfilters 
delete from sysmergesubscriptions 
delete from sysmergepublications
delete from sysmergeschemachange
return (0)

GO
exec dbo.sp_MS_marksystemobject sp_cleanupdbreplication
go

grant execute on dbo.sp_cleanupdbreplication to public
go


 

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

create procedure sp_MSarticlecleanup
	(@pubid uniqueidentifier, @artid uniqueidentifier, @ignore_merge_metadata bit = 0)
as
	set nocount on
	declare @source_table 	nvarchar(270)
	declare @conflict_table nvarchar(270)
	declare @ownername 		sysname
	declare @objectname 	sysname
	declare @tablenick		int
	declare @objid 			int
	declare @sync_objid 	int
	declare @view_type		int
	declare @tsview			nvarchar(50)
	declare @guidstr		nvarchar(50)
	declare @csview			nvarchar(50)
	declare @viewname		nvarchar(270)
	declare @retcode		smallint
	declare @qualified_name	nvarchar(270)
	declare @bi_tablename	sysname
	declare	@bi_viewname	sysname
	declare @bi_procname	sysname
	declare @constraintname	sysname
	declare @merge_pub_markcolumn_bit int
	declare @merge_pub_unmarkcolumn_bit int
	declare @bitableview sysname
	
	-- to be called after article is set up in a subscriber

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

	select @merge_pub_markcolumn_bit = 0x4000
	select @merge_pub_unmarkcolumn_bit = ~@merge_pub_markcolumn_bit

	select @objid = max(objid) from sysmergearticles where artid = @artid

	-- get owner name, and table name
	select @objectname = name, @ownername = user_name(uid)
		from sysobjects	where id = @objid

	-- construct the qualified table name
	select @source_table = QUOTENAME(@ownername) + '.' + QUOTENAME(@objectname)

	exec @retcode=sp_MSguidtostr @artid, @guidstr out
	if @retcode<>0 or @@ERROR<>0 return (1)
	
	-- get the insert, update and conflict proc names from sysmergearticles
	select 	@sync_objid = sync_objid, 
			@view_type = view_type, 
			@tablenick = nickname,
			@bi_tablename = object_name(before_image_objid),
			@bi_viewname = object_name(before_view_objid),
			@conflict_table = conflict_table 
		from sysmergearticles where
			pubid = @pubid and artid = @artid

	select @qualified_name = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(@conflict_table) from sysobjects where name = @conflict_table

	/* Drop the conflict table */
	if (@conflict_table IS NOT NULL) and exists (select * from sysobjects where
			name = @conflict_table and type = 'U')
		begin
			exec ('drop table ' + @qualified_name)
			if @@ERROR<>0 return (1)
		end


	/* If there is a before image table, drop it and its cleanup proc */
	if (@bi_tablename is not null)
		begin
		set @bi_procname = @bi_tablename + '_clean'

		if exists (select * from sysobjects where
			name = @bi_procname and type = 'P')
			begin
			exec ('drop proc ' + @bi_procname)
			if @@ERROR<>0 return (1)
			end
		exec ('drop table ' + @bi_tablename)
		if @@ERROR<>0 return (1)
		end
	/* If there is a before image view, drop it */
	if (@bi_viewname is not null)
		begin
		exec ('drop view ' + @bi_viewname)
		if @@ERROR<>0 return (1)
		end
		
	/* Drop the article procs */
	exec @retcode=sp_MSdroparticleprocs @pubid, @artid
	if @@ERROR<>0 or @retcode<>0 return (1)

	/* Drop the article triggers */
	exec @retcode=sp_MSdroparticletriggers @source_table
	if @@ERROR<>0 or @retcode<>0 return (1)

	exec @retcode=sp_MSunmarkreplinfo @objectname, @ownername
	if @@ERROR<>0 or @retcode<>0 return (1)

	/* so that columns can be dropped */
	update syscolumns set colstat=colstat & @merge_pub_unmarkcolumn_bit where id=@objid
	if @@ERROR<>0 return (1)

	/* If the article's has a temporary ( view type = 2) or a permanent view (view_type = 1 ) drop the sync object */
	if (@view_type = 1 OR @view_type = 2)
		begin
			select @viewname = sysobjects.name from sysobjects where 
				ObjectProperty (sysobjects.id, 'IsView') = 1 
				and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
				and sysobjects.id = @sync_objid
			if @viewname IS NOT NULL
				begin
					select @ownername = user_name(uid) from sysobjects where name=@viewname
					set @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@viewname)
					exec ('drop view ' + @viewname)
					if @@ERROR<>0 return (1)
				end
		end

	/*
	** Drop the views created for MSmerge_contents, MSmerge_tombstone and sysmergearticles before dropping these two tables
	*/
	set @csview = 'ctsv_' + @guidstr
	set @tsview = 'tsvw_' + @guidstr
	set @bitableview = 'MSbivw_' + @guidstr

	if EXISTS (select * from sysobjects where name=@csview and type='V')
	BEGIN
		select @ownername = user_name(uid) from sysobjects where  name=@csview
		select @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@csview)
		exec ('drop view ' + @viewname)
			if @@ERROR<>0 return (1)
	END
		
	if EXISTS (select * from sysobjects where name=@tsview and type='V')
	BEGIN
		select @ownername = user_name(uid) from sysobjects where  name=@tsview
		select @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@tsview)
		exec ('drop view ' + @viewname)
			if @@ERROR<>0 return (1)
	END
	
	if EXISTS (select * from sysobjects where name=@bitableview and type='V')
	BEGIN
		select @ownername = user_name(uid) from sysobjects where  name=@bitableview
		select @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@bitableview)
		exec ('drop view ' + @viewname)
			if @@ERROR<>0 return (1)
	END

	select @constraintname = 'repl_identity_range_pub_' + convert(nvarchar(36), @artid)
	select @constraintname = REPLACE(@constraintname, '-', '_')
	if exists (select * from sysobjects where name = @constraintname and xtype='C')
	begin
		exec ('alter table '+ @source_table + ' drop constraint ' + @constraintname)
		if @@ERROR<>0
			return (1)
	end

	select @constraintname = 'repl_identity_range_repub_' + convert(nvarchar(36), @artid)
	select @constraintname = REPLACE(@constraintname, '-', '_')
	if exists (select * from sysobjects where name = @constraintname and xtype='C')
	begin
		exec ('alter table '+ @source_table + ' drop constraint ' + @constraintname)
		if @@ERROR<>0
			return (1)
	end

	/* Delete from contents, tombstone, delete conflicts; Ignore errors that occur */
	if @ignore_merge_metadata = 0
	begin
    	delete from MSmerge_contents where tablenick = @tablenick
    	delete from MSmerge_tombstone where tablenick = @tablenick
    	/* Delete rows from MSmerge_genhistory - if this is the last table that refers to them */
    	if not exists (select * from sysmergearticles where nickname = @tablenick and pubid <> @pubid)
    		delete from MSmerge_genhistory where art_nick = @tablenick

    	delete from MSmerge_delete_conflicts where tablenick = @tablenick
    end
    
	if exists (select 1 from MSrepl_identity_range where objid=@objid)
	begin
    	delete from MSrepl_identity_range where objid=@objid
    	dbcc checkident(@source_table, RESEED)
    end
GO

exec dbo.sp_MS_marksystemobject sp_MSarticlecleanup
go

grant execute on dbo.sp_MSarticlecleanup to public
go

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

create procedure sp_MSdroparticleprocs
	(@pubid uniqueidentifier, @artid uniqueidentifier)
as
	set nocount on
	declare @ins_procname 	sysname
	declare @upd_procname 	sysname
	declare @conf_procname 	sysname
	declare @sel_procname	sysname
	declare @tmp_procname	nvarchar(260)
	declare @view_sel_proc 	nvarchar(290)
	declare @sel_procname_pal sysname
	declare @owner			sysname
	declare @objid			int
	
	-- get the insert, update and conflict proc names from sysmergearticles
	select @ins_procname = insert_proc,	
			@upd_procname = update_proc, 
			@sel_procname = select_proc,
			@conf_procname = ins_conflict_proc,
			@view_sel_proc = view_sel_proc,
			@objid = objid
		from sysmergearticles where
			pubid = @pubid and artid = @artid

	if (@ins_procname IS NOT NULL) and exists (select * from sysobjects where
			name = @ins_procname and type = 'P')
		begin
			select @owner = user_name(uid) from sysobjects where name=@ins_procname
			select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@ins_procname)
			exec ('drop proc ' + @tmp_procname)
			if @@ERROR<>0 return (1)
			update sysmergearticles set insert_proc = NULL where pubid=@pubid and artid=@artid
		end
	if (@upd_procname IS NOT NULL) and exists (select * from sysobjects where
			name = @upd_procname and type = 'P')
		begin
			select @owner = user_name(uid) from sysobjects where name=@upd_procname
			select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@upd_procname)
			exec ('drop proc ' + @tmp_procname)
			if @@ERROR<>0 return (1)
			update sysmergearticles set update_proc = NULL where pubid=@pubid and artid=@artid

		end
	if (@sel_procname IS NOT NULL) and exists (select * from sysobjects where
			name = @sel_procname and type = 'P')
		begin
			select @owner = user_name(uid) from sysobjects where name=@sel_procname
			select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@sel_procname)
			exec ('drop proc ' + @tmp_procname)
			if @@ERROR<>0 return (1)
			update sysmergearticles set select_proc = NULL where pubid=@pubid and artid=@artid
		end

    select @sel_procname_pal = @sel_procname + '_pal'
	if (@sel_procname_pal IS NOT NULL) and exists (select * from sysobjects where
			name = @sel_procname_pal and type = 'P')
	begin
		select @owner = user_name(uid) from sysobjects where name=@sel_procname_pal
		select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@sel_procname_pal)
		exec ('drop proc ' + @tmp_procname)
		if @@ERROR<>0 return (1)
	end

	if (@view_sel_proc IS NOT NULL) and exists (select * from sysobjects where
			name = @view_sel_proc and type = 'P')
		begin
			select @owner = user_name(uid) from sysobjects where name=@view_sel_proc
			select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@view_sel_proc)
			exec ('drop proc ' + @tmp_procname)
			if @@ERROR<>0 return (1)
			update sysmergearticles set view_sel_proc = NULL where pubid=@pubid and artid=@artid
		end

	if (@conf_procname IS NOT NULL) and	not exists (select * from sysmergearticles where
			artid=@artid and pubid<>@pubid) and exists (select * from sysobjects where
			name = @conf_procname and type = 'P')
		begin
			select @owner = user_name(uid) from sysobjects where name=@conf_procname
			select @tmp_procname = QUOTENAME(@owner) + '.' + QUOTENAME(@conf_procname)
			exec ('drop proc ' + @tmp_procname)
			if @@ERROR<>0 return (1)
			update sysmergearticles set ins_conflict_proc = NULL where pubid=@pubid and artid=@artid
		end
	
	return 0		

GO

exec dbo.sp_MS_marksystemobject sp_MSdroparticleprocs
go

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

/*
** We need to qualify sysmergearticle with pubid
*/
create procedure sp_MSdroparticletriggers
	(@source_table nvarchar(270),
	 @table_owner	sysname = NULL)
as
	set nocount on
	declare @instrigger 	nvarchar(270)
	declare @updtrigger 	nvarchar(270)
	declare @deltrigger 	nvarchar(270)
	declare @retcode		int
	declare @owner			sysname
	declare @artid			uniqueidentifier
	declare @guidstr		nvarchar(32)

	-- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
    -- END PARSENAME VARS

    select @UnqualName = PARSENAME(@source_table, 1)
    select @QualName1 = PARSENAME(@source_table, 2)
    if @UnqualName IS NULL
         return 1
	if @QualName1 is not NULL
		select @owner = @QualName1
			else if @table_owner is not NULL 
				select @owner = @table_owner
					else select @owner='dbo'
	
	select @artid = artid from sysmergearticles where objid = object_id(@source_table)

	exec @retcode=sp_MSguidtostr @artid, @guidstr out
	if @retcode<>0 or @@ERROR<>0 return (1)

	select @instrigger = QUOTENAME(@owner) + '.ins_' + @guidstr
	select @updtrigger = QUOTENAME(@owner) + '.upd_' + @guidstr
	select @deltrigger = QUOTENAME(@owner) + '.del_' + @guidstr
	
/*	
	select @instrigger = sysobjects.name from sysobjects where 
		ObjectProperty (sysobjects.id, 'ExecIsInsertTrigger') = 1 
		and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
		and parent_obj = OBJECT_ID(@source_table) 

	select @updtrigger = sysobjects.name from sysobjects where 
		ObjectProperty (sysobjects.id, 'ExecIsUpdateTrigger') = 1 
		and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
		and parent_obj = OBJECT_ID(@source_table) 

	select @deltrigger = sysobjects.name from sysobjects where 
		ObjectProperty (sysobjects.id, 'ExecIsDeleteTrigger') = 1 
		and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 
		and parent_obj = OBJECT_ID(@source_table) 
*/

	if object_id(@instrigger) is not NULL
		begin
			exec ('drop trigger ' + @instrigger)
			if @@ERROR<>0 return (1)
		end
	if object_id(@updtrigger) is not NULL
		begin
			exec ('drop trigger ' + @updtrigger)
			if @@ERROR<>0 return (1)
		end
	if object_id(@deltrigger) IS NOT NULL
		begin
			exec ('drop trigger ' + @deltrigger)
			if @@ERROR<>0 return (1)
		end

	return 0
GO

exec dbo.sp_MS_marksystemobject sp_MSdroparticletriggers
go


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

CREATE PROCEDURE sp_mergesubscription_cleanup (
	@publisher		sysname,
	@publisher_db	sysname,
	@publication 	sysname
	) AS
	declare @pubid 				uniqueidentifier
	declare @artid 				uniqueidentifier
	declare @retcode			smallint
	declare @subscription_type  int
    declare @objid              int
    declare @objectname         sysname
    declare @objectowner        sysname

    /* 
    ** Security check
    */
    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
	IF @@ERROR <> 0 or @retcode <> 0
		RETURN(1)
		
	/*
	** if there is nothing to cleanup, then just return.
	*/
	if not exists (select * from sysobjects where name='sysmergesubscriptions')
		return (0)
		
	/* This only gets called after database is enable to subscribe, so sysmergepublications should exist */
	select @pubid = pubid FROM sysmergepublications 
		WHERE name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db

	/* Normal case - nothing to cleanup, just return */
	if @pubid is null
		return (1)

	select @subscription_type = subscription_type from sysmergesubscriptions where pubid=@pubid and subid<>pubid

	/* This procedure is not intended to be used for cleanning-up pull/anonymous subscriptions */
	if @subscription_type > 0
		begin
			raiserror(20091, 16, -1)
			return (1)
		end

	/* Clean up the articles for this publication, and delete the row */
	select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
	while @artid is not null
		begin
		if not exists (select * from sysmergearticles WHERE artid = @artid and pubid <> @pubid)
			begin
				exec @retcode=sp_MSarticlecleanup @pubid, @artid
				if @retcode<>0 or @@ERROR<>0 return (1)
			end
		delete from sysmergearticles where artid = @artid and pubid = @pubid
		set @artid = NULL
		select @artid = artid FROM sysmergearticles WHERE pubid = @pubid
		end
		
    /* Cleanup the schema articles */

    /* Unmark all schema article objects unconditionally */
    if exists (select * from sysobjects where name = 'sysmergeschemaarticles')
    begin
        declare hschemaarticle_cur cursor local fast_forward for
            select destination_object, destination_owner from sysmergeschemaarticles where
            pubid = @pubid 
        for read only
        open hschemaarticle_cur
        fetch hschemaarticle_cur into @objectname, @objectowner
        while (@@fetch_status<>-1)
        begin
                -- Ignore errors
                exec  sp_MSunmarkschemaobject @objectname, @objectowner    
                fetch hschemaarticle_cur into @objectname, @objectowner
        end
        close hschemaarticle_cur
        deallocate hschemaarticle_cur

        /* Delete all schema article rows for this publication*/
        delete from sysmergeschemaarticles where pubid = @pubid
    end

	/* 
	** Make sure you NULL out gen_cur for other articles that share this table 
	** since we are deleting the genhistroy row for that generation 
	*/
	update sysmergearticles set gen_cur=NULL where gen_cur in
		(select generation from MSmerge_genhistory where pubid = @pubid)

	/* Now clean up any traces in other system tables */
	delete from MSmerge_genhistory where pubid = @pubid 
	delete from MSmerge_replinfo where repid in (select subid from sysmergesubscriptions where pubid = @pubid)
	delete from sysmergesubscriptions where pubid = @pubid
	delete from sysmergepublications where pubid = @pubid
	delete from sysmergeschemachange where pubid = @pubid
	/* 
	** If last subscription is dropped and the DB is not enabled for publishing,
	** then remove the merge system tables
	*/
	IF (not exists (select * from sysmergesubscriptions )) 
		AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME() collate database_default )=0
	BEGIN
		execute @retcode = dbo.sp_MSdrop_mergesystables
		if @@ERROR <> 0 or @retcode <> 0
		begin
			return (1)
		end
	END	
GO
exec dbo.sp_MS_marksystemobject sp_mergesubscription_cleanup
go
grant execute on dbo.sp_mergesubscription_cleanup to public

raiserror('Creating procedure sp_subscription_cleanup', 0,1)
GO
CREATE PROCEDURE sp_subscription_cleanup (
	@publisher		sysname,
	@publisher_db	sysname,
	@publication	sysname = NULL,
	@reserved		nvarchar(10) = NULL
)
AS
BEGIN

	declare @object_name sysname
			,@object_type char(2)
			,@independent_agent bit
			,@retcode int
			,@synctran_bit int
			,@parent_obj int
			,@object_id int
			,@cmd nvarchar(4000)

	select @synctran_bit			= 256

	/*
    ** Security Check
    */

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

	if @publication = '' OR @publication is NULL
		select @independent_agent = 0
	else
		select @independent_agent = 1

	IF exists (select name from sysobjects where name = 'MSreplication_objects')
	BEGIN
		declare object_cursor CURSOR LOCAL FAST_FORWARD for 
			select DISTINCT object_name, object_type from MSreplication_objects o
					where (UPPER(o.publisher) = UPPER(@publisher) and
			  		  o.publisher_db = @publisher_db and
				  	  o.publication = @publication) or
						@reserved = 'drop_all'

		OPEN object_cursor
    	FETCH object_cursor INTO @object_name, @object_type
 	    WHILE (@@fetch_status <> -1)
    	      BEGIN
        	      IF @object_type = 'T' 
				  begin
					select @parent_obj = NULL
					select @parent_obj = parent_obj, @object_id = id from
						sysobjects where name = @object_name 
					if @parent_obj is not null
					begin
						-- Unmark synctran bit
						update sysobjects set replinfo = replinfo & ~@synctran_bit where 
							id = @parent_obj and
							(replinfo & @synctran_bit) <> 0
						IF @@ERROR <> 0 
							GOTO UNDO
						exec @retcode = dbo.sp_MSdrop_object 
							@object_id = @object_id
						if @retcode <> 0 or @@error <> 0
							goto UNDO

						-- Clean up identity range entry
						-- Since we only support one trigger per subscriber table
						-- we assume identity range row can not be reused by multiple
						-- subscriptions.
						IF EXISTS(select * from sysobjects where type='U' and name = 'MSsub_identity_range')
						BEGIN
							if exists (select * from MSsub_identity_range where objid = @parent_obj)
							begin
								-- Drop the identity range constraits.
								exec @retcode = dbo.sp_MSreseed
									@objid =  @parent_obj,
									-- range or seed can be anything
									@next_seed = 10,
									@range = 10,
									@is_publisher = -1,
									@check_only = 1,
									@drop_only = 1
								IF @retcode <> 0 or @@ERROR <> 0 
									GOTO UNDO

								delete MSsub_identity_range where objid = @parent_obj
								IF @@ERROR <> 0 
									GOTO UNDO
							end

							IF NOT EXISTS (SELECT * FROM MSsub_identity_range)
							BEGIN
								DROP TABLE MSsub_identity_range
								IF @@ERROR <> 0 
									GOTO UNDO
							END
						END
					end
				  end
        	      delete from MSreplication_objects where object_name=@object_name
            	  FETCH object_cursor INTO @object_name, @object_type
         	 END
    	CLOSE object_cursor
    	DEALLOCATE object_cursor
    	
		if not exists (select * from MSreplication_objects) 
		begin
    		drop table MSreplication_objects
			IF @@ERROR <> 0 
				GOTO UNDO
		end
    	
	END

	--
	-- cleanup queued conflict tables
	--
	IF exists (select name from dbo.sysobjects where name = 'MSsubscription_agents')
	BEGIN
		declare		@agent_id int
					,@cft_table sysname
					,@owner sysname

		--
		-- first get the agent(s) for this queued subscription(s) and 
		-- 
		declare #agent_cursor CURSOR LOCAL FAST_FORWARD for 
			select id from dbo.MSsubscription_agents 
			where ((UPPER(publisher) = UPPER(@publisher) and 
					publisher_db = @publisher_db and 
					publication = @publication) or (@reserved = 'drop_all')) and
					update_mode in (2,3,4,5)

		open #agent_cursor
		fetch #agent_cursor into @agent_id
		while (@@fetch_status != -1)
		begin
			--
			-- drop the conflict table for each article in this subscription
			--
			if exists (select name from dbo.sysobjects where name = 'MSsubscription_articles')
			begin
			
				declare #object_cursor CURSOR LOCAL FAST_FORWARD for 
					select owner, cft_table from dbo.MSsubscription_articles
					where agent_id = @agent_id

				OPEN #object_cursor
				FETCH #object_cursor INTO @owner, @cft_table
				WHILE (@@fetch_status != -1)
				BEGIN
					--
					-- drop the conflict table(s) for this article - ignore errors
					--
					select @cmd = case 
						when (@owner IS NULL) then
							N'if exists (select * from dbo.sysobjects where name = N''' + 
							master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
							quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
						else
							N'if exists (select * from dbo.sysobjects where name = N''' + 
							master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
							quotename(master.dbo.fn_MSgensqescstr(@owner)) collate database_default + N'.' +
							quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
						end
					execute ( @cmd )

					-- get next row
					FETCH #object_cursor INTO @owner, @cft_table
				END
				CLOSE #object_cursor
				DEALLOCATE #object_cursor

				--
				-- delete entries from MSsubscription_articles for this agent id
				--
				delete dbo.MSsubscription_articles where agent_id = @agent_id

				--
				-- drop MSsubscription_articles if empty (should we do it)
				-- 
				IF NOT EXISTS (SELECT * FROM dbo.MSsubscription_articles)
				BEGIN
					DROP TABLE dbo.MSsubscription_articles
					IF @@ERROR != 0 
						GOTO UNDO
				END
			end

			--
			-- get the next agent
			--
			fetch #agent_cursor into @agent_id
		end
		close #agent_cursor
		deallocate #agent_cursor
	END

	--
	-- clean discarded queued transactions
	--
	if exists (select name from dbo.sysobjects where name = 'MSreplication_queue')
	begin
		delete dbo.MSreplication_queue
		where (publisher = UPPER(@publisher) and 
				publisher_db = @publisher_db and 
				publication = @publication) or 
				@reserved = 'drop_all'
	end
	if exists (select name from dbo.sysobjects where name = 'MSrepl_queuedtraninfo')
	begin
		delete dbo.MSrepl_queuedtraninfo
		where (publisher = UPPER(@publisher) and 
				publisher_db = @publisher_db and 
				publication = @publication) or 
				@reserved = 'drop_all'
	end
	
	IF exists (select name from sysobjects where name = 'MSreplication_subscriptions')
	BEGIN
	delete from MSreplication_subscriptions 
		where (UPPER(publisher) = UPPER(@publisher) AND
			  publisher_db = @publisher_db AND
			  -- Drop the subscription as long as the publication name matches even if
			  -- the publication is not independent agent
			  -- This behaviour is expected by sp_droppullsubscription
			  -- -- independent_agent = @independent_agent and 
			  ((@independent_agent=0 and independent_agent = 0) or 
			  publication = @publication))
			  or @reserved = 'drop_all'
 
		IF NOT EXISTS (SELECT * FROM MSreplication_subscriptions)
		BEGIN
			DROP TABLE MSreplication_subscriptions
			IF @@ERROR <> 0 
				GOTO UNDO
		END
	END


	IF exists (select name from sysobjects where name = 'MSsubscription_agents')
	BEGIN
		delete from MSsubscription_agents
		where (UPPER(publisher) = UPPER(@publisher) AND
			  publisher_db = @publisher_db AND
			  -- Drop the subscription as long as the publication name matches even if
			  -- the publication is not independent agent
			  -- This behaviour is expected by sp_droppullsubscription
			  (publication = @publication or
			   (@independent_agent=0 and publication = N'ALL')))
			  or @reserved = 'drop_all'

		-- Delete the agent entry if no corresponding rows found in MSreplication_subscription
		-- table.
		-- This is to cleanup share agent entry.
		-- This behaviour is expected by sp_droppullsubscription
		if object_id('MSreplication_subscriptions') is not null
		begin
			if not exists (select * from MSreplication_subscriptions s where
					s.publisher = @publisher and
					s.publisher_db = @publisher_db and
					s.independent_agent = 0)
				delete from MSsubscription_agents where
					publisher = @publisher and
					publisher_db = @publisher_db and
					publication = N'ALL'
		end
		else
			delete  MSsubscription_agents

		IF NOT EXISTS (SELECT * FROM MSsubscription_agents)
		BEGIN
			DROP TABLE MSsubscription_agents
			IF @@ERROR <> 0 
				GOTO UNDO
		END
	END

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

		IF @@ERROR <> 0 
			GOTO UNDO

		IF NOT EXISTS (SELECT * FROM MSsubscription_properties)
		BEGIN
			exec @retcode = dbo.sp_MSsub_cleanup_prop_table
			IF @@ERROR <> 0 or @retcode <> 0
				GOTO UNDO
		END
	END

    -- Ignore errors.
    exec dbo.sp_MSsub_cleanup_orphans
	
    return (0)
            
UNDO:
	return(1)
END
GO
exec dbo.sp_MS_marksystemobject sp_subscription_cleanup 
go


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

-- Called by the UI to find out if the distributor is installed without doing RPC.
CREATE PROCEDURE sp_get_distributor 
AS
    SET NOCOUNT ON

    /*
    ** Declarations.
    */
    DECLARE @distributor sysname
	DECLARE @installed bit
	declare @distdb_installed bit
	declare @is_distpublisher bit
	declare @has_remote_distpublisher bit
 	declare @distbit int

	SELECT @distbit = 16
       
	SELECT @distributor = datasource FROM master..sysservers
		WHERE srvstatus & 8 <> 0

	if @distributor is not null
		select @installed = 1
	else
		select @installed = 0

	if UPPER(@distributor) = UPPER(@@servername)
	begin
		if exists (select * from msdb.dbo.MSdistributiondbs) 
			select @distdb_installed = 1
		else
			select @distdb_installed = 0

		if exists (select * from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername) collate database_default)
			select @is_distpublisher = 1
		else
			select @is_distpublisher = 0

		if exists (select * from msdb..MSdistpublishers where UPPER(name) <> UPPER(@@servername) collate database_default)
			select @has_remote_distpublisher = 1
		else
			select @has_remote_distpublisher = 0
	end
	else
	begin
		select @distdb_installed = 0
		select @has_remote_distpublisher = 0	
		select @is_distpublisher = 0
	end

	select 'installed' = @installed, 'distribution server' = @distributor,
			'distribution db installed' = @distdb_installed,
			'is distribution publisher' = @is_distpublisher,
			'has remote distribution publisher' = @has_remote_distpublisher
GO

exec dbo.sp_MS_marksystemobject sp_get_distributor
go


-- Called by sp_addrolemember
raiserror('Creating procedure sp_MSrepl_addrolemember', 0,1)
go
CREATE PROCEDURE sp_MSrepl_addrolemember
	@rolename       sysname,
	@membername     sysname
AS
    -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
	set	nocount on
	
	return(0)

go		

exec dbo.sp_MS_marksystemobject sp_MSrepl_addrolemember
go

-- Called by sp_droprolemember
raiserror('Creating procedure sp_MSrepl_droprolemember', 0,1)
go
CREATE PROCEDURE sp_MSrepl_droprolemember
	@rolename       sysname,
	@membername     sysname
AS
	set	nocount on
	return(0)
go		

exec dbo.sp_MS_marksystemobject sp_MSrepl_droprolemember
go

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

create procedure sp_table_validation
@table sysname,				-- table name or sync object name
@expected_rowcount bigint = NULL OUTPUT,
@expected_checksum numeric = NULL OUTPUT,
@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.  The name "rowcount_only" is now a 
misnomer given the overloaded functionality.  It is really a "type of check requested"
parameter.   But, the old name is retained for backward compatibility.   It can take 
these values:

0 - Do a 7.0 compatible checksum
1 - Do a rowcount check only (remains the default)
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.)

*/

@owner	sysname = NULL,
@full_or_fast tinyint = 2,		-- full (value 0) does COUNT(*) 
					-- fast (value 1) uses sysindexes.rowcnt 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 replication agent to shutdown
@table_name sysname	= NULL,		-- table name of sync object or the table name for output message,
@column_list nvarchar(4000) = NULL, 	-- the list of columns - that way the user can skip computed columns etc 
@column_list_16_to_30	nvarchar(4000) = N'',
@column_list_31_to_45	nvarchar(4000) = N'',
@column_list_46_to_60	nvarchar(4000) = N'',
@column_list_61_to_75	nvarchar(4000) = N'',
@column_list_76_to_90	nvarchar(4000) = N'',
@column_list_91_to_105	nvarchar(4000) = N'',
@column_list_106_to_120	nvarchar(4000) = N'',
@column_list_121_to_135	nvarchar(4000) = N'',
@column_list_136_to_150	nvarchar(4000) = N'',
@column_list_151_to_165	nvarchar(4000) = N'',
@column_list_166_to_180	nvarchar(4000) = N'',
@column_list_181_to_195	nvarchar(4000) = N'',
@column_list_196_to_210	nvarchar(4000) = N'',
@column_list_211_to_225	nvarchar(4000) = N'',
@column_list_226_to_240	nvarchar(4000) = N'',
@column_list_241_to_255	nvarchar(4000) = N'',
@column_list_256_to_270	nvarchar(4000) = N''

as

set nocount on

declare @num_rows bigint
declare @checksum numeric
declare @checksum_string varchar(100)
declare @expected_checksum_string varchar(21)
declare @rowcount_string varchar(21)
declare @exp_rowcount_string varchar(21)
declare @width int
declare @qualified_table_name nvarchar(262)  -- two names plus []'s and a .
declare @temp_table_used bit
declare @retstatus int
declare @failed_fast tinyint
declare @min_indid int
declare @asked_for_exp_checksum tinyint
declare @asked_for_exp_rows tinyint



SET @retstatus=0	-- initialize to SUCCESS
SET @failed_fast=0


if (@expected_checksum IS NULL AND isnull(@rowcount_only,-9999) <> 1 )  -- Wants an expected checksum value
	SET @asked_for_exp_checksum=1
ELSE
	SET @asked_for_exp_checksum=0


if (@expected_rowcount IS NULL)  -- Wants an expected rowcount value
	SET @asked_for_exp_rows=1
ELSE
	SET @asked_for_exp_rows=0

-- Only values 0,1,2 make sense for @rowcount_only. 
if (@rowcount_only NOT BETWEEN 0 and 2)
	BEGIN
	-- msg 20543 says that @rowcount_only must be 0,1,2 and explains the values.
	RAISERROR (20543,16,-1,@qualified_table_name)
	SET @retstatus=1
	return @retstatus
	END

-- RHS:  
-- Some states do not make sense.  For example,  it does not make sense to ask for conditional
-- fast row count checking, yet not provide an expected value.  If this is done, provide a warning
-- message and use fast checking method.
if (@full_or_fast = 2 AND @expected_rowcount IS NULL)
	BEGIN
	-- (20559,10,0,'Conditional Fast Rowcount method requested without specifying an expected count. Fast method will be used.', 1033)
	raiserror (20559, 10, -1)
	SET @full_or_fast = 1
	END

-- Another state that doesn't make sense is to pass an expected checksum value, yet
-- ask for rowcount only validation
if (@expected_checksum IS NOT NULL AND @rowcount_only = 1)
	BEGIN
	-- (Msg 20560,10,0,'An expected checksum value was passed, but checksums will not be compared because rowcount only checking was requested.', 1033)
	raiserror (20560, 10, -1)
	SET @expected_checksum = NULL
	END


if @owner is null
begin
	if left(ltrim(rtrim(@table)), 1) <> '[' or right(ltrim(rtrim(@table)), 1) <> ']'
		set @qualified_table_name = '[' + @table + ']'
	else
		set @qualified_table_name = @table
end
else
begin
	if left(ltrim(rtrim(@table)), 1) <> '[' or right(ltrim(rtrim(@table)), 1) <> ']'
		set @qualified_table_name = '[' + @owner + '].[' + @table + ']'
	else
		set @qualified_table_name = '[' + @owner + '].' + @table
end

IF (OBJECT_ID(@qualified_table_name) IS NULL)
	-- No such object.  Return with error.
	BEGIN
	-- Msg (20585,10,0,'Object '%s' does not exist.  Exiting validation check.', 1033)  
	RAISERROR (20585,16,-1,@qualified_table_name)
	SET @retstatus=1
	return @retstatus
	END

-- If the object is a table (not view) and fast checking (1) requested,
-- then get rowcount from sysindexes, rather than scanning.
-- Fast rowcount method gets value from sysindexes - and the row_cnt value is only maintained for tables.

IF (SELECT @full_or_fast) > 0    -- IF Fast row checking asked for
	AND 
   (SELECT OBJECTPROPERTY(OBJECT_ID(@qualified_table_name),'IsTable')) > 0  -- Must be a table, not a view

	BEGIN
		-- Do the fast rowcount method
		-- Temporarily put a SHARE lock on table to ensure no simultaneous updates going on
		-- Minimizes chances of getting an out of date value from sysindexes.   True that
		-- it reduces concurrency, but if the fast method doesnt work the user will very likely
		-- go do the full method, which will be much more costly.   Better I think to take a little more cost here
		-- and hopefully get a good number.   The @foo variable is used so that its an
		-- assignment and doesn't make another result set get returned.

		BEGIN TRAN
		EXEC ('DECLARE @foo int SELECT @foo=1 FROM ' + @qualified_table_name + ' (TABLOCK HOLDLOCK) WHERE 1=2')
		SELECT @num_rows=rowcnt,@min_indid=indid FROM sysindexes WHERE id=OBJECT_ID(@qualified_table_name)and indid < 2
		COMMIT TRAN
	END

ELSE 
	SET @full_or_fast = 0   -- Full checking will be used, regardless of whether it was requested

--	set the output name if not set
	if (@table_name IS NULL)
		SELECT @table_name = @table

-- If fast row checking was used, and request for rowcount check only, we're done.
if (@full_or_fast = 1  AND  @rowcount_only = 1) 
	GOTO ROWCOUNT_MSG
	
-- If conditional fast row checking was used, and request for rowcount check only, 
-- we're also done IFF rows and expected rows match.
if (@full_or_fast = 2  AND  @rowcount_only = 1 
	AND @expected_rowcount IS NOT NULL AND @expected_rowcount=@num_rows)
	BEGIN
		-- Fast checking was actually used.
		SET @full_or_fast = 1
		GOTO ROWCOUNT_MSG
	END


-- If we're still here we are doing full row checking at a minimum, and will need the temp table

IF (SELECT ISNULL(OBJECT_ID('tempdb..#tab_validt1'),0)) = 0    -- Table Does Not exist
	CREATE TABLE #tab_validt1 (tmp_rows bigint NULL, tmp_checksum numeric NULL)
ELSE -- table already exists 
	TRUNCATE TABLE #tab_validt1

-- If we are only doing row checking, we'll do it here.  If we will do both row checking 
-- and checksum, then do them together so as to not scan table twice.


if @rowcount_only = 1
	BEGIN   -- Must do full count(*) checking but not checksums
	
	if @full_or_fast=2   
		-- if we are here with conditional check (2) requested, it is because
		-- a conditional was possible, but it failed.  We wiil later alert user of this.
		BEGIN 
		SET @full_or_fast=0
		SET @failed_fast=1
		END

	insert into #tab_validt1 (tmp_rows,tmp_checksum) 
		exec ('select count_big(*), NULL from ' +	@qualified_table_name + ' (TABLOCK HOLDLOCK)')

	-- Get row count value
	select  TOP 1 @num_rows = tmp_rows from #tab_validt1   -- Should only be one row
		
	-- IF there were no rows from above, the table was empty so use ZERO.
	IF @num_rows IS NULL
		SELECT @num_rows=0

	-- Done with the temp table
	DROP TABLE #tab_validt1
	
	IF @expected_rowcount IS NULL
		BEGIN
		SET @expected_rowcount = @num_rows
		END
	GOTO ROWCOUNT_MSG
	END -- Done with full row count only

ELSE  -- Doing checksums in addition to ROWCOUNT

	BEGIN	-- DO checksum and rowcount in same pass thru the table
	-- Decide whether must use the 7.0 compatible checksum, or use the Shiloh checksum:
	
	IF (@rowcount_only = 0)   -- 7.0 Compatible Checksum
		BEGIN
		insert into #tab_validt1 (tmp_rows,tmp_checksum)
			exec ('select count_big(*), sum (convert(numeric, getchecksum(NULL,1))) from ' +	@qualified_table_name + ' (TABLOCK HOLDLOCK)')
		END
	ELSE
	
		BEGIN  -- Shiloh Checksum
		
		
		if @column_list IS NULL OR @column_list = ' * '
			begin
				insert into #tab_validt1 (tmp_rows,tmp_checksum)
					exec ('select count_big(*), sum (convert(numeric, binary_checksum(*) ) ) from ' +	@qualified_table_name + ' (TABLOCK HOLDLOCK)')
			end
		else
			begin
				insert into #tab_validt1 (tmp_rows,tmp_checksum)
					exec ('select count_big(*), sum (convert(numeric, binary_checksum( '  +
						@column_list + 
						@column_list_16_to_30 + 
						@column_list_31_to_45 + 
						@column_list_46_to_60 + 
						@column_list_61_to_75 + 
						@column_list_76_to_90 + 
						@column_list_91_to_105 + 
						@column_list_106_to_120 + 
						@column_list_121_to_135 + 
						@column_list_136_to_150 + 
						@column_list_151_to_165 + 
						@column_list_166_to_180 + 
						@column_list_181_to_195 + 
						@column_list_196_to_210 + 
						@column_list_211_to_225 + 
						@column_list_226_to_240 + 
						@column_list_241_to_255 + 
						@column_list_256_to_270 + 
					') ) ) from ' +	@qualified_table_name + ' (TABLOCK HOLDLOCK)')
			
			end			
		
		
		END
	-- Get the checksum & rowcount values
	select TOP 1 @checksum = tmp_checksum, @num_rows= tmp_rows from #tab_validt1
	
	-- IF there were no rows from above, the table was empty so use ZERO.
	IF @checksum IS NULL or @num_rows IS NULL
		SELECT @checksum=isnull(@checksum,0),@num_rows=isnull(@checksum,0)

	-- Done with the temp table
	DROP TABLE #tab_validt1
	
	IF @expected_rowcount IS NULL  -- Just getting value - no expected value yet.
		SET @expected_rowcount = @num_rows
	
	-- Validate checksum
	IF @expected_checksum is null		-- Just getting value - no expected value yet.
		set @expected_checksum = @checksum
	else
		-- Raise error if checksums OR rowcounts do not match
		if @checksum <> @expected_checksum OR @num_rows <> @expected_rowcount
			begin
			-- Checksum failed.
			SELECT 	@checksum_string = convert(varchar(21), @checksum),
				@expected_checksum_string = convert(varchar(21), @expected_checksum),
				@rowcount_string = convert(varchar(21),@num_rows),
				@exp_rowcount_string = convert(varchar(21),@expected_rowcount)

			-- Msg (20525,10,0,'Table ''%s'' might be out of synchronization. Rowcounts (actual: %s, expected %s). Checksum values (actual: %s, expected: %s).', 1033)
			raiserror (20525, 10, -1, @table, @rowcount_string, @exp_rowcount_string, @checksum_string, @expected_checksum_string)
			SET @retstatus=1
			END
		else
		BEGIN
		-- Row count and checksum validation passed.
		-- 
		if @asked_for_exp_checksum=0 -- Only give message if not generating the expected value
			BEGIN
			-- Msg (20527,10,0,'Table ''%s'' passed rowcount (%s) and checksum validation. (Note: checksum is not compared for any text and image columns.)', 1033)
			SET @rowcount_string=convert(varchar(21),@num_rows)
			raiserror (20527, 10, -1, @table,@rowcount_string)
			END
		END
	-- Done with checksum and rowcount scan.
	END
-- We did checksum method, and so are done and skip over the rowcount only messages.

GOTO ALL_DONE

ROWCOUNT_MSG:
-- Raise error if rows counts do not match
	IF @expected_rowcount IS NULL  -- just return the found value
		SET @expected_rowcount=@num_rows
	ELSE
		IF @num_rows <> @expected_rowcount
		begin
			SELECT 	@rowcount_string=convert(varchar(21),@num_rows),
				@exp_rowcount_string=convert(varchar(21),@expected_rowcount)
			-- Msg (20524,10,0,'Table ''%s'' may be out of synchronization. Rowcounts (actual: %s, expected: %s). Rowcount method %d used (0 = Full, 1 = Fast).', 1033)
			raiserror (20524, 10, -1, @table_name, @rowcount_string, @exp_rowcount_string, @full_or_fast )
			SET @retstatus=1
		end
		ELSE	-- Row count validation passed. 
		begin
			SET @rowcount_string=convert(varchar(21),@num_rows)
			if @asked_for_exp_rows=0 -- Only give message if not generating the expected value
		      	-- Msg (20526,10,0,'Table ''%s'' passed rowcount (%s) validation. Rowcount method %d used (0 = Full, 1 = Fast).', 1033)

				raiserror (20526, 10, -1, @table_name, @rowcount_string, @full_or_fast)
			
			if @failed_fast=1
			BEGIN
			-- if we had to revert to FULL on a CONDITIONAL FAST, Make that known too.
			-- And Update usage to fix the problem
			-- Msg 20558: 'Table ''%s'' passed full row count validation after failing the fast check.  DBCC UPDATEUSAGE will be automatically initiated.'
			raiserror (20558, 10, -1, @table_name)
			DBCC UPDATEUSAGE (0,@qualified_table_name,@min_indid) WITH COUNT_ROWS, NO_INFOMSGS
			END
		end

ALL_DONE:

-- Give nice message if only generating the expected value:

-- Msg for rows and checksum:
-- TEMPORARY:   Remove rowcount string & change message if/when RAISERROR can handle bigint directly.

SET @rowcount_string = convert(varchar(21),@expected_rowcount)
if @asked_for_exp_checksum=1 and @asked_for_exp_rows=1 -- Only give message if generating the expected value
       BEGIN
	
       SET @expected_checksum_string = convert(varchar(21), @expected_checksum)
       -- (20579,10,0,'Generated expected rowcount value of %s and expected checksum value of %s for %s.', 1033)
	RAISERROR (20579, 10, -1,@rowcount_string,@expected_checksum_string,@table_name)
       END
       
ELSE
	BEGIN
		if @asked_for_exp_checksum=0 and @asked_for_exp_rows=1
		-- Msg (20561,10,0,'Generated expected rowcount value of %s for %s.', 1033)
		raiserror (20561, 10, -1,@rowcount_string, @table_name)
	END


-- Raise error that will shutdown replication agents
if @shutdown_agent = 1
	--Msg 20578: 'Shutdown replication agent request.'
	raiserror (20578, 10, -1)
	
return @retstatus
go

exec dbo.sp_MS_marksystemobject sp_table_validation
go

/* Create  sp_removedbreplication */
raiserror('Creating procedure sp_removedbreplication', 0,1)
GO

/* Permission to sysadmin */
CREATE PROCEDURE sp_removedbreplication (
	  @dbname	 sysname
	) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

	DECLARE @retcode int
	DECLARE @proc nvarchar(255)
	DECLARE @optbit int
	DECLARE @restoreoverride int
	/*
	** Initialization
	*/

	--if database is in read-only mode, don't try to cleanup anything
	if databasepropertyex(db_name(), 'Updateability') = 'READ_ONLY'
		return (0)

	/*
	** Support override of replication remove on attach and restore
	*/

	declare @instance sysname
	declare @regkey nvarchar(260)
	select @instance = convert(sysname, SERVERPROPERTY('InstanceName'))
	select @regkey = 'SOFTWARE\Microsoft\'
	-- default installation
	if @instance is null
		SELECT @regkey = @regkey + 'MSSQLServer\Replication' 
	else
		SELECT @regkey = @regkey + 'Microsoft SQL Server\' + @instance + '\Replication'

	SELECT @restoreoverride = 0 -- assume normal remove behavior
	SELECT @proc = 'master.dbo.xp_regread '
	EXECUTE @retcode = @proc	'HKEY_LOCAL_MACHINE', 
								@regkey,
								'RestoreOverride',
								@param = @restoreoverride OUTPUT,
								@no_output = 'no_output'

	IF ( @@error = 0 ) and ( @retcode = 0 )
	BEGIN
		-- ReplRestoreOverride = 1 = user elects to take no cleanup on restore or attach
		IF ( ISNULL( @restoreoverride, 0 ) = 1 )
			RETURN(0)
	END

	/*
	** Parameter check
	** @dbname
	*/
	IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE
		name = @dbname collate database_default)
	BEGIN
		RAISERROR(15010, 16, -1, @dbname)
		RETURN(1)
	END

	begin tran
	save tran sp_removedbreplication
	
	-- Clear tran bit
	SELECT @optbit = 1
	IF EXISTS (SELECT * FROM master..sysdatabases
		WHERE name = @dbname collate database_default
		AND (category & @optbit) <> 0)
	begin
		/*
		** Toggle the category bit in master..sysdatabases
		*/
		UPDATE master..sysdatabases SET category = category & ~@optbit
    			WHERE name = @dbname collate database_default
		IF @@ERROR <> 0 
		BEGIN
			goto FAILURE
		END
	end

	--this proc should be called after sysdatabase.category bit was cleared
	--otherwise sp_MScleandbobjectsforreplication won't cleanup repl bits
	SELECT @proc = quotename(@dbname) + '.dbo.sp_MSremovedbreplication'
	
	EXEC @retcode = @proc 
	IF @@ERROR <> 0 or @retcode <> 0
	BEGIN
		goto FAILURE
	END

	-- Clear merge bit
	SELECT @optbit = 4
	IF EXISTS (SELECT * FROM master..sysdatabases
		WHERE name = @dbname collate database_default
		AND (category & @optbit) <> 0)
	begin
		/*
		** Toggle the category bit in master..sysdatabases
		*/
		UPDATE master..sysdatabases SET category = category & ~@optbit
    			WHERE name = @dbname collate database_default
		IF @@ERROR <> 0 
		BEGIN
			goto FAILURE
		END
	end
	
	if @@trancount > 0
		commit tran
	return 0
	
FAILURE:

	if @@trancount > 0
	begin
		rollback tran sp_removedbreplication
		commit tran
	end
	return 1


GO
 
exec dbo.sp_MS_marksystemobject sp_removedbreplication
go
--
-- Name:    
--          sp_MScleandbobjectsforreplication
--          
-- Description: 
--          Resets replication bits for objects in the current db that are marked for replication
--  
-- Security: 
--          Internal
--
-- Returns:
--          Success (0) or Failure (1)
--      
-- Owner:   
--          <current owner> 
raiserror('Creating procedure sp_MScleandbobjectsforreplication', 0,1)
GO
create procedure sp_MScleandbobjectsforreplication
as
begin
    set nocount on
    declare @tabid int
    			,@colname sysname
    			,@publish smallint        /* Constant: 0x1000 */
    			,@nonsqlsub smallint        /* Constant: 0x2000 */
				,@initiated smallint			/* Constant: 0x4000 */
				,@repldts smallint			/* Constant: 0x8000 */
				,@publish_bit smallint 
				,@replicate_bit smallint
				,@filter smallint
				,@schema_replicated smallint
				,@procexec smallint
				,@db_tranbit smallint

    SELECT @publish = 0x1000
    			,@nonsqlsub = 0x2000
				,@repldts = 0x8000
				,@publish_bit = 1
    			,@replicate_bit = 2
    			,@filter = 32
    			,@procexec = 24
    			,@schema_replicated = 0x00000200
    			,@db_tranbit = 1
	
	--if database is in read-only mode, don't try to cleanup anything
	if databasepropertyex(db_name(), 'Updateability') = 'READ_ONLY'
		return (0)

	begin tran
	save tran sp_MScleandb
	--
	--these two conditions are required for us to get here, but double check again just to make sure
	--
	IF NOT EXISTS (SELECT * FROM master..sysdatabases
		WHERE name = db_name() collate database_default AND (category & @db_tranbit) = @db_tranbit)
		and NOT EXISTS (select * from sysobjects where name = 'syspublications' )
	begin
	    --
	    -- cleanup the objects in the database if they are not in clean state (replication metadata is marked)
	    -- check columns
	    --
		update syscolumns set colstat = colstat & ~(@publish  | @nonsqlsub | @repldts) 
					where colstat & (@publish  | @nonsqlsub | @repldts) > 0
		if (@@error <> 0)
			goto FAILURE
	    --
	    --check tables/views/proc/fns and proc exec
	    --
	    UPDATE sysobjects SET replinfo = replinfo & ~ (@publish_bit | @replicate_bit | @filter | @schema_replicated | @procexec) 
	    			where replinfo &  (@publish_bit | @replicate_bit | @filter | @schema_replicated | @procexec)  > 0
		if (@@error <> 0)
			goto FAILURE
	    --
	    -- all done
	    --
    end
    if @@trancount > 0
	    commit tran
    return 0
FAILURE:
	if @@trancount > 0
	begin
		rollback tran sp_MScleandb
		commit tran
	end
	return 1
	
end
go
exec dbo.sp_MS_marksystemobject sp_MScleandbobjectsforreplication
go
--grant execute on dbo.sp_MScleandbobjectsforreplication to public
go 
raiserror('Creating procedure sp_removesrvreplication', 0,1)
GO

create procedure sp_removesrvreplication
as
begin
/* 
 * unmark replication bits for all servers, databases; used by setup in vupgrade 
 * assumes override is on; db in single user mode
 * no need to check rowcounts affected by updates, may not be any repl dbs
 * failure label avoids repetition of errs if not in single user mode
*/

	set nocount on 

	-- server bits
	declare @srv_distbit int
	declare @srv_pubbit int
	declare @srv_subbit int
	declare @srv_dsnbit int

	select @srv_distbit = 8, @srv_pubbit = 16, @srv_subbit = 4, @srv_dsnbit = 32 -- dsn subscriber

	-- db bits
	declare @db_tranbit int
	declare @db_mergbit int
	declare @db_distbit int

	select @db_tranbit = 1, @db_mergbit = 4, @db_distbit = 16

	-- setup attach overrides removedb option
	declare @dbname sysname

	declare cur_db CURSOR LOCAL FAST_FORWARD for 
		select name from master..sysdatabases where name <> N'master' collate database_default
		for read only
	open cur_db
	fetch cur_db into @dbname
	while ( @@fetch_status <> -1 )
	begin
		exec dbo.sp_removedbreplication @dbname
		-- clean up system tables
		exec ( @dbname + '.dbo.sp_MSdrop_pub_tables' )
		exec ( @dbname + '.dbo.sp_MSdrop_mergesystables' )
		fetch next from cur_db into @dbname
	end
	close cur_db
	deallocate cur_db

	-- unmark db bits
	-- select name, category from sysdatabases where category & @tranbit = @tranbit 
	update master..sysdatabases set category = category & ~@db_tranbit where category & @db_tranbit = @db_tranbit
	if @@ERROR <> 0
		goto fail

	update master..sysdatabases set category = category & ~@db_mergbit where category & @db_mergbit = @db_mergbit
	if @@ERROR <> 0
		goto fail

	-- clean up old dist db bit
	update master..sysdatabases set category = category & ~@db_distbit where category & @db_distbit = @db_distbit
	if @@ERROR <> 0
		goto fail

	-- unmark srv bits (srvstatus = @dsnbit no longer used by replication subscribers but by server )
	-- select name, srvstatus from sysservers where srvstatus & @srv_distbit = @srv_distbit
	update master..sysservers set srvstatus = srvstatus & ~@srv_subbit where srvstatus & @srv_subbit = @srv_subbit
	if @@ERROR <> 0
		goto fail

	update master..sysservers set srvstatus = srvstatus & ~@srv_pubbit where srvstatus & @srv_pubbit = @srv_pubbit
	if @@ERROR <> 0
		goto fail

	update master..sysservers set srvstatus = srvstatus & ~@srv_distbit where srvstatus & @srv_distbit = @srv_distbit
	if @@ERROR <> 0
		goto fail

	return (0)

fail:
-- ad hoc updates not allowed and not single user
return (1)

end
go

exec dbo.sp_MS_marksystemobject sp_removesrvreplication
go

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

CREATE PROCEDURE sp_MSremovedbreplication
	AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */

	DECLARE @retcode int
					,@regkey nvarchar(1000)
					,@local_regkey nvarchar(2000)
					,@publisher_db_prefix nvarchar(1000)
					,@subscription_name nvarchar(1000)

	-- If the attach info table exists, we need to restore the subscriptions, not
	-- deleting anything. Do nothing.
	if exists (select * from sysobjects where
		name = 'MSreplication_restore_stage')
		return 0

	--if database is in read-only mode, don't try to cleanup anything
	if databasepropertyex(db_name(), 'Updateability') = 'READ_ONLY'
		return (0)

	begin tran
	save tran sp_MSremovedbreplication
	
	if exists (select * from sysobjects where name = 'sysarticles')
	-- clean up transactional 
	begin
		if not exists (select * from master..MSreplication_options
			where optname = 'transactional')
		begin
			RAISERROR(21027, 16, -1, 'transactional')
			goto FAILURE
		end
	
		--drop replication system tables
		EXEC @retcode = dbo.sp_MSdrop_pub_tables
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			goto FAILURE
		END
		
		--this proc clears repl bits in syscolumns/sysobjects 
		--as long as master..sysdatabases.category bit is cleared
		--and syspublications does not exist in current db
		EXEC @retcode = dbo.sp_MScleandbobjectsforreplication
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			goto FAILURE
		END

	end

	if exists (select * from sysobjects where name = 'sysmergearticles')
	-- clean up merge
	-- can not use sp_MSmergepublishdb or sp_dropmergepullsubscriptions
	-- since they depend on serverid and dbname
	begin
		declare @pubid uniqueidentifier
		declare @artid uniqueidentifier
		declare hC CURSOR LOCAL FAST_FORWARD FOR select DISTINCT pubid, artid FROM 
			sysmergearticles
		FOR READ ONLY       

        OPEN hC
        FETCH hC INTO @pubid, @artid
        WHILE (@@fetch_status <> -1)
		begin

			EXEC @retcode = dbo.sp_MSarticlecleanup
				@pubid, @artid, 1 -- ignore the merge metadata tables since we are going to drop the tables after this
			IF @@ERROR <> 0 or @retcode <> 0
			BEGIN
				goto FAILURE
			end
			FETCH hC INTO @pubid, @artid
		end

        execute @retcode = dbo.sp_MSdrop_mergesystables
        if @@ERROR <> 0 or @retcode <> 0
        begin
			goto FAILURE
        end
	end

	if exists (select * from sysobjects where name = 'MSreplication_subscriptions')
	-- clean up tran sub
	begin
		-- drop pull subscription
		EXEC @retcode = dbo.sp_droppullsubscription
			@publisher = N'all', 
			@publisher_db = N'all', 
			@publication = N'all'
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			goto FAILURE
		END

	    -- drop push subscription
		EXEC @retcode = dbo.sp_subscription_cleanup
			@publisher = N'all', 
			@publisher_db = N'all', 
			@publication = N'all',
			@reserved = 'drop_all'
		IF @@ERROR <> 0 or @retcode <> 0
		BEGIN
			goto FAILURE
		END
	end

	-- this was done in sp_dropsubscription before now that we no longer call sp_MSpublishdb
	-- to loop through every subscriptions, let's clean up this key for current publisher database
	-- can't simply drop the entire key as this server may service other publisher db
	-- read all keys starts with our publisher:publisher_db and delete these ones only.
	
	--notes on Windows Sync manager:
	--UI only allow you to add pull subscription with this property, but sp_addsubscription does allow you to 
	--specific it for push subscription, interesting enough, if oyu add subscription to publication level without 
	--specifying article name, sp_addsubscription loops through article collection and calls itself recursively, 
	--but @enabled_for_syncmgr pramemter is not propogated to this recursively call, looks like a bug to me 
	--but I won't fix it for sp4, workaround is to call sp_addsubscription with explicit article name if @anbled_for_syncmgr
	--is used

	--the following code section is only meant for push subscription with @enabled_for_syncmgr, as pulled
	--subscription had been cleaned up by sp_droppullsubscription call earlier, but in case pull entries were not
	--cleaned up for whatever reason, the follow code will handle it anyway.
	declare @keyexist int
	
	create table #keyexist (keyexist int)
	create table #syncmgr_subscriptions (subscription_name nvarchar(2000) collate database_default)
	
	set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\'
	set @publisher_db_prefix = @@servername + ':' + db_name()

	insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @regkey
	select @keyexist = keyexist from #keyexist

	if @keyexist = 1
	begin
		insert into #syncmgr_subscriptions EXECUTE master.dbo.xp_regenumkeys 'HKEY_LOCAL_MACHINE', @regkey

		declare #subscriptioncursor CURSOR LOCAL FAST_FORWARD FOR 
				select DISTINCT subscription_name
	   				FROM #syncmgr_subscriptions	where left(subscription_name, len(@publisher_db_prefix)) = @subscription_name
	   				FOR READ ONLY

		open #subscriptioncursor
		fetch next from #subscriptioncursor into @subscription_name
		while (@@fetch_status <> -1)
		begin
			set @local_regkey = @regkey + @subscription_name

			EXECUTE @retcode = master.dbo.xp_regdeletekey 'HKEY_LOCAL_MACHINE', @local_regkey
			if @@error <> 0 OR @retcode <> 0
				goto FAILURE

			fetch next from #subscriptioncursor into @subscription_name
		end
		close #subscriptioncursor
		deallocate #subscriptioncursor
	end
	
	if @@trancount > 1
		commit tran
		
	return 0
FAILURE:
	if @@trancount > 1
	begin
		rollback tran sp_MSremovedbreplication
		commit tran
	end
	return 1
	
GO

exec dbo.sp_MS_marksystemobject sp_MSremovedbreplication
go

raiserror('Creating procedure sp_vupgrade_subscription_databases', 0,1)
GO
create procedure sp_vupgrade_subscription_databases
as
begin
/* 
 * Process schema and metadata changes common to all databases. This proc loops
 * through each database and upgrades MSsubscription_properties, transactional tables
 * and merge tables.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases
*/
	set nocount on

	-- raiserror('sp_vupgrade_subscription_databases', 0,1) with nowait
	declare @dbname nvarchar(270), @has_dbaccess bit

	declare current_db CURSOR LOCAL FAST_FORWARD for 
		select N'[' + replace(name, N']', N']]') + N']', has_dbaccess(name) from master..sysdatabases 
			WHERE name <> N'master' collate database_default
			AND name <> N'tempdb' collate database_default
			AND name <> N'msdb' collate database_default
		for read only

	-- Note: dbname is quoted!
	open current_db
	fetch current_db into @dbname, @has_dbaccess
	while ( @@fetch_status <> -1 )
	begin

		-- upgrade repl tables in sub dbs if needed - sub dbs are not marked with subscribed status 
		-- skip any database in an offline state and write warning to upgrade log
		if ( @has_dbaccess = 1 )
		begin
			--
			-- NOTE : there are several things to process here
			-- for each upgrade - all these steps may NOT be necessary
			-- and should be commented/uncommented out as required
			-- 
			-- Current setting for SQL 2000 SP1 upgrade
			--
			raiserror( 21377, 0, 1, @dbname) with nowait
			-- exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_MSsubscription_properties')
			exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_subscription_tables')
			exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_mergetables')
			-- exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_subpass')
		end
		else
		begin
			raiserror( 21373, 10, 1, @dbname) with nowait
		end

		fetch next from current_db into @dbname, @has_dbaccess
	end
	close current_db
	deallocate current_db
end
go

raiserror('Creating procedure sp_MScopyregvalue', 0,1)
GO
create procedure sp_MScopyregvalue(	
	@oldregkey			nvarchar(1000),
	@newregkey			nvarchar(1000),
	@param_type			nvarchar(20),
	@param_name			sysname)
as
	set nocount on
	declare @retcode 	int
	create table #binaryvalues ( value sysname collate database_default, data varbinary(256))
	if (@param_type = 'REG_SZ')
		begin
			declare @value_str nvarchar(1000)
			set @value_str = NULL
			-- Read value from old reg location and write to new one
			EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
	                               @oldregkey,
	                               @param_name,
	                               @param = @value_str OUTPUT,
	                               @no_output = 'no_output'
			if @retcode <> 0 or @@ERROR <> 0
				begin
					set @retcode = 0
					goto FAILURE
				end				
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
	                       	@newregkey,
	                       	@param_name,
							'REG_SZ',
	                       	@value_str
			if @retcode <> 0 OR @@ERROR <> 0
			begin
				set @retcode = 1
				goto FAILURE
			end				
		end
	if (@param_type = 'REG_DWORD')
		begin
			declare @value_int int
			set @value_int = NULL
			-- Read value from old reg location and write to new one
			EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
	                               @oldregkey,
	                               @param_name,
	                               @param = @value_int OUTPUT,
	                               @no_output = 'no_output'
			if @retcode <> 0 or @@ERROR <> 0
				begin
					set @retcode = 0
					goto FAILURE
				end				
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
	                       	@newregkey,
	                       	@param_name,
							'REG_DWORD',
	                       	@value_int
			if @retcode <> 0 OR @@ERROR <> 0
			begin
				set @retcode = 1
				goto FAILURE
			end
		end
	if (@param_type = 'REG_BINARY')
		begin
			declare @value_binary varbinary(256)
			set @value_binary = NULL
			-- Read value from old reg location and write to new one
/*
	-- binary output buffer was corrupted for a couple of builds;looks to be working now
	-- if reverting to this read, must pre-check exists on regkey to avoid regopenkey failure 
	-- on non-existent key when no OUTPUT parm specified
			insert into #binaryvalues EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
	                               @oldregkey,
	                               @param_name
			if @@ERROR <> 0
				begin
					set @retcode = 0
					goto FAILURE
				end		
	        select @value_binary = data from #binaryvalues
	        if @value_binary is NOT NULL
				EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
	                           	@newregkey,
	                           	@param_name,
								'REG_BINARY',
	                           	@value_binary
	                           	
*/
			EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
	                               @oldregkey,
	                               @param_name,
	                               @param = @value_binary OUTPUT,
	                               @no_output = 'no_output'
			if @retcode <> 0 or @@ERROR <> 0
				begin
					set @retcode = 0
					goto FAILURE
				end				
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
	                       	@newregkey,
	                       	@param_name,
							'REG_BINARY',
	                       	@value_binary
			if @retcode <> 0 OR @@ERROR <> 0
				begin
					set @retcode = 1
					goto FAILURE
				end
		end
	set @retcode = 0
FAILURE:
	drop table #binaryvalues
	return @retcode
go

raiserror('Creating procedure sp_vupgrade_registry', 0,1)
GO
create procedure sp_vupgrade_registry
as
	set nocount on
	declare @oldregkey						nvarchar(1000)
	declare @newregkey						nvarchar(1000)
	declare @subscription_name				nvarchar(1000)
	declare @resolver_name					nvarchar(1000)
	declare @resolver_clsid					nvarchar(1000)
	declare @retcode						int
	declare @keyexist 						int
	
	-- raiserror('sp_vupgrade_registry', 0,1)
	
	create table #keyexist (keyexist int)

	set @oldregkey = 'SOFTWARE\Microsoft\MSSQLServer\Replication\Subscriptions\'
	insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @oldregkey
	select @keyexist = keyexist from #keyexist

	if @keyexist = 1
	begin
		-- Move the registered subscriptions to new location in registry
		create table #syncmgr_subscriptions (subscription_name nvarchar(1000) collate database_default)
		set @oldregkey = 'SOFTWARE\Microsoft\MSSQLServer\Replication\Subscriptions\'
		insert into #syncmgr_subscriptions EXECUTE master.dbo.xp_regenumkeys 'HKEY_LOCAL_MACHINE', @oldregkey
		declare #subscriptioncursor CURSOR LOCAL FAST_FORWARD FOR 
			select DISTINCT subscription_name
   				FROM #syncmgr_subscriptions	FOR READ ONLY

		open #subscriptioncursor
		fetch next from #subscriptioncursor into @subscription_name
		while (@@fetch_status <> -1)
		begin

			set @newregkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
			set @oldregkey = 'SOFTWARE\Microsoft\MSSQLServer\Replication\Subscriptions\' + @subscription_name

			delete from #keyexist
			insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @oldregkey
			select @keyexist = keyexist from #keyexist
			if @keyexist = 1
				begin

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'ProfileName'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'HostName'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'ReplicationType'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'SubscriptionType'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'ExchangeType'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'Validate'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'LoginTimeout'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'QueryTimeout'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'SubscriptionName'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_BINARY', 'LastUpdateTime'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'Subid'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'Publication'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				


					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'Publisher'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'PublisherDb'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'PublisherSecurityMode'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'PublisherLogin'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'PublisherEncryptedPassword'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_BINARY', 'PublisherEncryptedPasswordBinary'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'PublisherAddress'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'PublisherNetwork'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end	

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'Subscriber'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'SubscriberDb'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				


					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'SubscriberSecurityMode'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'SubscriberLogin'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'SubscriberEncryptedPassword'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_BINARY', 'SubscriberEncryptedPasswordBinary'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'SubscriberDatasourceType'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'SubscriberDatabasePath'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'Distributor'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'DistributorSecurityMode'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'DistributorLogin'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'DistributorEncryptedPassword'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_BINARY', 'DistributorEncryptedPasswordBinary'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'DistributorAddress'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_SZ', 'DistributorNetwork'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end	

					exec @retcode = sp_MScopyregvalue	@oldregkey,	@newregkey,	'REG_DWORD', 'UseInteractiveResolver'		
					if @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end	

					-- regdelete returns 'Access Denied' message if key does not exist; check before delete
					delete from #keyexist
					insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @oldregkey
					select @keyexist = keyexist from #keyexist
					if @keyexist = 1
					begin
						exec @retcode = master.dbo.xp_regdeletekey 'HKEY_LOCAL_MACHINE', @oldregkey
						if @@error <> 0 OR @retcode <> 0
						begin
							set @retcode = 1
							goto FAILURE
						end				
					end
				end
			fetch next from #subscriptioncursor into @subscription_name
		end

		close #subscriptioncursor
		deallocate #subscriptioncursor
		drop table #syncmgr_subscriptions 

		-- done moving reg keys/values.  delete old key; check key exists before delete
		set @oldregkey = 'SOFTWARE\Microsoft\MSSQLServer\Replication\Subscriptions\'
		delete from #keyexist
		insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @oldregkey
		select @keyexist = keyexist from #keyexist
		if @keyexist = 1
		begin
			exec @retcode = master.dbo.xp_regdeletekey 'HKEY_LOCAL_MACHINE', @oldregkey
			if @@error <> 0 OR @retcode <> 0
			begin
				set @retcode = 1
				goto FAILURE
			end
		end				
	end			

	-- Move the registered article resolvers to new location in registry
	set @oldregkey = 'SOFTWARE\Microsoft\MSSQLServer\Replication\ArticleResolver'
	set @newregkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\ArticleResolver' 
	delete from #keyexist
	insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @oldregkey
	select @keyexist = keyexist from #keyexist
	if @keyexist = 1
		begin

			create table #article_resolvers (resolver_name nvarchar(1000) collate database_default, resolver_clsid nvarchar(1000))
			insert into #article_resolvers EXECUTE master.dbo.xp_regenumvalues 'HKEY_LOCAL_MACHINE', @oldregkey
			declare #resolvercursor CURSOR LOCAL FAST_FORWARD FOR 
				select DISTINCT resolver_name, resolver_clsid
		   			FROM #article_resolvers
					FOR READ ONLY

			open #resolvercursor
			fetch next from #resolvercursor into @resolver_name, @resolver_clsid
			while (@@fetch_status <> -1)
			begin
				exec @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE', @newregkey, @resolver_name, 'REG_SZ', @resolver_clsid
				if @retcode <> 0 OR @@ERROR <> 0
					begin
						set @retcode = 1
						goto FAILURE
					end				
				fetch next from #resolvercursor into @resolver_name, @resolver_clsid
			end

			-- done moving reg keys/values.  delete old key 
			exec @retcode = master.dbo.xp_regdeletekey 'HKEY_LOCAL_MACHINE', @oldregkey
			if @@error <> 0 OR @retcode <> 0
			begin
				set @retcode = 1
				goto FAILURE
			end				
			close #resolvercursor
			deallocate #resolvercursor
			drop table #article_resolvers 
		end
	set @retcode = 0
FAILURE:
	drop table #keyexist
	return @retcode

go
exec dbo.sp_MS_marksystemobject sp_vupgrade_registry
go

raiserror('Creating procedure sp_vupgrade_subscription_tables', 0,1)
GO
create procedure sp_vupgrade_subscription_tables
as
begin
/* 
 * Process schema and metadata changes common to transactional pub/sub databases. Exception is creation
 * of MSrepl_identity_range table needed for tran and merge publishing databases and merge subscr db's.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_subscription_tables
*/

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

	set nocount on 

	DECLARE @table_name sysname
	declare @retcode int

	-- Identity range management; create in  publishing databases
	if exists (select * from sysobjects where name = 'sysarticles')
	begin
		if not exists (select * from sysobjects where name = 'MSpub_identity_range')
		begin		
			CREATE TABLE dbo.MSpub_identity_range
			(
				objid int not null,
				range bigint not null,
				pub_range bigint not null,
				current_pub_range bigint not null,
				threshold int not null,
				last_seed bigint null -- It will be not when uninitialized.
			)     

			IF @@ERROR <> 0
			BEGIN
				return(1)
			END

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

			IF @@ERROR <> 0
			BEGIN
				return(1)
			END

			create unique nonclustered index unc1MSpub_identity_range
				on MSpub_identity_range (objid)

			IF @@ERROR <> 0
			BEGIN
				return(1)
			END
		end
	end

	-- Identity range management; create in all publishing databases and merge subscription databases (Shiloh)
	if exists (select * from sysobjects where name = 'sysmergearticles')
	begin
		if not exists (select * from sysobjects where name = 'MSrepl_identity_range')
		begin		
			create table dbo.MSrepl_identity_range (
				objid					int not NULL primary key,
				next_seed				bigint NULL, --resource control
				pub_range				bigint NULL, --publisher range
				range					bigint NULL, -- set by sp_addmergearticle
				max_identity			bigint NULL, --resource control
				threshold				int	NULL,	--in percentage, set by sp_addmergearticle
				current_max				bigint NULL	--max value for current check constraint,set by sp_addmergearticle
				)
			exec dbo.sp_MS_marksystemobject MSrepl_identity_range
			if @@ERROR <> 0
				return(1)
			grant select on MSrepl_identity_range to public
		end
	end

	--	Create unique index on tables that did not have one previously. The index is not created
	--	if duplicates rows exist in the table. 

	--	MSreplication_subscriptions (SQL7.0 SP1)
	SELECT @table_name = N'MSreplication_subscriptions'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSreplication_subscriptions' ) or 
		EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSsubscription_agents' )
	BEGIN
		IF EXISTS ( SELECT publication, publisher_db, publisher, subscription_type 
			FROM MSreplication_subscriptions
			GROUP BY publication, publisher_db, publisher, subscription_type
			HAVING COUNT(*) > 1 )
			RAISERROR (21203, 10, 1, @table_name)
		ELSE
			IF NOT EXISTS ( SELECT * FROM sysindexes WHERE name = 'uc1MSReplication_subscriptions' AND
				id = OBJECT_ID('MSreplication_subscriptions') )
				CREATE UNIQUE CLUSTERED INDEX uc1MSReplication_subscriptions ON
				MSreplication_subscriptions(publication, publisher_db, publisher, subscription_type)
		
		-- Create MSsubscription_agents table 
		exec @retcode = dbo.sp_MScreate_sub_tables
			@tran_sub_table = 1,
			@property_table = 0,
			@sqlqueue_table = 0
		IF @@ERROR <> 0 or @retcode <> 0
			RETURN(1)

		-- Add new columns to MSsubscription_agents, for 8.0 pre beta upgrade.

		-- status of the last sync (Shiloh)
		if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
							name = 'last_sync_status')
		begin
				alter table MSsubscription_agents add last_sync_status int NULL
				if @@ERROR <> 0
					return 1
		end

		-- summary message of the last sync (Shiloh)
		if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
							name = 'last_sync_summary')
		begin
				alter table MSsubscription_agents add last_sync_summary sysname NULL
				if @@ERROR <> 0
					return 1
		end

		-- summary message of the last sync (Shiloh)
		if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
							name = 'last_sync_time')
		begin
				alter table MSsubscription_agents add last_sync_time datetime NULL
				if @@ERROR <> 0
					return 1
		end
	END

	--	MSreplication_objects (SQL7.0 SP1)
	SELECT @table_name = N'MSreplication_objects'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSreplication_objects' ) 
	BEGIN
		IF EXISTS ( SELECT object_name
			FROM MSreplication_objects
			GROUP BY object_name
			HAVING COUNT(*) > 1 )
			RAISERROR (21203, 10, 3, @table_name)
		ELSE	
			IF NOT EXISTS ( SELECT * FROM sysindexes WHERE name = 'ucMSreplication_objects' AND
				id = OBJECT_ID('MSreplication_objects') )
				CREATE UNIQUE CLUSTERED INDEX ucMSreplication_objects ON dbo.MSreplication_objects(object_name)
	END

	--	MSreplication_queue (SQL2000 SP3)
	SELECT @table_name = N'MSreplication_queue'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = @table_name ) 
	BEGIN
		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

	--	MSrepl_queuedtraninfo (SQL2000 SP3)
	SELECT @table_name = N'MSrepl_queuedtraninfo'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = @table_name ) 
	BEGIN
		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

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_subscription_tables
go

raiserror('Creating procedure sp_vupgrade_mergetables', 0,1)
GO
create procedure sp_vupgrade_mergetables( @skip_procgen bit = 0 )
as
begin
/* 
 * Process schema and metadata changes common to transactional pub/sub databases.
 *
 * @skip_procgen is set by sp_restoredbreplication when calling this proc directly to update
 * system tables during restore of a down-level (e.g. - SQL7.0) database to current version
 * 
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_mergetables
*/

	set nocount on 

	declare @artnick int
	declare @objid  int
	declare @col_track int
	declare @article sysname
	declare @pubname sysname
	declare @artid uniqueidentifier
	declare @pubid uniqueidentifier
    declare @qualified_name         nvarchar(257)
    declare @source_owner           sysname
    declare @source_object			sysname
	declare @table_name				sysname
	declare @retcode				integer
	declare @snapshot_ready			int
	declare @cmd 					nvarchar(4000)
	declare @distributor sysname

	-- raiserror('sp_vupgrade_mergetables', 0,1)

	/*
	 * sysmergearticles
	*/
	if (exists (select * from sysobjects where name = 'sysmergearticles'))
	begin

        -- Set all invalid sysmergearticles.sync_objid to the corresponding 
        -- objid, this will allow regeneration of article procs to succeed
        update dbo.sysmergearticles 
           set sync_objid = objid 
         where object_name(sync_objid) is null

        if @@ERROR<>0
            return(1)

		exec @retcode = dbo.sp_MSUpgradeConflictTable @skip_procgen
		if @@ERROR<>0 or @retcode<>0
			return (1)		
		if not exists (select * from syscolumns where id = object_id('sysmergearticles') and
						name = 'maxversion_at_cleanup')
		begin
			alter table sysmergearticles add maxversion_at_cleanup int NOT NULL default 1
			if @@ERROR <> 0 return 1
		end

		if not exists (select * from syscolumns where id = object_id('sysmergearticles') and
						name = 'published_in_tran_pub')
		begin
			alter table sysmergearticles add published_in_tran_pub bit NOT NULL default 0
			if @@ERROR <> 0 return 1
		end

		if not exists (select * from syscolumns where id = object_id('dbo.sysmergearticles') and
						name = 'compensate_for_errors')
		begin
			alter table dbo.sysmergearticles add compensate_for_errors bit not null default 1
			if @@error <> 0	return 1
		end

	    if not exists (select * from sysobjects where name = 'sysmergeschemaarticles')
	        begin	            
	            create table dbo.sysmergeschemaarticles 
	            (   name                    sysname             NOT NULL,
	                type                    tinyint             NULL,
	                objid                   int                 NOT NULL,
	                artid                   uniqueidentifier    NOT NULL,
	                description             nvarchar(255)       NULL,
	                pre_creation_command    tinyint             NULL,
	                pubid                   uniqueidentifier    NOT NULL,
	                status                  tinyint             NULL,
	                creation_script         nvarchar(255)       NULL,
	                schema_option           binary(8)           NULL,
	                destination_object      sysname             NOT NULL,
	                destination_owner       sysname             NULL
	                -- Note: Please update sysmergeextendedarticlesview whenever
	                -- there is a schema change in sysmergeschemaarticles
	            )
	            
	            exec dbo.sp_MS_marksystemobject sysmergeschemaarticles
				create unique clustered index uc1sysmergeschemaarticles on sysmergeschemaarticles(artid, pubid)


	        end

		if not exists (select * from sysobjects where name = 'MSmerge_errorlineage')
			begin		
				create table dbo.MSmerge_errorlineage (
				tablenick		int NOT NULL,
				rowguid			uniqueidentifier NOT NULL,
				lineage			varbinary(255)
				)
				exec dbo.sp_MS_marksystemobject MSmerge_errorlineage
				create unique clustered index uc1errorlineage on MSmerge_errorlineage(tablenick, rowguid)
				
				grant select on MSmerge_errorlineage to public
			end

	    if not exists (select * from sysobjects where name = 'MSmerge_altsyncpartners')
	        begin	        
	            create table dbo.MSmerge_altsyncpartners (
	                subid 				uniqueidentifier 	not null,
	                alternate_subid 	uniqueidentifier 	not null,
	                description			nvarchar(255)		NULL

	            )

	            exec dbo.sp_MS_marksystemobject MSmerge_altsyncpartners

	            create unique clustered index uciMSmerge_altsyncpartners on 
	                dbo.MSmerge_altsyncpartners(subid, alternate_subid)
	            
	        end


		-- create view now that sysmergearticles is altered and sysmergeextendedarticles is created
		if exists (select * from sysobjects where name='sysmergeextendedarticlesview')
		begin
            drop view dbo.sysmergeextendedarticlesview
		end    

		-- cannot create view directly in proc
		exec ('create view dbo.sysmergeextendedarticlesview
		    	   as
               select name, type, objid, sync_objid, view_type, artid, description, pre_creation_command, pubid,
			   nickname, column_tracking, status, conflict_table, creation_script, conflict_script, article_resolver,
			   ins_conflict_proc, insert_proc, update_proc, select_proc, schema_option, destination_object,
			   resolver_clsid, subset_filterclause, missing_col_count, missing_cols, columns, resolver_info,
			   view_sel_proc, gen_cur, excluded_cols, excluded_col_count, vertical_partition, identity_support,
			   destination_owner, before_image_objid, before_view_objid, verify_resolver_signature, 
			   allow_interactive_resolver, fast_multicol_updateproc, check_permissions, maxversion_at_cleanup,
			   published_in_tran_pub				   
			   from sysmergearticles
	           union all
               select name, type, objid, NULL, NULL, artid, description, pre_creation_command, pubid, 
			   NULL, NULL, status, NULL, creation_script, NULL, NULL, 
			   NULL, NULL, NULL, NULL, schema_option, destination_object, 
			   NULL, NULL, NULL, NULL, NULL, NULL, 
			   NULL, NULL, NULL, NULL, NULL, NULL, 
			   destination_owner, NULL, NULL, NULL, 
			   0, 0, 0, NULL, 0
			   from sysmergeschemaarticles
			   go')

	    exec dbo.sp_MS_marksystemobject sysmergeextendedarticlesview

		-- Do not regenerate views, procs if this is called from sp_restoredbreplication. Restore only
		-- needs to update schema, then it can call existing system procs to remove db replication cleanly
		if @skip_procgen = 0
		begin
			select @artnick = min(a.nickname) from sysmergearticles a inner join sysmergepublications p on p.pubid = a.pubid where p.snapshot_ready =1
			while @artnick is not null
			begin
				-- find base table to compute number of columns
				select @objid = objid, @col_track = column_tracking
					from sysmergearticles where nickname = @artnick

				-- regenerate the triggers
				select @source_owner = user_name(uid), @source_object = name from sysobjects where id = @objid
				select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_object)
				exec dbo.sp_MSaddmergetriggers @qualified_name, NULL, @col_track

				/* Loop through all articles that this table is involved in and regenerate the article procs */
	            declare hcArtCursor CURSOR LOCAL FAST_FORWARD FOR select artid, pubid from sysmergearticles where nickname = @artnick order by artid, pubid
	            
    	        OPEN hcArtCursor
        	    FETCH hcArtCursor INTO @artid, @pubid
                WHILE (@@fetch_status <> -1)
                    BEGIN
                        select @pubname = name, @snapshot_ready = snapshot_ready from sysmergepublications where pubid = @pubid
                        -- regenerate procs, triggers, and views only for articles with snapshot ready
                        if @snapshot_ready>0
                            begin
                            	declare @rgcol nvarchar(270)
								declare @indname nvarchar(270)
								declare @quotedname nvarchar(270)
								declare @conflict_table sysname
								declare @conflict_table_id int
								declare @owner sysname
                                select @article = name, @conflict_table=conflict_table, @conflict_table_id=object_id(conflict_table)  
                                	from sysmergearticles where artid = @artid and pubid = @pubid

								--make sure conflict table has already got the indexes needed for performance enhancement
								--if not there we will add it up
 								if ( @conflict_table_id is not null) and not exists 
 									(select * from sysindexes where id = @conflict_table_id and keys is not null)
 								begin
							        select @owner=user_name(uid) from sysobjects where id= @conflict_table_id
									select @rgcol = QUOTENAME(name) from syscolumns 
										where id = @objid and ColumnProperty(id, name, 'isrowguidcol') = 1
							        select @indname = 'uc_' + @conflict_table
							        if len(@indname) > 128
        							begin
							            select @indname = substring(@indname,1,92) + convert(nvarchar(36), newid())
        							end
						        	set @indname = QUOTENAME(@indname)
						        	set @quotedname = QUOTENAME(@owner) + '.' + QUOTENAME(@conflict_table)
						        	exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname +
        								' (' + @rgcol + ', origin_datasource)' )
	        						if @@error <> 0
    	    							return (1)
								end
                                
                                -- remake the articles procs
                                exec @retcode = dbo.sp_MSsetartprocs @publication = @pubname,   @article = @article, @force_flag = 1, @pubid = @pubid
                                if @@ERROR <>0 OR @retcode <>0 
                                    return (1)
                            END
                        FETCH hcArtCursor INTO @artid, @pubid
                    END                         
                CLOSE hcArtCursor
                DEALLOCATE hcArtCursor

				-- we no longer try to delete metadata rows that might have truncated colv1
				--  deleting can cause non-convergence problems where they previously didn't
				--  exist, so we will try to patch up any truncated colv1 values in the merge agent.
				
				-- find next article
				select @artnick = min(a.nickname) from sysmergearticles a inner join sysmergepublications p on p.pubid = a.pubid where p.snapshot_ready > 0 and a.nickname > @artnick
			end -- end colv metadata fixup, article proc and trigger re-gen

			-- Loop over publications and recreate the views, skipping publications where snapshot is not ready
			select @pubname = min(name) from sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() and snapshot_ready > 0
			while @pubname is not null
			begin
				-- remake the publication views
				exec dbo.sp_MSpublicationview @pubname, 1
				select @pubname = min(name) from sysmergepublications where name > @pubname and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() and snapshot_ready > 0

			end
		end -- end @skip_procgen

        -- check if the distributor is on the same server as the publisher
        -- if so fix up the PAL user role.
        SELECT @distributor = datasource FROM master..sysservers WHERE srvstatus & 8 <> 0
        IF @@error = 0 and @distributor IS not NULL
        BEGIN
            SELECT @distributor = RTRIM(@distributor)

            -- if the distributor is on the same server. Hence we can fix the pal role
            -- right now instead of waiting for a snapshot to do it.
            IF LOWER(@@SERVERNAME) = LOWER(@distributor)
            BEGIN
                declare @role sysname
                declare @pubidother uniqueidentifier
                -- we need to fix the pal role for all publications in the current database
                declare pubs_cursor cursor LOCAL FAST_FORWARD
                for select pubid from dbo.sysmergepublications 
                where UPPER(publisher) collate database_default = UPPER(@@servername) collate database_default 
                    and publisher_db = db_name()
                open pubs_cursor
                fetch pubs_cursor into @pubidother
                while (@@fetch_status <> -1)
                begin
                    exec @retcode = sp_MSrepl_FixPALRole @pubidother, @role output
                    if (@role is NULL or @retcode <> 0 or @@error <> 0)
                    begin
                        return 1
                    end
                    fetch pubs_cursor into @pubidother
                end
                close pubs_cursor
                deallocate pubs_cursor
            END
            else
            begin
                -- force invalidate snapshot for all the publications.
        		-- this is needed for sp3 upgrade since we have introduced role based
        		-- security in shiloh sp3. the role will be created and setup when
        		-- the snapshot agent calls sp_MSenumpubreferences
                raiserror(20605, 10, -1)
        		update dbo.sysmergepublications set snapshot_ready=2 where UPPER(publisher) collate database_default = UPPER(@@servername) collate database_default and publisher_db = db_name()
            end
        END
        else
        begin
            -- force invalidate snapshot for all the publications.
    		-- this is needed for sp3 upgrade since we have introduced role based
    		-- security in shiloh sp3. the role will be created and setup when
    		-- the snapshot agent calls sp_MSenumpubreferences
    		update dbo.sysmergepublications set snapshot_ready=2 where UPPER(publisher) collate database_default = UPPER(@@servername) collate database_default and publisher_db = db_name()
        end
        
		-- revoke select access to public on table which were previously granted to public
		revoke select on MSmerge_errorlineage from public
		revoke select on MSrepl_identity_range from public
		revoke select on sysmergearticles from public
	    grant select(nickname,gen_cur,maxversion_at_cleanup) on sysmergearticles to public
		revoke select on sysmergesubscriptions from public
		revoke select on MSmerge_replinfo from public
		revoke select on MSmerge_tombstone from public
		revoke select on MSmerge_contents from public
		revoke select on MSmerge_genhistory from public
		revoke select on MSmerge_delete_conflicts from public
		revoke select on sysmergeschemachange from public
		revoke select on sysmergesubsetfilters from public
	end -- end sysmergearticles modifications

	SELECT @table_name = N'MSmerge_tombstone'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSmerge_tombstone' )
	BEGIN
		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'unc3MSmerge_tombstone' AND id = OBJECT_ID('MSmerge_tombstone'))
			drop index MSmerge_tombstone.unc3MSmerge_tombstone
		
	END

	SELECT @table_name = N'MSmerge_contents'
	IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSmerge_contents' )
	BEGIN
		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc2MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc2MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc3MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc3MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'nc4MSmerge_contents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.nc4MSmerge_contents

		IF EXISTS (SELECT * FROM sysindexes WHERE name = 'unc3SycContents' AND id = OBJECT_ID('MSmerge_contents'))
			drop index MSmerge_contents.unc3SycContents
		
		create index nc2MSmerge_contents on MSmerge_contents(generation)
		if @@ERROR <> 0 return 1

		create index nc3MSmerge_contents on MSmerge_contents(partchangegen)
		if @@ERROR <> 0 return 1

		create index nc4MSmerge_contents on MSmerge_contents(rowguid)
		if @@ERROR <> 0 return 1
	END

	if (exists (select * from sysobjects where name = 'sysmergearticles'))
	begin
		-- before image tables
		declare @binames table (biname sysname)
		insert into @binames select name from sysobjects 
								where xtype='U' 
								and name like 'MS_bi%'
								and id in (select before_image_objid from sysmergearticles)
		declare @biname nvarchar(255)
		set @biname= (select top 1 biname from @binames)
		while @biname is not null
		begin
			set @cmd= 'drop index ' + quotename(@biname) + '.' + quotename(@biname + '_gen')
			exec dbo.sp_executesql @cmd
			set @cmd= 'create clustered index ' + quotename(@biname + '_gen') + ' on ' + quotename(@biname) + '(generation)'
			exec dbo.sp_executesql @cmd
			delete from @binames where biname=@biname
			set @biname= (select top 1 biname from @binames)
		end
	end

	-- remove orphaned rows in MSmerge_contents
	if (
			exists (select * from sysobjects where name = 'sysmergearticles') and
			exists (select * from sysobjects where name = 'sysmergepublications') and
			exists (select * from sysobjects where name = 'MSmerge_genhistory') and
			exists (select * from sysobjects where name = 'MSmerge_contents') and
			exists (select * from sysobjects where name = 'MSmerge_tombstone')
		)
	begin
		exec @retcode= sp_MSpurgecontentsorphans
		if @retcode<>0 or @@error<>0 return 1
	end
end
GO
exec sp_MS_marksystemobject 'sp_vupgrade_mergetables'
go

raiserror('Creating procedure sp_vupgrade_subpass', 0,1)
GO
create procedure sp_vupgrade_subpass
as
begin
	/* 
	 * Upgrade replication ftp_password and distributor_passwords
	 * in subscriber database.
	 *
	 * Setup version upgrade procedure call order:
	 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_subpass
	*/
	begin transaction

	/*
	 * MSsubscription_properties
	*/
	if exists (select name from sysobjects where name='MSsubscription_properties')
	begin
		if not exists (select * from syscolumns where id = Object_Id('MSsubscription_properties') and name = 'ftp_password' and length = '1048')
		begin
			declare @dbname sysname
			declare @cmptlevel tinyint
			set @dbname = db_name()
			select @cmptlevel = cmptlevel from master..sysdatabases where name = @dbname collate database_default
			if @cmptlevel < 70
			begin
                                raiserror (15048, -1, -1, 70, 70, 70, 80)
			end
			else
			begin
			        /*
				 * alter ftp_password column from sysname to nvarchar(524)
				*/
				exec( 'alter table MSsubscription_properties alter column ftp_password nvarchar(524)' )
				exec( 'alter table MSsubscription_properties alter column distributor_password nvarchar(524)' )
				exec( 'alter table MSsubscription_properties alter column publisher_password nvarchar(524)' )
				exec( 'alter table MSsubscription_properties alter column dts_package_password nvarchar(524)' )
			end

			/*
			 * convert all the ftp_passwords to new encryption
			 */
			declare @ftp_password nvarchar(524)
			declare @distributor_password nvarchar(524)
			declare @publisher_password nvarchar(524)
			declare @dts_package_password nvarchar(524)
			declare @retcode int

			declare cur_MSsubscription_properties CURSOR LOCAL FORWARD_ONLY for 
			select ftp_password, distributor_password, publisher_password, dts_package_password
			from MSsubscription_properties
			for update of ftp_password, distributor_password, publisher_password, dts_package_password
		
			open cur_MSsubscription_properties
			fetch next from cur_MSsubscription_properties into @ftp_password, @distributor_password, @publisher_password, @dts_package_password
			while ( @@fetch_status <> -1 )
			begin
				EXEC @retcode = master.dbo.xp_repl_convert_encrypt @ftp_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					rollback transaction
					return 1
				end
      				
				EXEC @retcode = master.dbo.xp_repl_convert_encrypt @distributor_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					rollback transaction
					return 1
				end
	
				EXEC @retcode = master.dbo.xp_repl_convert_encrypt @publisher_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					rollback transaction
					return 1
				end

				EXEC @retcode = master.dbo.xp_repl_convert_encrypt @dts_package_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					rollback transaction
					return 1
				end
       	
				update MSsubscription_properties
				set ftp_password=@ftp_password, distributor_password=@distributor_password, publisher_password=@publisher_password, dts_package_password=@dts_package_password
				where current of cur_MSsubscription_properties
		
			        fetch next from cur_MSsubscription_properties into @ftp_password, @distributor_password, @publisher_password, @dts_package_password
			end
		end
	end
	commit transaction
end
GO
exec sp_MS_marksystemobject 'sp_vupgrade_subpass'
go

raiserror('Creating procedure sp_vupgrade_MSsubscription_properties', 0,1)
GO
create procedure sp_vupgrade_MSsubscription_properties
as
begin
/* 
 * Process schema and metadata changes common to transactional and merge MSsubscription_properties.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_MSsubscription_properties
*/
	set nocount on 

	declare @cmd nvarchar(1000)
	declare @table_name sysname

	-- raiserror('sp_vupgrade_MSsubscription_properties', 0,1)

	if exists( select * from sysobjects where name = 'MSsubscription_properties'
		and type = 'U')
	begin
		-- Add FTP properties to MSsubscription_properties.  
		if not exists (select * from syscolumns where name = 'ftp_address' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD ftp_address sysname NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'ftp_port' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD ftp_port int NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'ftp_login' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD ftp_login sysname NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'ftp_password' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD ftp_password sysname NULL
			if @@ERROR <> 0
				return 1
		end

		-- Portable snapshot (Shiloh)
		if not exists (select * from syscolumns where name = 'alt_snapshot_folder' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD alt_snapshot_folder nvarchar(255) NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'working_directory' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin

			alter table MSsubscription_properties ADD working_directory nvarchar(255) NULL
			if @@ERROR <> 0
				return 1
		end

		-- Subscriber need only set this bit and have valid login info to publisher (Shiloh)
		if not exists (select * from syscolumns where name = 'use_ftp' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin

			alter table MSsubscription_properties ADD use_ftp bit default 0 NOT NULL
			if @@ERROR <> 0
				return 1
		end

        -- Since ftp login information is not required to be persisted at the 
        -- database anymore and the use_ftp column is now the sole indicator 
        -- of whether ftp is going to be used for a particular subscription,
        -- set the use_ftp column to 1 for subscriptions that used to have
        -- a non-null ftp address
        if exists (select * from syscolumns where id = object_id('MSsubscription_properties') and
            name = 'ftp_address')
        begin
			-- must exec in separate process; deferred syntax will fail if update references non-existent column
			select @cmd = 'update dbo.MSsubscription_properties set use_ftp = 1 where ftp_address is not null and ftp_address <> N'''''
			exec (@cmd)
        end 

		-- Transformable subscriptions (Shiloh)
		if not exists (select * from syscolumns where name = 'dts_package_name' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD dts_package_name sysname NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'dts_package_password' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD dts_package_password nvarchar(524) NULL
			if @@ERROR <> 0
				return 1
		end

		if not exists (select * from syscolumns where name = 'dts_package_location' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD dts_package_location int default 1 NOT NULL
			if @@ERROR <> 0
				return 1
		end

		-- Windows Synchronization Manager support (Shiloh)
		if not exists (select * from syscolumns where name = 'enabled_for_syncmgr' and
			id = OBJECT_ID('MSsubscription_properties'))
		begin
			alter table MSsubscription_properties ADD enabled_for_syncmgr bit default 0 NOT NULL
			if @@ERROR <> 0
				return 1
		end

		-- Remote (DCOM) agents support (Shiloh)
        if not exists (select * from syscolumns where id = object_id('MSsubscription_properties') and
            name = 'offload_agent')
        begin
            alter table MSsubscription_properties ADD offload_agent bit default 0 NOT NULL
            if @@ERROR <> 0
                return 1
        end

        if not exists (select * from syscolumns where id = object_id('MSsubscription_properties') and
            name = 'offload_server')
        begin
            alter table MSsubscription_properties ADD offload_server sysname default NULL
            if @@ERROR <> 0
                return 1
        end        

        -- Dynamic snapshot location (Shiloh)
        if not exists (select * from syscolumns where id = object_id('MSsubscription_properties') and
            name = 'dynamic_snapshot_location')
        begin
            alter table MSsubscription_properties ADD dynamic_snapshot_location sysname default NULL
            
            if @@ERROR <> 0
                return 1
        end

		--	MSsubscription_properties indexes (SQL7.0 SP1)
		select @table_name = N'MSsubscription_properties'
		if exists( select * from sysobjects where name = 'MSsubscription_properties' ) 
		begin
			if exists( select publication, publisher_db, publisher
				from MSsubscription_properties
				group by publication, publisher_db, publisher
				having count(*) > 1 )
				raiserror(21203, 10, 2, @table_name)
			else
				if not exists( select * from sysindexes where name = 'uc1MSsubscription_properties' and
					id = OBJECT_ID('MSsubscription_properties') )
					create unique clustered index uc1MSsubscription_properties on
					MSsubscription_properties(publication, publisher_db, publisher)
		end
	end

end
go
exec sp_MS_marksystemobject 'sp_vupgrade_MSsubscription_properties'
go

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

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

	set nocount on 

	declare @dbname sysname
	declare @has_dbaccess bit
	declare @retcode int
	declare @db_distbit int
	declare @ver_min 			int
	declare @ver_retention	int 
    
	select @db_distbit = 16
	select @ver_retention = 576 --build # on 9/17

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

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

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

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

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

                    declare @instdistproc nvarchar(4000)
                    set @instdistproc = quotename(@dbname) + '.dbo.sp_instdist'
                    exec @instdistproc
                    if @@error <> 0
                        return(1)

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

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

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


	end

	return (0)

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_replication
go


raiserror('Creating procedure sp_vupgrade_distdb', 0,1)
go
create procedure sp_vupgrade_distdb 
as
begin
/* 
 * Process schema and metadata changes specific to a distribution database. Some schema modifications
 * may have already been made by the apply of instdist.sql against the distribution database. Both steps
 * are needed for a complete distribution database upgrade.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_distdb
*/

	set nocount on

	declare @table_name sysname
	declare @retcode integer

	-- raiserror('sp_vupgrade_publisher', 0,1) with nowait
	/*
	 * MSdistribution_agents
	*/
	if exists (select name from sysobjects where name='MSdistribution_agents')
	begin
		if not exists (select * from syscolumns where id = object_id('MSdistribution_agents') and name = 'queue_server')
		begin
			alter table MSdistribution_agents add queue_server sysname null
			EXEC dbo.sp_MSupdate_mqserver_distdb
		end
	end
	/* mark helper tables in msdb as system object */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistpublishers'
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSdistpublishers
    end

    /* Create MSdistributiondbs table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistributiondbs'
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSdistributiondbs
    end

    /* create MSdistributor table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdistributor'
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSdistributor
    end

    /* create sysreplicationalerts table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'sysreplicationalerts'
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject sysreplicationalerts
    end
    
    /* create MSagent_profiles table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSagent_profiles'
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSagent_profiles
    end

    /* create MSagent_parameters table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSagent_parameters' 
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSagent_parameters
    end

    /* create MSdatatype_mappings table */
    IF EXISTS (SELECT * FROM msdb..sysobjects WHERE name = 'MSdatatype_mappings' 
        and xtype = 'U')
    begin
		exec msdb.dbo.sp_MS_marksystemobject MSdatatype_mappings
    end

	-- because X-db chaining may be turned off in SP3  
	-- we need to ensure that SA is the distdb owner.
	IF ISNULL(IS_SRVROLEMEMBER('sysadmin'), 0) = 1
    BEGIN
        EXEC dbo.sp_changedbowner N'sa'
    END
end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_distdb
go


raiserror('Creating procedure sp_vupgrade_publisher', 0,1)
go
create procedure sp_vupgrade_publisher @ver_old int, @ver_retention int
as
begin
/* 
 * Process schema and metadata changes specific to a publisher and dispatch calls to sp_vupgrade_publisherdb
 * for any databases marked with the publishing bits.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_publisher
*/

	set nocount on

	declare @proc_name			nvarchar(350)
	declare @publication		sysname
	declare @upgraded			bit 
	declare @retcode 			int
	declare @publisher_db		nvarchar(270)
	declare @agentname			sysname
	declare @has_dbaccess		bit

	-- raiserror('sp_vupgrade_publisher', 0,1)

	/*
	 * Expired subscription cleanup agent name needs set to localized string (message 20569) and 
	 * jobstep set to correct procedure name based on name change between SQL7.0 and SQL7.5
	*/
	set @agentname = formatmessage(20569)  
	
	update msdb.dbo.sysjobs
		set name = @agentname
		from msdb.dbo.sysjobs, msdb.dbo.sysjobsteps as s
		where msdb.dbo.sysjobs.job_id = s.job_id
		and 
		( upper(s.command) = upper(N'EXEC sp_MScleanup_subscription') 
		or upper(s.command) = upper(N'EXEC dbo.sp_MScleanup_subscription') )

	update msdb.dbo.sysjobsteps 
		set  command = N'EXEC dbo.sp_expired_subscription_cleanup' 
		where upper(command) = upper(N'EXEC sp_MScleanup_subscription')
		or upper(command) = upper(N'EXEC dbo.sp_MScleanup_subscription')
			
	/*
	 * Process schema and metadata changes for each publishing database on the publisher.
	 * 
	 * Transactional replication system tables at the publisher are updated by sp_vupgrade_publisherdb.
	 * Most merge system tables exist in both the publishing and subscribing databases; merge schema 
	 * and metadata changes are processed by a separate pass over all databases in sp_vupgrade_mergetables.
	*/
	declare DC cursor local FAST_FORWARD for select distinct name, has_dbaccess(name) from master..sysdatabases 
	--	where ((category & 4) = 4) or ((category & 1) = 1)
			WHERE name <> N'master' collate database_default
			AND name <> N'tempdb' collate database_default
			AND name <> N'msdb' collate database_default
		for read only
	open DC
	fetch DC into @publisher_db, @has_dbaccess
	while (@@fetch_status <> -1)
	begin
		-- upgrade repl tables in publishing dbs if needed
		-- skip any database in an offline state and write warning to upgrade log
		if ( @has_dbaccess = 1 )
		begin
			-- Check write access
			if (databaseproperty(@publisher_db, 'IsReadOnly') = 0)
			begin
				-- We have write access
				raiserror( 21375, 10, 1, @publisher_db) with nowait

				select @proc_name = quotename(@publisher_db) + '.dbo.sp_vupgrade_publisherdb'
				exec @retcode = @proc_name 
					@ver_old = @ver_old,
					@ver_retention = @ver_retention
				if @retcode<>0 or @@ERROR<>0
				begin
					close DC
					deallocate DC
					return (1)
				end
			end
			else
			begin
				-- report informational message stating database is not accessible.
				raiserror( 21376, 10, 2, @publisher_db) with nowait
			end
		end
		else
		begin 
			-- report informational message stating database is not accessible.
			raiserror( 21376, 10, 1, @publisher_db) with nowait
		end

		fetch DC into @publisher_db, @has_dbaccess
	end
	close DC
	deallocate DC
		
    /*
     * We need to mark sp_MScleanupmergepublisher as a startup procedure
     * if there are any databases enabled for merge replication.
     */
    if exists (select * from sysdatabases where (category & 4) <> 0)
    begin
        exec dbo.sp_procoption 'sp_MScleanupmergepublisher', 'startup', 'true'
    end

end
go

exec dbo.sp_MS_marksystemobject sp_vupgrade_publisher
go


raiserror('Creating procedure sp_vupgrade_syscol_status', 0,1)
go
create procedure sp_vupgrade_syscol_status
as
begin
/* 
 * Transactional published tables should have their column bits set to indicate they are published.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_publisher -> sp_vupgrade_publisherdb -> sp_vupgrade_syscol_status
*/

	set nocount on 

	declare @artid int
	declare @src_objid int
	declare @columns binary(32)
	declare @this_col int
	declare @isset int

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

	-- cursor through table based articles
	declare hCArt cursor local FAST_FORWARD for 
		select artid, objid, columns from sysarticles where type & 1 = 1
	open hCArt
	fetch hCArt into @artid, @src_objid, @columns
	while (@@fetch_status <> -1)
	begin
		-- cursor through columns on replicated object
		declare hCColid cursor local FAST_FORWARD for 
			select colid from syscolumns where id = @src_objid
		open hCColid
		fetch hCColid into @this_col
		while (@@fetch_status <> -1)
		begin
		   exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
		   if @isset != 0 
		   begin
				exec sp_MSarticlecol @artid, @this_col, 'publish', 'add'
		   end
		   fetch hCColid into @this_col
		end
		close hCColid
		deallocate hCColid

		fetch hCArt into @artid, @src_objid, @columns
	end

	close hCArt
	deallocate hCArt
end
go
exec dbo.sp_MS_marksystemobject sp_vupgrade_syscol_status
go

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

	set nocount on 

	declare @default_name sysname 

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

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

	end -- end of syssubscriptions upgrade

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		end

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

		exec dbo.sp_MS_marksystemobject 'sysextendedarticlesview'

		exec sp_vupgrade_syscol_status

	end

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

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

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

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

	end

	-- Upgrade dbt->distbackuplsn
	-- Make sure the upgrade is done for 8.0 Beta 2 customers.
	-- no need to do this if called during restoration of sql70 backup
	-- so to avoid sp_repldone error out with 18757, 
	-- master..sysdatbases.category is bound to be 0 when 70 db is restored into 80 
	-- since 70 dbtable did not have this field
	if exists (select * from sysobjects where name = 'sysarticles') and
		not exists (select * from sysobjects where name = 'systranschemas') and 
            exists( select * from master..sysdatabases 
                        where dbid = db_id() and category & 1 = 1)
	begin
		-- Force to get in even if the logreader is running.
		exec sp_replflush 
		exec sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0,
		    @time = 0, @reset = 0, @code = 1
		-- Unmark the connection as the logreader.
		exec sp_replflush
	end

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

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

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

raiserror('Creating procedure sp_vupgrade_replmsdb', 0,1)
go
create procedure sp_vupgrade_replmsdb 
as
begin
/* 
 * Process schema and metadata changes specific to a msdb database. Updates datatype
 * mappings for heterogeneous replication.
 *
 * Setup version upgrade procedure call order:
 *	sp_vupgrade_replication -> sp_vupgrade_replmsdb (only called at distributors)
*/

	set nocount on 

	declare @retcode int
			,@profile_id int
			,@table_name sysname
			,@profile_name nvarchar(100)
			,@profile_desc nvarchar(100)

	-- raiserror('sp_vupgrade_replmsdb', 0,1)
	
	-- Drop and regenerate agent parameters and associated values from system profiles.
	select @profile_id = 1
	while (@profile_id < 8)
	begin

		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
	    if (@retcode = 1)
	        return (1)

		exec @retcode = dbo.sp_generate_agent_parameter @profile_id
	    if (@retcode = 1)
	        return (1)

		select @profile_id = @profile_id + 1

	end
	
	declare hUserProfile CURSOR LOCAL FAST_FORWARD FOR
        select distinct profile_id from msdb..MSagent_profiles where profile_id >= 8 for read only   
	open hUserProfile 
	fetch hUserProfile into @profile_id

	while @@fetch_status <> -1
    	begin
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id, @parameter_name = '-ReadBatchThreshold'
		if (@retcode = 1)
		begin
			close hUserProfile 
			deallocate hUserProfile 
	        	return (1)
		end

		fetch hUserProfile into @profile_id
    	end    
    	close hUserProfile 
    	deallocate hUserProfile 

	--
	-- Add 8.0 agent profiles
	--

    /* 
	** Distribution agent : Synchronization Manager Profile
	*/
    select @profile_id = NULL
		,@profile_name = formatmessage(20550) -- Dist SyncMgr Profile
		,@profile_desc = formatmessage(20551)
	select @profile_id = profile_id from msdb..MSagent_profiles 
		where agent_type = 3 and profile_name = @profile_name
	if (@profile_id is null)
	begin
		--
		-- Add profile
		--
		select @profile_id = NULL

		exec @retcode = dbo.sp_add_agent_profile
				@profile_id = @profile_id OUT,
				@profile_name = @profile_name,
				@agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
				@profile_type = 0,   -- 0-System, 1-Custom 
				@description = @profile_desc,
				@default = 0
		if (@retcode = 1 or @@ERROR <> 0)
			return (1)
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end
    exec @retcode = dbo.sp_generate_agent_parameter 
		@profile_id = 10,
		@real_profile_id = @profile_id
    if (@retcode = 1 or @@ERROR <> 0)
		return (1)


	-- Queue default profile
	select @profile_id = NULL
	select @profile_id = profile_id from msdb..MSagent_profiles 
		where agent_type = 9 and def_profile = 1
	if (@profile_id is null)
	begin
		--
		-- Add profile
		--
		select @profile_id = NULL
				,@profile_name = formatmessage(20545) -- Default QueueReader Profile
				,@profile_desc = formatmessage(20589)

		exec @retcode = dbo.sp_add_agent_profile
			@profile_id = @profile_id OUT,
			@profile_name = @profile_name,
			@agent_type = 9,
			@profile_type = 0, 
			@description = @profile_desc,
			@default = 1
		if (@retcode = 1 or @@ERROR <> 0)
			return (1)
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end
	exec @retcode = dbo.sp_generate_agent_parameter 
		@profile_id = 11,
		@real_profile_id = @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

	--
	-- Add 'skip data consistency error' profile
	--
	select @profile_id = NULL
		,@profile_name = formatmessage(20599) -- Default Distribution Profile
		,@profile_desc = formatmessage(20600)
	select @profile_id = profile_id from msdb..MSagent_profiles 
		where agent_type = 3 and profile_name = @profile_name
	if (@profile_id is null)
	begin
		--
		-- Add profile
		--
		select @profile_id = NULL

		exec @retcode = dbo.sp_add_agent_profile
				@profile_id = @profile_id OUT,
				@profile_name = @profile_name,
				@agent_type = 3,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
				@profile_type = 0,   -- 0-System, 1-Custom 
				@description = @profile_desc,
				@default = 0
		if (@retcode = 1 or @@ERROR <> 0)
			return (1)
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end
	exec @retcode = dbo.sp_generate_agent_parameter 
		@profile_id = 14,
		@real_profile_id = @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)
		
    /* 
	** Merge agent : Non default profile for disconnected scenarios ( unreliable link ) 
	*/
    set @profile_id = NULL
	set @profile_name = formatmessage(20548) -- Non-Default Merge Profile
    set @profile_desc = formatmessage(20549)

	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 7, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

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

	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 8, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

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

	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 9, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

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

	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 12, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

    /* 
	** Merge agent : Rowcount & Checksum Validation profile  
	*/
    set @profile_id = NULL
    set @profile_name = formatmessage(21310) -- Rowcount & Checksum Validation Profile
    set @profile_desc = formatmessage(21311) -- Rowcount & Checksum Validation Profile Description
	
	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 13, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

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

	select @profile_id = profile_id from msdb..MSagent_profiles where agent_type = 4 and profile_name = @profile_name
	if (@profile_id is null)
	begin
	    exec @retcode = dbo.sp_add_agent_profile
            @profile_id = @profile_id OUT,
            @profile_name = @profile_name,
            @agent_type = 4,   -- 1-Snapshot, 2-Logreader, 3-Distribution, 4-Merge
            @profile_type = 0,   -- 0-System, 1-Custom 
            @description = @profile_desc,
            @default = 0
	end
	else
	begin
		--
		-- Profile exists - drop the parameters for regeneration
		--
		exec @retcode = dbo.sp_drop_agent_parameter @profile_id
		if (@retcode = 1)
			return (1)
	end

	exec @retcode = dbo.sp_generate_agent_parameter 15, @profile_id
	if (@retcode = 1 or @@ERROR <> 0)
		return (1)

	-- Add MSdatatype_mappings table and default mappings
    if not exists( select * from msdb..sysobjects where name = 'MSdatatype_mappings' 
        and xtype = 'U')
    begin
        create table msdb.dbo.MSdatatype_mappings 
        (
        dbms_name           sysname NOT NULL,
        sql_type            sysname NOT NULL,
        dest_type           sysname NOT NULL,
        dest_prec           int     NOT NULL,
        dest_create_params  int     NOT NULL,
        dest_nullable       bit     NOT NULL
        )

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

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

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

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

		exec dbo.sp_add_datatype_mapping 'DB2/400', 'char', 'CHAR', 8000, 4, 1
		exec dbo.sp_add_datatype_mapping 'DB2/400', 'varchar', 'VARCHAR', 8000, 4, 1
		exec dbo.sp_add_datatype_mapping 'DB2/400', 'smalldatetime', 'TIMESTAMP', 26, 0, 1
		exec dbo.sp_add_datatype_mapping 'DB2/400', 'datetime', 'TIMESTAMP', 26, 0, 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

    end

	/*
	 * New indexes added starting with 7.0 sp1
	*/

	--	MSdistpublishers
	select @table_name = N'MSdistpublishers'
	IF EXISTS ( SELECT * FROM msdb.dbo.sysobjects WHERE name = 'MSdistpublishers' ) 
	BEGIN
		IF EXISTS ( SELECT name
			FROM msdb.dbo.MSdistpublishers
			GROUP BY name 
			HAVING COUNT(*) > 1 )
			RAISERROR (21203, 10, 19, @table_name)
		ELSE
			IF NOT EXISTS ( SELECT * FROM msdb.dbo.sysindexes WHERE name = 'uc1MSdistpublishers' AND
				id = OBJECT_ID('msdb.dbo.MSdistpublishers') )
				CREATE UNIQUE CLUSTERED INDEX uc1MSdistpublishers ON msdb.dbo.MSdistpublishers(name)

	END
	
	--	MSdistributiondbs
	SELECT @table_name = N'MSdistributiondbs'
	IF EXISTS ( SELECT * FROM msdb.dbo.sysobjects WHERE name = 'MSdistributiondbs' )
	BEGIN
		IF EXISTS ( SELECT name
			FROM msdb.dbo.MSdistributiondbs
			GROUP BY name 
			HAVING COUNT(*) > 1 )
			RAISERROR (21203, 10, 20, @table_name)			
		ELSE				
			IF NOT EXISTS ( SELECT * FROM msdb.dbo.sysindexes WHERE name = 'uc1MSdistributiondbs' AND
				id = OBJECT_ID('msdb.dbo.MSdistributiondbs') )
				CREATE UNIQUE CLUSTERED INDEX uc1MSdistributiondbs ON msdb.dbo.MSdistributiondbs(name)
	END
	
	--	MSdistributor
	SELECT @table_name = N'MSdistributor'
	IF EXISTS ( SELECT * FROM msdb.dbo.sysobjects WHERE name = 'MSdistributor' )
	BEGIN
		IF EXISTS ( SELECT property
			FROM msdb.dbo.MSdistributor
			GROUP BY property 
			HAVING COUNT(*) > 1 )
			RAISERROR (21203, 10, 21, @table_name)			
		ELSE					
			IF NOT EXISTS ( SELECT * FROM msdb.dbo.sysindexes WHERE name = 'uc1MSdistributor' AND
				id = OBJECT_ID('msdb.dbo.MSdistributor') )
				CREATE UNIQUE CLUSTERED INDEX uc1MSdistributor ON msdb.dbo.MSdistributor(property)
	END	

	/* 
	 * Upgrade replication passwords in msdb database.
	*/
	begin transaction
	/*
	 * MSdistpublishers
	*/
	if exists (select name from msdb.dbo.sysobjects where name='MSdistpublishers')
	begin
		if not exists (select * from msdb.dbo.syscolumns where id = Object_Id('msdb.dbo.MSdistpublishers') and name = 'password' and length = '1048')
		begin
			/*
			 * alter password column from sysname to nvarchar(524)
			*/

			alter table msdb.dbo.MSdistpublishers alter column password nvarchar(524)
		end

		/*
		 * convert all the passwords to new encryption
		 */
		declare @password nvarchar(524)
		declare cur_MSdistpublishers CURSOR LOCAL FORWARD_ONLY for 
			select password
			from msdb.dbo.MSdistpublishers
			for update of password
			
		open cur_MSdistpublishers
		fetch next from cur_MSdistpublishers into @password
		while ( @@fetch_status <> -1 )
		begin
			EXEC @retcode = master.dbo.xp_repl_convert_encrypt @password OUTPUT
			IF @@error <> 0 OR @retcode <> 0
			begin
				rollback transaction
				return 1
			end

			update msdb.dbo.MSdistpublishers
			set password=@password
			where current of cur_MSdistpublishers

			fetch next from cur_MSdistpublishers into @password
		end
	end
	commit transaction

	return (0)
end
go
exec dbo.sp_MS_marksystemobject sp_vupgrade_replmsdb
go

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

create procedure sp_restoredbreplication ( @srv_orig sysname, @db_orig sysname
,@keep_replication int = 0 -- Make it int so that we can expand later.
 )
as 
/*
 * used by restore process to strip out replication settings if restoring to non-originating
 * server/db or system otherwise not capable of keeping replication working
 * WARNING : procs called here run internal to server and must be owner qualified
*/
begin

	set nocount on

	-- db bits
	declare @db_tranbit int
	declare @db_mergbit int
	declare @db_distbit int
	select @db_tranbit = 1, @db_mergbit = 4, @db_distbit = 16

	declare @repl_installed bit -- repl procs installed flag
	declare @remove_repl bit	-- remove replication flag ; remove on true (1)
	declare @restoreoverride int
	declare @db_curr sysname
	DECLARE @retcode int
	DECLARE @proc nvarchar(255)

	-- Fixup lsns for dist db if needed
	-- This is to make sure that after the restore, the lsns are equal to or larger than
	-- the ones that have been sent to the publishers before the restore.
	-- reuse the procedures used by backup.
	exec @retcode = dbo.sp_MSrepl_backup_start
	if @retcode <> 0 or @@error <> 0
		return 0
	exec @retcode = dbo.sp_MSrepl_backup_complete
	if @retcode <> 0 or @@error <> 0
		return 0

	-- Support override of replication remove on attach and restore
	declare @instance sysname
	declare @regkey nvarchar(260)
	select @instance = convert(sysname, SERVERPROPERTY('InstanceName'))
	select @regkey = 'SOFTWARE\Microsoft\'
	-- default installation
	if @instance is null
		SELECT @regkey = @regkey + 'MSSQLServer\Replication' 
	else
		SELECT @regkey = @regkey + 'Microsoft SQL Server\' + @instance + '\Replication'

	SELECT @restoreoverride = 0 -- assume normal remove behavior
	SELECT @proc = 'master.dbo.xp_regread '
	EXECUTE @retcode = @proc	'HKEY_LOCAL_MACHINE', 
								@regkey,
								'RestoreOverride',
								@param = @restoreoverride OUTPUT,
								@no_output = 'no_output'

	if ( @@error = 0 ) and ( @retcode = 0 )
	begin
		-- ReplRestoreOverride = 1 = user elects to take no cleanup on restore or attach
		if ( isnull( @restoreoverride, 0 ) = 1 )
			return(0)
	end
	
		
	select @remove_repl = 0, @repl_installed = 1 

	select @db_curr = db_name() 

	-- check server has replication installed; if not, we cannot remove replication; this should be benign
	if not exists ( select * from master..MSreplication_options 
						where optname = 'transactional' 
						   or optname = 'merge' )
		select @repl_installed = 0

	-- check restore to same server/db backed up
	if (( UPPER(@srv_orig) <> UPPER(@@SERVERNAME) ) or ( @db_orig <> @db_curr )) and 
		@keep_replication = 0
		select @remove_repl = 1

	-- even it is the same server/db, if it is enabled for neither merge nor tran, we will do rmove_repl.
	
--	if not exists (select * from master..sysdatabases where name = @db_curr collate database_default and category & @db_tranbit = @db_tranbit )
--		and not exists (select * from master..sysdatabases where name = @db_curr collate database_default and category & @db_mergbit = @db_mergbit )
--		select @remove_repl = 1		
	-- in order to comply with BOL on restoring subscriber databases, this code segment has to go. 

	-- upgrade repl schema to latest version if it is restore of earlier database version (e.g. SQL70 backup)
	if ( exists( select * from sysobjects where name = N'syspublications' ) -- we think this is a tran pub db
			and not exists ( select * from sysobjects where name = N'sysextendedarticlesview' ) )
		or
	   ( exists( select * from sysobjects where name = N'sysmergepublications' ) -- we think this is a merge pub db
			and not exists ( select * from sysobjects where name = N'sysmergeextendedarticlesview' ) )
	begin
		exec dbo.sp_vupgrade_publisherdb @ver_old = 999, @ver_retention = 999 -- retention and old version not relevant on restore

		-- update subscription tables schema only -- skip any recompile of procs, views, etc. -- we will just drop them after restore
		exec dbo.sp_vupgrade_MSsubscription_properties
		exec dbo.sp_vupgrade_subscription_tables
		exec dbo.sp_vupgrade_mergetables @skip_procgen = 1

	end

	-- subscribing dbs are assumed ok
	-- distribution dbs are assumed ok

	-- publishing db check : transactional : requires coordinated restore of dist db - no way to check
	if not exists( select * from master..sysdatabases 
				where name = @db_curr collate database_default and category & @db_tranbit = @db_tranbit )
	begin
		if exists( select * from sysobjects where name = 'syspublications' )
		begin
			-- publications exist in db, but db on server is not published; 
			-- unpublish the db, ignoring distributor cleanup

			update master.dbo.sysdatabases set category = category | @db_tranbit where name = @db_curr collate database_default
			exec dbo.sp_MSpublishdb 'false', 1
			update master.dbo.sysdatabases set category = category & ~@db_tranbit where name = @db_curr collate database_default

			-- we've already brute force stripped replication from the db, 
			-- don't call sp_removedbreplication at proc exit
		end
		else 
		begin
			--
			-- cleanup the objects that are still marked by replication bits
			--
			exec @retcode = dbo.sp_MScleandbobjectsforreplication
			if @retcode <> 0 or @@error <> 0
			    return (1)
		end
	end

	if ( @repl_installed = 1 ) and ( @remove_repl = 1 ) 
		exec dbo.sp_removedbreplication @db_curr


end
go
 
exec dbo.sp_MS_marksystemobject sp_restoredbreplication
go

--
-- Name: sp_MSget_publisher_rpc
--
-- Description: This proc is invoked on subscriber by synctran trigger
-- for retrieving publisher RPC connection information during  
-- immediate updating operation.
--
-- 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_MSget_publisher_rpc', 0,1)
GO
CREATE PROCEDURE sp_MSget_publisher_rpc
(
    @trigger_id int
    ,@connect_string nvarchar(2000) output
    ,@owner sysname = null
)
AS
begin
    SET NOCOUNT ON
    declare @publisher sysname
                ,@publisher_db sysname
                ,@login sysname
                ,@password nvarchar(524)
                ,@security_mode int
                ,@object_id int
                ,@retcode int

    --
    -- Security check
    -- Make sure this proc is infact being called from the given object(trigger)
    -- 
    if trigger_nestlevel(@trigger_id) = 0
    begin
        raiserror(14126, 16, 4)
        return (1) -- current user does not have insert permission to underlying table
    end
    --
    -- Security check: the caller of this SP has to be one of the 
    -- predefined replication triggers defined in the db
    --
    if (@owner is null)
    begin
        if (@trigger_id not in (select object_id(object_name) 
                from dbo.MSreplication_objects
                where object_type = 'T'))
        begin
            raiserror(14126, 16, 4)
            return -1
        end
    end
    else
    begin
        if (@trigger_id not in (select object_id(quotename(@owner) + N'.' + quotename(object_name)) 
                from dbo.MSreplication_objects
                where object_type = 'T'))
        begin
            raiserror(14126, 16, 4)
            return -1
        end
    end
    --
    -- Get security from property table, if nothing find, the rpc will fail.
    --
    IF EXISTS (select * from dbo.sysobjects where name = 'MSsubscription_properties' and type = 'U')
    begin
        select @login = publisher_login,
                @password = publisher_password,
                @security_mode = publisher_security_mode,
                @publisher = o.publisher,
                @publisher_db = o.publisher_db
        from (dbo.MSsubscription_properties p join dbo.MSreplication_objects o
            on UPPER(p.publisher) = UPPER(o.publisher)
                and p.publisher_db = o.publisher_db
                and p.publication = o.publication)
        where o.object_name = object_name(@trigger_id) 

        exec @retcode = master.dbo.xp_repl_help_connect @password OUTPUT
        if @@error <> 0 OR @retcode <> 0
            return 1
    end
    else
    begin
        -- RPC security info invalid
        raiserror(21079, 16, -1)
        return(1)
    end
    --
    -- prepare the connect string now
    --
    if @security_mode = 2 -- 2 = use sysservers
    begin
        select @connect_string = null
    end
    else
    begin
        if @login is null
        begin
            -- RPC security info invalid
            raiserror(21079, 16, -1)
            return(1)
        end

        if @password is null
            select @password = N''
        -- Names containing space in connection string is automatically enabled.
        -- [] and ' are not recoginized by opendatasource
        -- Note ';' in names in connection string will mess things up.
        select @connect_string = 'SERVER=' + @publisher + ';UID=' + 
                @login + ';PWD=' + @password + ';'
    end
end
GO
exec dbo.sp_MS_marksystemobject sp_MSget_publisher_rpc
go

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

CREATE PROCEDURE sp_link_publication (
    @publisher      sysname,            -- publishing server name
    @publisher_db   sysname,            -- publishing database name. If NULL then same as current db
    @publication	sysname,			-- publication name
	@security_mode  int,				-- 0 = standard; 2 = static linked server entry
	@login			sysname = NULL,
	@password		sysname = NULL,
	@distributor	sysname = NULL
)
AS
BEGIN
    set nocount on
	declare @retcode int
	declare @enc_password nvarchar(524)
    
	--  Security Check
    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
    IF @@ERROR <> 0 or @retcode <> 0
	RETURN(1)

	-- Parameter check: @security_mode
	if @security_mode <> 0 and @security_mode <> 2
	begin
		RAISERROR(21055, 16, -1, '@security_mode','sp_link_publication')
		RETURN (1)
	end

	if @security_mode = 2 and not exists (select * from master..sysservers where
		UPPER(srvname) = UPPER(@publisher) collate database_default)
	begin
		RAISERROR(20620, 16, -1, @publisher)
		RETURN (1)
	end

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

    /* 
	** Check to see if MSsubscription_properties table exists.
	** If not, create it.
	*/
	exec @retcode = dbo.sp_MScreate_sub_tables
	IF @@ERROR <> 0 or @retcode <> 0
		return 1

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

	IF NOT EXISTS (select * from MSsubscription_properties 
            where UPPER(publisher) = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication) 
	BEGIN
		INSERT INTO MSsubscription_properties 
			(publisher, publisher_db, publication, publication_type, 
			 publisher_login,publisher_password, publisher_security_mode, 
			 distributor, distributor_login, distributor_password, 
			 distributor_security_mode)
		values (@publisher, @publisher_db, @publication, 0,	@login, @enc_password, 
			@security_mode, @distributor, NULL, NULL, 1)
	END
	ELSE
	BEGIN
		update MSsubscription_properties set
			publisher_login = @login,
			publisher_password = @enc_password,
			publisher_security_mode = @security_mode,
			distributor = isnull(@distributor, distributor)
			where UPPER(publisher) = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication
	END
END
go

exec dbo.sp_MS_marksystemobject sp_link_publication
go

-- This proc is invoked on subscriber.
-- internal routine - not granted to public
raiserror('Creating procedure sp_MSreset_queue', 0,1)
GO
CREATE PROCEDURE sp_MSreset_queue (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. 
    @publication	sysname,    			    -- publication name,
	@artid 		int)
as
begin
	declare @subserver sysname
			,@subdbname sysname
			,@queue_id  sysname
			,@update_mode int
			,@retcode smallint
			,@vbartid varbinary(20)
			,@queue_server sysname

	set nocount on

	select 	@subserver = @@servername, 
			@subdbname = db_name(),
			@update_mode = update_mode, 
			@queue_id = queue_id,
			@queue_server = queue_server
	from MSsubscription_agents
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication

	if (@update_mode in (2,3))
	begin
		--
		-- MSMQ processing
		-- prefix the queue_id with queue server in direct format
		-- and then perform the queue reset
		--						
		select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
		
		begin distributed tran
		exec @retcode = master.dbo.xp_resetqueue @queue_id, @subserver, 
							@subdbname, @publication, @artid
		if (@retcode != 0 or @@error != 0)
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
	end
	else if (@update_mode in (4,5))
	begin
		declare @tranid sysname

		begin tran
		--
		-- process MSreplication_queue
		--
		select @retcode = 0
		if (exists (select * from sysobjects 
			where name = 'MSreplication_queue'))
		begin
			--
			-- Strictly speaking we do no need
			-- to delete but, makes it easy for
			-- the queue reader agent
			-- Do not delete any reset messages
			--
			delete dbo.MSreplication_queue
				where publisher = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication
				and tranid not like N'sub-reset%'
		end
		else
		begin
			--
			-- first queue subscription is being initialized
			-- create queue if necessary
			--
			exec @retcode = sp_MScreate_sub_tables
				@tran_sub_table = 0,
				@property_table = 0,
				@sqlqueue_table = 1
		end
		if (@retcode != 0 or @@error != 0)
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
		--
		-- process MSrepl_queuedtraninfo
		--
		if (exists (select * from sysobjects 
			where name = 'MSrepl_queuedtraninfo'))
		begin
			--
			-- Strictly speaking we do no need
			-- to delete but, makes it easy for
			-- the queue reader agent
			-- Do not delete any reset messages
			--
			delete dbo.MSrepl_queuedtraninfo
				where publisher = UPPER(@publisher)
				and publisher_db =  @publisher_db
				and publication = @publication
				and tranid not like N'sub-reset%'
		end
		else
		begin
			--
			-- first queue subscription is being initialized
			-- create the traninfo if necessary
			--
			exec @retcode = sp_MScreate_sub_tables
				@tran_sub_table = 0,
				@property_table = 0,
				@sqlqueue_table = 1
		end
		if (@retcode != 0 or @@error != 0)
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
		--
		-- for subscription reinitialization we
		-- need to insert a RESYNC command message
		--
		select @vbartid = cast(@artid as varbinary(20))
				,@tranid = N'sub-reset-' + cast(NEWID() as sysname)
		insert into dbo.MSreplication_queue (publisher, publisher_db,
			publication,tranid, commandtype, data, datalen)
		values (UPPER(@publisher), @publisher_db, 
			@publication, @tranid, 2, @vbartid, datalength(@vbartid))
		if ((@@error != 0) or (@retcode != 0))
		begin
			if (@@trancount > 0)
				rollback tran
			return (1)	
		end
		--
		-- add an entry in MSrepl_queuedtraninfo
		--
		insert into dbo.MSrepl_queuedtraninfo (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
		values (UPPER(@publisher),@publisher_db,@publication,@tranid,@@identity,1)
	end

	commit tran
	return 0
end            
GO
exec dbo.sp_MS_marksystemobject sp_MSreset_queue
go

--
-- Name: sp_MSreset_queued_reinit
--
-- Description: This proc is invoked on publisher, for resetting
-- the queued_reinit flag for a given subscription
--
-- 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_MSreset_queued_reinit', 0,1)
GO
create procedure sp_MSreset_queued_reinit (
	@subscriber      sysname,					-- subscriber server name
	@subscriber_db   sysname,					-- subscribing database name. 
	@artid	int)				   				-- article id
as
begin
	set nocount on
	declare @srvid int
		,@retcode int
		,@publication sysname
	--
	-- PAL security check
	-- Get publication name using artid
	--
	select @publication = p.name
	from syspublications p join sysarticles a on p.pubid = a.pubid
	where a.artid = @artid
	if (@publication is null)
	begin
		return 1
	end
	exec @retcode = dbo.sp_MSreplcheck_pull @publication = @publication
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end
	select @srvid = srvid from master.dbo.sysservers where UPPER(srvname) = UPPER(@subscriber) collate database_default
	--
	-- set the reinit flag
	--
	update dbo.syssubscriptions
	set queued_reinit = 0
	where 
		artid = @artid 
		and srvid = @srvid
		and dest_db = @subscriber_db
	if (@@error != 0)
	    return 1

	-- all done
	return 0
end            
GO
exec dbo.sp_MS_marksystemobject sp_MSreset_queued_reinit
go
grant execute on dbo.sp_MSreset_queued_reinit to public
go

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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSinit_subscription_agent
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int
AS
    set nocount on
	declare @retcode int
    declare @login_time datetime

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

    -- For non independent agent publications
	if @publication is null or @publication = ''
        set @publication = 'ALL'
	
  	select @login_time = login_time from master..sysprocesses where spid = @@spid

    if not exists (select * from MSsubscription_agents where
	        UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type)
    begin
	    INSERT INTO MSsubscription_agents
		    (publisher, publisher_db, publication, subscription_type,
             queue_id, update_mode, failover_mode, spid, login_time )
	    values (@publisher, @publisher_db, @publication, @subscription_type, 
		    null, 1, 0, @@spid, @login_time)
    end
    else
    begin
		-- It is possible that 2 instance of the distribution agent do this update at 
		-- the same time. One will fail later at the instance check at the distributor
		-- side. We no longer use the spid and login_time column anywhere else. 
	    update MSsubscription_agents set      
            spid = @@spid,
            login_time = @login_time
		    where UPPER(publisher) = UPPER(@publisher)
			    and publisher_db =  @publisher_db
			    and publication = @publication
                and subscription_type = @subscription_type
    end
go

exec dbo.sp_MS_marksystemobject sp_MSinit_subscription_agent
go
grant execute on dbo.sp_MSinit_subscription_agent to public
go

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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSupdatelastsyncinfo
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
	@subscription_type int,
	@last_sync_status 	int,
	@last_sync_summary 	sysname
AS
    set nocount on
	declare @retcode int

	--  Security Check
    EXEC @retcode = dbo.sp_MSreplcheck_subscribe
    IF @@ERROR <> 0 or @retcode <> 0
		RETURN(1)
	
	if object_id('dbo.MSsubscription_agents') is null
		return(1)

    -- For non independent agent publications
	if @publication is null or @publication = ''
        set @publication = 'ALL'

    if not exists (select * from MSsubscription_agents where
	        UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type)
	begin
		exec dbo.sp_MSinit_subscription_agent
			@publisher,
			@publisher_db,
			@publication,
			@subscription_type
	end

	update MSsubscription_agents set     
		last_sync_time = getdate(), 
		last_sync_status = @last_sync_status, 
		last_sync_summary = @last_sync_summary
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type

	update MSreplication_subscriptions set
		time = convert(smalldatetime, getdate()) 
	WHERE UPPER(publisher) = UPPER(@publisher) AND
		publisher_db  = @publisher_db AND
		((@publication = N'ALL' and independent_agent = 0) or 
		@publication = publication) and
		subscription_type = @subscription_type
go

exec dbo.sp_MS_marksystemobject sp_MSupdatelastsyncinfo
go
grant execute on dbo.sp_MSupdatelastsyncinfo to public
go


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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSget_attach_state
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int
AS
    set nocount on
	declare @retcode int

	--  Security Check
	--  We only run on subscriber so we only need sysadmin and dbo
	exec @retcode = dbo.sp_MSreplcheck_publish
	if @@error <> 0 or @retcode <> 0
	begin
		return (1)
	end

	
    -- For non independent agent publications
	if @publication is null or @publication = ''
        set @publication = 'ALL'

	select attach_state, attach_version from MSsubscription_agents
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type
go

exec dbo.sp_MS_marksystemobject sp_MSget_attach_state
go
grant execute on dbo.sp_MSget_attach_state to public
go


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

-- This proc is called by distribution agent.
CREATE PROCEDURE sp_MSreset_attach_state (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int
    )
AS
BEGIN
    set nocount on
	declare @retcode int

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

    -- For non independent agent publications
	if @publication is null or @publication = ''
        select @publication = 'ALL'

	--
	-- For Queued updating subscriptions, (re)initialize
	-- the queue
	--
	if exists (select * from dbo.MSsubscription_agents 
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
			and subscription_type = @subscription_type
			and update_mode in (2,3,4,5))
	begin
		declare @artid int

		--
		-- for each article in this subscription
		--
		declare #hc_article CURSOR LOCAL FORWARD_ONLY for 
			select artid 
			from dbo.MSsubscription_articles as art join dbo.MSsubscription_agents as agent
				on art.agent_id = agent.id
			where UPPER(agent.publisher) = UPPER(@publisher)
				and agent.publisher_db =  @publisher_db
				and agent.publication = @publication
				and agent.subscription_type = @subscription_type

		open #hc_article
		fetch #hc_article into @artid
		while (@@fetch_status = 0)
		begin		
			--
			-- we cannot have an NULL article id
			--
			if (@artid IS NULL)
			begin
				raiserror('sp_MSreset_attach_state(debug) - queued article id cannot be NULL', 16, 1)
				return (1)
			end
			--
			-- reset the queue
			--
			exec @retcode = dbo.sp_MSreset_queue @publisher, @publisher_db, @publication, @artid
			IF (@retcode != 0 or @@ERROR != 0)
			begin
				raiserror('sp_MSreset_attach_state(debug) - sp_MSreset_queue failed', 16, 2)
				return (1)
			end
			--
			-- fetch next article
			--
			fetch #hc_article into @artid
		end
		close #hc_article
		deallocate #hc_article
	end

	update MSsubscription_agents set attach_state = 0
		where UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
            and subscription_type = @subscription_type
END
go

exec dbo.sp_MS_marksystemobject sp_MSreset_attach_state
go
grant execute on dbo.sp_MSreset_attach_state to public
go

--
-- Name: sp_MSset_subscription_properties
--
-- Description: This procedure is called by distribution agent to set the 
-- subscription metadata during subscription initialization. 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_MSset_subscription_properties', 0,1)
GO
CREATE PROCEDURE sp_MSset_subscription_properties (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int,
    @allow_subscription_copy bit,
    @queue_id sysname,
    @update_mode int,
    @attach_version binary(16),
    @queue_server sysname = NULL
)
AS
BEGIN
    set nocount on
    declare @retcode int

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

    -- For non independent agent publications
    if @publication is null or @publication = ''
        set @publication = 'ALL'

    if @queue_server = N''
        select @queue_server = NULL

    if @queue_id = N''
        select @queue_id = NULL
    --
    -- Update metadata in MSsubscription_agents
    --
    update dbo.MSsubscription_agents set      
        allow_subscription_copy = @allow_subscription_copy,
        update_mode = @update_mode,
        queue_id = @queue_id,
        queue_server = @queue_server,
        attach_version = @attach_version
    where UPPER(publisher) = UPPER(@publisher)
        and publisher_db =  @publisher_db
        and publication = @publication
        and subscription_type = @subscription_type
    --
    -- for queued pull subscriptions 
    -- update column update_mode in MSreplication_subscriptions
    -- as we never know the right update_mode until initialization
    --
    if ((@subscription_type = 1) and (@queue_id IS NOT NULL) and
    exists (select * from MSreplication_subscriptions 
        WHERE UPPER(publisher) = UPPER(@publisher) AND
            publisher_db  = @publisher_db AND
            publication = @publication AND
            subscription_type = @subscription_type))
    begin
        update MSreplication_subscriptions 
        set update_mode = @update_mode
        WHERE UPPER(publisher) = UPPER(@publisher) AND
            publisher_db  = @publisher_db AND
            publication = @publication AND
            subscription_type = @subscription_type
    end
END
go

exec dbo.sp_MS_marksystemobject sp_MSset_subscription_properties
go
grant execute on dbo.sp_MSset_subscription_properties to public
go

--
-- Name: sp_MSset_sub_guid
--
-- Description: This procedure is called by distribution agent to set the 
-- subscription metadata during subscription attach. 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_MSset_sub_guid', 0,1)
GO
CREATE PROCEDURE sp_MSset_sub_guid (
    @publisher      sysname,                    -- publishing server name
    @publisher_db   sysname,                    -- publishing database name. If NULL then same as current db
    @publication	sysname,    			    -- publication name,
    @subscription_type int,
    @subscription_guid binary(16),
    @queue_id		sysname,
    @queue_server	sysname = NULL
)
AS
BEGIN
    set nocount on
    declare @retcode int
                ,@independent_agent bit
                ,@subqueue_id sysname

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

    -- For non independent agent publications
    if @publication is null or @publication = ''
    begin
        select @publication = 'ALL'
                ,@independent_agent = 0
    end
    else
        select @independent_agent = 1

    if @queue_id = N''
        select @queue_id = NULL

    if @queue_server = N''
        select @queue_server = NULL
    --
    -- Special processing when we are dealing with pull SQL queue updating subscription
    --
    if ((@subscription_type = 1) and substring(@queue_id, 1, 10) = N'mssqlqueue')
    begin
        --
        -- For SQL Queue case - Check the current queue_id on the table
        --
        select @subqueue_id = queue_id
        from dbo.MSsubscription_agents
        where UPPER(publisher) = UPPER(@publisher)
            and publisher_db =  @publisher_db
            and publication = @publication
            and subscription_type = @subscription_type
        if (@subqueue_id is not NULL and substring(@subqueue_id, 1, 10) = N'mssqlqueue')
        begin
            --
            -- Use the local Queue ID on subscriber as this contains the queue version. 
            -- We are attaching an initialized subscription and do not want to change the 
            -- queue version stored in queue_id for SQL Queues. The value passed by Distribution
            -- Agent is from the distributor metadata and does not contain the queue version information.
            -- This is specific to SQL Queues only.
            --
            select @queue_id = @subqueue_id
        end
    end
    --
    -- Update metadata in MSsubscription_agents
    --
    update MSsubscription_agents set      
        queue_id = @queue_id
        ,queue_server = @queue_server
    where UPPER(publisher) = UPPER(@publisher)
    and publisher_db =  @publisher_db
    and publication = @publication
    and subscription_type = @subscription_type

    update MSreplication_subscriptions set      
        [time] = getdate(),
        subscription_guid = @subscription_guid
    where UPPER(publisher) = UPPER(@publisher)
        and publisher_db =  @publisher_db
        and (@independent_agent = 0 or publication = @publication)
        and subscription_type = @subscription_type
        and independent_agent = @independent_agent
END
go
exec dbo.sp_MS_marksystemobject sp_MSset_sub_guid
go
grant execute on dbo.sp_MSset_sub_guid to public
go

--
-- sp_populateqtraninfo
--
-- Owner: KaushikC
--
-- Description: this stored procedure populates table 
-- MSrepl_queuedtraninfo based on the existing data
-- in MSreplication_queue. It is used during the 
-- upgrade process when MSrepl_queuedtraninfo is 
-- created. Executed on subscriber database.
--
-- Parameters:  
--		as defined in the create proc statement
--
-- Results:
--	None
--
-- Returns:
-- 		0 if success
--		1 if failure
--
-- Security: internal helper procedure - not granted to public 
--
raiserror('Creating procedure sp_populateqtraninfo', 0,1)
GO
CREATE PROCEDURE sp_populateqtraninfo 
as
begin
	--
	-- initiate local transaction
	--
	begin tran sp_populateqtraninfo
	save tran sp_populateqtraninfo
	--
	-- see if we need to populate
	--
	if EXISTS (SELECT * FROM dbo.MSreplication_queue)
	begin
		--
		-- There is data in queue
		-- Populate MSrepl_queuedtraninfo based on what is there
		--
		declare @publisher sysname
				,@publisherdb sysname
				,@publication sysname
				,@tranid sysname
				,@orderkey bigint
				,@commandcount bigint
				
		declare #htctranseq cursor local for
			select publisher, publisher_db, publication, tranid, orderkey
			from dbo.MSreplication_queue with (READPAST) 
			order by orderkey asc
		open #htctranseq
		fetch #htctranseq into @publisher, @publisherdb, @publication, @tranid, @orderkey
		IF @@ERROR <> 0
			goto cleanup
		while (@@fetch_status != -1)
		begin
			--
			-- update/insert entry in MSrepl_queuedtraninfo for this transaction
			--				
			if exists (select *
				from dbo.MSrepl_queuedtraninfo
				where publisher = UPPER(@publisher) 
					and publisher_db = @publisherdb 
					and publication = @publication
					and tranid = @tranid)
			begin
				--
				-- row for this transaction exists - update it
				--
				update dbo.MSrepl_queuedtraninfo
				set maxorderkey = @orderkey
					,commandcount = commandcount + 1
				where publisher = UPPER(@publisher) 
					and publisher_db = @publisherdb 
					and publication = @publication
					and tranid = @tranid
			end
			else
			begin
				--
				-- row for this transaction does not exist - insert it
				--
				insert into dbo.MSrepl_queuedtraninfo (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
				values (UPPER(@publisher),@publisherdb,@publication,@tranid,@orderkey,1)
			end
			IF @@ERROR <> 0
				goto cleanup
			--
			-- get the next row
			--
			fetch #htctranseq into @publisher, @publisherdb, @publication, @tranid, @orderkey
		end
		close #htctranseq
		deallocate #htctranseq
	end
	--
	-- commit local transaction
	--
	commit tran sp_populateqtraninfo
	--
	-- all done
	--
	return 0

cleanup:
	--
	-- error cleanup
	-- rollback local tran
	--
	rollback tran sp_populateqtraninfo
	commit tran
	return 1
end
go
exec dbo.sp_MS_marksystemobject sp_populateqtraninfo
go

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

CREATE PROCEDURE sp_MScreate_sub_tables (
@tran_sub_table bit = 0,
@property_table bit = 1,
@sqlqueue_table bit = 0
)
as
BEGIN
	set nocount on
	declare @retcode int

	IF @tran_sub_table = 1 and
		(NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND name = 'MSreplication_subscriptions')) 
	BEGIN
		CREATE TABLE dbo.MSreplication_subscriptions
		(
		publisher sysname NOT NULL,
        publisher_db sysname NOT NULL, 
        publication sysname NULL, 
		independent_agent bit NOT NULL,
        subscription_type int NOT NULL,
        distribution_agent sysname NULL, 
		time smalldatetime NOT NULL,
		description nvarchar(255) NULL,
        transaction_timestamp varbinary(16) NOT NULL,
		-- SyncTran
		update_mode tinyint NOT NULL,
		agent_id binary(16) NULL,
		subscription_guid binary(16) NULL,
		subid binary(16) NULL,
		immediate_sync bit NOT NULL default 1 -- sync_mode with a default of 1
		)
		IF @@ERROR <> 0
			GOTO UNDO
		CREATE UNIQUE CLUSTERED INDEX uc1MSReplication_subscriptions ON
				MSreplication_subscriptions(publication, publisher_db, publisher, subscription_type)
		IF @@ERROR <> 0
			GOTO UNDO

		EXEC dbo.sp_MS_marksystemobject 'MSreplication_subscriptions'
		 IF @@ERROR <> 0
			GOTO UNDO
	END	


	IF @tran_sub_table = 1
	BEGIN
		IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
			type = 'U' AND name = 'MSsubscription_agents') 
		BEGIN
			CREATE TABLE dbo.MSsubscription_agents
			(
			id int identity,
			publisher sysname NOT NULL,
			publisher_db sysname NOT NULL, 
			publication sysname NOT NULL, 
			subscription_type int NOT NULL,
			queue_id sysname NULL,
			update_mode tinyint default 0 not null, -- 0 = read only, 1 = sync/immediate, 2 = queued, 3 = failover, 4 = sqlqueued, 5 = sqlqueued failover
			failover_mode bit default 0 not null, -- 0 - sync/immediate, 1 = queued
			spid int NOT NULL,
			login_time datetime NOT NULL,
			allow_subscription_copy bit default 0 not null,
			attach_state int default 0 not null,	-- 0: not attached 1 attached but not processed 2 attached and processed.
			attach_version binary(16) default newid() not null,
			last_sync_status int NULL, -- allow null for upgrade
			last_sync_summary sysname NULL, -- allow null for upgrade
			last_sync_time datetime NULL, -- allow null for upgrade
			queue_server sysname NULL -- only used for MSMQ based updating subscribers
			)
			IF @@ERROR <> 0
				GOTO UNDO

			CREATE unique CLUSTERED INDEX ucMSsubscription_agents ON dbo.MSsubscription_agents
				(publication, publisher_db, publisher, subscription_type)

			CREATE INDEX ucMSsubscription_agents_id ON dbo.MSsubscription_agents
				(id)

			EXEC dbo.sp_MS_marksystemobject 'MSsubscription_agents'
			IF @@ERROR <> 0
				GOTO UNDO

			grant select on dbo.MSsubscription_agents to public
			IF @@ERROR <> 0
				GOTO UNDO
		END
		ELSE
		BEGIN
			--
			-- table exists - add new columns
			--
			if not exists (select * from dbo.syscolumns where 
				id = object_id('MSsubscription_agents') and
				name = 'queue_server')
			begin
				alter table dbo.MSsubscription_agents add queue_server sysname NULL
				exec dbo.sp_MSupdate_mqserver_subdb
			end
		END
 	END

	IF @property_table = 1 and
		NOT EXISTS (SELECT * FROM sysobjects WHERE 
		type = 'U' AND
		name = 'MSsubscription_properties')
	BEGIN
		BEGIN TRAN

		CREATE TABLE dbo.MSsubscription_properties
		(
		publisher						sysname		NOT NULL,
		publisher_db					sysname		NOT NULL,
		publication						sysname		NOT NULL,
		publication_type				int			NOT NULL,
		publisher_login					sysname		NULL,
		publisher_password				nvarchar(524) NULL,
		publisher_security_mode			int			NOT NULL,
		distributor						sysname		NULL,
		distributor_login				sysname		NULL,
		distributor_password			nvarchar(524) NULL,
		distributor_security_mode		int			NOT NULL,
		ftp_address						sysname		NULL,
		ftp_port						int			NULL,
		ftp_login						sysname		NULL,
		ftp_password					nvarchar(524) NULL,
        alt_snapshot_folder             nvarchar(255) NULL,
        working_directory               nvarchar(255) NULL,
        use_ftp		                    bit default 0 NOT NULL,
		dts_package_name				sysname NULL,
		dts_package_password			nvarchar(524) NULL,
		-- default to be at the subscriber
		dts_package_location			int	default 1 NOT NULL,
		enabled_for_syncmgr				bit default 0 NOT NULL,
        offload_agent                   bit default 0 NOT NULL,
        offload_server                  sysname     NULL,
        dynamic_snapshot_location       nvarchar(255) NULL
		)
		IF @@ERROR <> 0
			GOTO UNDO

		CREATE UNIQUE CLUSTERED INDEX uc1MSsubscription_properties ON
				MSsubscription_properties(publication, publisher_db, publisher)
		IF @@ERROR <> 0
			GOTO UNDO
		
		EXEC @retcode = dbo.sp_MS_marksystemobject 'MSsubscription_properties'
		if @retcode <> 0 or @@error <> 0
			GOTO UNDO

		COMMIT TRAN
	END

	IF @sqlqueue_table = 1
	BEGIN
		declare @folddata bit

		BEGIN TRAN	
		if EXISTS (SELECT * FROM dbo.sysobjects WHERE 
				type = 'U' AND name = 'MSreplication_queue')
		BEGIN
			--
			-- table exists - check if we need to add columns
			--
			if not exists (select * from dbo.syscolumns where 
					id = object_id('MSreplication_queue') and
					name = 'cmdstate')
			BEGIN
				ALTER TABLE dbo.MSreplication_queue ADD cmdstate bit DEFAULT 0 NOT NULL
				IF @@ERROR <> 0
					GOTO UNDO
			END	

			--
			-- change data column from text to varbinary(8000)
			-- SPECIAL CASE : since a simple ALTER does not work here
			-- we create a temp table to save the existing data and then
			-- recreate the table
			--
			if exists (select * from dbo.syscolumns 
				where id = object_id('MSreplication_queue') and
				name = 'data' and xtype = 34)
			begin
				--
				-- save existing column data
				--
				if exists (select * from dbo.MSreplication_queue)
				begin
					select @folddata = 1
					create table #olddata (
						publisher					sysname collate database_default not null ,
						publisher_db				sysname collate database_default not null ,
						publication					sysname collate database_default not null ,
						tranid						sysname collate database_default not null ,
						data						varbinary(8000) NULL ,
						datalen 					int,
						commandtype					int,
						insertdate					datetime ,
						orderkey					bigint,
						cmdstate					bit)
						
					insert into #olddata 
						select publisher, publisher_db, publication, tranid, CAST(data as varbinary(8000)), 
								datalen, commandtype, insertdate, orderkey, cmdstate 
						from dbo.MSreplication_queue
					if @@error != 0
						goto UNDO
				end

				--
				-- drop table
				--
				DROP TABLE dbo.MSreplication_queue
				IF @@ERROR <> 0
					GOTO UNDO				
			end		
		END

		--
		-- Create table if it does not exist
		--
		if NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE 
				type = 'U' AND name = 'MSreplication_queue')		
		BEGIN		
			CREATE TABLE dbo.MSreplication_queue (
				publisher 					sysname NOT NULL ,
				publisher_db 				sysname NOT NULL ,
				publication 				sysname NOT NULL ,
				tranid 						sysname NOT NULL ,
				data 						varbinary(8000) NULL ,
				datalen 					int DEFAULT 0 ,
				commandtype 				int NULL ,
				insertdate 					datetime DEFAULT GETDATE(),
				orderkey					bigint IDENTITY(1,1) PRIMARY KEY,
				cmdstate					bit DEFAULT 0 NOT NULL
			)
			IF @@ERROR <> 0
				GOTO UNDO

			/****
			CREATE NONCLUSTERED INDEX nc1MSreplication_queue ON
					MSreplication_queue(tranid)
			IF @@ERROR <> 0
				GOTO UNDO
			****/

			EXEC @retcode = dbo.sp_MS_marksystemobject 'MSreplication_queue'
			if @retcode <> 0 or @@error <> 0
				GOTO UNDO

			--
			-- Do we need to restore old data
			--
			if (@folddata = 1)
			begin
				insert dbo.MSreplication_queue (publisher, publisher_db, publication, tranid, data,
							datalen, commandtype, insertdate, cmdstate)
					select publisher, publisher_db, publication, tranid, data, 
								datalen, commandtype, insertdate, cmdstate 
						from #olddata
						order by orderkey
				if @@error != 0
					goto UNDO
				
				drop table #olddata
				if @@error != 0
					goto UNDO
			end
		END
		--
		-- Table MSrepl_queuedtraninfo
		-- Create table if it does not exist
		--
		if NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE 
				type = 'U' AND name = 'MSrepl_queuedtraninfo')
		BEGIN
			CREATE TABLE dbo.MSrepl_queuedtraninfo (
				publisher 					sysname NOT NULL ,
				publisher_db 					sysname NOT NULL ,
				publication 					sysname NOT NULL ,
				tranid 						sysname NOT NULL ,
				maxorderkey					bigint NOT NULL,
				commandcount				bigint NOT NULL
			)
			IF @@ERROR <> 0
				GOTO UNDO
			CREATE CLUSTERED INDEX nc1MSrepl_queuedtraninfo ON
					MSrepl_queuedtraninfo(publisher,publisher_db,publication,tranid)
			IF @@ERROR <> 0
				GOTO UNDO
			EXEC @retcode = dbo.sp_MS_marksystemobject 'MSrepl_queuedtraninfo'
			if @retcode <> 0 or @@error <> 0
				GOTO UNDO
			--
			-- Populate this table as necessary
			--
			exec @retcode = dbo.sp_populateqtraninfo
			if @retcode <> 0 or @@error <> 0
				GOTO UNDO
		END
		COMMIT TRAN
	END

	return(0)
	
UNDO:
    IF @@TRANCOUNT = 1
        ROLLBACK TRAN
    ELSE
        COMMIT TRAN  
	return(1) 
END
go

exec dbo.sp_MS_marksystemobject sp_MScreate_sub_tables
go

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

		DECLARE hC CURSOR LOCAL FAST_FORWARD FOR 
			select publisher, publisher_db, publication
			from dbo.MSsubscription_agents
			where queue_id IS NOT NULL 
				and substring(queue_id, 1, 10) != N'mssqlqueue' 
				and queue_server IS NULL

		OPEN hC
		FETCH hC INTO @publisher, @publisher_db, @publication
		WHILE (@@fetch_status != -1)
		BEGIN
			--
			-- the table MSsubscription_properties has to exist;
			-- prepare the queue server name from distributor name
			-- strip the instance name if necessary
			--
			select @queue_server = ISNULL(distributor, @@servername)
			from dbo.MSsubscription_properties
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			if (charindex(N'\', @queue_server) > 0)
				select @queue_server = substring(@queue_server, 1, charindex(N'\', @queue_server) - 1)

			--
			-- set the queue_server for this entry
			--
			update dbo.MSsubscription_agents
			set queue_server = @queue_server
			where UPPER(publisher) = UPPER(@publisher) and
						publisher_db = @publisher_db and
						publication = @publication

			--
			-- get next entry
			--
			FETCH hC INTO @publisher, @publisher_db, @publication
		END
		CLOSE hC
		DEALLOCATE hC
	end
end
go
exec dbo.sp_MS_marksystemobject sp_MSupdate_mqserver_subdb
go

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

CREATE PROCEDURE sp_MS_replication_installed
as
	set nocount on

	declare @isinstalled int
	select @isinstalled = 0
	
	create table #keyvalues (keyvalue nvarchar(255) collate database_default not null, keyvaluedata nvarchar(255) collate database_default null)

	declare @instance sysname
	declare @regkey nvarchar(260)
	select @instance = convert(sysname, SERVERPROPERTY('InstanceName'))
	select @regkey = 'SOFTWARE\Microsoft\'
	-- default installation
	if @instance is null
		SELECT @regkey = @regkey + 'MSSQLServer\Replication' 
	else
		SELECT @regkey = @regkey + 'Microsoft SQL Server\' + @instance + '\Replication'

	insert into #keyvalues exec master..xp_regenumvalues 'HKEY_LOCAL_MACHINE',
		@regkey
	
	if @@ERROR <> 0
	begin
		drop table #keyvalues
		return (-1)
	end

	select @isinstalled = convert (int, (select keyvaluedata from #keyvalues where keyvalue = N'IsInstalled'))
	
	drop table #keyvalues

	if (@isinstalled is null or @isinstalled = 0)
	begin
		raiserror (21028, 16, -1)
		return (0)
	end

	return (1)
go
exec dbo.sp_MS_marksystemobject sp_MS_replication_installed
go

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

CREATE PROCEDURE sp_MSunc_to_drive (
        @unc_path nvarchar(255), 
		@local_server sysname, 
		@local_path nvarchar(255) output
		)
    AS

    SET NOCOUNT ON

	declare @pattern nvarchar(150)

	select @pattern = N'\\' + upper(@local_server) + N'\'

	if	charindex(@pattern, upper(substring(@unc_path, 1, len(@pattern)))) <> 0 
		and charindex(N'$\', substring(@unc_path, len(@pattern)+2, 2))<>0
		select @local_path = substring(@unc_path, len(@pattern) + 1, 1) + N':' +
			substring(@unc_path, len(@pattern) + 3, len(@unc_path) - len(@pattern) -1)
	else
		select @local_path = @unc_path
GO
exec dbo.sp_MS_marksystemobject sp_MSunc_to_drive
go

raiserror('Creating procedure sp_MSretrieve_publication_attributes', 0,1)
GO
create proc sp_MSretrieve_publication_attributes 
@name 			sysname,
@database 		sysname
AS

SET NOCOUNT ON

declare @mergepublish_bit	int
declare @tranpublish_bit	int
declare @procname			nvarchar(640)
declare @retcode			int

select @mergepublish_bit    = 4 
select @tranpublish_bit     = 1

/*
** Security Check, will be checked inside sp_MSretrieve_publication
** and sp_MSretrieve_mergepublication
*/

create table #publication_property (
	Name 					sysname collate database_default,
	dbanme					sysname collate database_default,
	Publisher				sysname collate database_default,
	Type					nvarchar(15) collate database_default,
	Description				nvarchar(255) collate database_default,
	Status					tinyint,
	allow_pull				bit,
	allow_sync_tran			bit,
	allow_anonymous			bit,
	allow_queued_tran		bit,
	enabled_for_internet	bit,
	third_party				bit
)

if (select category & @tranpublish_bit from master..sysdatabases where name = @database collate database_default) <> 0
	begin
		select @procname = quotename(@database) + '.dbo.sp_MSretrieve_publication '
		insert into #publication_property exec @retcode = @procname @name
	end

if (select category & @mergepublish_bit from master..sysdatabases where name = @database collate database_default) <> 0
	begin
		select @procname = quotename(@database) + '.dbo.sp_MSretrieve_mergepublication '
		insert into #publication_property exec @retcode = @procname @name
	end
select * from #publication_property
drop table #publication_property
Go
exec dbo.sp_MS_marksystemobject sp_MSretrieve_publication_attributes
go

raiserror('Creating procedure sp_MScleanup_publication_ADinfo', 0,1)
GO
create proc sp_MScleanup_publication_ADinfo 
@name 			sysname,
@database 		sysname
AS

SET NOCOUNT ON

declare @mergepublish_bit	int
declare @tranpublish_bit	int
declare @cmd			nvarchar(640)

select @mergepublish_bit    = 4 
select @tranpublish_bit     = 1

/*
** Security Check
*/
select @cmd = quotename(@database) + '.dbo.sp_MSreplcheck_publish'
exec (@cmd)
IF @@ERROR <> 0
	return (1)

if (select category & @tranpublish_bit from master..sysdatabases where name = @database collate database_default) <> 0
	begin
		select @cmd = N'update' + quotename(@database) + N'.dbo.syspublications set ad_guidname=NULL where name=N' + quotename(@name, N'''')
		exec (@cmd)
	end

if (select category & @mergepublish_bit from master..sysdatabases where name = @database collate database_default) <> 0
	begin
		select @cmd = N'update' + quotename(@database) + N'.dbo.sysmergepublications set ad_guidname=NULL where name=N' + quotename(@name, N'''')
		exec (@cmd)
	end
Go
exec dbo.sp_MS_marksystemobject sp_MScleanup_publication_ADinfo
go

raiserror('Creating procedure sp_MSrepl_linkedservers_rowset', 0,1)
GO
create proc sp_MSrepl_linkedservers_rowset @srvname sysname
as
	select
		SVR_NAME 		= srvname,
		SVR_PRODUCT		= srvproduct,
		SVR_PROVIDERNAME	= providername,
		SVR_DATASOURCE		= datasource,
		SVR_PROVIDERSTRING	= providerstring,
		SVR_LOCATION		= location,
		SVR_CATALOG		= catalog
	from master.dbo.sysservers
	where UPPER(srvname) = UPPER(@srvname) collate database_default and 
	isnull(providername,' ') <> ' ' and
	( isnull(datasource, ' ') <> ' ' or
	isnull(location, ' ') <> ' ' or
	isnull(providerstring, ' ') <> ' '  or
	isnull(catalog, ' ') <> ' ' )
	order by 1	

    if @@error <> 0
        return 1
    else
        return 0
go
exec dbo.sp_MS_marksystemobject sp_MSrepl_linkedservers_rowset
go



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

CREATE PROCEDURE sp_MSregistersubscription (
	@replication_type			int, /* Transactional = 1, Merge = 2 */
    @publisher 					sysname,
    @publisher_db 				sysname,
	@publisher_security_mode	int = NULL,						/* 0 standard; 1 integrated */
	@publisher_login			sysname = NULL,
	@publisher_password	nvarchar(524) = NULL,
    @publication 				sysname,         
	@subscriber 				sysname,
    @subscriber_db 				sysname,
	@subscriber_security_mode	int = NULL,						/* 0 standard; 1 integrated */
	@subscriber_login			sysname = NULL,
	@subscriber_password	    nvarchar(524) = NULL,
	@distributor 				sysname,
	@distributor_security_mode 	int = NULL,
	@distributor_login 			sysname = NULL,
	@distributor_password	    nvarchar(524) = NULL,
    @subscription_id			uniqueidentifier ,
	@independent_agent			int = NULL,
	@subscription_type			int,
	@use_interactive_resolver	int = NULL,
	@failover_mode				int = NULL
    ) AS

    SET NOCOUNT ON

	/* MobileSync Support */
	declare @subscription_name				nvarchar(1000)
	declare @regkey							nvarchar(1000)
    declare @subidstr						nvarchar(38)
    declare @profile_name 					nvarchar(100)
	declare @retcode						int
	
	set @subscription_name = @publisher + ':' + @publisher_db + ':' + @publication + ':' + @subscriber + ':' + @subscriber_db
	/* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */
	set @subscription_name = REPLACE(@subscription_name,'\','/')
	set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
	set @subidstr = '{' + convert ( nchar(36), @subscription_id) + '}'
    set @profile_name = formatmessage(20550) -- SyncMgr Profile

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'ProfileName',
                               'REG_SZ',
                                @profile_name	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'ReplicationType',
                               'REG_DWORD',
                                @replication_type	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriptionType',
                               'REG_DWORD',
                                @subscription_type	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Subid',
                               'REG_SZ',
                                @subidstr	
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Publisher',
                               'REG_SZ',
                                @publisher	                                    
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'PublisherDb',
                               'REG_SZ',
                                @publisher_db
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	
	IF @use_interactive_resolver IS NOT NULL
	BEGIN
		EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'UseInteractiveResolver',
                               'REG_DWORD',
                                @use_interactive_resolver
		if @retcode <> 0 OR @@ERROR <> 0
			return 1
	END

	/* If Publisher security mode is NOT NULL, write out the entries */
	if @publisher_security_mode IS NOT NULL
		begin
		   	EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
		                               @regkey,
		                               'PublisherSecurityMode',
		                               'REG_DWORD',
		                                @publisher_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
		                               @regkey,
		                               'PublisherLogin',
		                               'REG_SZ',
		                                @publisher_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end
    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Publication',
                               'REG_SZ',
                                @publication
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Subscriber',
                               'REG_SZ',
                                @subscriber
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	/* If Subscriber security mode is NOT NULL, write out the entries */
	if @subscriber_security_mode IS NOT NULL
		begin
		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberSecurityMode',
                               'REG_DWORD',
                                @subscriber_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberLogin',
                               'REG_SZ',
                                @subscriber_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end

    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'SubscriberDb',
                               'REG_SZ',
                                @subscriber_db                                    
	if @retcode <> 0 OR @@ERROR <> 0
		return 1
				
    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'Distributor',
                               'REG_SZ',
                                @distributor
	if @retcode <> 0 OR @@ERROR <> 0
		return 1

	/* If Distributor security mode is NOT NULL, write out the entries */
	if @distributor_security_mode IS NOT NULL
		begin
		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'DistributorSecurityMode',
                               'REG_DWORD',
                                @distributor_security_mode
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		    EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'DistributorLogin',
                               'REG_SZ',
                                @distributor_login                                    
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end

    if @independent_agent IS NOT NULL
    	begin
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'IndependentAgent',
                               'REG_DWORD',
                                @independent_agent	
			if @retcode <> 0 OR @@ERROR <> 0
				return 1
		end				

	IF @failover_mode IS NOT NULL
		begin
			EXECUTE @retcode = master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE',
                               @regkey,
                               'FailoverMode',
                               'REG_DWORD',
                                @failover_mode	
			if @retcode <> 0 OR @@ERROR <> 0
				return 1

		end			

	-- Mark enabled_for_syncmgr bit if every thing succeeded.
	-- If the row exists in MSreplication_properties table, 
	-- set enabled_for_syncmgr bit
	-- The logic need to be here because UI call this sp directly.
	if exists (select * from sysobjects where name = 'MSsubscription_properties')
	begin
		update MSsubscription_properties set enabled_for_syncmgr = 1 where
			UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
		if @retcode <> 0 OR @@ERROR <> 0
			return 1
	end

	return 0
GO

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

CREATE PROCEDURE sp_MSunregistersubscription
        @publisher 		sysname = NULL, 
		@publisher_db 	sysname = NULL, 
		@publication 	sysname = NULL, 
		@subscriber 	sysname = NULL,
		@subscriber_db 	sysname = NULL
    AS

	/* 
	** Drop the corresponding registry entry for MobileSync
	*/
	declare @enabled			int
	declare	@retcode 			int
	declare @regkey				nvarchar(1000)
	
    select @retcode = 0
	-- Mark enabled_for_syncmgr bit before trying to delete the key
	-- If the row exists in MSreplication_properties table, 
	-- set enabled_for_syncmgr bit
	-- The logic need to be here because UI call this sp directly.
	if exists (select * from sysobjects where name = 'MSsubscription_properties')
	begin
		update MSsubscription_properties set enabled_for_syncmgr = 0 where
			UPPER(publisher) = UPPER(@publisher)
			and publisher_db =  @publisher_db
			and publication = @publication
		if @@ERROR <> 0
			return 1
	end

	-- regdelete returns 'Access Denied' message if key does not exist; check before delete
	exec sp_MSsubscription_enabled_for_syncmgr
		@publisher, @publisher_db, @publication, @subscriber, @subscriber_db, @enabled OUT, @regkey OUT
	if @@ERROR <> 0
		return 1
		
	if @enabled = 1
		begin
			EXECUTE @retcode = master.dbo.xp_regdeletekey 'HKEY_LOCAL_MACHINE', @regkey
			if @@error <> 0 OR @retcode <> 0
				return 1
		end

	return 0		

GO

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

CREATE PROCEDURE sp_MSsubscription_enabled_for_syncmgr
        @publisher 		sysname = NULL, 
		@publisher_db 	sysname = NULL, 
		@publication 	sysname = NULL, 
		@subscriber 	sysname = NULL,
		@subscriber_db 	sysname = NULL,
		@enabled		int = NULL OUTPUT,
		@regkey			nvarchar(1000) = NULL OUTPUT
    AS

	/* 
	** Drop the corresponding registry entry for MobileSync
	*/
	declare @subscription_name 	nvarchar(1000)
	declare @keyexist			int
	
	-- no reg key to clean up for virtual subscribers
	if @subscriber is null
	begin
		select @enabled = 0
		return 0
	end
    
	set @subscription_name = @publisher + ':' + @publisher_db + ':' + @publication + ':' + @subscriber + ':' + @subscriber_db
	/* Replace back slash with forward slash so that the key name is a valid REGISTRY key name */
	set @subscription_name = REPLACE(@subscription_name,'\','/')
	set @regkey = 'SOFTWARE\Microsoft\Microsoft SQL Server\80\Replication\Subscriptions\' + @subscription_name
	create table #keyexist (keyexist int)
	insert into #keyexist EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @regkey
	select @enabled = keyexist from #keyexist
	drop table #keyexist
	return 0		

GO


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

-- Procedure sp_MSget_jobstate
--	The proc takes a specific Job ID and returns the Job State of the job
--		Returns a row with one column job_state
--		Returns a row with NULL if job does not exist
-- 

CREATE PROCEDURE sp_MSget_jobstate
	@job_id             UNIQUEIDENTIFIER
AS
BEGIN
	DECLARE @is_sysadmin INT
	DECLARE @job_owner   sysname
	DECLARE @job_state   INT 
	DECLARE @job_id_as_char VARCHAR(36)

	SET NOCOUNT ON

	CREATE TABLE #xp_results (job_id                UNIQUEIDENTIFIER NOT NULL,
							last_run_date         INT              NOT NULL,
							last_run_time         INT              NOT NULL,
							next_run_date         INT              NOT NULL,
							next_run_time         INT              NOT NULL,
							next_run_schedule_id  INT              NOT NULL,
							requested_to_run      INT              NOT NULL, -- BOOL
							request_source        INT              NOT NULL,
							request_source_id     sysname          collate database_default null,
							running               INT              NOT NULL, -- BOOL
							current_step          INT              NOT NULL,
							current_retry_attempt INT              NOT NULL,
							job_state             INT              NOT NULL)

	-- Need a job_id
	if (@job_id IS NULL)
	BEGIN
		SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
		RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
		RETURN(1) -- Failure
	END

	-- Capture job execution information (for local jobs only since that's all SQLServerAgent caches)
	SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)
	SELECT @job_owner = suser_sname(suser_sid())
	INSERT INTO #xp_results
	EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner

	-- Select the job state of the job in question
	SELECT @job_state = job_state FROM #xp_results WHERE @job_id = job_id

	-- Error if we have no rows selected
	if (@job_state IS NULL)
	BEGIN
		SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
		RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
		RETURN(1) -- Failure
	END
	ELSE
		SELECT @job_state
	
	-- All done
	DROP TABLE #xp_results
	RETURN(0)	-- Success
END
GO

raiserror('Creating procedure sp_MSscript_pkvar_assignment', 0,1)
go
create procedure sp_MSscript_pkvar_assignment
(
	@objid		  int,
	@columns      binary(32), 
	@indent       int = 0,
	@identity_col sysname = NULL, -- Not null value used by trigger scripting
	@ts_col       sysname = NULL,  -- Not null value used by trigger scripting
	@primary_key_bitmap varbinary(4000) = null, -- NULL when synctran processing
	@fisqueuedpub bit = 0  -- 1 = processing a queued publication on publisher
)
as
begin
	-- This stored procedure will assign the '_old' var to new var
	-- based on @bitmap. This is to avoid using case statement
	-- in the where clause in the synctran pub proc, which
	-- will cause a table scan.
	declare @cmd          nvarchar(4000)
		,@spacer       nvarchar(20)
		,@indkey       int
		,@indid        int
		,@this_col     int
		,@col          sysname
		,@qualname     nvarchar(512)
		,@column		  nvarchar(255)
		,@key	      sysname
		,@src_cols	  int
		,@total_col		int
		,@fcreatedcolmap	bit
		,@art_col int -- relative position of column
	declare @colmap table (relativeorder int identity(1,1), colid int)

	select @spacer = N'select '
		,@cmd = N''
		,@indkey = 1
		,@indid = 0
		,@fcreatedcolmap = 0
	exec sp_MSget_qualified_name @objid, @qualname OUTPUT
	select @src_cols = max(colid)
			,@total_col = count(colid)
		from syscolumns where id = @objid
	exec dbo.sp_MSpad_command @cmd output, @indent
	exec dbo.sp_MSflush_command @cmd output, 1, @indent

	if @primary_key_bitmap is null
	begin
		exec @indid = dbo.sp_MStable_has_unique_index @objid
		if @indid is null
		begin
			raiserror('Debug: Cannot find unique index', 16, -1)
			return (1)
		end
	end

	--
	-- check if column Id match relative column order
	-- for trigger scripting
	--
	if ((@total_col < @src_cols) and 
		(@columns is null) and (@primary_key_bitmap is not null))
	begin
		--
		-- this table may have altered columns, so when we need to 
		-- set a mapping for using the bitmaps properly as the bitmap
		-- always refers relative column order
		--
		insert into @colmap (colid)
			select colid from syscolumns where id = @objid order by colid
		if (@@error != 0)
		begin
			raiserror('Could not create column mapping', 16, -1)
			return (1)
		end
		select @fcreatedcolmap = 1
	end

	while (1=1)
	begin
		if @primary_key_bitmap is null 
		begin
			select @key = index_col(@qualname, @indid, @indkey)
			if @key is null
				break
			exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, 0, NULL, @this_col output
		end
		else
		begin
			exec dbo.sp_MSget_map_position @primary_key_bitmap, @indkey, @col output, @this_col output
			if @this_col is null
				break

    			--
    			-- set the actual column id for this relative order in the PK bitmap if necessary
    			--
			if (@fcreatedcolmap = 1)
			begin
				select @art_col = @this_col
				select @this_col = colid
					,@col = 'c' + convert(sysname, colid) 
				from @colmap 
				where relativeorder = @art_col 
			end
			else
			begin
				select @art_col = NULL
			end

			-- Get column name
			exec dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @key output
		end
		select @indkey = @indkey + 1
		--
		-- check if identity/timestamp column were specified
		-- for skipping during subscriber trigger scripting
		--
		if @key in (@identity_col, @ts_col)
			continue
		--
		-- If we are scripting on publisher 
		--
		if (@primary_key_bitmap is null)
		begin
			declare @isset int
			--
			-- skip column if not replicated
			--
			exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
			if (@isset != 1)
				continue
			--
			-- skip timestamp processing for queued
			--
			if ((@fisqueuedpub = 1) and 
				exists (select name from syscolumns 
					where id = @objid and colid = @this_col and xtype = 189))
				continue
		end

		select @cmd = @spacer + N'@c' + convert(nvarchar(10), @this_col)

		-- Get the new values for the columns in primary key.
		exec dbo.sp_MSget_synctran_column 
			@ts_col = null,
			@op_type = null , -- 'ins, 'upd', 'del'
			@is_new = null,
			@primary_key_bitmap = null,
			@colname = null,
			@this_col = @this_col,
			@column = @column output,
			@from_proc = 0,
			@coltype = null,
			@type = 'pk_var',
			@art_col = @art_col
			select @cmd = @cmd + N' = ' + @column 
			select @spacer = ',
	'

		-- flush command if necessary
		exec dbo.sp_MSflush_command @cmd output, 1, @indent
	end

end
go
EXEC dbo.sp_MS_marksystemobject sp_MSscript_pkvar_assignment
GO

raiserror('Creating procedure sp_MSget_publication_from_taskname', 0,1)
go
create procedure sp_MSget_publication_from_taskname
    @taskname     sysname,
    @publisher    sysname, 
    @publisherdb  sysname,
    @publication  sysname OUTPUT
as
	declare @value       sysname
	declare @value2      sysname
	declare @position    INT

    select @publication = NULL

	-- Parse out publication name from the task name "publisher_publisherdb_publication_number"
    -- Expect publisher name
    if charindex(@publisher, @taskname) <> 1
    begin
        return 1
    end   

    -- Eat up the publisher name
    select @value = stuff(@taskname, 1, len(@publisher), N'')  

    -- Expect '_' + publisherdb + '_'
    select @value2 = N'_' + @publisherdb + N'_'
    if charindex(@value2, @value) <> 1
    begin
        return 1
    end

    -- Eat up '_' + publisherdb + '_'
    select  @value = stuff(@value, 1, LEN(@publisherdb) + 2, N'')
      
    -- Reverse the string in the hope of finding the first '_' 
    -- from the right which denotes the end of the publication 
    -- name. The number at the end should not contain '_'
    select @value2 = reverse(@value)
    select @position = charindex(N'_', @value2)
    if @position < 2
    begin
        return 1
    end
       
    select @publication = left(@value, len(@value) - @position)      
    return 0
go

EXEC dbo.sp_MS_marksystemobject sp_MSget_publication_from_taskname
go

-- sp_MSacquireHeadofQueueLock, sp_MSacquireSlotLock and sp_MSreleaseSlotLock work together
-- to ensure the number of concurrent merge processes does not exceed a given value. A merge
-- process has to acquire headofqueue, i.e., Im-First lock before it can acquire slot lock. 
-- All merge processes are queued for the Im-First lock and only the one process holding that
-- lock will poll to see if there is any slot available for it to get it.

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

CREATE PROC sp_MSacquireHeadofQueueLock 
@process_name					sysname,
@queue_timeout					int = 0,  -- means wait indefinitely
@no_result                      bit = 0,
@return_immediately				bit = 0	  -- if 1, do not wait: return and post a progress message.
AS
declare @entry_date		datetime
declare @delay_time		int --in second
declare @retcode 		int
declare @max_waiting	int
declare @lock_acquired	bit

-- Security Checking 
-- sysadmin or db_owner or PAL user of any publication
if not exists (select * from dbo.sysmergepublications 
					where 1 = {fn ISPALUSER(pubid)})
begin
	RAISERROR (14260, 16, -1)
	return (1)
end

if @queue_timeout<0
	begin
		raiserror(21344, 16, -1, '@queue_timeout')
		return (1)		
	end
		
if @queue_timeout> 3600*12 -- more than 12 hours is not allowed: make it 0 in this case.
	begin
		raiserror(21417, 16, -1) 
		return (1)
	end

--quick peek and leave
if @return_immediately=1
	begin
		--take a peek: return without wait regardless of whether the lock is successfully acquired.
		exec @retcode=sp_getapplock @Resource=@process_name,@LockMode=N'Exclusive',@LockOwner='Session',@LockTimeout=0
		if (@retcode <> 0 AND @retcode <> -1)
			begin
				RAISERROR(21414,16,-1)
				RETURN(@retcode)
			end
		IF (@retcode = 0)   	-- AppLock acquired
			select 1, 0 		-- 1 means lock acquired, 0 is the time consumed to acquired this lock.
		else if @retcode = -1	-- AppLock is not available	
			select 0, 0			-- first 0 means lock not available, second column will be ignored.
		return (0)				-- OK
	end		

-- from now on, @return_immediately=0
--if @queue_timeout=0, means waiting indefinitely
if @queue_timeout=0
	select @max_waiting = NULL
else
--otherwise convert to minisecond and pass it down.
	select @max_waiting = @queue_timeout * 1000


select @delay_time=0
select @entry_date=getdate()

-- First try to acquire EXCLUSIVE lock which signfies at front of queue.   i.e. I'm next.

exec @retcode=sp_getapplock @process_name, @LockMode=N'Exclusive',@LockOwner=N'Session', @LockTimeout=@max_waiting
-- We shouldn't return from above until we have it 
-- RC should be either 0 (got immediately) or 1 (waited and got it eventually) or -1 (timed out); Exit on anything else.
-- We need value -1 because @LockTimeout value is no longer NULL, meaning waiting indefinitely. It is possible 
-- that we waited for a given length of time and timed out
IF (@retcode <> 0 and @retcode <> 1) and @retcode<>-1
	BEGIN
		RAISERROR(21413, 16, -1)
		RETURN(@retcode)
	END
	
-- Im-first lock is to be released after successfully obtained a slot lock later.
select @delay_time=datediff(ss, @entry_date, getdate())
if @retcode=-1
	select @lock_acquired=0
else
	select @lock_acquired=1

if @no_result = 0
begin
    select @lock_acquired, @delay_time
end

RETURN(0)

exec dbo.sp_MS_marksystemobject sp_MSacquireHeadofQueueLock
go

grant execute on dbo.sp_MSacquireHeadofQueueLock to public
go

-- this stored procedure is called by merge agent to limit the max number of
-- concurrent merge processes at publisher side. The merge process that calls
-- this SP must be the one that is currently holding HeadOfQueue lock. Once
-- a slot lock is granted, HeadOfQueue lock will be released for use the next
-- merge process waiting in the queue for that lock.
-- @queue_timeout value gives
-- the maximum length of time (in seconds) a merge agent would like to wait
-- before acquring Im-first lock and the available serve slots. A value of 0
-- means it would wait indefinitely until getting the lock or being canceled
-- by the caller of the procedure

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

CREATE PROC sp_MSacquireSlotLock 
@process_name					sysname,
@concurrent_max 				int,
@queue_timeout					int = 0,-- means wait indefinitely
@return_immediately				bit = 0 -- if set to 1, take a peek at the server and return immediately.

AS
declare @entry_date		datetime
declare @slot_name 		nvarchar(150)  -- OUTPUT - must give back slot acquired to caller so caller can later release.
declare @basetime 		datetime
declare @delaytime 		datetime
declare @retcode 		int
declare @i				int
declare @lock_acquired  bit

-- Security Checking 
if not exists (select * from dbo.sysmergepublications 
					where 1 = {fn ISPALUSER(pubid)})
begin
	RAISERROR (15247, 11, -1)
	return (1)
end

select @lock_acquired = 0
if @queue_timeout<0
	begin
		raiserror(21344, 16, -1, '@queue_timeout')
		return (1)		
	end
	
if @concurrent_max<=0
	begin
		raiserror(21344, 16, -1, '@concurrent_max')
		return (1)		
	end
		
select @entry_date=getdate()
select @delaytime = '00:00:02' --polling interval is defaulted to 2 seconds

SET @slot_name=NULL -- If terminate anywhere unexpectedly, dont want to give caller a lock they didnt really get.

-- We are at front of queue, so check if any available 'slot' is open.   
-- We do not wait at all for these locks, and hence expect either it was granted or timed out (-1).

SET @i=1

WHILE (@i <= @concurrent_max)
	BEGIN
		--the process has waited long enough. quit now and try later. If @queue_timeout is 0, keep waiting until succeeds.
		if @queue_timeout>0 and DATEADD(second, -@queue_timeout,  getdate()) > @entry_date
			begin
				select @lock_acquired = 1 -- not a peek but has waited as specified
				select @slot_name = NULL -- waited but failed to get one
				BREAK
			end

		SET @slot_name=@process_name+convert(varchar,@i)
		
		--the call is not blocking, return immediately having acquired the lock or not
		exec @retcode=sp_getapplock @Resource=@slot_name,@LockMode=N'Exclusive',@LockOwner='Session',@LockTimeout=0
		IF (@retcode <> 0 AND @retcode <> -1)
			BEGIN
				RAISERROR(21414,16,-1)
				RETURN(@retcode)
			END
	
		IF (@retcode = 0)   	-- got lock for that slot - cleanup and leave.
			BEGIN
				-- Release the "Im first lock"
				exec @retcode=sp_releaseapplock @process_name,@LockOwner=N'Session'
				IF (@retcode <> 0)
				BEGIN
					SET @slot_name=NULL
					RAISERROR(21415, 16, -1)
					RETURN(@retcode)
				END
				select @lock_acquired = 1
			-- We got our slot and released the Im first lock.  We're done.
				BREAK
			END
		ELSE
		IF (@retcode = -1)  -- Couldn't immediately get the lock.  So try the next one.
			BEGIN
			SET @i=@i+1
				IF @i <= @concurrent_max
					CONTINUE   -- restart the loop
				ELSE
					BEGIN		-- Sleep and start over.
					if @return_immediately=1
						begin
							select @lock_acquired = 0 --slot name does not matter in this case
							BREAK
						end
					else
						begin
							WAITFOR DELAY @delaytime
							SET @i=1
							CONTINUE   -- restart the loop
						end
					END
			END
		
	END
	
	--output the slot name for the purpose of releasing the lock by the caller
	--if the value if NULL, the caller does not acquire the lock
	select @lock_acquired, @slot_name
RETURN(0)

exec dbo.sp_MS_marksystemobject sp_MSacquireSlotLock
go

grant execute on dbo.sp_MSacquireSlotLock to public
go

-- this procedure is called by merge process to release slot lock
-- that is acquired by calling sp_MSacquireSlotLock.

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

-- this stored procedure is called by merge agent to release the application lock
-- acquired by sp_MSacquireSlotLock

CREATE PROC sp_MSreleaseSlotLock
@process_name	sysname
AS
declare @retcode int

-- Security Checking 
-- sysadmin or db_owner or PAL user have access
if not exists (select * from dbo.sysmergepublications 
					where 1 = {fn ISPALUSER(pubid)})
begin
	RAISERROR (15247, 11, -1)
	return (1)
end


exec @retcode=sp_releaseapplock @process_name,@LockOwner=N'Session'
IF (@retcode <> 0)
	BEGIN
		RAISERROR(21415, 16, -1)
		return (1)
	END
return @retcode
GO
exec dbo.sp_MS_marksystemobject sp_MSreleaseSlotLock 
go
grant exec on dbo.sp_MSreleaseSlotLock to public
go

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

CREATE PROCEDURE sp_MSrepl_check_server (
    @srvname sysname,
	@check_distdb bit = 0
        ) AS
	-- This sp is called by sp_dropserver to check if the server is in use by replication.
	declare @subscriber_bit smallint
	declare @distributor_bit smallint
	declare @retcode int
	declare @proc nvarchar(255)
	declare @dbname sysname

	-- Intialize
	select @distributor_bit = 8
	select @subscriber_bit = 4

	if @check_distdb = 0
	begin
		-- Check to see if the server is marked as a Distributor
		if exists (select * from sysservers where UPPER(srvname) = UPPER(@srvname) and
			srvstatus & @distributor_bit <> 0)
		begin
			raiserror(20581, 16, -1, @srvname) 
			return (1)
		end
		-- Check to see if the server is marked as a subscriber
		if exists (select * from sysservers where UPPER(srvname) = UPPER(@srvname) and
			srvstatus & @subscriber_bit <> 0)
		begin
			raiserror(20583, 16, -1, @srvname) 
			return (1)
		end
		-- Check to see if the server is a dist publisher
		if object_id('msdb.dbo.MSdistpublishers') is not null
		begin
			if exists (select * from msdb.dbo.MSdistpublishers where
				UPPER(name) = UPPER(@srvname) collate database_default)
			begin
				raiserror(20582, 16, -1, @srvname) 
				return (1)
			end
		end
		-- Check to see if the server is in use as a subscriber in the distribution dbs.
		if object_id('msdb.dbo.MSdistributiondbs') is not null
		begin
			declare hCForEachDb CURSOR LOCAL FAST_FORWARD FOR 
				select name from msdb.dbo.MSdistributiondbs
			FOR READ ONLY
			open hCForEachDb
			fetch hCForEachDb into @dbname
			/* Loop for each database */
			while (@@fetch_status >= 0) 
			begin
				select @proc = quotename(@dbname) + '.dbo.sp_MSrepl_check_server'
				exec @retcode = @proc
					@srvname = @srvname,
					@check_distdb = 1
				if @retcode <> 0 or @@error <> 0
					return (1)
				fetch hCForEachDb into @dbname
			end /* while FETCH_SUCCESS */
		end
	end
	else
	begin
		if object_id('MSsubscriber_info') is not null
		begin
			declare @publisher sysname
			select @publisher =  publisher from MSsubscriber_info sub
				where UPPER(subscriber) = UPPER(@srvname)
			if @publisher is not null
			begin
				raiserror(20584, 16, -1, @srvname, @publisher) 
				return (1)
			end
		end
	end

GO

EXEC dbo.sp_MS_marksystemobject sp_MSrepl_check_server
go

raiserror('Creating procedure sp_MSreset_synctran_bit', 0,1)
go
CREATE PROCEDURE sp_MSreset_synctran_bit (
	@owner  		sysname,
	@table      	sysname
)AS
    declare @qualified_name nvarchar(300)
    declare @synctran_bit int

	select @synctran_bit			= 256
    
    if @owner = N''
        select @qualified_name = @table
    else
        select @qualified_name = quotename(@owner) + '.' + quotename(@table) 

	-- Unmark synctran bit
	update sysobjects set replinfo = replinfo & ~@synctran_bit where 
		id = object_id(@qualified_name) and
		(replinfo & @synctran_bit) <> 0
	IF @@ERROR <> 0 
	    return(1)
    return(0)
GO

EXEC dbo.sp_MS_marksystemobject sp_MSreset_synctran_bit
go

grant execute on dbo.sp_MSreset_synctran_bit to public
go

--
-- Name: sp_MSenum_replsqlqueues
--
-- Description: Proc that enumerates all the subscriber + subscriber_db for the currently 
-- active queued subscriptions in all the distribution databases in this system. Invoked on
-- Distributor for SQL based queues in Updating subscribers by Queue reader Agent
--
-- Parameter :
-- @curdistdb	sysname : specified distribution database. If NULL, then
-- 			enumerate the queues for all the distribution databases
--
-- Owner: KaushikC
--
-- Returns: 0 - succeeded
--          1 - failed
--
-- Resultset: 
--		publisher sysname collate database_default not null,
--		publisher_db sysname collate database_default not null,
--		subscriber sysname collate database_default not null,
--		subscriber_db sysname collate database_default not null,
--		publication sysname collate database_default not null,
--		dist_db sysname collate database_default not null
--
-- Security: Procedural security check is done inside this procedure
--           to make sure that the caller is either a member of the db_owner
--           role of the distribution database or a member of the sysadmin role
--
raiserror('Creating procedure sp_MSenum_replsqlqueues', 0,1)
go
create procedure sp_MSenum_replsqlqueues
(
	@curdistdb	sysname = NULL
)
as
begin
	declare @distbit int
	declare @db_name sysname
	declare @cmd nvarchar(1024)

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

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

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

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

	--
	-- cleanup
	--
	drop table #replqueue
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSenum_replsqlqueues
go

--
-- Name: sp_MSenum_replqueues
--
-- Description: Proc that enumerates all the all the MSMQ based queues that 
-- are currently active in the specified distribution database. Invoked on
-- Distributor for SQL based queues in Updating subscribers by Queue reader Agent
--
-- Owner: KaushikC
--
-- Parameter :
-- @curdistdb	sysname : specified distribution database. If NULL, then
-- 			enumerate the queues for all the distribution databases
--
-- Returns: 0 - succeeded
--          1 - failed
--
-- Resultset: 
--		queue_server sysname collate database_default not null,
--		queue_id sysname collate database_default not null,
--		dist_db sysname collate database_default not null
--
-- Security: Procedural security check is done inside this procedure
--           to make sure that the caller is either a member of the db_owner
--           role of the distribution database or a member of the sysadmin role
--
raiserror('Creating procedure sp_MSenum_replqueues', 0,1)
go
create procedure sp_MSenum_replqueues
(
	@curdistdb	sysname = NULL
)
as
begin
	declare @distbit int
	declare @db_name sysname
	declare @cmd nvarchar(1024)

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

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

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

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

	--
	-- select the contents of the temp table to present
	-- the formatted queue name
	--
	select 	N'DIRECT=OS:' + queue_server + N'\PRIVATE$\' + queue_id AS 'queue_format'
			,dist_db
	from #replqueue
	
	--
	-- cleanup
	--
	drop table #replqueue
end
go

EXEC dbo.sp_MS_marksystemobject sp_MSenum_replqueues
go

raiserror('Creating procedure sp_browsemergesnapshotfolder', 0,1)
go
CREATE PROCEDURE sp_browsemergesnapshotfolder (
    @publication sysname
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @dbname sysname
    DECLARE @alt_directory_type INT
    DECLARE @directory_type INT
    SELECT @alt_directory_type = 25
    SELECT @directory_type = 7

    if (1 <> is_member('db_owner'))
	begin    
		RAISERROR (15247, 11, -1)
		return (1)
	end

    IF (EXISTS (SELECT * FROM sysobjects WHERE name = N'sysmergepublications')) AND
       (EXISTS (SELECT * FROM sysobjects WHERE name = N'sysmergeschemachange'))
    BEGIN
        SELECT 'snapshot_folder' = schematext 
          FROM sysmergeschemachange sc 
    INNER JOIN sysmergepublications mp
            ON sc.pubid = mp.pubid
         WHERE mp.name = @publication
           AND upper(mp.publisher) = upper(@@servername)
           AND publisher_db = db_name()  
           AND (schematype = @directory_type OR schematype = @alt_directory_type)
      ORDER BY schematype desc
    END  
    ELSE
    BEGIN
        SELECT @dbname = DB_NAME()
        RAISERROR(21147, 16, -1, @dbname)
        RETURN 1
    END
END
GO
EXEC dbo.sp_MS_marksystemobject sp_browsemergesnapshotfolder
go

raiserror('Creating procedure sp_browsesnapshotfolder', 0,1)
go
CREATE PROCEDURE sp_browsesnapshotfolder (
    @publication    sysname,
    @subscriber     sysname = NULL,
    @subscriber_db  sysname = NULL
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @publisher      sysname
    DECLARE @publisher_db   sysname
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       nvarchar(300)
    DECLARE @article_id     INT
    
    SELECT @retcode = 0
    SELECT @publisher = NULL
    SELECT @publisher_db = DB_NAME()
    SELECT @distributor = NULL
    SELECT @distributiondb = NULL
    SELECT @article_id = NULL
    
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

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

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

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

        EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                               @distribdb = @distributiondb OUTPUT
        IF @retcode <> 0
            RETURN @retcode
    
        SELECT @distributor = RTRIM(@distributor)
    
        IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
        BEGIN
            SELECT @distproc = @distributor + '.' + @distributiondb + 
                               '.dbo.sp_MSbrowsesnapshotfolder'
        END
        ELSE
        BEGIN
            SELECT @distproc = @distributiondb + '.dbo.sp_MSbrowsesnapshotfolder'
        END
        EXECUTE @retcode = @distproc
                    @publisher = @publisher, 
                    @publisher_db = @publisher_db,
                    @article_id = @article_id,
                    @subscriber = @subscriber,
                    @subscriber_db = @subscriber_db
        RETURN @retcode
    END
    ELSE
    BEGIN
        RAISERROR(21149, 16, -1, @publisher_db)
        RETURN 1
    END
END
GO
EXEC dbo.sp_MS_marksystemobject sp_browsesnapshotfolder
go

raiserror('Creating procedure sp_MScopysnapshot', 0,1)
go
CREATE PROCEDURE sp_MScopysnapshot (
    @source_folder           nvarchar(255),
    @destination_folder      nvarchar(255)
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @directory_exists bit    
    DECLARE @ftporuncdir      nvarchar(5)
    DECLARE @pubdir           nvarchar(255)
    DECLARE @timestampdir     nvarchar(255)
    DECLARE @bslashindex      int
    DECLARE @bslashindex2     int
    DECLARE @bslashcounter    int
    DECLARE @command          nvarchar(1000)
    DECLARE @retcode          int
    DECLARE @platform_nt      bit

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

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

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

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

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

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

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

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

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

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

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

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

raiserror('Creating procedure sp_copymergesnapshot', 0,1)
go
CREATE PROCEDURE sp_copymergesnapshot (
    @publication          sysname,
    @destination_folder   nvarchar(255)
    )
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @retcode       int
    DECLARE @source_folder nvarchar(255)
    SELECT @retcode = 0
    
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 OR @retcode <> 0
		RETURN (1)

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

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

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

    DROP TABLE #snapshot_folders
    RETURN 0
Failure:
    SET ROWCOUNT 0    
    DROP TABLE #snapshot_folders        
    RETURN 1
END
GO
EXEC dbo.sp_MS_marksystemobject sp_copymergesnapshot
go

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

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

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

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

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

    DROP TABLE #snapshot_folders
    RETURN 0
Failure:
    SET ROWCOUNT 0
    DROP TABLE #snapshot_folders        
    RETURN 1
END
GO
EXEC dbo.sp_MS_marksystemobject sp_copysnapshot
go

raiserror('Creating procedure sp_MSrepl_validate_dts_package', 0,1)
go
CREATE PROCEDURE sp_MSrepl_validate_dts_package (
    @name sysname
	 ) AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	if not exists (select * from msdb.dbo.sysdtspackages where
		name = @name)
	begin
		raiserror(21171, 
			16, -1, @name, @@servername )
		return 1
	end
go
EXEC dbo.sp_MS_marksystemobject sp_MSrepl_validate_dts_package
go

grant execute on dbo.sp_browsemergesnapshotfolder to public
go

grant execute on dbo.sp_browsesnapshotfolder to public
go

grant execute on dbo.sp_copymergesnapshot to public
go

grant execute on dbo.sp_copysnapshot to public
go

grant execute on dbo.sp_MSenum_replsqlqueues to public
grant execute on dbo.sp_MSenum_replqueues to public
go

raiserror('Creating procedure sp_MSget_load_hint', 0,1)
go
create procedure sp_MSget_load_hint @objname sysname, @type int
as
declare @objid int
declare @tabname sysname
declare @tabid int
declare @hint   nvarchar(2048)
declare @i int
declare @thiskey sysname
declare @indid smallint
declare @indstat int

select @objid = object_id( @objname )

if exists ( select * from sysobjects where id = @objid and type = 'V' )
begin
	select @tabid = depid from sysdepends where id = object_id( @objname )
	select @tabname = object_name( @tabid )
	
	select @indid = indid, @indstat = status 
	    from sysindexes where id = @tabid and ( status & @type ) = @type
	if @indid is not null
	begin
		create table #colnames ( idxcolname sysname collate database_default)

		select @thiskey = index_col( @tabname, @indid, 1 )
		select @i = 2
		while (@thiskey is not null )
		begin
			insert into #colnames( idxcolname ) values( @thiskey )
			select @thiskey = index_col(@tabname, @indid, @i)
			select @i = @i + 1
		end
		if exists ( select idxcolname from #colnames 
                     where idxcolname not in
	                    (select name from syscolumns where id = object_id( @objname ) ) )
		begin
			select @tabid = 0
		end	
		drop table #colnames
	end
	else
	begin
		select @tabid = 0
	end
end
else 
begin
	select @tabname = @objname
	select @tabid = object_id( @objname )

	select @indid = indid, @indstat = status 
	    from sysindexes where id = @tabid and ( status & @type ) = @type
	if @indid is null
	begin
		select @tabid = 0
	end
end

-- Check for computed columns in chosen index. If computed columns exist,
-- don't return a load hint.
if @indid is not null
begin
    select @i = 1
    select @thiskey = index_col( @tabname, @indid, @i )
    while @thiskey is not null
    begin
        if isnull( columnproperty( @tabid, @thiskey, 'IsComputed' ), 0 ) = 1
        begin
            select @indid = null,
                   @tabid = 0
            break
        end
        select @i = @i + 1
        select @thiskey = index_col( @tabname, @indid, @i )
    end
end

if @tabid <> 0
begin
	select @hint = 'ORDER( '+QUOTENAME(index_col( @tabname, @indid, 1 )) collate database_default
	select @thiskey = index_col( @tabname, @indid, 2 ) 
	select @i = 3
	while (@thiskey is not null )
	begin
		select @hint = @hint + ',' + QUOTENAME(@thiskey) collate database_default
		select @thiskey = index_col(@tabname, @indid, @i)
		select @i = @i + 1
	end

	select @hint = @hint + ' ASC)'

	select @hint, @indstat
end
GO

EXEC dbo.sp_MS_marksystemobject sp_MSget_load_hint
go

grant execute on dbo.sp_MSget_load_hint to public
go

raiserror('Creating procedure sp_getsubscriptiondtspackagename', 0,1)
go
CREATE PROCEDURE sp_getsubscriptiondtspackagename (
    @publication sysname,
	@subscriber sysname = NULL
	 ) AS

    SET NOCOUNT ON

	declare @name sysname
	declare @name_full sysname
	declare @id	int
	
	select @id = 1
	select @name = @publication
	if @subscriber is not null
		select @name = @name + N'_' + @subscriber

	-- reserver space for numbers to make the name unique
	select @name = substring(@name, 1, 100)
	select @name_full = @name

	while (1=1)
	begin
		if not exists (select * from msdb.dbo.sysdtspackages where
			name = @name_full)
			break
		select @name_full = @name + '_' + convert(nvarchar(10), @id)
		select @id = @id + 1
	end
	select N'new_package_name' = @name_full
go

EXEC dbo.sp_MS_marksystemobject sp_getsubscriptiondtspackagename
go

grant execute on dbo.sp_getsubscriptiondtspackagename to public
go

raiserror('Creating procedure sp_MSverifytranfilter', 0, 1)
GO
create procedure sp_MSverifytranfilter @objid int
as
DECLARE @artname sysname
DECLARE @sync_objid int
DECLARE @qual_sync_object nvarchar(1024)

DECLARE #testcursor CURSOR LOCAL FAST_FORWARD for
	SELECT name, sync_objid from sysarticles
	WHERE  objid = @objid
	
open #testcursor
fetch #testcursor into @artname, @sync_objid
while @@fetch_status <> -1
begin
	select @qual_sync_object = quotename( user_name(objectproperty(@sync_objid,'OwnerId'))) collate database_default + N'.' + quotename(object_name(@sync_objid)) collate database_default

	exec ( N'declare @var int select @var = count(*) from '+ @qual_sync_object + N' where 0 = 1' )

	if @@ERROR<> 0
	BEGIN
		raiserror( 14090, 16, -1, @artname )
		return 1
	END
	fetch #testcursor into @artname, @sync_objid
end
close #testcursor
deallocate #testcursor
return 0
GO

EXEC dbo.sp_MS_marksystemobject sp_MSverifytranfilter
go


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

CREATE PROCEDURE sp_repldropcolumn(
    @source_object  	nvarchar(270),
	@column				sysname,
	@from_agent			int = 0, 
	@schema_change_script nvarchar(4000) = NULL,
	@force_invalidate_snapshot bit = 1,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */

	)
as

set nocount on
declare @objid			int
declare @at_publisher	bit
declare @pubname		sysname
declare @artname		sysname
declare @tran_pubname	sysname
declare @tran_artname	sysname
declare @tran_artid		int
declare @tran_pubid		int
declare @colid			int
declare @missing_index	int
declare @tablename		sysname
declare @pubid			uniqueidentifier
declare @artid			uniqueidentifier
declare @partitioned	int
declare @missing_count	int
declare @missing_bm		varbinary(32)
declare @old_missing_bm	varbinary(32)
declare @schematext		nvarchar(4000)
declare @schemaversion	int
declare @not_for_merge	bit
declare @qual_source_object nvarchar(262)
declare @qual_dest_object nvarchar(262)
declare @schematype		int
declare @schemaguid		uniqueidentifier
declare @conflict_table	sysname
declare @ins_conflict_proc sysname
declare @publisher		sysname
declare @publisher_db	sysname
declare @command		nvarchar(3000)
declare @sync_objid		int
declare @retcode 		int
declare @snapshot_ready int
declare @con_id			int
declare @dest_owner		sysname
declare @dest_object	nvarchar(386)
declare @owner			sysname
declare @columnbm		varbinary(128)
declare @in_partition	int
declare @merge_pub_object_bit	int
declare @is_for_merge	bit
declare @is_for_tran    bit
declare @no_schema_replication bit
declare @servername		sysname
declare @dbname			sysname
declare @con_name		sysname
declare @v_unique_index	int
declare @qual_column		nvarchar(140)
declare @indid				int
declare @index_cnt 			int
declare @pkkey				sysname
declare @v_unique_constraint	int
declare @merge_pub_unmarkcolumn_bit	int
declare @merge_pub_markcolumn_bit	int
declare @schema_start_lsn binary(10)
declare @schema_end_lsn binary(10)

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

-- check to see if this stored procedure is called via replication agent.
if sessionproperty('replication_agent')<>1
	select @from_agent = 0
else
	select @from_agent = 1
select @merge_pub_markcolumn_bit = 0x4000
select @merge_pub_unmarkcolumn_bit = ~@merge_pub_markcolumn_bit
select @v_unique_constraint = 4096
select @v_unique_index 	 = 2 		-- status in sysindexes

select @qual_column=QUOTENAME(@column)

select @no_schema_replication = 0
select @not_for_merge	= 0
select @merge_pub_object_bit 	= 128
select @objid = object_id(@source_object)
if @objid is null 
	select @objid = object_id(quotename(@source_object))
select @servername=@@SERVERNAME
select @dbname=db_name()

if @objid is NULL
begin
	--if table does not exists and the SP is called from replication agent, ignore the error and exit with success.
	if @from_agent=1
		return (0)
	else
		begin
			raiserror(14027, 16, -1, @source_object)
			return (1)
		end
end

if not exists (select * from syscolumns where name=@column and id=@objid)
begin
	if @from_agent=0
	begin
		raiserror(21166, 16, -1, @column)
		return (1)
	end
	else
		return (0)
end

select @indid = indid from sysindexes where id = @objid and (status & 2048) <> 0    /* PK index */
select @index_cnt = 1
while (@index_cnt <= 16)
begin
	select @pkkey = INDEX_COL(@source_object, @indid, @index_cnt)
	if @pkkey is NULL
		select @pkkey = INDEX_COL(quotename(@source_object), @indid, @index_cnt)
	if @pkkey is NULL
		break
	if @pkkey=@column
	begin
		raiserror(21264, 16, -1, @column, @source_object)
		return (1)
	end
	select @index_cnt = @index_cnt + 1
end
	
/*
** Check for unique index defined on this column - to disallow such a column from being dropped
*/	
if exists (select * from sysindexes where id=@objid 
	and (status & @v_unique_index = @v_unique_index 
			or status & @v_unique_constraint = @v_unique_constraint))
begin
	declare @keys varbinary(816)
	declare @i 		int
	declare #check_unique CURSOR LOCAL FAST_FORWARD for 
		select indid from sysindexes where id=@objid 
				and (status & @v_unique_index = @v_unique_index 
					or status & @v_unique_constraint = @v_unique_constraint)
	open #check_unique
	fetch #check_unique into @indid
	while (@@fetch_status<>-1)
	begin
		SELECT @i = 1
		WHILE (@i <= 16)
		BEGIN
			SELECT @pkkey = INDEX_COL(@source_object, @indid, @i)
			if @pkkey is NULL
				SELECT @pkkey = INDEX_COL(quotename(@source_object), @indid, @i)
			if @pkkey is NULL
				break
			if @pkkey=@column
			BEGIN
				raiserror(21265, 16, -1, @column, @source_object)
				close #check_unique
				deallocate #check_unique
				return (1)
			END
			select @i = @i + 1
		END	
		fetch #check_unique into @indid
	end
	close #check_unique
	deallocate #check_unique
end

if exists (select * from sysobjects where name='sysmergearticles')
begin
	if @from_agent=0 and exists (select * from sysmergearticles where objid=@objid and pubid not in 
		(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@@SERVERNAME) and publisher_db=db_name()))
	begin
		raiserror(21260, 16, -1, @dbname, @servername, @source_object)
		return (1)
	end
end

-- if not for TRAN, it has to be a merge publication
if not exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysmergearticles where objid=@objid)
		select @no_schema_replication = 1
end

-- if not for merge, it has to be a tran publication
if not exists (select * from sysobjects where name='sysmergepublications')
begin
	if not exists (select * from sysarticles where objid=@objid)
		select @no_schema_replication =1
end

if exists (select * from sysobjects where name='sysmergepublications')
	and exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysarticles where objid=@objid)
			and not exists (select * from sysmergearticles where objid=@objid)
		select @no_schema_replication=1
end

if @no_schema_replication=1
	begin
		raiserror(21246, 16, -1, @source_object)
		return (1)
	end

if exists (select * from sysobjects where name = 'sysmergearticles')
begin
	if exists  (select * from sysmergearticles where objid=@objid)
		select @is_for_merge=1
	else
		select @is_for_merge=0
end
else
	select @is_for_merge=0

-- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
-- END PARSENAME VARS

    select @UnqualName = PARSENAME(@source_object, 1)
	if @UnqualName is null 
	    select @UnqualName = PARSENAME(quotename(@source_object), 1)

    select @QualName1 = PARSENAME(@source_object, 2)
	if @QualName1 is null 
	    select @QualName1 = PARSENAME(quotename(@source_object), 2)

    if @UnqualName IS NULL
         return 1
	if @QualName1 is not NULL
		select @owner = @QualName1
			else select @owner=user_name(uid) from dbo.sysobjects where id = @objid

select @tablename = @UnqualName
select @qual_source_object = QUOTENAME(@owner) + N'.' + QUOTENAME(@tablename)
select @at_publisher = 0
select @colid=colid from dbo.syscolumns where id=@objid and name=@column
if @colid is NULL
	begin
		raiserror(21166, 16, -1, @column)
		return (1)
	end

/*
** Considering holes, colid is not necessarily the one in bitmap. Get this value from count(*)
*/
select @missing_index = @colid
begin TRAN
save tran sp_repldropcolumn
	if @is_for_merge=1
	begin
		exec sp_replupdateschema @qual_source_object
		if @@ERROR<>0
			goto FAILURE
		exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
		--unmark this column so that it can be dropped
		update dbo.syscolumns set colstat=colstat & @merge_pub_unmarkcolumn_bit where id=@objid and colid = @colid
		if @@ERROR<>0 
			goto FAILURE
	end


	select @is_for_tran = 0	
	if exists (select * from dbo.sysobjects where name='sysarticles')
	begin
		if exists (select * from dbo.sysarticles where objid=@objid)
		begin
			if exists (SELECT P.pubid FROM dbo.syspublications P, dbo.sysarticles A, dbo.syssubscriptions S 
					WHERE A.objid = @objid	and A.pubid = P.pubid and A.artid = S.artid
						and (P.allow_sync_tran = 1 or P.allow_queued_tran = 1) 
						and S.status = 2  -- active
						and S.sync_type != 2 -- not 'none'
						and S.update_mode != 0 ) -- not 'read only'
			 and @force_reinit_subscription = 0
			begin 
				raiserror(21381, 16, -1, @tablename)
				goto FAILURE
			end

			select @is_for_tran =1
			select pubid, artid, columns 
			    into #oldcols 
				from sysarticles
				where objid = @objid
		end
	end

	/*
	** First call TRAN Level stored procedure to 
	*/
	if @is_for_tran = 1
	begin
		exec @retcode = sp_MSprep_exclusive @qual_source_object
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		exec @retcode = sp_replincrementlsn @schema_start_lsn OUTPUT
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		exec @retcode = sp_replpostschema @objid
		if @@ERROR<>0 or @retcode <> 0
			goto FAILURE

		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name from sysarticles a, syspublications p where a.objid=@objid
					and p.pubid = a.pubid
		open #trancolumn
		fetch #trancolumn into @tran_artid, @tran_pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @tran_artname=name from sysarticles where artid=@tran_artid
			exec @retcode = sp_articlecolumn @publication = @tran_pubname, @article = @tran_artname, @column = @column, 
						 @operation = 'drop', @change_active = 2
						,@force_invalidate_snapshot = 1
						,@force_reinit_subscription = 1
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @tran_pubname			
		END
		close #trancolumn
		deallocate #trancolumn
	end

	if not exists (select * from sysobjects where name='sysmergearticles')
		select @not_for_merge = 1
	else
		if not exists (select * from sysmergearticles where objid=@objid)
			select @not_for_merge =1
	
			
	if @not_for_merge = 1 
	begin
		if exists (select * from syscolumns where name=@column and id =@objid)
		begin
			exec ('alter table '+ @qual_source_object + ' drop column ' + @qual_column )
					if @@ERROR<>0
						goto FAILURE
			
			exec @retcode = sp_MSverifytranfilter @objid
			if @@ERROR <> 0 or @retcode <> 0
			begin
				goto FAILURE
			end					
		end
	end
	else
	begin
		if exists (select * from sysmergepublications where pubid in 
			(select pubid from sysmergearticles where objid=@objid) and snapshot_ready=0)
			and exists (select * from syscolumns where name=@column and id =@objid)
			begin
				declare #nosnapshot CURSOR LOCAL FAST_FORWARD for
					select p.name, a.name from sysmergepublications p, sysmergearticles a 
						where p.pubid=a.pubid and a.objid=@objid and p.snapshot_ready=0
				open #nosnapshot
				fetch #nosnapshot into @pubname, @artname
				while (@@fetch_status<>-1)
				begin
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'drop', 'true'
					if @retcode <>0 or @@ERROR<>0
						goto ERROR_EXIT
					fetch #nosnapshot into @pubname, @artname
				end
				close #nosnapshot
				deallocate #nosnapshot
			end

		declare #dropcolumn_schema CURSOR LOCAL FAST_FORWARD fast_forward for 
				select name, pubid, artid, destination_owner, columns from sysmergearticles where objid=@objid and pubid
							in (select pubid from sysmergepublications where snapshot_ready>0) order by pubid ASC
		open #dropcolumn_schema
		fetch #dropcolumn_schema into @artname, @pubid, @artid, @dest_owner, @columnbm
		while (@@fetch_status <> -1)
		BEGIN
				if @dest_owner is not NULL
					select @dest_object = QUOTENAME(@dest_owner) + N'.' + QUOTENAME(@tablename)
				else
					select @dest_object = QUOTENAME(@tablename)

				exec @in_partition = sp_MStestbit @bm=@columnbm, @coltotest=@colid

				select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
					from sysmergepublications where pubid=@pubid
				select @at_publisher=0
				if @publisher=@@SERVERNAME and @publisher_db=db_name() and @in_partition<>0
				begin
					select @at_publisher=1
					select @schematext = 'exec sp_repldropcolumn ''' + @dest_object + ''', ''' + @column + ''', 1'
					select @schemaversion = schemaversion from sysmergeschemachange
					if (@schemaversion is NULL)
						set @schemaversion = 1
					else
						select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
					set @schemaguid = newid()
					set @schematype = 11 /* alter table */
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'drop', 'true'
					if @retcode<>0 or @@ERROR<>0
						goto INNER_FAIL2 -- need to deallocate cursor for this loop.
					exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
					if @@ERROR<>0 or @retcode<>0 
						goto INNER_FAIL2
						
					select @schematext = 'alter table ' +  @dest_object + ' drop column ' + @column 
					select @schemaversion = @schemaversion + 1
					set @schematype = 13 -- for Jet use only
					set @schemaguid = newid()
					exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext						
					if @@ERROR<>0 or @retcode<>0 
						goto INNER_FAIL2
				end
			fetch #dropcolumn_schema into @artname, @pubid, @artid, @dest_owner, @columnbm
		END
		close #dropcolumn_schema
		deallocate #dropcolumn_schema

        /* drop the column only once */
        if exists (select  *  from syscolumns where id=@objid and name=@column)
        begin
            select @command = 'alter table ' + @qual_source_object + ' drop column ' + @qual_column
            exec (@command)
            if @@ERROR<>0
                GOTO INNER_FAIL

            -- if transactionally replicated, verify that filter columns weren't dropped

            if( @is_for_tran = 1 )
            begin
                exec @retcode = sp_MSverifytranfilter @objid
                if @@ERROR <> 0 or @retcode <> 0
                begin
                    goto FAILURE
                end                    
            end
        end
        declare #dropcolumn CURSOR LOCAL FAST_FORWARD fast_forward for 
                select pubid, name, sync_objid, artid, missing_col_count, missing_cols, 
                    conflict_table, ins_conflict_proc from sysmergearticles where objid=@objid and pubid
                            in (select pubid from sysmergepublications where snapshot_ready>0) order by pubid ASC
        open #dropcolumn
        fetch #dropcolumn into @pubid, @artname, @sync_objid, @artid, 
                @missing_count, @missing_bm, @conflict_table, @ins_conflict_proc
        while (@@fetch_status <> -1)
        BEGIN                
            select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
                from sysmergepublications where pubid=@pubid
            select @at_publisher=0
            if @publisher=@@SERVERNAME and @publisher_db=db_name()
                select @at_publisher=1

            if @conflict_table is not NULL 
            begin
                declare @qual_conflict_table nvarchar(300)

                select @qual_conflict_table = quotename(user_name(uid)) + '.' + quotename(name) from dbo.sysobjects where name = @conflict_table
                select @con_id = object_id(@qual_conflict_table)
                if @con_id is NULL
                begin
                    raiserror(21286, 16, -1, @qual_conflict_table)
                    GOTO INNER_FAIL
                end

                select @colid=colid from syscolumns where id = @con_id and name=@column            
            
    
                if exists (select name from syscolumns where name=@column and id=@con_id)
                begin
                    select @command = 'alter table ' + @qual_conflict_table + ' drop column ' + @qual_column
                    exec (@command)
                    if @@ERROR<>0
                        goto INNER_FAIL
                end
            end

            /*
            ** Force the re-generation of conflict insert table cause the schema is changed for sure
            */
            if @ins_conflict_proc is not NULL and object_id(@ins_conflict_proc) is not NULL
            begin
                exec ('drop procedure ' + @ins_conflict_proc)
                if @@ERROR<>0
                    goto INNER_FAIL
                update sysmergearticles set ins_conflict_proc=NULL where pubid=@pubid and artid=@artid
                if @@ERROR<>0
                    goto INNER_FAIL
            end
    
            if @at_publisher=1
            begin
                exec @retcode = sp_MSpublicationview @publication = @pubname, @force_flag = 2, @articlename = @artname
                if @retcode<>0 or @@ERROR<>0
                begin
                    raiserror(21201, 16, -1) 
                    goto INNER_FAIL
                end
            end
            select @missing_count=@missing_count + 1
            select @old_missing_bm=@missing_bm
            exec @retcode=sp_MSsetbit @missing_bm OUTPUT, @missing_index
            if @retcode<>0 or @@ERROR<>0
                goto INNER_FAIL
            --if no change, that is, the column is already marked as missing, do not increase 
            --its count
            if @missing_bm<>@old_missing_bm
            begin
                update sysmergearticles set missing_col_count=@missing_count, missing_cols=@missing_bm
                    where pubid=@pubid and artid=@artid
                if @@ERROR<>0
                goto INNER_FAIL
            end
            
                
            exec @retcode = sp_MSdroparticletriggers @qual_source_object
            if @retcode<>0 or @@ERROR<>0
                goto INNER_FAIL
            exec @retcode = sp_MSaddmergetriggers @qual_source_object
            if @retcode<>0 or @@ERROR<>0
                goto INNER_FAIL
            exec @retcode = sp_MSsetartprocs @publication=@pubname, @article=@artname, @force_flag=1, @pubid = @pubid
            if @retcode<>0 or @@ERROR<>0
                goto INNER_FAIL
            /*
            ** passing in one more parameter to sp_MSgetconflictinsertproc such that there is 
            ** no select statement at the end of that SP as needed else where. The default is 1.
            */
            exec @retcode = sp_MSgetconflictinsertproc @artid, @pubid, 0
            if @retcode<>0 or @@ERROR<>0
                goto INNER_FAIL

            fetch #dropcolumn into @pubid, @artname, @sync_objid, @artid, 
                @missing_count, @missing_bm, @conflict_table, @ins_conflict_proc
        END
        CLOSE #dropcolumn
        DEALLOCATE #dropcolumn
	
		if @is_for_merge=1
		begin
			exec @retcode = sp_MSmarkreplinfo @tablename, @owner
			if @retcode<>0 or @@ERROR<>0
				goto FAILURE
		end
	end

-- finally, if it's transactional, trigger a reinit
if @is_for_tran = 1
begin

	if exists (select * from sysarticles where objid = @objid)
	begin
		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name 
			from sysarticles a, syspublications p, #oldcols oc
			where a.objid=@objid
			and p.pubid = a.pubid
			and oc.artid = a.artid
			and oc.columns <> a.columns

		open #trancolumn
		fetch #trancolumn into @tran_artid, @tran_pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @tran_artname=name, @tran_pubid = pubid, @owner = dest_owner, @tablename = dest_table from sysarticles where artid=@tran_artid
			if(@force_reinit_subscription = 0)
			begin 
				if(@owner is not NULL) and (len(@owner) > 0)
					select @qual_dest_object = QUOTENAME(@owner) + N'.' 
				else 
					select @qual_dest_object = N'' 
				if(@tablename is not null) and (len(@tablename) > 0)
					select @qual_dest_object = @qual_dest_object + QUOTENAME(@tablename)
				else 
					select @qual_dest_object = @qual_source_object
				exec @retcode = sp_MSrepl_schema @pubname = @tran_pubname 
							,@artid = @tran_artid
							,@qual_source_object = @qual_dest_object
							,@column = @column
							,@operation = 1 -- 0 is add, 1 is delete
							,@schema_change_script = @schema_change_script
				if @retcode <>0 or @@ERROR<>0
					goto DROPTRAN
			end
			exec @retcode = dbo.sp_MSreinit_article 
							@publication = @tran_pubname
							,@article = @tran_artname
							,@need_new_snapshot = @force_invalidate_snapshot
							,@need_reinit_subscription = @force_reinit_subscription
							,@force_invalidate_snapshot = @force_invalidate_snapshot
							,@force_reinit_subscription = @force_reinit_subscription
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @tran_pubname			
		END
		close #trancolumn
		deallocate #trancolumn
	 	exec @retcode = sp_replincrementlsn @schema_end_lsn OUTPUT
 		if @@ERROR<>0 or @retcode <> 0
	 		goto FAILURE
 		if (@schema_start_lsn is not null) and (@schema_end_lsn is not null)
	 	begin
 			insert systranschemas (tabid, startlsn, endlsn) values (@objid, @schema_start_lsn, @schema_end_lsn)
 			if @@ERROR<>0
	 			goto FAILURE
 			exec @retcode = sp_replflush @objid, @schema_start_lsn, @schema_end_lsn
 			if @@ERROR<>0 or @retcode <> 0
 				goto FAILURE
	 	end
 		else
 			goto FAILURE
	end
end


COMMIT TRAN
return (0)

DROPTRAN:
CLOSE #trancolumn
DEALLOCATE #trancolumn
GOTO FAILURE

INNER_FAIL:
CLOSE #dropcolumn
DEALLOCATE #dropcolumn
GOTO FAILURE

INNER_FAIL2:
CLOSE #dropcolumn_schema
DEALLOCATE #dropcolumn_schema
GOTO FAILURE


ERROR_EXIT:
CLOSE #nosnapshot
DEALLOCATE #nosnapshot

FAILURE:
	rollback tran sp_repldropcolumn
	commit tran
	raiserror(21284, 16, -1, @column, @source_object)
	return (1)	
go

exec dbo.sp_MS_marksystemobject sp_repldropcolumn 
go
grant execute on dbo.sp_repldropcolumn to public
go
raiserror('Creating procedure sp_repladdcolumn', 0,1)
GO

CREATE PROCEDURE sp_repladdcolumn(
    @source_object  		nvarchar (358),
	@column					sysname,
	@typetext 				nvarchar(3000),
	@publication_to_add		nvarchar(4000) = 'all',
	@from_agent				int = 0, 
	@schema_change_script	nvarchar(4000) = NULL,
	@force_invalidate_snapshot bit = 1,	/* Force invalidate existing snapshot */
	@force_reinit_subscription bit = 0	/* Force reinit subscription */
	)
as
set nocount on
declare @objid			int
declare @pubid			uniqueidentifier
declare @retcode		int
declare @partitioned	int
declare @at_publisher	bit
declare @pubname		sysname
declare @artname		sysname
declare @colid			int
declare @tablename		sysname
declare @artid			uniqueidentifier
declare @tran_artid		int
declare @tran_pubid		int
declare @schematext		nvarchar(4000)
declare @schemaversion	int
declare @schematype		int
declare @schemaguid		uniqueidentifier
declare @conflict_table	sysname
declare @ins_conflict_proc sysname
declare @publisher		sysname
declare @qual_column	nvarchar(140)
declare @not_for_merge	int
declare @publisher_db	sysname
declare @command		nvarchar(3000)
declare @sync_objid		int
declare @con_id			int
declare @owner			sysname
declare @dest_owner		sysname
declare @dest_object	nvarchar(386)
declare @merge_pub_object_bit	int
declare @is_for_merge	bit
declare @is_for_tran	bit
declare @dbname			sysname
declare @servername		sysname
declare @no_publication bit
declare @no_schema_replication bit
declare @qual_source_object nvarchar(362)
declare @len 			int
declare @prec 			int
declare @scale int
declare @typename nvarchar(270)
declare @qual_dest_object nvarchar(362)
declare @invalid_datatype	bit
declare @is_identity_or_timestamp bit
declare @xtype 		int
declare @iscomputed bit
declare @pass_to_heterogenious bit
declare @merge_pub_markcolumn_bit	int
declare @schema_start_lsn binary(10)
declare @schema_end_lsn binary(10)
declare @nickname 		int
declare @columns_in_partition	int
/*
** Security Check
*/
EXEC @retcode = dbo.sp_MSreplcheck_publish
IF @@ERROR <> 0 or @retcode <> 0
	return (1)


select @qual_column=QUOTENAME(@column)
select @merge_pub_markcolumn_bit = 0x4000

select @objid = object_id(@source_object)
if @objid is null
	select @objid = object_id(quotename(@source_object))


-- check to see if this stored procedure is called via replication agent.
if sessionproperty('replication_agent')<>1
	select @from_agent = 0
else
	begin --if table does not exists and the SP is called from replication agent, ignore the error and exit with success.
		select @from_agent = 1
		if @objid is NULL
			return (0)
	end

if @objid is NULL
begin
	raiserror(14027, 16, -1, @source_object)
	return (1)
end

if exists (select * from syscolumns where id=@objid and name=@column)
begin
	if @from_agent=0
	begin
		raiserror(21255, 16, -1, @column, @source_object)
		return (1)
	end
	else
		return (0)
end


-- PARSENAME VARS
	declare  	@UnqualName      sysname  --rightmost name node
	declare  	@QualName1       sysname  
-- END PARSENAME VARS

    select @UnqualName = PARSENAME(@source_object, 1)
	if @UnqualName is null 
	    select @UnqualName = PARSENAME(quotename(@source_object), 1)

    select @QualName1 = PARSENAME(@source_object, 2)
	if @QualName1 is null 
	    select @QualName1 = PARSENAME(quotename(@source_object), 2)
    if @UnqualName IS NULL
         return 1
	if @QualName1 is not NULL
		select @owner = @QualName1
			else select @owner=user_name(uid) from sysobjects where id = @objid
	select @tablename = @UnqualName

	select @qual_source_object = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename)
select @no_schema_replication = 0
select @no_publication=0
select @servername=@@SERVERNAME
select @dbname=db_name()
select @merge_pub_object_bit 	= 128
select @not_for_merge = 0

if exists (select * from sysobjects where name='sysmergearticles')
begin
	if @from_agent=0 and exists (select * from sysmergearticles where objid=@objid and pubid not in 
		(select pubid from sysmergepublications where LOWER(publisher)=LOWER(@servername) and publisher_db=@dbname))
	begin
		raiserror(21260, 16, -1, @dbname, @servername, @source_object)
		return (1)
	end
end

select @invalid_datatype=0

/* the transaction below is just an experiment to validate type text */
BEGIN TRAN
SAVE TRANSACTION fake_move
	exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
	if @retcode<>0 or @@ERROR<>0
	begin
		goto CHECKING_DONE
	end
	declare @temp_id 		int
	declare @temp_colid 	int
	select @is_identity_or_timestamp = 0
	exec ('alter table ' + @qual_source_object + ' add ' + @qual_column + ' ' + @typetext)
	select @temp_id = object_id(@qual_source_object)
	if @temp_id is NULL
	begin
		raiserror(21285, 16, -1, @column, @source_object)
		select @invalid_datatype = 1
		GOTO CHECKING_DONE
	end
	select @pass_to_heterogenious=0, @temp_colid = colid, @xtype=xtype, @iscomputed=iscomputed 
		from syscolumns where id = @temp_id and name=@column
	if @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'
		select @pass_to_heterogenious=1
	if COLUMNPROPERTY(@temp_id, @column, 'IsIdentity') = 1 or type_name(@xtype) = 'timestamp'
		select @is_identity_or_timestamp = 1
	if COLUMNPROPERTY(@temp_id, @column, 'IsIdentity') = 0
		and not exists (select * from syscolumns where id = @temp_id and name=@column and isnullable=1)
		and not exists (select * from sysconstraints where id=@temp_id and colid=@temp_colid and status & 5 = 5)
		and @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'  --not computed column nor timestamp column
	begin
		select @invalid_datatype = 1
	end
CHECKING_DONE:
ROLLBACK TRANSACTION fake_move
COMMIT TRAN
if @invalid_datatype = 1
	begin
		raiserror(21285, 16, -1, @column, @source_object)
		return (1)
	end
	
if exists (select * from sysobjects where id=@objid and replinfo & @merge_pub_object_bit <>0)
	select @is_for_merge = 1
else
	select @is_for_merge = 0
select @is_for_tran = 0
if not exists (select * from sysobjects where name='sysmergepublications') and
	not exists (select * from sysobjects where name='syspublications')
begin
	raiserror(21230, 16, -1)
	return (1)
end

create table #tmp_table (name sysname collate database_default)

if LOWER(@publication_to_add)='all' or LOWER(@publication_to_add)='[all]'
begin	
	select @publication_to_add = '%'
end
else 
begin
if charindex(',', @publication_to_add)<>0 --publication list
	begin
		declare @tmp_publist	nvarchar(4000)
		declare @total 			int
		declare @invalid_pub	sysname
		select @invalid_pub = NULL
			select @tmp_publist = @publication_to_add
		while @tmp_publist <> ''
		begin
			select @tmp_publist = LTRIM(@tmp_publist)
			select @total=len(@tmp_publist)
			select @len=charindex(',', @tmp_publist)
			if @len=0
				begin
					insert #tmp_table values(@tmp_publist)
					select @tmp_publist=''
				end
			else
				begin
					insert #tmp_table values(substring(@tmp_publist, 1, @len-1))
					select @tmp_publist = right(@tmp_publist, @total-@len)
				end
		end
		if exists (select * from sysobjects where name='sysmergepublications') and 
			exists (select * from sysobjects where name='syspublications')
			select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from sysmergepublications) and 
															name not in (select ('[' + name + ']') from syspublications)
		else 
			if exists (select * from sysobjects where name='sysmergepublications') 
				select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from sysmergepublications)			
			else
				if exists (select * from sysobjects where name='syspublications') 		
					select @invalid_pub=name from #tmp_table where name not in (select ('[' + name + ']') from syspublications)						
		if @invalid_pub is not NULL and @from_agent=0
		begin
			raiserror(21274, 16, -1, @invalid_pub)
			return (1)		
		end
	end
else 
	begin --single publication
		insert #tmp_table values(@publication_to_add)
		insert #tmp_table values('[' + @publication_to_add + ']')
	end
	
end



-- if not for TRAN, it has to be a merge publication
if not exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from sysmergepublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
		select @no_publication = 1

	if not exists (select * from sysmergearticles where objid=@objid and pubid in 
			(select pubid from sysmergepublications where name like @publication_to_add 
					or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication = 1
end

-- if not for merge, it has to be a tran publication
if not exists (select * from sysobjects where name='sysmergepublications')
begin
	if not exists (select * from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))) 
		select @no_publication = 1
		
	if not exists (select * from sysarticles where objid=@objid and pubid in 
			(select pubid from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication =1
end

if exists (select * from sysobjects where name='sysmergepublications')
	and exists (select * from sysobjects where name='syspublications')
begin
	if not exists (select * from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
			and not exists (select * from sysmergepublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table)))
		select @no_publication = 1

	if not exists (select * from sysarticles where objid=@objid and pubid in 
			(select pubid from syspublications where name like @publication_to_add 
				or (('[' + name + ']') in (select name from #tmp_table))))
		and not exists (select * from sysmergearticles where objid=@objid and pubid in 
			(select pubid from sysmergepublications where name like @publication_to_add 
					or (('[' + name + ']') in (select name from #tmp_table))))
		select @no_schema_replication=1
end

if @no_publication=1 and @publication_to_add <> '%' and LOWER(@publication_to_add)<>'none' and LOWER(@publication_to_add)<>'[none]'
	begin
		raiserror(21200, 16, -1, @publication_to_add)
		return (1)
	end

if @no_schema_replication=1 and LOWER(@publication_to_add)<>'none' and LOWER(@publication_to_add)<>'[none]'
	begin
		if @publication_to_add = '%'
			begin
				raiserror(21246, 16, -1, @source_object)
				return (1)
			end
		else
			begin
				raiserror(21245, 16, -1, @source_object, @publication_to_add)
				return (1)
			end
	end

select @at_publisher = 0

if exists (select * from sysobjects where name = 'sysarticles')
begin
	if exists (select a.objid from sysarticles a, syspublications p where a.objid=@objid
				and p.pubid = a.pubid
				and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0))
	begin
		select @is_for_tran = 1
	end
end

if (@is_for_tran =1 and @force_reinit_subscription = 0)
begin
	if (@is_identity_or_timestamp  = 1 )
	begin
		raiserror(21380, 16, -1)
		return (1)
	end
	if exists (SELECT P.pubid FROM dbo.syspublications P, dbo.sysarticles A, dbo.syssubscriptions S 
					WHERE A.objid = @objid	and A.pubid = P.pubid and A.artid = S.artid
						and (P.allow_sync_tran = 1 or P.allow_queued_tran = 1) 
						and S.status = 2  -- active
						and S.sync_type != 2 -- not 'none'
						and S.update_mode != 0 ) -- not 'read only'

	begin 
		raiserror(21381, 16, -1, @tablename)
		return (1)
	end
end

begin TRAN
save tran sp_repladdcolumn
	if @is_for_merge=1
	begin
		exec sp_replupdateschema @qual_source_object
 		if @@ERROR<>0
			goto FAILURE
		
		exec @retcode = sp_MSunmarkreplinfo @object=@tablename, @owner=@owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
	end
	if not exists (select * from sysobjects where name='sysmergearticles')
		select @not_for_merge = 1
	else
		if not exists (select * from sysmergearticles where objid=@objid)
			select @not_for_merge =1

	if @is_for_tran = 1
	begin
		if not exists (select * from syscolumns where name=@column and id =@objid)
		begin
			exec @retcode = sp_MSprep_exclusive @qual_source_object
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec @retcode = sp_replincrementlsn @schema_start_lsn OUTPUT
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec @retcode = sp_replpostschema @objid
			if @@ERROR<>0 or @retcode <> 0
				goto FAILURE
			exec ('alter table '+ @qual_source_object + ' add ' + @qual_column + ' ' + @typetext )
				if @@ERROR<>0
					goto FAILURE
		end
	end
	if @not_for_merge = 0
	begin		
		if  not exists (select * from syscolumns where name=@column and id =@objid)
			begin
				exec ('alter table '+ @qual_source_object + ' add ' + @qual_column + ' ' + @typetext )
				if @@ERROR<>0
					goto FAILURE
			end

		/*
		** whether the column is added to this publication, the articles whose underlying table contains
		** a new column will be regareded as vertically partitioned.
		*/ 
		update sysmergearticles set vertical_partition=1 where objid=@objid
		if @@ERROR<>0
			goto FAILURE

		/*
		** Heterogenious subscriber are not to receive computed column or timestamp columns
		*/
		declare #nosnapshot CURSOR LOCAL FAST_FORWARD for
			select p.name, a.name, a.pubid from sysmergepublications p, sysmergearticles a 
					where p.pubid=a.pubid and a.objid=@objid and p.snapshot_ready=0 and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0)
							and (p.sync_mode=0 or @pass_to_heterogenious=1)					
			open #nosnapshot
			fetch #nosnapshot into @pubname, @artname, @pubid
				while (@@fetch_status<>-1)
				begin
					exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'add', 'true'
					if @retcode <>0 or @@ERROR<>0
						goto ERROR_EXIT
					fetch #nosnapshot into @pubname, @artname, @pubid					
				end
		CLOSE #nosnapshot
		DEALLOCATE #nosnapshot
				
		
        /*
        ** Handle those cases where snapshot is already ran and new schema change needs to be added
        ** ; Heterogenious subscriber are not to receive computed column or timestamp columns
        */
        declare #addcolumn CURSOR LOCAL FAST_FORWARD fast_forward for 
                select pubid, name, sync_objid, artid, conflict_table, ins_conflict_proc, destination_owner
                    from sysmergearticles where objid=@objid and pubid
                        in (select pubid from sysmergepublications where snapshot_ready>0 
                            and (sync_mode=0 or @pass_to_heterogenious=1))
        open #addcolumn
        fetch #addcolumn into @pubid, @artname, @sync_objid, @artid, @conflict_table, @ins_conflict_proc, @dest_owner
        while (@@fetch_status <> -1)
        BEGIN
                if @dest_owner is not NULL
                    select @dest_object = QUOTENAME(@dest_owner) + '.' + QUOTENAME(@tablename)
                else
                    select @dest_object = QUOTENAME(@tablename)

                select @pubname=name, @publisher=publisher, @publisher_db=publisher_db
                    from sysmergepublications where pubid=@pubid

                if @conflict_table is not NULL 
                begin
                    declare @qual_conflict_table nvarchar(300)

                    select @qual_conflict_table = quotename(user_name(uid)) + '.' + quotename(name) from dbo.sysobjects where name = @conflict_table
                    select @con_id = object_id(@qual_conflict_table)
                    if @con_id is NULL
                    begin
                        raiserror(21286, 16, -1, @qual_conflict_table)
                        GOTO INNER_FAIL
                    end
                    
                    if not exists (select name from syscolumns where name=@column and id=@con_id) and (@pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0)
                    begin
                        select @typename = type_name(xtype), @len = length, @prec = COLUMNPROPERTY(id, name, 'precision'),
                                @scale = scale, @iscomputed=iscomputed, @xtype=xtype    
                            from syscolumns where name=@column and id=@objid
                        --we want to column property of 'computed' or 'timestamp' of the newly added column
                        if @iscomputed <> 1 and type_name(@xtype) <> 'timestamp'
                        begin
                            if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes 
                                select @len = @len/2
                            exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale
                            if @@error<>0 OR @retcode <>0 
                                GOTO INNER_FAIL
                            --doing so instead of using @typetext as we once did is that we do not want any constraint or identity properties 
                            --defined on conflict tables. Also it is safe to make the column NULLable in conflict tables.
                            select @command = 'alter table ' + @qual_conflict_table + ' add ' + @qual_column + ' ' + @typename + ' NULL '
                        end
                        else
                        --continue to use typetext when adding computed/timestamp column to the conflict tables.
                        begin
                            select @command = 'alter table ' + @qual_conflict_table + ' add ' + @qual_column + ' ' + @typetext                        
                        end
                        exec (@command)
                        if @@ERROR<>0
                        goto INNER_FAIL

                    end
                end
			
			/*
			** Force the re-generation of conflict insert table cause the schema is changed for sure
			*/
				if @ins_conflict_proc is not NULL and object_id(@ins_conflict_proc) is not NULL and (@pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0)
				begin
					exec ('drop procedure ' + @ins_conflict_proc)
					if @@ERROR<>0
						goto INNER_FAIL
					update sysmergearticles set ins_conflict_proc=NULL where pubid=@pubid and artid=@artid
					if @@ERROR<>0
						goto INNER_FAIL
				end

			/*
			** Force the regeneration of publication view for all publications that publish the current table.
			*/
				update sysmergearticles set vertical_partition=1 where artid=@artid and pubid=@pubid
				if @@ERROR<>0
					goto INNER_FAIL
			
				select @at_publisher=0
				if @publisher=@@SERVERNAME and @publisher_db=db_name()
				begin
					select @at_publisher=1
					if @pubname like @publication_to_add or charindex('[' + @pubname + ']', @publication_to_add)>0
					begin
						select @schematext = 'exec sp_repladdcolumn ''' + @dest_object + ''',''' + @column + ''','''+  replace(@typetext,'''', '''''') + ''', ''' + @publication_to_add + ''', 1'  
						select @schemaversion = schemaversion from sysmergeschemachange
						if (@schemaversion is NULL)
							set @schemaversion = 1
						else
							select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange        
						set @schemaguid = newid()
						set @schematype = 11 /* alter table */
						exec @retcode = sp_mergearticlecolumn @pubname, @artname, @column, 'add','true'
						if @retcode<>0 or @@ERROR<>0
							goto INNER_FAIL -- need to deallocate cursor for this loop.
						exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext
						if @@ERROR<>0 or @retcode<>0 
							goto INNER_FAIL
							
						--insert a schema change for Jet specifically subscribers	
						select @schematext = 'alter table ' +  @dest_object + ' add ' + @column + ' ' + @typetext
						select @schemaversion = @schemaversion + 1
						set @schematype = 13 -- for Jet use only
						set @schemaguid = newid()
						exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext						
						if @@ERROR<>0 or @retcode<>0 
							goto INNER_FAIL
					end
				end
	
				if @at_publisher=1
				begin
                    exec @retcode = sp_MSpublicationview @publication = @pubname, @force_flag = 2, @articlename = @artname
					if @retcode<>0 or @@ERROR<>0
						goto INNER_FAIL
				end

				select @columns_in_partition=count(*) from syscolumns where id = @sync_objid
				if @columns_in_partition>246
				begin
					raiserror('Failed to add column ''%s'' to table ''%s'' because there are too many columns in the partition', 16, -1,@column, @source_object)
					goto INNER_FAIL
				end
			
				exec @retcode = sp_MSdroparticletriggers @qual_source_object
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL
				exec @retcode = sp_MSaddmergetriggers @qual_source_object
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL

				/*
				** Force the regeneration of merge procs for all publications that publish the current table
				*/
					
				exec @retcode = sp_MSsetartprocs @publication=@pubname, @article=@artname, @force_flag=1, @pubid = @pubid
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL
		/*
		** passing in one more parameter to sp_MSgetconflictinsertproc such that there is 
		** no select statement at the end of that SP as needed else where. The default is 1.
		*/
				exec @retcode = sp_MSgetconflictinsertproc @artid, @pubid, 0
				if @retcode<>0 or @@ERROR<>0
					goto INNER_FAIL

				fetch #addcolumn into @pubid, @artname, @sync_objid, @artid, @conflict_table, @ins_conflict_proc, @dest_owner
		END
		close #addcolumn
		deallocate #addcolumn
	
		declare @column_tracking int
		select @column_tracking=column_tracking, @nickname=nickname from sysmergearticles where objid=@objid
		if @column_tracking = 1
		begin
			--make sure there is no colv overflow, which was not caught by 246 column restriction because
			--users keep adding/dropping column, which causes no increase in number of coumns but consume
			--colv slot cause we never release the slot when a column is dropped
			if exists (select * from MSmerge_contents where tablenick=@nickname and len(colv1)>2040)
			begin				
				raiserror(21418, 16, -1,@column, @source_object)
				goto INNER_FAIL
			end
			--apend an lineage slot for the new column. 
			update MSmerge_contents set 
				colv1=substring(colv1, 1, (datalength(colv1)-1)) + substring(colv1, 1, 4) + 0x01000000FF
					where tablenick=@nickname
			if @@ERROR<>0
				goto FAILURE
		end
	end

	if @is_for_tran = 1
	begin 
		declare #trancolumn CURSOR LOCAL FAST_FORWARD for 
			select a.artid, p.name from sysarticles a, syspublications p where a.objid=@objid
				and p.pubid = a.pubid
				and (p.name like @publication_to_add or charindex('[' + p.name + ']', @publication_to_add)>0)
		open #trancolumn
		fetch #trancolumn into @tran_artid, @pubname
		while (@@fetch_status <> -1)
		BEGIN
			select @artname = name, @tran_pubid = pubid, @owner = dest_owner, @tablename = dest_table from sysarticles where artid=@tran_artid
			exec @retcode = sp_articlecolumn @publication = @pubname, @article = @artname, @column = @column, 
							 @operation = 'add', @change_active = 2
							,@force_invalidate_snapshot = 1
							,@force_reinit_subscription = 1
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			if(@force_reinit_subscription = 0)	
			begin
				if(@owner is not NULL) and (len(@owner) > 0)
					select @qual_dest_object = QUOTENAME(@owner) + N'.' 
				else 
					select @qual_dest_object = N'' 
				if(@tablename is not null) and (len(@tablename) > 0)
					select @qual_dest_object = @qual_dest_object + QUOTENAME(@tablename)
				else 
					select @qual_dest_object = @qual_source_object
				exec @retcode = sp_MSrepl_schema @pubname = @pubname 
							,@artid = @tran_artid
							,@qual_source_object = @qual_dest_object
							,@column = @column
							,@operation = 0 -- 0 is add, 1 is delete
							,@typetext = @typetext
							,@schema_change_script = @schema_change_script
				if @retcode <>0 or @@ERROR<>0
					goto DROPTRAN
			end
			exec @retcode = dbo.sp_MSreinit_article 
							@publication = @pubname
							,@article = @artname
							,@need_new_snapshot = @force_invalidate_snapshot
							,@need_reinit_subscription = @force_reinit_subscription 
							,@force_invalidate_snapshot = @force_invalidate_snapshot
							,@force_reinit_subscription = @force_reinit_subscription
			if @retcode <>0 or @@ERROR<>0
				goto DROPTRAN
			fetch #trancolumn into @tran_artid, @pubname			
		END
		close #trancolumn
		deallocate #trancolumn
 		exec @retcode = sp_replincrementlsn @schema_end_lsn OUTPUT
 		if @@ERROR<>0 or @retcode <> 0
 			goto FAILURE
 		if (@schema_start_lsn is not null) and (@schema_end_lsn is not null)
 		begin
 			insert systranschemas (tabid, startlsn, endlsn) values (@objid, @schema_start_lsn, @schema_end_lsn)
 			if @@ERROR<>0
 				goto FAILURE
 			exec @retcode = sp_replflush @objid, @schema_start_lsn, @schema_end_lsn
 			if @@ERROR<>0 or @retcode <> 0
 				goto FAILURE
 		end
 		else
 			goto FAILURE
	end
	
	/* Get back to its original replication state */
	if @is_for_merge=1
	begin
		exec @retcode = sp_MSmarkreplinfo @tablename, @owner
		if @retcode<>0 or @@ERROR<>0
			goto FAILURE
		update syscolumns set colstat = colstat | @merge_pub_markcolumn_bit where id=@objid and name= @column
		if @@ERROR<>0
			goto FAILURE
	end

COMMIT TRAN
return (0)

INNER_FAIL:
CLOSE #addcolumn
DEALLOCATE #addcolumn
GOTO FAILURE

ERROR_EXIT:
CLOSE #nosnapshot
DEALLOCATE #nosnapshot
GOTO FAILURE

DROPTRAN:
CLOSE #trancolumn
DEALLOCATE #trancolumn

FAILURE:
	rollback tran sp_repladdcolumn
	commit tran
	raiserror(21285, 16, -1, @column, @source_object)
	return (1)	
go

exec dbo.sp_MS_marksystemobject sp_repladdcolumn 
go
grant execute on dbo.sp_repladdcolumn to public
go
EXEC dbo.sp_MS_marksystemobject sp_MSget_jobstate
GO

exec dbo.sp_MS_marksystemobject sp_MSunc_to_drive
go

exec dbo.sp_MS_marksystemobject sp_MSrepl_isdbowner
go

dump tran master with no_log
go

raiserror('Creating procedure sp_MSagent_access_check',0,1)
go
CREATE PROCEDURE sp_MSagent_access_check (
    @job_id         VARBINARY(16),
    @agent_type     sysname = NULL -- 'distribution' or 'merge', case insensitive
) AS

    DECLARE @retcode int
    DECLARE @count   int

    IF @agent_type IS NOT NULL
    BEGIN
        IF LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN (N'distribution', N'merge')
        BEGIN
            RAISERROR(21170, 16, -1)
            RETURN (1)
        END
    END

    SELECT @retcode = 0
    -- Create a list of owners of the subscriptions depending on the given 
    -- agent 
    CREATE TABLE #sub_owner_list (owner_name sysname collate database_default)

    -- Try querying the Transactional subscriptions for the owner 
    IF @agent_type IS NULL OR LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) = N'distribution'
    BEGIN

        IF EXISTS (SELECT * 
                     FROM sysobjects 
                    WHERE type in ('U', 'S') AND name = N'syssubscriptions')
        BEGIN
            INSERT INTO #sub_owner_list 
            SELECT DISTINCT login_name 
              FROM dbo.syssubscriptions 
             WHERE distribution_jobid = @job_id 
        END

        IF NOT EXISTS (SELECT * FROM #sub_owner_list) AND 
           @agent_type IS NOT NULL
        BEGIN
            RAISERROR(21167, 16, -1, 'Distribution')
            SELECT @retcode = 1
            GOTO FAILURE
        END 
    END

    IF (@agent_type IS NULL AND NOT EXISTS (SELECT * FROM #sub_owner_list)) OR
       LOWER(@agent_type collate SQL_Latin1_General_CP1_CS_AS) = N'merge' 
    BEGIN
        
        SELECT @count = COUNT(*)
          FROM sysobjects
         WHERE name IN (N'sysmergesubscriptions', N'MSmerge_replinfo')
        
        IF @count = 2        
        BEGIN
            INSERT INTO #sub_owner_list 
            SELECT DISTINCT sms.login_name 
              FROM dbo.MSmerge_replinfo mr
        INNER JOIN dbo.sysmergesubscriptions sms
                ON mr.repid = sms.subid
             WHERE mr.merge_jobid = @job_id
        END

        IF NOT EXISTS (SELECT * FROM #sub_owner_list) AND 
           @agent_type IS NOT NULL
        BEGIN
            RAISERROR(21167, 16, -1, 'Merge')
            SELECT @retcode = 1
            GOTO FAILURE
        END 
    END

    IF NOT EXISTS (SELECT * FROM #sub_owner_list) 
    BEGIN
        RAISERROR(21134, 16, -1)
        SELECT @retcode = 1
        GOTO FAILURE
    END

    IF suser_sname(suser_sid()) NOT IN (SELECT owner_name FROM #sub_owner_list) AND
       is_srvrolemember('sysadmin') <> 1 AND
       is_member('db_owner') <> 1
    BEGIN

        RAISERROR(21168, 16, -1)
        SELECT @retcode = 1
        GOTO FAILURE
    END

FAILURE:

    DROP TABLE #sub_owner_list
    RETURN @retcode

GO

EXEC dbo.sp_MS_marksystemobject sp_MSagent_access_check
GO

raiserror('Creating procedure sp_enableagentoffload',0,1)
go
CREATE PROCEDURE sp_enableagentoffload (
    @job_id         VARBINARY(16),
    @offloadserver  sysname = NULL,
    @agent_type     sysname = NULL -- 'distribution' or 'merge', case insensitive
    ) AS
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       NVARCHAR(300)

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

    EXEC @retcode = sp_MSreplcheckoffloadserver @offloadserver
    IF @retcode<>0 OR @@error<>0
        RETURN (1)

    EXEC @retcode = sp_MSagent_access_check @job_id = @job_id, 
                                            @agent_type = @agent_type

    IF @retcode <> 0
        RETURN @retcode        

    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distributiondb OUTPUT
    IF @retcode <> 0
        RETURN @retcode

    SELECT @distributor = RTRIM(@distributor)

    IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
    BEGIN 
        SELECT @distproc = @distributor + '.' + @distributiondb + 
                           '.dbo.sp_MSenableagentoffload'
    END
    ELSE
    BEGIN
        SELECT @distproc = @distributiondb + '.dbo.sp_MSenableagentoffload'
    END

    EXECUTE @retcode = @distproc 
                @job_id = @job_id,
                @offloadserver = @offloadserver

    RETURN @retcode
GO
EXEC dbo.sp_MS_marksystemobject sp_enableagentoffload
GO

print ''
print 'Creating procedure sp_disableagentoffload'
go
CREATE PROCEDURE sp_disableagentoffload (
    @job_id         VARBINARY(16),
    @offloadserver  sysname = NULL,
    @agent_type     sysname = NULL -- 'distribution' or 'merge', case insensitive
) AS
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       NVARCHAR(300)

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

    EXEC @retcode = sp_MSagent_access_check @job_id = @job_id, 
                                            @agent_type = @agent_type

    IF @retcode <> 0
        RETURN @retcode        
    
    EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
                                           @distribdb = @distributiondb OUTPUT

    IF @retcode <> 0
        RETURN @retcode

    SELECT @distributor = RTRIM(@distributor)

    IF LOWER(@@SERVERNAME) <> LOWER(@distributor)
    BEGIN 
        SELECT @distproc = @distributor + '.' + @distributiondb + 
                           '.dbo.sp_MSdisableagentoffload'
    END
    ELSE
    BEGIN
        SELECT @distproc = @distributiondb + '.dbo.sp_MSdisableagentoffload'
    END

    EXECUTE @retcode = @distproc 
                @job_id = @job_id,
                @offloadserver = @offloadserver

    RETURN @retcode
GO
EXEC dbo.sp_MS_marksystemobject sp_disableagentoffload
GO

print ''
print 'Creating procedure sp_getagentoffloadinfo'
go
CREATE PROCEDURE sp_getagentoffloadinfo (
    @job_id         VARBINARY(16)
) AS
    SET NOCOUNT ON
    DECLARE @retcode        INT
    DECLARE @distributor    sysname
    DECLARE @distributiondb sysname
    DECLARE @distproc       NVARCHAR(300)

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

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


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

    IF @retcode <> 0
        RETURN @retcode

    SELECT @distributor = RTRIM(@distributor)

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

    EXECUTE @retcode = @distproc 
                @job_id = @job_id

    RETURN @retcode
GO
EXEC dbo.sp_MS_marksystemobject sp_getagentoffloadinfo
GO

print ''
print 'Creating procedure sp_copysubscription'
go
CREATE PROCEDURE sp_copysubscription (
@filename nvarchar(260),
@temp_dir nvarchar(260) = NULL,
-- Directory contains temp files. If not specified, SQL
-- server default data directory will be used.
@overwrite_existing_file bit = 0
)
AS

    SET NOCOUNT ON

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


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

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

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

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

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

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

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

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

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

		end			

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

	if @overwrite_existing_file is null
		set @overwrite_existing_file = 0

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

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

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

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

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

	select @temp_db_name = 'repl_sub_restore_' + @guid_name

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

	return @retcode
go
EXEC dbo.sp_MS_marksystemobject sp_copysubscription
GO

print ''
print 'Creating procedure sp_attachsubscription'
go
CREATE PROCEDURE sp_attachsubscription (
@dbname	sysname,
@filename nvarchar(260),
@subscriber_security_mode		int = NULL,						/* 0 standard; 1 integrated */
@subscriber_login				sysname = NULL,
@subscriber_password			sysname = NULL
)
AS

    SET NOCOUNT ON

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

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

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

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

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

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

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

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


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

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

	select @copy_created = 1

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

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

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

    if isnull(is_srvrolemember('sysadmin'), 0) <> 0
    begin
        select @cmd = quotename(@dbname) + '.dbo.sp_changedbowner'
        exec @retcode = @cmd N'sa'
        if @retcode<>0 or @@error<>0
        begin
            select @retcode = 1
            goto Cleanup
        end
    end

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

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

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

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

	return @retcode
go
EXEC dbo.sp_MS_marksystemobject sp_attachsubscription
GO


print ''
print 'Creating procedure sp_MSrestore_sub_merge'
go
CREATE PROCEDURE sp_MSrestore_sub_merge (
	@subscriber_security_mode		int,						
	@subscriber_login				sysname,
	@subscriber_password			nvarchar(524)
	)
AS

    SET NOCOUNT ON
	declare @retcode 			int
	declare @detached 			int
	declare @attached 			int
    DECLARE @publisher 			sysname        /* Expression used in the cursor */
    DECLARE @publisher_db 		sysname     /* Expression used in the cursor */
    DECLARE @publication 		sysname      /* Expression used in the cursor */
    DECLARE @distributor		sysname        /* Expression used in the cursor */
    declare @subnickname		int
    declare @subid	 			uniqueidentifier
    declare @detached_subid		uniqueidentifier
	declare @subscriber_srvid 	int
	declare @subscriber_server	sysname
	declare @subscriber_db		sysname
	declare @enabled_for_syncmgr_int 	int
	declare @enabled_for_syncmgr nvarchar(5)
	declare @retention			int
	declare @retention_date   	datetime
    declare @pubid	 			uniqueidentifier
	declare	@distributor_security_mode	int						
	declare @distributor_login			sysname
	declare @distributor_password		nvarchar(524)
	declare	@publisher_security_mode	int						
	declare @publisher_login			sysname
	declare @publisher_password			nvarchar(524)

	-- Initialization
	select @retcode = 0
	select @detached = 3
	select @attached = 4
	select @subscriber_srvid = 0
	select @subscriber_db = db_name()

    IF EXISTS (SELECT * from sysmergepublications where
        allow_subscription_copy = 0)
    BEGIN
        RAISERROR (21205, 16, -1, @publication)    
        RETURN (1)
    END

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

	-- Touch up system tables for merge subscriptions

	-- Open a cursor for all subscriptions 
	DECLARE hCallsubscriptions CURSOR LOCAL FAST_FORWARD FOR
		SELECT subid, subscriber_server from sysmergesubscriptions
	FOR READ ONLY
	OPEN hCallsubscriptions

	FETCH hCallsubscriptions INTO @subid, @subscriber_server
	WHILE (@@fetch_status <> -1)
	BEGIN
		/*
		** Validate that the subscriber is a valid server and has an entry in sysservers, else add it
		*/
		select @subscriber_srvid = NULL
		select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber_server) collate database_default
	    IF @subscriber_srvid IS NULL
			BEGIN
			    EXECUTE @retcode = dbo.sp_addserver @subscriber_server
		        IF @@error <> 0 OR @retcode <> 0
	    			BEGIN
			    		RAISERROR (14010, 16, -1)
				       	RETURN (1)
		            END
	        	select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber_server) collate database_default
			    IF @subscriber_srvid IS NULL
	    			BEGIN
			    		RAISERROR (14010, 16, -1)
				       	RETURN (1)
		            END
			END

	
		FETCH hCallsubscriptions INTO @subid, @subscriber_server
	END

	/*
	** Touch up srvid of existing rows in sysmergesubscriptions that correspond
	** to the subscription that is not attached. Note that this has to be a bulk 
	** update since doing it a row at a time will cause the unique_pubsrvdb constaint
	** in sysmergesubscriptions to be violated.
	*/
	update sysmergesubscriptions 
		set srvid = fn_serverid(subscriber_server)
			where status <> @detached
	if @@ERROR <> 0
		goto Cleanup
			

	-- Open a cursor for all subscriptions that have a status of 'detached'
	DECLARE hCdetachedsubscriptions CURSOR LOCAL FAST_FORWARD FOR
		SELECT subid from sysmergesubscriptions where status = @detached 
	FOR READ ONLY
	OPEN hCdetachedsubscriptions

	FETCH hCdetachedsubscriptions INTO @detached_subid
	WHILE (@@fetch_status <> -1)
	BEGIN
		/*
		** Select the srvid of the local server
		*/
		select @subscriber_srvid = 0

		/* Generate a guid for the Subscriber ID */
		set @subid = newid()

		/* Look for existing nickname from any other subscription */
		exec dbo.sp_MSgetreplnick NULL, NULL , NULL,  @subnickname out
		if @@ERROR <> 0
			goto Cleanup

		/* Generate a new replica nickname from the @subid */
		if (@subnickname is null)
			begin
				EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output
				if @@ERROR <> 0
					goto Cleanup
			end						

		/*
		** Touch up existing rows in sysmergesubscriptions & MSmerge_replinfo.
		** Set status of attached subsription as "attached"
		*/
		update sysmergesubscriptions 
			set subid 				= @subid, 
				srvid 				= @subscriber_srvid, 
				subscriber_server 		= @@servername,
				db_name 			= @subscriber_db, 
				status 				= @attached,
				login_name 			= suser_sname(suser_sid())
			where subid = @detached_subid
		if @@ERROR <> 0
			goto Cleanup
			
		update MSmerge_replinfo set repid = @subid, 
			replnickname = @subnickname 
				where repid = @detached_subid
		if @@ERROR <> 0
			goto Cleanup
	
		FETCH hCdetachedsubscriptions INTO @detached_subid 
	END

	/* Add pull subscription agents only if MSsubscription_properties exists */
	if exists (select * from sysobjects where name = 'MSsubscription_properties')
		begin			
			-- Add the agents for pull or anonymous subscriptions.
			DECLARE hCmergesubscription CURSOR LOCAL FAST_FORWARD FOR
				SELECT publisher, publisher_db, publication, distributor, enabled_for_syncmgr,
					distributor_security_mode, distributor_login, distributor_password,
					publisher_security_mode, publisher_login, publisher_password
					FROM MSsubscription_properties
					-- only do this for merge subscriptions 
					where publication_type = 2
					--where publication is not NULL and
					--	publication <> N'' and
					--	subscription_type <> @push
			FOR READ ONLY
			OPEN hCmergesubscription

			FETCH hCmergesubscription INTO @publisher, 
				@publisher_db, @publication, @distributor, @enabled_for_syncmgr_int,
				@distributor_security_mode, @distributor_login, @distributor_password,
				@publisher_security_mode, @publisher_login, @publisher_password

			WHILE (@@fetch_status <> -1)
			BEGIN
			    /* Enable the subscription to be synchronized via SyncMgr if the original one was */
				if @enabled_for_syncmgr_int = 0
					set @enabled_for_syncmgr = 'false'
				else
					set @enabled_for_syncmgr = 'true'

				if @distributor_security_mode = 0 and @distributor_login is NULL
					select @distributor_login = 'sa'

				if @publisher_security_mode = 0 and @publisher_login is NULL
					select @publisher_login = 'sa'


				EXEC @retcode = master.dbo.xp_repl_help_connect @distributor_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					select @retcode = 1
					goto Cleanup
				end

				EXEC @retcode = master.dbo.xp_repl_help_connect @publisher_password OUTPUT
				IF @@error <> 0 OR @retcode <> 0
				begin
					select @retcode = 1
					goto Cleanup
				end

				EXECUTE @retcode  = dbo.sp_addmergepullsubscription_agent 
					@publisher = @publisher, 
					@publisher_db = @publisher_db, 
					@publication = @publication,
					@distributor = @distributor,
					@subscriber_security_mode = @subscriber_security_mode,	
					@subscriber_login = @subscriber_login,
					@subscriber_password = @subscriber_password,
					@publisher_security_mode = @publisher_security_mode,	
					@publisher_login = @publisher_login,
					@publisher_password = @publisher_password,
					@publisher_encrypted_password = 0,
					@distributor_security_mode = @distributor_security_mode,	
					@distributor_login = @distributor_login,
					@distributor_password = @distributor_password,
					@encrypted_password = 0,
				    @frequency_type  = 2 ,  /* 2== OnDemand */
				    @enabled_for_syncmgr = @enabled_for_syncmgr,	
					@reserved = 'attach_subscription'

				if @@error <> 0 or @retcode <> 0 
				begin
					select @retcode = 1
					goto Cleanup
				end

				FETCH hCmergesubscription INTO @publisher, 
					@publisher_db, @publication, @distributor, @enabled_for_syncmgr_int,
					@distributor_security_mode, @distributor_login, @distributor_password,
					@publisher_security_mode, @publisher_login, @publisher_password
			END
		end			
	else
		begin
			/* 
			** Check to see if MSsubscription_properties table exists.
			** If not, create it.
			*/
			exec @retcode = dbo.sp_MScreate_sub_tables
				@tran_sub_table = 0,
				@property_table = 1,
				@sqlqueue_table = 0
			if @@error <> 0 or @retcode <> 0 
			begin
				select @retcode = 1
				goto Cleanup
			end
		end
	return 0
Cleanup:
	return	1
    
go
EXEC dbo.sp_MS_marksystemobject sp_MSrestore_sub_merge
GO


 
print ''
print 'Creating procedure sp_MSrestore_sub_tran'
go
CREATE PROCEDURE sp_MSrestore_sub_tran (
	@subscriber_security_mode		int,						
	@subscriber_login				sysname,
	@subscriber_password			nvarchar(524)
	)
AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @push int
	declare @retcode int
    DECLARE @publisher sysname          /* Expression used in the cursor */
    DECLARE @publisher_db sysname     /* Expression used in the cursor */
    DECLARE @publication sysname      /* Expression used in the cursor */

	-- Initialization
	select @push = 0
	select @retcode = 0


	-- Reset agent_id and anonymous agent id and time
	update MSreplication_subscriptions set agent_id = NULL, subid = NULL,
		distribution_agent = NULL, time = getdate()
	if @@error <> 0
	begin
		select @retcode = 1
		goto Cleanup
	end

	-- Set attach_state value
	-- It is only used by pull subscription.
	-- The attach state is "attached but not processed".
	update MSsubscription_agents set attach_state = 1

	-- Add the agents for pull or anonymous subscriptions. 
	DECLARE hCsubscription CURSOR LOCAL FAST_FORWARD FOR
		SELECT publisher, publisher_db, publication    
			FROM MSreplication_subscriptions where 
				publication is not NULL and
				publication <> N'' and
				subscription_type <> @push
	FOR READ ONLY
	OPEN hCsubscription

	FETCH hCsubscription INTO @publisher, 
		@publisher_db, @publication
	WHILE (@@fetch_status <> -1)
	BEGIN
		EXECUTE @retcode  = dbo.sp_addpullsubscription_agent 
			@publisher = @publisher, 
			@publisher_db = @publisher_db, 
			@publication = @publication, 
			@subscriber_security_mode = @subscriber_security_mode,	
			@subscriber_login = @subscriber_login,
			@subscriber_password = @subscriber_password,
		    @frequency_type  = 2 ,  /* 2== OnDemand */
			@reserved = 'no_change_to_properties'

		if @@error <> 0 or @retcode <> 0 
		begin
			select @retcode = 1
			goto Cleanup
		end

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

Cleanup:
	-- Nothing to cleanup
	return	@retcode
go
EXEC dbo.sp_MS_marksystemobject sp_MSrestore_sub_tran
GO

print ''
print 'Creating procedure sp_MSrestore_sub'
go
CREATE PROCEDURE sp_MSrestore_sub (
	@subscriber_security_mode		int,						
	@subscriber_login				sysname,
	@subscriber_password			nvarchar(524)
	)
AS

    SET NOCOUNT ON

    /*
    ** Declarations.
    */
	declare @retcode int

	-- Initialization
	select @retcode = 0

	if exists (select * from sysobjects where name = 'MSreplication_subscriptions')
	begin
		exec @retcode = dbo.sp_MSrestore_sub_tran
			@subscriber_security_mode = @subscriber_security_mode,	
			@subscriber_login = @subscriber_login,
			@subscriber_password = @subscriber_password

		if @@error <> 0 or @retcode <> 0
		begin
			select @retcode = 1
			goto Cleanup
		end
	end
	if exists (select * from sysobjects where name = 'sysmergesubscriptions')
	begin
		exec @retcode = dbo.sp_MSrestore_sub_merge
			@subscriber_security_mode = @subscriber_security_mode,	
			@subscriber_login = @subscriber_login,
			@subscriber_password = @subscriber_password
		if @@error <> 0 or @retcode <> 0
		begin
			select @retcode = 1
			goto Cleanup
		end
	end

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

	return	@retcode
go
EXEC dbo.sp_MS_marksystemobject sp_MSrestore_sub
GO


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

CREATE PROCEDURE sp_validatemergepullsubscription
	(@publication			sysname,
	 @publisher				sysname,
	 @publisher_db			sysname,
	 @level					tinyint
	 ) AS

	declare @subscriber_srvid		int
	declare @retcode				int
	declare @pubid					uniqueidentifier
	declare @subscriber				sysname
	declare @subscriber_db			sysname
	/*
	** Security Check
	*/
    EXEC @retcode = dbo.sp_MSreplcheck_publish
    IF @@ERROR <> 0 or @retcode <> 0
        return (1)

	select @subscriber = @@SERVERNAME, @subscriber_db=db_name()
	select @subscriber_srvid = srvid from master..sysservers where LOWER(srvname)=LOWER(@subscriber) collate database_default

	select @pubid=pubid from sysmergepublications where LOWER(publisher)=LOWER(@publisher) and publisher_db=@publisher_db and name=@publication
	if @pubid is NULL
        begin
            raiserror (20026, 16, -1, @publication)
            return (1)
        end
	if @level <0 or @level > 3
		begin
			raiserror(21184, 16, -1, '@level', '1', '2','3')
			return (1)
		end

	if not exists (select * from sysmergesubscriptions where pubid=@pubid and db_name=@subscriber_db and srvid=@subscriber_srvid)
		begin
			raiserror(14055, 16, -1)
			return (1)
		end

	update sysmergesubscriptions set validation_level=@level where pubid=@pubid and db_name=@subscriber_db and srvid=@subscriber_srvid
	if @@ERROR<>0
		return (1)
	return (0)

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


print ''
print 'Creating procedure sp_MSprepare_sub_for_detach'
go
CREATE PROCEDURE sp_MSprepare_sub_for_detach 
	@subscriber_srvid 	int,
	@subscriber_db	  	sysname
as
	set nocount on
	declare @detached 	int
	select @detached = 3
	
	-- Stage: attach and restore subscription.
	update dbo.MSreplication_restore_stage set stage_id = 2
	if @@error <> 0
		return 1

	/* Touch up the merge subscriptions for detach */
	if exists (select * from sysobjects where name = 'sysmergesubscriptions')
	begin			
		/* Mark all subscriptions to have a status of detached */
		update sysmergesubscriptions set status = @detached where srvid = @subscriber_srvid and db_name = @subscriber_db
		if @@error <> 0
			return 1
	end		
	if exists (select * from sysobjects where name = 'MSsub_identity_range')
	begin
		-- Set range to 0 so that the attached db will get new ranges
		-- Refer to sp_MSsub_check_identity
		update MSsub_identity_range set range = 0
		if @@error <> 0
			return 1
	end	
go
EXEC dbo.sp_MS_marksystemobject sp_MSprepare_sub_for_detach
GO

print ''
print 'Creating procedure sp_MSsub_check_identity'
go
CREATE PROCEDURE sp_MSsub_check_identity
@lower_bound_id int
as
	declare @retcode int
	declare @cmd nvarchar(1000)
	declare @objid int, @threshhold bigint, @range bigint, @next_seed bigint
	declare	@last_seed bigint, @identity_so_far bigint, @threshold int
	declare @table_name sysname
	declare @qualname nvarchar(512)

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

	-- This proc will be called by distribution agent called repeatedly until
	-- one result returned
	if exists (select * from sysobjects where name = 'MSsub_identity_range')
	begin
		while 1 = 1
		begin
			select @objid = null
			select top 1 @objid = objid from MSsub_identity_range where
				objid > @lower_bound_id 
				order by objid ASC
			if @objid is null
				break

            select @lower_bound_id = @objid
			-- Since we don't always clean up the subscriber, Skipping invalid entry.
			if object_name(@objid) is null 
				continue
			if objectproperty(@objid, 'TableHasIdentity') <> 1
				continue

		    exec sp_MSget_qualified_name @objid, @qualname OUTPUT

			select @range = range, @last_seed = last_seed, @threshold = threshold from 
				MSsub_identity_range where objid=@objid
				
			if @range = 0
				-- First time after initial bcp, always request a new range
				-- return this object
				break
			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 @range > 0
					select @actual_range = @range - 1
				else
					select @actual_range = @range + 1

				select @identity_so_far = ident_current(@qualname)

				if 100*(@identity_so_far - @last_seed)/@actual_range >= @threshold
					-- Need new range
					break
			end

			select @lower_bound_id = @objid
		end
	end
	select @table_name = object_name(@objid)			

	-- Return nothing if @table_name is null, which means no more table needs to be adjust
	select 'objid' = @objid, 'table_name' = @table_name where @objid is not null	
go
EXEC dbo.sp_MS_marksystemobject sp_MSsub_check_identity
GO

print ''
print 'Creating procedure sp_MSsub_cleanup_orphans'
go
CREATE PROCEDURE sp_MSsub_cleanup_orphans AS


	/*
    ** Security Check
    */
    -- Internal sp, not granted to public.
    -- Ignore all errrors

   	if exists (select * from sysobjects where name = 'MSreplication_objects')
    begin
        delete MSreplication_objects where not exists (select * from sysobjects
            where name = object_name)
        if not exists (select * from MSreplication_objects)
            drop table MSreplication_objects
    end
            
   	if exists (select * from sysobjects where name = 'MSsub_identity_range')
    begin
        delete MSsub_identity_range where not exists (select * from sysobjects
            where id = objid)
        if not exists (select * from MSsub_identity_range)
            drop table MSsub_identity_range
    end
GO
EXEC dbo.sp_MS_marksystemobject sp_MSsub_cleanup_orphans
GO

print ''
print 'Creating procedure sp_MSsub_cleanup_prop_table'
go
CREATE PROCEDURE sp_MSsub_cleanup_prop_table AS


	/*
    ** Security Check
    */
    -- Internal sp, not granted to public.
    -- Ignore all errrors
	declare @drop_table bit

	-- Init to drop table
	select @drop_table = 1

   	if exists (select * from sysobjects where name = 'MSreplication_subscriptions')
    begin
        if exists (select * from MSreplication_subscriptions where 
			subscription_type <> 0)
			select @drop_table = 0
    end
            
   	if exists (select * from sysobjects where name = 'sysmergesubscriptions')
    begin
		if exists (select * from sysmergesubscriptions where subid <> pubid and 
			db_name = db_name() and 
			subscriber_server = convert(sysname, SERVERPROPERTY('ServerName')) collate database_default and
			subscription_type <> 0)
			select @drop_table = 0
    end

	if @drop_table = 1
		drop table dbo.MSsubscription_properties
 GO
EXEC dbo.sp_MS_marksystemobject sp_MSsub_cleanup_prop_table
GO

print ''
print 'Creating procedure sp_MSreseed'
go

CREATE PROCEDURE sp_MSreseed(
@objid				int,
@next_seed			bigint,
@range 				bigint,
@is_publisher		int = 0,
@check_only         bit = 0,
@drop_only			bit = 0,
@initial_setting 	bit = 0,
@bound_value		bigint = 0
)
AS
declare @min_value				bigint
declare @max_value				bigint
declare @constraintname			sysname
declare @artid					uniqueidentifier
declare @min_str				nvarchar(20)
declare @identity_column		sysname
declare @colid					int
declare @colname				sysname
declare @max_str				nvarchar(20)
declare @owner					sysname
declare @tablename				sysname
declare @qualname				nvarchar(270)
declare @dbname					sysname
declare @prefix					sysname

SET NOCOUNT ON
	select @prefix = 'repl_identity_range_'
	select @colid=1
	select @dbname=db_name()
	select @colname=name from syscolumns where colid=@colid and id = @objid
	while COLUMNPROPERTY(@objid, @colname, 'IsIdentity')=0 and @colname is not NULL
	begin
		select @colid = @colid + 1
		select @colname=name from syscolumns where colid=@colid and id = @objid
	end
	if @colname is NULL
	begin
		raiserror('there is no identity column in this table', 16, -1)
		return (1)
	end
    if @range > 0
    begin 
	    select @min_value = @next_seed 
	    if @initial_setting = 1
				    select @min_value = @bound_value - 1 -- allow for race condition with ident_current. 	    	
        -- @next_seed + @range can be used by this db, but not other db.
	    -- 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.
		-- select @max_value = @next_seed + @range + 1
	    select @max_value = @next_seed + @range
		select @next_seed=@next_seed + 1
    end
    else
    begin
	    select @max_value = @next_seed 
	    if @initial_setting = 1
				    select @max_value = @bound_value + 1 -- allow for race condition with ident_current. 	    		    
        -- @next_seed + @range can be used by this db, but not other db.
	    -- 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.
	    -- select @min_value = @next_seed + @range - 1
	    select @min_value = @next_seed + @range
		select @next_seed=@next_seed - 1
    end

	select @min_str = convert(nvarchar, @min_value)
	select @max_str = convert(nvarchar, @max_value)
	select @owner = user_name(uid) from sysobjects where id = @objid
	select @tablename = object_name(@objid)
	select @qualname = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename)

    if @check_only = 0
    begin 
	    DBCC CHECKIDENT(@qualname, RESEED, @next_seed) with no_infomsgs
	    if @@ERROR<>0
			    return (1)
    end

	if @is_publisher < 0
    begin
        -- Used by tran
		-- Publisher side constraint maybe transfered to subscriber.
		-- If so, it will be dropped with code below.
		select @constraintname = NULL
  		select @constraintname = name from sysobjects where name like @prefix + 'tran_[0-9]%' and 
			xtype='C' and
			parent_obj = @objid
		if @constraintname is not null
		begin
			exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
			if @@ERROR<>0
				return (1)
		end
  		select @constraintname = @prefix + 'tran_' + convert(nvarchar(10), @objid)
    end
	else
    begin 
        -- Used by merge
	    select @artid=artid from dbo.sysmergearticles where objid=@objid
		select @constraintname = @prefix + 'pub_' + convert(nvarchar(36), @artid)
		select @constraintname = REPLACE(@constraintname, '-', '_')
		if exists (select * from sysobjects where name = @constraintname and xtype='C')
		begin
			exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
			if @@ERROR<>0
				return (1)
		end
		select @constraintname = @prefix + 'repub_' + convert(nvarchar(36), @artid)
		select @constraintname = REPLACE(@constraintname, '-', '_')
		if exists (select * from sysobjects where name = @constraintname and xtype='C')
		begin
			exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
			if @@ERROR<>0
				return (1)
		end
	    select @constraintname = @prefix + 'sub_' + convert(nvarchar(36), @artid)
		select @constraintname = REPLACE(@constraintname, '-', '_')
		if exists (select * from sysobjects where name = @constraintname and xtype='C')
		begin
			exec ('alter table '+ @qualname + ' drop constraint ' + @constraintname)
			if @@ERROR<>0
				return (1)
		end    
		if @is_publisher=1
			select @constraintname = @prefix + 'pub_' + convert(nvarchar(36), @artid)
		else 
			if @is_publisher = 2
				select @constraintname = @prefix + 'repub_' + convert(nvarchar(36), @artid)
			else
			    select @constraintname = @prefix + 'sub_' + convert(nvarchar(36), @artid)
		select @constraintname = REPLACE(@constraintname, '-', '_')
	end

	-- Don't add new constraint if only drop is needed.
	if @drop_only = 1
		return (0)

    declare @qualcolname sysname
    select @qualcolname = quotename(@colname)

	exec ('alter table '+ @qualname + ' with NOCHECK add CONSTRAINT ' + @constraintname + ' check NOT FOR REPLICATION ( ' + @qualcolname + ' > ' 
		+ @min_str + ' and ' + @qualcolname + ' < ' + @max_str + ')')
	if @@ERROR<>0
		return (1)
	return (0)
GO
EXEC dbo.sp_MS_marksystemobject sp_MSreseed
GO

print ''
print 'Creating procedure sp_MSsub_set_identity'
go
CREATE PROCEDURE sp_MSsub_set_identity
@objid int,
@threshold int,
@range bigint,
@next_seed bigint
as
	declare @retcode int

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

    -- Stored last_seed in @next_seed
    select @next_seed = @next_seed - @range

	update MSsub_identity_range set 
		last_seed = @next_seed,
		threshold = @threshold,
		range = @range
		where objid = @objid
	IF @@ERROR <> 0
		return 1
	-- RESEED and change constraint
	exec @retcode = dbo.sp_MSreseed
		@objid = @objid,
		@next_seed = @next_seed,
		@range = @range,
		@is_publisher = -1
	IF @@ERROR <> 0 OR @retcode <> 0
		return 1
go
EXEC dbo.sp_MS_marksystemobject sp_MSsub_set_identity
GO

print ''
print 'Creating procedure sp_MSinstance_qv'
go
create procedure sp_MSinstance_qv @qv varchar(10)
as
begin
	declare @qv_value varchar(10)
	set nocount on
	-- -------------------------------------------------------------
	--
	-- BUGBUG 236535 : IA64 workaround
	--
	-- since xp_qv has not been ported yet - detect the
	-- the platform and preset the config for IA64 servers
	--
	-- NOTE : this code should be later cleaned up
	-- once SETUP is completely functional on IA64
	--
	-- -------------------------------------------------------------
	declare @fia64 bit
	
	create table #tosversion ( propid int, propname sysname collate database_default, value int null, charvalue nvarchar(255) collate database_default)
	insert into #tosversion (propid, propname, value, charvalue)
		exec master.dbo.xp_msver N'Platform'
	
	select @fia64 = case when patindex(N'%IA64%', charvalue) != 0 then 1 else 0 end
	from #tosversion

	if (@fia64 = 1)
	begin
		select @qv_value = 0
	end
	else
	begin
		if serverproperty('instancename') is null
			exec @qv_value = master.dbo.xp_qv @qv	
	    else
		begin
			declare @instance_name varchar(257)
			select @instance_name = cast(serverproperty('instancename') as varchar(257))
			exec @qv_value = master.dbo.xp_qv @qv, @instance_name
		end
	end
	-- -------------------------------------------------------------
	return @qv_value
end
go
EXEC dbo.sp_MS_marksystemobject sp_MSinstance_qv
GO

print ''
print 'Creating procedure sp_MSget_shared_agent'
go
CREATE PROCEDURE sp_MSget_shared_agent (
    @server_name sysname,
    @database_name sysname,
	@agent_type int,
	@publisher sysname = NULL -- Only usec by third party.
	,@publisher_db sysname = NULL -- Only usec by third party.
	) AS

	declare @server_id smallint
	select @server_id = srvid from master..sysservers where
		UPPER(srvname) = UPPER(@server_name) collate database_default
	-- push agents to SQL publications
	if @agent_type = 0
	begin
		if object_id('syssubscriptions') is not null
		begin
			select top 1 N'job_id' = distribution_jobid from syssubscriptions s, sysarticles a,
				syspublications p where
				srvid = @server_id and
				dest_db = @database_name and
				subscription_type = 0 and
				independent_agent = 0 and
				s.artid = a.artid and
				p.pubid = a.pubid
		end
	end
	-- push agents to third party
	else if @agent_type = 1
	begin
		if object_id('MSsubscriptions') is not null
		begin
			declare @publisher_id smallint
			select top 1 @publisher_id from master..sysservers where
				UPPER(srvname) = UPPER(@publisher) collate database_default
			select top 1 N'job_id' = job_id from MSdistribution_agents where
				subscriber_id = @server_id and
				subscriber_db = @database_name and
				publication = N'ALL' and
				publisher_id = @publisher_id and
				publisher_db = @publisher_db and
				subscription_type = 0
		end
	end
	else if @agent_type = 2
	begin
		if object_id('MSreplication_subscriptions') is not null
		begin
			-- For subscriptions added through Active X control
			-- where there's no local agent created, we still don't
			-- want to create new agent.
			select top 1 N'job_id' = agent_id from MSreplication_subscriptions where
				UPPER(publisher) = UPPER(@server_name) and
				publisher_db = @database_name and
				independent_agent = 0 and
				subscription_type in (1,2)
		end
	end
GO
EXEC dbo.sp_MS_marksystemobject sp_MSget_shared_agent
GO

print ''
print 'Creating procedure sp_MSrepl_backup_start'
go
create procedure sp_MSrepl_backup_start
as
	declare @sync_bit int
	declare @dist_bit int

	set nocount on
	
	set @sync_bit = 32
	set @dist_bit = 16

	-- If this is a distribution database and it is marked by 'sync with backup'
	if exists (select * from master.dbo.sysdatabases where
		name = db_name() collate database_default and
		category & (@sync_bit | @dist_bit) = @sync_bit | @dist_bit)
	begin
		update MSrepl_backup_lsns set next_xact_id = t2.xact_id, next_xact_seqno = m.xact_seqno from 
			(select tm.publisher_database_id, max(tm.xact_seqno) from 
				-- max seqno of xacts not involved in partial tran processing
				(select t.publisher_database_id, max(substring(t.xact_seqno, 1, 10)) from 
					MSrepl_transactions t where
					not t.xact_id = 0x0 
					group by t.publisher_database_id, substring(t.xact_seqno, 1, 10)
					having count(t.xact_seqno) < 2
				union
				-- max seqno of xacts involved in and completed partial tran processing
				select t.publisher_database_id, max(substring(xact_seqno, 1, 10)) from
					MSrepl_transactions t where
					not t.xact_id = 0x0 
					and t.xact_id = substring(t.xact_seqno, 1, 10)
					group by t.publisher_database_id
				)as tm(publisher_database_id, xact_seqno) -- derived table containing up to 2 rows per publication_database_id
			group by tm.publisher_database_id -- derived table containing up to 1 row per publication_database_id
			)as m(publisher_database_id, xact_seqno), 
			MSrepl_transactions t2				
		where m.publisher_database_id = MSrepl_backup_lsns.publisher_database_id and
				t2.publisher_database_id = MSrepl_backup_lsns.publisher_database_id and
				t2.xact_seqno	= m.xact_seqno
		if @@error <> 0
			return 1
	end

	return 0
go
EXEC dbo.sp_MS_marksystemobject sp_MSrepl_backup_start
GO

print ''
print 'Creating procedure sp_MSrepl_backup_complete'
go
create procedure sp_MSrepl_backup_complete
as
	declare @sync_bit int
	declare @dist_bit int

	set nocount on
	
	set @sync_bit = 32
	set @dist_bit = 16

	-- If this is a distribution database and it is marked by 'sync with backup'
	if exists (select * from master.dbo.sysdatabases where
		name = db_name() collate database_default and
		category & (@sync_bit | @dist_bit) = @sync_bit | @dist_bit)
	begin
		update MSrepl_backup_lsns set valid_xact_id = next_xact_id, 
			valid_xact_seqno = next_xact_seqno 
		if @@error <> 0
			return 1
	end
	return 0
go
EXEC dbo.sp_MS_marksystemobject sp_MSrepl_backup_complete
GO

--
-- sp_MSadd_compensating_cmd
--
-- Owner: KaushikC
--
-- Proc executed from publisher that POSTS COMPENSATING command into 
-- Publisher Log OR Inserts COMPENSATING command into Distributor 
-- command table for a given subscriber/subscriberdb based on the mode
--
-- Parameters:
--	@orig_srv			originating subscriber
--	@orig_db			subscriber db
--	@command			command or command fragment (max 4000 chars)
--	@article_id 		article id
--	@publication_id		publication id
--	@cmdstate			flag to indicate command fragment - to handle case
--						where actual commands len exceeds 4000 chars
--	@mode				mode of operation, 0 = POST IN PUBLISHER LOG
--						1 = INSERT IN DISTRIBUTOR COMMAND TABLE
--	@setprefix			flag to indicate if we should prefix command with originator info
--
-- Security: Public access. Internal security check for publish
--
raiserror('Creating procedure sp_MSadd_compensating_cmd', 0,1)
go
CREATE PROCEDURE sp_MSadd_compensating_cmd(
	@orig_srv			sysname,
	@orig_db			sysname,
	@command			nvarchar(4000),
	@article_id 		int,
	@publication_id		int,
	@cmdstate			bit=0,
	@mode				int=0,
	@setprefix			bit=1
)	
AS
BEGIN
	set nocount on
	declare 	

	--
	-- variable declarations for all modes
	--
				@retcode			int,
				@command_id 		int,				-- command sequence
				@partial_cmd 		int,				-- partial command flag
				@curlen				int,				-- current length to read
				@start_index		int,				-- index to start reading
				@max_fragment		int,				-- max binary fragment
				@full_command		nvarchar(4000),		-- qualified command
				@readsize			int,				-- read length chars or bytes based on mode
				@mode_postpublog 	int,
				@mode_insdistcmd 	int,

	--
	-- variable declarations specific to mode = 1
	--

				@partial_cmdbit		bit,				-- partial command flag
				@xact_seqno			varbinary(16),
				@publisher_id 		int,				-- publisher ID
				@publisher_db		sysname, 			-- publisher Db
				@distributor		sysname,			-- distribution server
				@distribdb			sysname,			-- distribution db
				@charsize			int,				-- char size
				@binary_cmd			varbinary(1024),	-- Binary converted command
				@distproc			nvarchar(300)		-- RPC string

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

	--
	-- Initialize
	--
	select 		@mode_postpublog = 0,
				@mode_insdistcmd = 1

	if (@mode NOT in (@mode_postpublog,@mode_insdistcmd))
		return(1)
	--
	-- We will not post final partial empty(may contain space) command 
	-- since logreader skips empty commands and this causes distribution 
	-- agent to get confused when it selects the commands to read.
	-- If this partial command happens to be the final partial command which 
	-- has a single space - then add a comment
	--
	if  ((len(@command) = 0) and (@cmdstate = 0))
		select @command = N'/*c*/'
	--
	-- process based on @mode
	--
	if (@mode = @mode_insdistcmd)
	begin
		select 	@publisher_db = db_name(),
				@publisher_id = srvid 
		from master.dbo.sysservers where UPPER(srvname) = UPPER(@@servername) collate database_default

		--
		-- Get distribution server information for remote RPC calls
		--
		EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
									@distribdb  = @distribdb OUTPUT
		if ((@@ERROR != 0) or (@retcode != 0))
			return(1)
		
		--
		-- Get the new xact_seqno
		--
		create table #new_xact_seqno ( seqno varbinary(16) NOT NULL )
		select @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSget_new_xact_seqno'
		insert into #new_xact_seqno
			EXECUTE @retcode = @distproc
				@publisher_id = @publisher_id,
				@publisher_db = @publisher_db,
				@len = 14
		if ((@@ERROR != 0) or (@retcode != 0))
			return(1)
		select @xact_seqno = seqno from #new_xact_seqno	
		select @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSadd_repl_command'
	end
	
	--
	-- Do the command insertion in a tran
	--
	select @full_command = case when (@setprefix = 1) then 
								QUOTENAME(@orig_srv) + QUOTENAME(@orig_db) + @command
								else @command end
	begin tran sp_MSadd_compensating_cmd
	
	--
	-- process the command
	-- for @mode_postpublog : just call sp_replpostcmd and that will do the job
	-- for @mode_insdistcmd : break the command into 1024 sized commands and add
	--
	if (@mode = @mode_postpublog)
	begin
		select 	@partial_cmd = CASE when (@cmdstate = 1) then 1 else 0 END
		exec @retcode = dbo.sp_replpostcmd 
				@partial_cmd,
				@publication_id, 
				@article_id, 
				12,
				@full_command
		if (@@ERROR != 0 or @retcode != 0)
			GOTO UNDO
	end
	else if (@mode = @mode_insdistcmd)
	begin
		select 	@command_id = 0,
				@start_index = 1,
				@max_fragment = 1024,
				@charsize = 2,
				@curlen = LEN(@full_command),
				@readsize = DATALENGTH(@full_command)

		while (@readsize > 0)
		begin
			-- set command id
			select @command_id = @command_id + 1

			-- Check if we have to process partial command
			if (@readsize > @max_fragment)
			begin
				--
				-- we have partial command to send
				--
				select @curlen = @max_fragment / @charsize
				select 	@partial_cmdbit = 1,
						@binary_cmd = CAST(
							SUBSTRING(@full_command, @start_index, @curlen)
							AS varbinary(1024)),
						@readsize = @readsize - @max_fragment

				select @start_index = @start_index + @curlen
				select @curlen = @readsize / @charsize
			end
			else
			begin
				--
				-- last fragment to send - end of command
				-- check for command state - if state is PARTIAL_CMD (1)
				-- then set the partial bit even though this is the last fragment
				--
				select 	@partial_cmdbit = CASE when (@cmdstate = 1) then 1 else 0 END,
						@binary_cmd = CAST(
							SUBSTRING(@full_command, @start_index, @curlen) 
							AS varbinary(1024)),
						@readsize = 0
			end
				
			--
			-- Add the command to the distributor
			--
			EXECUTE @retcode = @distproc
				@publisher_id = @publisher_id, 
				@publisher_db = @publisher_db, 
				@xact_seqno = @xact_seqno,
				@type = 12, 
				@article_id = @article_id, 
				@command_id = @command_id, 
				@partial_command = @partial_cmdbit, 
				@command = @binary_cmd
			if (@@ERROR != 0 or @retcode != 0)
				GOTO UNDO
		end -- end of while loop
	end 	-- end of if (@mode = @mode_insdistcmd)

	--
	-- Command(s) added successfully - End Tran
	--
	commit tran sp_MSadd_compensating_cmd
	return (0)

UNDO:
	--
	-- Error - Rollback
	--
	IF (@@TRANCOUNT > 0)
	begin
		ROLLBACK TRAN sp_MSadd_compensating_cmd
		if (@@TRANCOUNT > 0)
			COMMIT TRAN   
	end
	return (1)	
END
go
EXEC dbo.sp_MS_marksystemobject sp_MSadd_compensating_cmd
GO

--
--  System UDF fn_varbintohexstr
-- 	This function takes as input a varbinary
--	and returns the Hexadecimal representation string
--
create function dbo.fn_varbintohexstr (
	@pbinin varbinary(8000) )
returns nvarchar(4000)
as
begin
	declare @pstrout nvarchar(4000)

	select @pstrout = master.dbo.fn_varbintohexsubstring(1,@pbinin,1,0)
	return @pstrout
end
go

--
--  System UDF fn_varbintohexsubstring
-- 	This function takes as input a varbinary, and start offset and length
--	and returns the Hexadecimal representation string for the given substring
--
create function dbo.fn_varbintohexsubstring (
	@fsetprefix bit = 1		-- append '0x' to the output
	,@pbinin varbinary(8000) -- input binary stream
	,@startoffset int = 1	 -- starting offset 
	,@cbytesin int = 0		 -- length of input to consider, 0 means total length
)
returns nvarchar(4000)
as
begin
	declare @pstrout nvarchar(4000)
		,@i int
		,@firstnibble int
		,@secondnibble int
		,@tempint int
		,@hexstring char(16)

	--
	-- initialize and validate
	--
	if (@pbinin IS NOT NULL)
	begin	
		select @i = 0
				,@cbytesin = case when (@cbytesin > 0) then @cbytesin else DATALENGTH(@pbinin) end
				,@pstrout =  case when (@fsetprefix = 1) then N'0x' else N'' end
				,@hexstring = '0123456789abcdef'

		if ( ((@cbytesin * 2) + 2 > 4000) or ((@cbytesin * 2) + 2 < 1) )
			return NULL

		if ( ( @startoffset > @cbytesin ) or ( @startoffset < 1 ) )
			return NULL
			
		--
		-- do for each byte
		--
		while (@i < @cbytesin)
		begin
			--
			-- Each byte has two nibbles
			-- which we convert to character
			--
			select @tempint = cast(substring(@pbinin, @i + @startoffset, 1) as int)
			select @firstnibble = @tempint / 16
			select @secondnibble = @tempint % 16

			--
			-- we need to do an explicit cast with substring 
			-- for proper string conversion. 
			--
			select @pstrout = @pstrout +
				cast(substring(@hexstring, (@firstnibble+1), 1) as nvarchar) +
				cast(substring(@hexstring, (@secondnibble+1), 1) as nvarchar)

			select @i = @i + 1
		end
	end
	
	-- All done
	return @pstrout
end
go

-- system function : returns string corresponding to version number part of setup path
-- for the current instance 
raiserror(15339,-1,-1,'fn_MSsharedversion')
GO
CREATE FUNCTION dbo.fn_MSsharedversion ( @len_minorversion tinyint = 1 )
	RETURNS NVARCHAR(10)
AS
BEGIN
	
	DECLARE @version VARCHAR(20), @bookmark_begin SMALLINT, @bookmark_end SMALLINT
	DECLARE @tools_ver VARCHAR(20)

	SELECT @version = CONVERT( VARCHAR(20), SERVERPROPERTY( N'PRODUCTVERSION') )
 
 	SELECT @bookmark_begin = CHARINDEX( '-', @version, 1) + 1
	SELECT @bookmark_end = CHARINDEX( '.', @version, @bookmark_begin + 3 ) 
	SELECT @version = SUBSTRING( @version, @bookmark_begin, @bookmark_end - @bookmark_begin )

	SELECT @tools_ver = RTRIM(LTRIM(LEFT( @version, CHARINDEX('.', @version, 1) - 1 ) + LEFT(RIGHT( @version, CHARINDEX('.', @version, @len_minorversion ) ), @len_minorversion )))

	RETURN @tools_ver

END
GO


-- system procedure : Get install and data root paths (instance aware)
raiserror(15339,-1,-1,'sp_MSget_setup_paths')
GO
CREATE PROCEDURE sp_MSget_setup_paths (
@sql_path	NVARCHAR(260) = NULL OUTPUT, 
@data_path	NVARCHAR(260) = NULL OUTPUT )
AS
BEGIN
	
	DECLARE @retcode INTEGER
	DECLARE @regkey NVARCHAR(260)
	
	SET NOCOUNT ON 
	
	declare @instance sysname
	select @instance = convert(sysname, SERVERPROPERTY('InstanceName'))
	select @regkey = 'SOFTWARE\Microsoft\'
	-- default installation
	if @instance is null
		SELECT @regkey = @regkey + 'MSSQLServer\Setup' 
	else
		SELECT @regkey = @regkey + 'Microsoft SQL Server\' + @instance + '\Setup'

	EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 
		@regkey,
		'SQLPath',
		@param = @sql_path OUTPUT

	IF ( @retcode <> 0 ) or ( @@ERROR <> 0 ) 
		RETURN (1)
	
	EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 
		@regkey,
		'SQLDataRoot',
		@param = @data_path OUTPUT

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

	RETURN (0)

END
GO

-- No parameter checking is performed in sp_MSremoveoffloadparameter
raiserror(15339,-1,-1,'sp_MSremoveoffloadparameter')
GO
CREATE PROCEDURE sp_MSremoveoffloadparameter (
    @job_id    VARBINARY(16),
    @agenttype NVARCHAR(20) 
    ) AS
    SET NOCOUNT ON
    
    /*
    ** Declarations
    */
    
    DECLARE @paramstart    INT
    DECLARE @paramend      INT
    DECLARE @paramlen      INT
    DECLARE @paramend2     INT
    DECLARE @command       NVARCHAR(3200) 
    DECLARE @commandtail   NVARCHAR(3200)
    DECLARE @pattern       NVARCHAR(100)

    SELECT @pattern = N'%-[Oo][Ff][Ff][Ll][Oo][Aa][Dd]%'
    SELECT @paramlen = LEN(N'-offload')
    SELECT @command = NULL

    -- use the job_id and the agent type to retrieve the agent command
    -- line, only one agent command step is allowed in a job

    SELECT @command = command FROM msdb.dbo.sysjobsteps 
     WHERE job_id = @job_id AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)

    -- purge all instances of '-offload servername' from the agent command line
    SELECT @paramstart = PATINDEX(@pattern, @command)
    WHILE ((@command IS NOT NULL) AND (@paramstart <> 0))
    BEGIN       
        -- extract the part of the command line after the -Offload parameter
        SELECT @commandtail = SUBSTRING(@command, @paramstart + @paramlen, 
                                        LEN(@command) - 
                                        (@paramstart + @paramlen) + 1)

        -- search for the beginning of the server name that follows -offload
        -- in the command tail; note that the empty spaces in the square
        -- bracket of the pattern are actually a space and a tab

        SELECT @paramend = PATINDEX(N'%[^ 	]%', @commandtail)

        -- search for the end of the server name that follows -offload
        IF (@paramend <> 0) 
        BEGIN
            SELECT @commandtail = SUBSTRING(@commandtail, @paramend, 
                                            LEN(@commandtail) - @paramend + 1)
            SELECT @paramend2 = PATINDEX(N'%[ 	]%', @commandtail) 
            IF (@paramend2 <> 0)
            BEGIN
                SELECT @paramend = @paramend + @paramend2 - 1
            END
            ELSE
            BEGIN
                -- reaching the end of the command line
                SELECT @paramend = @paramend + LEN(@commandtail) - 1
                IF @paramstart > 1 
                BEGIN
                    SELECT @paramstart = @paramstart - 1
                    SELECT @paramend = @paramend + 1
                END
            END
        
        END                
        -- Remove the -Offload parameter from the command line
        SELECT @command = STUFF(@command, @paramstart, @paramlen + @paramend, N'')

        SELECT @paramstart = PATINDEX(@pattern, @command)
    END
    
    -- update the agent command line with all the -offload's removed
    UPDATE msdb.dbo.sysjobsteps 
       SET command = @command
     WHERE job_id = @job_id AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)   
    
    RETURN 0
GO
EXEC dbo.sp_MS_marksystemobject sp_MSremoveoffloadparameter
GO

-- No parameter checking is performed in sp_MSaddoffloadparameter 
raiserror(15339,-1,-1,'sp_MSaddoffloadparameter')
GO
CREATE PROCEDURE sp_MSaddoffloadparameter (
    @offloadserver sysname, /* Name of the target server to offload the agent to */
    @job_id        VARBINARY(16), 
    @agenttype     NVARCHAR(20) /* Agent type can either be 'merge' or 'distribution' */
    ) AS
    
    SET NOCOUNT ON

    /*
    **  Declarations
    */

    DECLARE @command               NVARCHAR(3200)
    
    -- initialize variables
    SELECT @command = NULL    

    -- call sp_MSremoveoffloadparameter to remove all exisiting instances of the 
    -- -offload parameters from the agent command line; the return status
    -- of sp_MSremoveoffloadparameter is ignored
    EXEC sp_MSremoveoffloadparameter @job_id=@job_id, @agenttype=@agenttype
    
    -- update the agent command line by appending '-Offload ' + 
    -- @offloadserver    
    
    UPDATE msdb.dbo.sysjobsteps
       SET command = command + N' -Offload ' + @offloadserver 
     WHERE job_id = @job_id 
       AND LOWER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@agenttype collate SQL_Latin1_General_CP1_CS_AS)
         
    RETURN 0
GO
EXEC dbo.sp_MS_marksystemobject sp_MSaddoffloadparameter
GO

--
--  System UDF fn_MSgensqescstr
-- 	This function takes as input a varchar
--	and stuffs an extra single quote for any single quotes in the string
--
raiserror(15339,-1,-1,'fn_MSgensqescstr')
go
create function dbo.fn_MSgensqescstr (
	@pstrin nvarchar(4000) )
returns nvarchar(4000)
as
begin
	declare @pstrout nvarchar(4000)

	select @pstrout = REPLACE(@pstrin, N'''', N'''''')
	return @pstrout
end
go

raiserror(15339,-1,-1,'sp_MSUpgradeConflictTable')
GO
create proc sp_MSUpgradeConflictTable
	@skip_procgen bit = 0
AS
declare @retcode int
declare @conflict_table sysname
declare @pubid uniqueidentifier 
declare @artid uniqueidentifier 
declare @ins_conflict_proc sysname
declare @conflict_id	int
declare @objid			int
declare @qual_conflict	nvarchar(132)


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

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

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

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

--
-- This SP is used by the queued tran triggers to insert data into the SQL queue
-- it enforces the security check and does the insert into the queue table
-- Note this transaction is always called with a transaction (local or distributed)
-- so do not add any save tran semantics
--
raiserror(15339,-1,-1,'sp_MSsendtosqlqueue')
GO
go
create proc sp_MSsendtosqlqueue (
	@objid int
	,@publisher sysname
	,@publisher_db sysname
	,@publication sysname
	,@owner sysname
	,@tranid sysname
	,@data varbinary(8000)
	,@datalen int
	,@commandtype int = 1
	,@cmdstate bit = 0
)
as
begin
	set nocount on
	--
	-- Security check
	-- Make sure this proc is infact being called from the given object(trigger)
	-- 
	if (trigger_nestlevel(@objid) = 0)
	begin
		raiserror(14126, 16, 2)
		return 1
	end
	--
	-- Security check: the caller of this SP has to be one of the 
	-- predefined replication objects for this subscription
	--
	if not exists (select so.id from (dbo.MSreplication_objects as ro join dbo.sysobjects as so
				on ro.object_name = so.name)
		where ro.publisher = @publisher and ro.publisher_db = @publisher_db 
		and ro.publication = @publication and ro.object_type = 'T' 
		and user_name(so.uid) = @owner)
	begin
		raiserror(14126, 16, 3)
		return 1
	end
	--
	-- insert into the queue table
	--
	insert into dbo.MSreplication_queue with (rowlock) (publisher,publisher_db,publication,tranid,data,datalen,commandtype,cmdstate)
		values(UPPER(@publisher),@publisher_db,@publication,@tranid,@data,@datalen,@commandtype,@cmdstate)
	if (@@error != 0)
		return 1
	--
	-- Update MSrepl_queuedtraninfo
	--
	if exists (select *
		from dbo.MSrepl_queuedtraninfo with (nolock)
		where publisher = UPPER(@publisher) 
			and publisher_db = @publisher_db 
			and publication = @publication
			and tranid = @tranid)
	begin
		--
		-- row for this transaction exists - update it
		--
		update dbo.MSrepl_queuedtraninfo with (rowlock)
		set maxorderkey = @@identity
			,commandcount = commandcount + 1
		where publisher = UPPER(@publisher)
			and publisher_db = @publisher_db 
			and publication = @publication
			and tranid = @tranid
	end
	else
	begin
		--
		-- row for this transaction does not exist - insert it
		--
		insert into dbo.MSrepl_queuedtraninfo with (rowlock) (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
		values (UPPER(@publisher),@publisher_db,@publication,@tranid,@@identity,1)
	end
	if (@@error != 0)
		return 1
	--
	-- all done
	--
	return 0
end
go
exec dbo.sp_MS_marksystemobject sp_MSsendtosqlqueue
go			

/*
** One and only one of these two parameters needs to be specified - meaning adjust publisher side
** identity range at publication level (all tables) or table level (whose name is given)
*/

raiserror(15339,-1,-1,'sp_adjustpublisheridentityrange')
GO
create procedure sp_adjustpublisheridentityrange (
    @publication	sysname = NULL,
    @table_name 		sysname = NULL,
    @table_owner	sysname = NULL
)
AS
set nocount on

declare @retcode 				int, @object_found bit
declare @objid					int
declare @qualified_table_name	nvarchar(260)
declare @identity_support		int
declare @pubid					uniqueidentifier

select @object_found = 0

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

if ((@publication is NULL and @table_name is NULL) or 
		(@publication is NULL and @table_name is NULL) or
		(@publication is not NULL and @table_name is not NULL))
begin
	raiserror(21314, 16, -1, '@publication', '@table_name')
	return (1)
end

if @publication is NULL
begin
	if @table_owner is NULL
		select @table_owner = user_name()
	select @qualified_table_name = QUOTENAME(@table_owner) + '.' + QUOTENAME(@table_name)
	
	select @objid = object_id(@qualified_table_name)
    if @objid is NULL
	begin 
        RAISERROR (14027, 11, -1, @qualified_table_name)
		return (1)
	end
end

--Do this for merge?
if exists (select * from sysobjects where name = 'sysmergepublications')
begin
	if @publication is NULL
	begin
    	select @identity_support = identity_support from sysmergearticles where objid=@objid
		if @identity_support is not null
		begin
			select @object_found = 1
			if @identity_support = 0
				return (0)
			exec @retcode = sp_MSadjustmergeidentity @tablename=@table_name	
			if @retcode<>0 or @@ERROR<>0
			begin
				raiserror(21315, 16, -1, @table_name)
				return (1)
			end
		end
	end

	if @table_name is NULL
	begin
		select @pubid=pubid FROM sysmergepublications
			WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()
		if @pubid is not null
		begin
			select @object_found = 1
			if not exists (select * from sysmergearticles where pubid=@pubid and identity_support=1)
				return (0)
			exec @retcode = sp_MSadjustmergeidentity @publication=@publication
			if @retcode<>0 or @@ERROR<>0
			begin
				raiserror(21316, 16, -1, @publication)
				return (1)
			end	
		end	
	end
end

if exists (select * from sysobjects where name = 'syspublications')
begin
	if @publication is NULL
	begin
		declare @artid int
		select top 1 @artid = artid from sysarticles where 
			objid = @objid
		if @artid is not null
		begin
			select @object_found = 1
			exec @retcode = sp_MSpub_adjust_identity @artid
			if @retcode<>0 or @@ERROR<>0
				return (1)
		end
	end
	else
	begin
		declare @publication_id int
		select @publication_id = pubid from syspublications where name = @publication
		if @publication_id is not null
		begin
			select @object_found = 1
			DECLARE adjust_identity CURSOR LOCAL FAST_FORWARD FOR
				SELECT art1.objid
				  FROM sysarticles art1,
					   sysarticleupdates art2
				  where art1.pubid = @publication_id and
						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
				exec @retcode = sp_MSpub_adjust_identity @artid
				if @retcode<>0 or @@ERROR<>0
					return (1)
				FETCH adjust_identity INTO @objid
			end
		end
	end
end
if @object_found = 0
begin
	if @publication is null
		raiserror(21246, 16, -1, @qualified_table_name)
	else
        RAISERROR (20026, 11, -1, @publication)
end

RETURN (0)
GO
exec dbo.sp_MS_marksystemobject sp_adjustpublisheridentityrange
GO			

grant execute on dbo.sp_adjustpublisheridentityrange to public
GO

-- sp_MSestimate(merge)snapshotworkload is called exclusively by the 
-- snapshot agent to estimate the amount of work that has to be done for
-- a snapshot session and a breakdown of the work load into subtasks

raiserror(15339,-1,-1,'sp_MSestimatemergesnapshotworkload')
GO
create proc sp_MSestimatemergesnapshotworkload (
    @publication sysname
    )
as
begin
    set nocount on

    declare @taskload                       int
    declare @bigtaskload                    bigint
    declare @table_created                  bit
    declare @retcode                        int

    -- constant
    declare @zerouuid                       uniqueidentifier
    select @zerouuid = convert(uniqueidentifier, N'{00000000-0000-0000-0000-000000000000}')
    -- Publication info
    declare @pubid                          uniqueidentifier
    declare @compress_snapshot              bit
    declare @snapshot_in_defaultfolder      bit
    declare @alt_snapshot_folder            nvarchar(255)
    declare @enabled_for_internet           bit
    declare @ftp_password                   nvarchar(524) 
    declare @ftp_subdirectory               nvarchar(255)
    declare @pre_snapshot_script            nvarchar(255)
    declare @post_snapshot_script           nvarchar(255)    
    declare @dynamic_filters                bit

    -- Per publication summary stats
    declare @numarticles                    int
    declare @totalrowcount                  int   
    declare @needsysprescript               bit
    declare @copysnapshot                   bit
    declare @deletefiles                    bit
    declare @scriptproccost                 int
    declare @addcommandstotal               int
    declare @numscripts                     int
    declare @totalbcpcostper100             int
    declare @numprescriptcommands           int 
    declare @numunsyncedarticles            int
    declare @numtablearticles               int
    declare @systablesrowcount              int
    declare @maxint                         int

    select @numarticles = 0
    select @totalrowcount = 0
    select @needsysprescript = 0
    select @copysnapshot = 0
    select @deletefiles = 0
    select @scriptproccost = 0
    select @deletefiles = 0
    select @addcommandstotal = 0
    select @numscripts = 0
    select @totalbcpcostper100 = 0
    select @numprescriptcommands = 0
    select @numunsyncedarticles = 0
    select @numtablearticles = 0
    select @systablesrowcount = 0
    select @maxint = 2147483647

    -- Per article variables
    declare @artid                          uniqueidentifier
    declare @schema_option                  int
    declare @creation_script                nvarchar(255)
    declare @type                           tinyint
    declare @objid                          int
    declare @rowcount                       int
    declare @name                           sysname
    declare @status                         int


    -- Security check
    select @retcode = 0
	EXEC @retcode = dbo.sp_MSreplcheck_publish
	IF @@ERROR <> 0 or @retcode <> 0
		return (1)

    select @table_created = 0

    select @pubid = null
    select @compress_snapshot = 0
    select @snapshot_in_defaultfolder = 0
    select @alt_snapshot_folder = null
    select @enabled_for_internet = 0
    select @ftp_password = null
    select @ftp_subdirectory = null
    select @pre_snapshot_script = null
    select @post_snapshot_script = null
    -- Validate publication and retrieve publication information 
    select @pubid = pubid, 
           @compress_snapshot = compress_snapshot,
           @snapshot_in_defaultfolder = snapshot_in_defaultfolder,
           @alt_snapshot_folder = alt_snapshot_folder,
           @enabled_for_internet = enabled_for_internet,
           @ftp_password = ftp_password,
           @ftp_subdirectory = ftp_subdirectory,
           @pre_snapshot_script = pre_snapshot_script,
           @post_snapshot_script = post_snapshot_script,
           @dynamic_filters = dynamic_filters
           from sysmergepublications
     where name = @publication
       and upper(@@servername) = publisher
       and publisher_db = db_name()
    if @pubid = null
    begin   
        raiserror(20026, 11, -1, @publication)
        return (1)
    end

    -- An artid of -1 means the task is a per publication
    -- task

    -- Task id mapping - This is the list of task whose completion can be 
    -- reported by the snapshot agent
    -- 0 - Total workload (not really a task)
    -- 1 - Schema script generation
    -- 2 - Trigger script generation 
    -- 3 - XProp script generation
    -- 4 - Bcp file generation
    -- 5 - Activating subscription (estimate number of subscriptions?)
    -- 6 - Adding snapshot commands
    -- 7 - System pre-script generation
    -- 8 - Flushing folder for scripts
    -- 9 - Constraint script generation
    -- 10 - Copying pre-script
    -- 11 - Copying post-script
    -- 12 - Copying custom schema creation script
    -- 13 - Index script generation
    -- 14 - Flushing the cabinet
    -- 15 - Adding rowguid column
    -- 16 - Setting article procs
    -- 17 - Adding merge triggers
    -- 18 - Generating system table scripts
    -- 19 - Generating system table bcp files
    -- 20 - Making publication generation
    -- 21 - Generating and setting conflict script
    -- 22 - Generating publication views
    
    -- Weights and overheads
    -- DMO Script generation - 7/script
    -- BCP 5 overhead + 5/100 rows
    -- Flush folder for bcp 2/100 rows
    -- Delete file 2
    -- System pre-snapshot script 1 overhead + 0.5/pre-creation command
    -- Copying user file 2
    -- Adding file to cabinet 1 for scripts and 1/100 rows in bcp file
    -- Loading article info 3
    -- Delete bcp file 2/100rows 
    -- Copy bcp file  2/100rows  
    -- Flush scripts folder 1/2 scripts
    -- Flushing cabinet per 5 scripts 1
    -- Flushing cabinet per 500 rows 1
    -- Script execution 3
    -- Adding rowguid columns 20/100 rows
    -- Adding merge triggers 7
    -- Setting article procs 5

    -- Here is the list of cost factors 
    declare @addcommandcost     int
    declare @dmoscriptcost      int
    declare @bcpoverhead        int
    declare @bcpcostper100      int
    declare @flushper100        int
    declare @flushperscript     int
    declare @delfilecost        int
    declare @syspreoverhead     int
    declare @syspreper2commands int
    declare @addbcptocabper100  int
    declare @addscripttocab     int
    declare @copyfilecost       int
    declare @loadartinfo        int    
    declare @deletebcpper100    int
    declare @copybcpper100      int
    declare @flushper2scripts   int
    declare @flushcabper5scripts int
    declare @flushcabper500bcprows int
    declare @scriptexeccost int
    declare @rowguidper100 int
    declare @addmergetriggers int
    declare @setartprocs int
    declare @pubviewperarticle int
    declare @genperarticle int

    select @addcommandcost = 2
    select @dmoscriptcost = 7
    select @bcpcostper100 = 20
    select @bcpoverhead = 2
    select @flushper100 = 2
    select @flushperscript = 3
    select @delfilecost = 2
    select @syspreoverhead = 1
    select @syspreper2commands = 1
    select @addbcptocabper100 = 1
    select @addscripttocab = 1
    select @copyfilecost = 2
    select @loadartinfo = 3    
    select @deletebcpper100 = 1
    select @copybcpper100 = 2
    select @flushper2scripts = 1
    select @flushcabper5scripts = 1
    select @flushcabper500bcprows = 1
    select @scriptexeccost = 3
    select @rowguidper100 = 20
    select @addmergetriggers = 3
    select @pubviewperarticle = 2
    select @genperarticle = 2
    select @setartprocs = 5

    create table #workload_breakdown
    (
        name        sysname collate database_default,
        artid       uniqueidentifier,
        taskid      int,
        taskload    int
    )
    if @@error <> 0
        goto Failure

    select @table_created = 1

    -- Per publication work load estimate that can be done using publication
    -- properties alone
    
    -- Adding snapshot header commands
    
    -- Snapshot header begins + Snapshot header ends +
    -- directory command + Snapshot trailer command = 3 * @addcommandcost
    select @addcommandstotal = 4
    
    -- Alternate snapshot folder = 1 * @addcommandcost
    if @alt_snapshot_folder is not null and
       @alt_snapshot_folder <> N'' and
       @snapshot_in_defaultfolder = 1
    begin
        select @addcommandstotal = @addcommandstotal + @addcommandcost
    end

    -- Ftp commands
    if @enabled_for_internet = 1
    begin
        -- ftp_address and ftp_port must be there +=2 * @addcommandcost
        select @addcommandstotal = @addcommandstotal + 2 * @addcommandcost

        -- ftp_password += 1 * @addcommandcost
        if @ftp_password is not null and
           @ftp_password <> N''
        begin
            select @addcommandstotal = @addcommandstotal + @addcommandcost
        end
        
        -- ftp_subdirectory += 1 * @addcommandcost
        if @ftp_subdirectory is not null and
           @ftp_subdirectory <> N''
        begin
            select @addcommandstotal = @addcommandstotal + 1 * @addcommandcost
        end
    end

    -- Compressed archive path
    if @compress_snapshot = 1
    begin
        select @addcommandstotal = @addcommandstotal + 1 * @addcommandcost
    end    

    -- Snapshot trailer command
    select @addcommandstotal = @addcommandstotal +  @addcommandcost

    -- Need to copy files?
    if @alt_snapshot_folder is not null and @alt_snapshot_folder <> N''
       and @snapshot_in_defaultfolder = 1 and @compress_snapshot = 0
    begin
        select @copysnapshot = 1
    end

    -- Compute per-script file post processing cost and bcp cost per 100 rows
    -- Need to delete files?
    if (@alt_snapshot_folder is null or @alt_snapshot_folder <> N''
       or @snapshot_in_defaultfolder = 0) and @compress_snapshot = 1
    begin
        select @deletefiles = 1
    end

    select @totalbcpcostper100 = @bcpcostper100
    -- Copy file?
    if @copysnapshot = 1
    begin
        select @scriptproccost = @scriptproccost + @copyfilecost
        select @totalbcpcostper100 = @totalbcpcostper100 + @copybcpper100
    end

    -- Add file to cabinet?
    if @compress_snapshot = 1
    begin
        select @scriptproccost = @scriptproccost + @addscripttocab 
        select @totalbcpcostper100 = @totalbcpcostper100 + @addbcptocabper100
    end

    -- Delete file?
    if @deletefiles = 1
    begin 
        select @scriptproccost = @scriptproccost + @delfilecost
        select @totalbcpcostper100 = @totalbcpcostper100 + @deletebcpper100
    end

    -- Pre/Post-snapshot scripts, has to be computed after the 
    -- the per-script post-processing cost is calculated 
    if @pre_snapshot_script is not null and
       @pre_snapshot_script <> N''
    begin
        -- Cost of copying the script file
        select @taskload = @copyfilecost + @scriptproccost
        insert #workload_breakdown values (N'', @zerouuid, 10, @taskload)
        -- Cost of adding the pre-snapshot command
        select @addcommandstotal = @addcommandstotal + @addcommandcost
        -- Increment scripts counter
        select @numscripts = @numscripts + 1
    end

    if @post_snapshot_script is not null and
       @post_snapshot_script <> N''
    begin
        -- Cost of copying the script file
        select @taskload = @copyfilecost + @scriptproccost
        insert #workload_breakdown values (N'', @zerouuid, 11, @taskload)
        -- Cost of adding the post-snapshot command
        select @addcommandstotal = @addcommandstotal + @addcommandcost
        -- Increment scripts counter
        select @numscripts = @numscripts + 1
    end
           
    -- Estimate the break down of per article tasks 
    declare hCarticles cursor local fast_forward
    for select artid, creation_script, objid, convert(int, schema_option), type, name,
               status  
          from sysmergeextendedarticlesview where pubid = @pubid 

    open hCarticles
   
    fetch hCarticles into @artid, @creation_script, @objid, @schema_option, @type, @name,
        @status
    while (@@fetch_status <> -1)
    begin
        if @type = 0x40 -- Schema view articles, may require index scripting
        begin
            select @taskload = 0
            -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                -- No need to worry about index script
            end
            else
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- DRI script containing the view's indexes?
                if (@schema_option & 0x50) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 9, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end

                -- Trigger script?
                if (@schema_option & 0x100) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 2, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end 

                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end
            end        
        end
        else if @type in (0x08, 0x18, 0x20, 0x80) -- Regular schema articles 
        begin
            select @taskload = 0
            -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
            end
            else 
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                end
            end
        end
        else -- Merge table articles, requires bcp
        begin
           select @taskload = 0
           -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                -- No need to worry about index script
            end
            else
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- Constraint script is not optional for merge table article
                -- Cost of script generation
                select @taskload = @dmoscriptcost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 9, @taskload)
                -- Cost of adding command for the script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
    
                -- Trigger script?
                if (@schema_option & 0x100) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 2, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end 
        
                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end
            end        

            -- Conflict script generation and setting
            -- Cost of script generation and execution 
            select @taskload = @dmoscriptcost + @scriptexeccost + @scriptproccost
            insert #workload_breakdown values (@name, @artid, 21, @taskload)

            -- Get fast row count from sysindexes for bcp op estimation
            select @rowcount = 
                    case when isnull(rowcnt,0) > @maxint then @maxint / 10000
                         when isnull(rowcnt,0) > @maxint / 10000 then rowcnt / 10000
                         else isnull(rowcnt,0)
                    end
              from sysindexes 
             where id = @objid and indid in (0,1)

            -- For unsynced articles, we need to 
            -- 1) Add rowguid column 
            -- 2) Set article procs
            -- 3) Add merge triggers
            if @status = 1
            begin
                -- Add rowguid column - use article row count to estimate the cost
                select @taskload = (@rowcount * @rowguidper100) / 100
                insert #workload_breakdown values (@name, @artid, 15, @taskload) 
      
                -- Set article procs
                select @taskload = @setartprocs
                insert #workload_breakdown values (@name, @artid, 16, @taskload)

                -- Add merge triggers    
                select @taskload = @addmergetriggers 
                insert #workload_breakdown values (@name, @artid, 17, @taskload)

                -- Increment the number of unsynced articles
                select @numunsyncedarticles = @numunsyncedarticles + 1
            end

            -- Increment the total row count
            select @totalrowcount = @totalrowcount + @rowcount        

            -- BCP computation            
            -- Bcp file generation
            select @taskload = @bcpoverhead + (@rowcount * @totalbcpcostper100) / 100 
            insert #workload_breakdown values (@name, @artid, 4, @taskload)

            -- Increment the table articles counter
            select @numtablearticles = @numtablearticles + 1

        end    

        -- System pre-snapshot script required?
        if @type in (0x40, 0x80)
        begin
            select @needsysprescript = 1
            -- Incrememt the number of pre-script command counter
            select @numprescriptcommands = @numprescriptcommands + 1
        end

        -- Increment the article count
        select @numarticles = @numarticles + 1

        fetch hCarticles into @artid, @creation_script, @objid, @schema_option, @type, @name,
            @status
    end
        
    -- The cost of making publication views depends upon the 
    -- number of unsynced articles
    if @numunsyncedarticles <> 0
    begin
        select @taskload = @numunsyncedarticles * @pubviewperarticle 
        insert #workload_breakdown values (N'', @zerouuid, 22, @taskload) 
    end

    -- Make publication generation - roughly proportional to the number of table
    -- articles we have
    select @taskload = @numtablearticles * @genperarticle
    insert #workload_breakdown values (N'', @zerouuid, 20, @taskload)

    -- Merge system tables processing 
    -- Script files
    select @taskload = 4 * (@dmoscriptcost + @scriptproccost)
    insert #workload_breakdown values (N'', @zerouuid, 18, @taskload)

    -- Cost of adding the commands
    select @addcommandcost = @addcommandcost + 4

    -- Bcp files - Generated only when the publication is not enabled for
    -- dynamic filters
    if @dynamic_filters = 0
    begin
        if exists (select * from sysobjects where name = N'MSmerge_contents')
        begin
            select @rowcount = 
                    case when isnull(rowcnt,0) > @maxint then @maxint / 10000
                         when isnull(rowcnt,0) > @maxint / 10000 then rowcnt / 10000
                         else isnull(rowcnt,0)       
                    end
              from sysindexes 
             where id = object_id('dbo.MSmerge_contents') 
               and indid in (0,1)
            select @systablesrowcount = @systablesrowcount + @rowcount
        end
        if exists (select * from sysobjects where name = N'MSmerge_tombstones')
        begin
            select @rowcount = 
                    case when isnull(rowcnt,0) > @maxint then @maxint / 10000
                         when isnull(rowcnt,0) > @maxint / 10000 then rowcnt / 10000
                         else isnull(rowcnt,0)       
                    end
              from sysindexes 
             where id = object_id('dbo.MSmerge_tombstoness') 
               and indid in (0,1)
            select @systablesrowcount = @systablesrowcount + @rowcount
        end
        if exists (select * from sysobjects where name = N'MSmerge_genhistory')
        begin
            select @rowcount = 
                    case when isnull(rowcnt,0) > @maxint then @maxint / 10000
                         when isnull(rowcnt,0) > @maxint / 10000 then rowcnt / 10000
                         else isnull(rowcnt,0)       
                    end
              from sysindexes 
             where id = object_id('dbo.MSmerge_genhistory') 
               and indid in (0,1)
            select @systablesrowcount = @systablesrowcount + @rowcount
        end
    end
    if exists (select * from sysobjects where name = N'sysmergesubsetfilters')
    begin
        select @rowcount = count(*) from sysmergesubsetfilters
        select @systablesrowcount = @systablesrowcount + @rowcount 
    end

    select @taskload = (4 * @bcpoverhead) + (@systablesrowcount * @totalbcpcostper100) / 100 
    insert #workload_breakdown values (N'', @zerouuid, 19, @taskload)
    select @totalrowcount = @totalrowcount + @systablesrowcount

    -- System pre-snapshot script processing cost 
    if @needsysprescript = 1
    begin
        select @taskload = @syspreoverhead + 
                (@numprescriptcommands * @syspreper2commands) / 2 +
               @scriptproccost
        insert #workload_breakdown values (N'', @zerouuid, 7, @taskload)         
        select @numscripts = @numscripts + 1
    end

    -- Cost of flushing folder for the scripts 
    if @compress_snapshot = 1
    begin
        select @taskload = (@numscripts * @flushper2scripts) / 2
        insert #workload_breakdown values (N'', @zerouuid, 8, @taskload) 
    end

    -- Cost for flushing the cabinet
    if @compress_snapshot = 1
    begin
        select @taskload = (@numscripts * @flushcabper5scripts / 5) +
                           (@totalrowcount * @flushcabper500bcprows / 500)
        insert #workload_breakdown values (N'', @zerouuid, 14, @taskload)
    end

    -- Add the total add commands cost
    insert #workload_breakdown values (N'', @zerouuid, 6, @addcommandstotal)

    -- Compute the total workload and put that in the 
    -- workload break down
    select @bigtaskload = sum(convert(bigint,taskload)) from #workload_breakdown
    select @taskload =
            case when @bigtaskload > @maxint then @maxint
            else @bigtaskload
            end
    insert #workload_breakdown values (N'', @zerouuid, 0, @taskload) 

    select name, taskid, taskload from #workload_breakdown order by artid, taskid asc
    drop table #workload_breakdown
    return 0

Failure:
    if @table_created = 1
       drop table #workload_breakdown
    return 1
end
go

exec dbo.sp_MS_marksystemobject sp_MSestimatemergesnapshotworkload
go			

grant execute on dbo.sp_MSestimatemergesnapshotworkload to public
go

raiserror(15339,-1,-1,'sp_MSestimatesnapshotworkload')
go
create proc sp_MSestimatesnapshotworkload (
    @publication sysname
    )
as
begin
    set nocount on

    declare @taskload                       int
    declare @bigtaskload                    bigint
    declare @table_created                  bit
    declare @retcode                        int

    -- Publication info
    declare @pubid                          int
    declare @compress_snapshot              bit
    declare @snapshot_in_defaultfolder      bit
    declare @alt_snapshot_folder            nvarchar(255)
    declare @enabled_for_internet           bit
    declare @ftp_password                   nvarchar(524) 
    declare @ftp_subdirectory               nvarchar(255)
    declare @pre_snapshot_script            nvarchar(255)
    declare @post_snapshot_script           nvarchar(255)    

    -- Per publication summary stats
    declare @numarticles                    int
    declare @totalrowcount                  int   
    declare @needsysprescript               bit
    declare @copysnapshot                   bit
    declare @deletefiles                    bit
    declare @scriptproccost                 int
    declare @addcommandstotal               int
    declare @numscripts                     int
    declare @totalbcpcostper100             int
    declare @numprescriptcommands           int 

    select @numarticles = 0
    select @totalrowcount = 0
    select @needsysprescript = 0
    select @copysnapshot = 0
    select @deletefiles = 0
    select @scriptproccost = 0
    select @deletefiles = 0
    select @addcommandstotal = 0
    select @numscripts = 0
    select @totalbcpcostper100 = 0
    select @numprescriptcommands = 0

    -- Per article variables
    declare @artid                          int
    declare @schema_option                  int
    declare @creation_script                nvarchar(255)
    declare @type                           tinyint
    declare @objid                          int
    declare @rowcount                       int
    declare @name                           sysname
    declare @pre_creation_command           int

    select @table_created = 0

    -- Security check
    select @retcode = 0
	EXEC @retcode = dbo.sp_MSreplcheck_publish
	IF @@ERROR <> 0 or @retcode <> 0
		return (1)

    select @pubid = null
    select @compress_snapshot = 0
    select @snapshot_in_defaultfolder = 0
    select @alt_snapshot_folder = null
    select @enabled_for_internet = 0
    select @ftp_password = null
    select @ftp_subdirectory = null
    select @pre_snapshot_script = null
    select @post_snapshot_script = null
    -- Validate publication and retrieve publication information 
    select @pubid = pubid, 
           @compress_snapshot = compress_snapshot,
           @snapshot_in_defaultfolder = snapshot_in_defaultfolder,
           @alt_snapshot_folder = alt_snapshot_folder,
           @enabled_for_internet = enabled_for_internet,
           @ftp_password = ftp_password,
           @ftp_subdirectory = ftp_subdirectory,
           @pre_snapshot_script = pre_snapshot_script,
           @post_snapshot_script = post_snapshot_script
           from syspublications
     where name = @publication
    if @pubid = null
    begin   
        raiserror(20026, 11, -1, @publication)
        return (1)
    end

    -- An artid of -1 means the task is a per publication
    -- task

    -- Task id mapping - This is the list of task whose completion can be 
    -- reported by the snapshot agent
    -- 0 - Total workload (not really a task)
    -- 1 - Schema script generation
    -- 2 - Trigger script generation 
    -- 3 - XProp script generation
    -- 4 - Bcp file generation
    -- 5 - Activating subscription (estimate number of subscriptions?)
    -- 6 - Adding snapshot commands
    -- 7 - System pre-script generation
    -- 8 - Flushing folder for scripts
    -- 9 - Constraint script generation
    -- 10 - Copying pre-script
    -- 11 - Copying post-script
    -- 12 - Copying custom schema creation script
    -- 13 - Index script generation
    -- 14 - Flushing the cabinet
    -- 15 - Adding rowguid column
    -- 16 - Setting article procs
    -- 17 - Adding merge triggers
    -- 18 - Generating system table scripts
    -- 19 - Generating system table bcp files
    -- 20 - Making publication generation
    -- 21 - Generating and setting conflict script
    -- 22 - Generating publication views

    -- Weights and overheads
    -- DMO Script generation - 7/script
    -- BCP 5 overhead + 5/100 rows
    -- Flush folder for bcp 2/100 rows
    -- Delete file 2
    -- System pre-snapshot script 1 overhead + 0.5/pre-creation command
    -- Copying user file 2
    -- Adding file to cabinet 1 for scripts and 1/100 rows in bcp file
    -- Loading article info 3
    -- Delete bcp file 2/100rows 
    -- Copy bcp file  2/100rows  
    -- Flush scripts folder 1/2 scripts
    -- Flushing cabinet per 5 scripts 1
    -- Flushing cabinet per 500 rows 1

    -- Here is the list of cost factors 
    declare @addcommandcost     int
    declare @dmoscriptcost      int
    declare @bcpoverhead        int
    declare @bcpcostper100      int
    declare @flushper100        int
    declare @flushperscript     int
    declare @delfilecost        int
    declare @syspreoverhead     int
    declare @syspreper2commands int
    declare @addbcptocabper100  int
    declare @addscripttocab     int
    declare @copyfilecost       int
    declare @loadartinfo        int    
    declare @deletebcpper100    int
    declare @copybcpper100      int
    declare @flushper2scripts   int
    declare @flushcabper5scripts int
    declare @flushcabper500bcprows int
    declare @maxint             int

    select @addcommandcost = 2
    select @dmoscriptcost = 7
    select @bcpcostper100 = 20
    select @bcpoverhead = 2
    select @flushper100 = 2
    select @flushperscript = 3
    select @delfilecost = 2
    select @syspreoverhead = 1
    select @syspreper2commands = 1
    select @addbcptocabper100 = 1
    select @addscripttocab = 1
    select @copyfilecost = 2
    select @loadartinfo = 3    
    select @deletebcpper100 = 1
    select @copybcpper100 = 2
    select @flushper2scripts = 1
    select @flushcabper5scripts = 1
    select @flushcabper500bcprows = 1
    select @maxint = 2147483647

    create table #workload_breakdown
    (
        name        sysname collate database_default,
        artid       int,
        taskid      int,
        taskload    int
    )
    if @@error <> 0
        goto Failure

    select @table_created = 1

    -- Per publication work load estimate that can be done using publication
    -- properties alone
    
    -- Adding snapshot header commands
    
    -- Snapshot header begins + Snapshot header ends +
    -- directory command + Snapshot trailer command = 3 * @addcommandcost
    select @addcommandstotal = 4
    
    -- Alternate snapshot folder = 1 * @addcommandcost
    if @alt_snapshot_folder is not null and
       @alt_snapshot_folder <> N'' and
       @snapshot_in_defaultfolder = 1
    begin
        select @addcommandstotal = @addcommandstotal + @addcommandcost
    end

    -- Ftp commands
    if @enabled_for_internet = 1
    begin
        -- ftp_address and ftp_port must be there +=2 * @addcommandcost
        select @addcommandstotal = @addcommandstotal + 2 * @addcommandcost

        -- ftp_password += 1 * @addcommandcost
        if @ftp_password is not null and
           @ftp_password <> N''
        begin
            select @addcommandstotal = @addcommandstotal + @addcommandcost
        end
        
        -- ftp_subdirectory += 1 * @addcommandcost
        if @ftp_subdirectory is not null and
           @ftp_subdirectory <> N''
        begin
            select @addcommandstotal = @addcommandstotal + 1 * @addcommandcost
        end
    end

    -- Compressed archive path
    if @compress_snapshot = 1
    begin
        select @addcommandstotal = @addcommandstotal + 1 * @addcommandcost
    end    

    -- Snapshot trailer command
    select @addcommandstotal = @addcommandstotal +  @addcommandcost

    -- Need to copy files?
    if @alt_snapshot_folder is not null and @alt_snapshot_folder <> N''
       and @snapshot_in_defaultfolder = 1 and @compress_snapshot = 0
    begin
        select @copysnapshot = 1
    end

    -- Compute per-script file post processing cost and bcp cost per 100 rows
    -- Need to delete files?
    if (@alt_snapshot_folder is null or @alt_snapshot_folder <> N''
       or @snapshot_in_defaultfolder = 0) and @compress_snapshot = 1
    begin
        select @deletefiles = 1
    end

    select @totalbcpcostper100 = @bcpcostper100
    -- Copy file?
    if @copysnapshot = 1
    begin
        select @scriptproccost = @scriptproccost + @copyfilecost
        select @totalbcpcostper100 = @totalbcpcostper100 + @copybcpper100
    end

    -- Add file to cabinet?
    if @compress_snapshot = 1
    begin
        select @scriptproccost = @scriptproccost + @addscripttocab 
        select @totalbcpcostper100 = @totalbcpcostper100 + @addbcptocabper100
    end

    -- Delete file?
    if @deletefiles = 1
    begin 
        select @scriptproccost = @scriptproccost + @delfilecost
        select @totalbcpcostper100 = @totalbcpcostper100 + @deletebcpper100
    end

    -- Pre/Post-snapshot scripts, has to be computed after the 
    -- the per-script post-processing cost is calculated 
    if @pre_snapshot_script is not null and
       @pre_snapshot_script <> N''
    begin
        -- Cost of copying the script file
        select @taskload = @copyfilecost + @scriptproccost
        insert #workload_breakdown values (N'', -1, 10, @taskload)        
        -- Cost of adding the pre-snapshot command
        select @addcommandstotal = @addcommandstotal + @addcommandcost
        -- Increment scripts counter
        select @numscripts = @numscripts + 1
    end

    if @post_snapshot_script is not null and
       @post_snapshot_script <> N''
    begin
        -- Cost of copying the script file
        select @taskload = @copyfilecost + @scriptproccost
        insert #workload_breakdown values (N'', -1, 11, @taskload)
        -- Cost of adding the post-snapshot command
        select @addcommandstotal = @addcommandstotal + @addcommandcost
        -- Increment scripts counter
        select @numscripts = @numscripts + 1
    end
           
    -- Estimate the break down of per article tasks 
    declare hCarticles cursor local fast_forward
    for select artid, creation_script, objid, convert(int, schema_option), type, name, pre_creation_cmd  
          from sysextendedarticlesview where pubid = @pubid 

    open hCarticles
   
    fetch hCarticles into @artid, @creation_script, @objid, @schema_option, @type, @name, @pre_creation_command
    while (@@fetch_status <> -1)
    begin
        if @type = 0x40 -- Schema view articles, may require index scripting
        begin
            select @taskload = 0
            -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                -- No need to worry about index script
            end
            else
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- Index script?
                if (@schema_option & 0x50) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 13, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end

                -- Trigger script?
                if (@schema_option & 0x100) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 2, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end 

                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end
            end        
        end
        else if @type in (0x08, 0x18, 0x20, 0x80) -- Regular schema or proc exec articles 
        begin
            select @taskload = 0
            -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
            end
            else 
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                end
            end
        end
        else -- Log based articles, requires bcp
        begin
           select @taskload = 0
           -- See if a custom creation script will be used 
            if @schema_option = 0 and @creation_script is not null and
               @creation_script <> N''
            begin
                -- Script generation
                select @taskload = @copyfilecost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 12, @taskload)
                -- Cost of adding commands for the custom script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1
                -- No need to worry about index script
            end
            else
            begin
                -- Script generation 
                select @taskload = @dmoscriptcost + @scriptproccost
                -- Must script out schema script
                insert #workload_breakdown values (@name, @artid, 1, @taskload)
                -- Cost of adding the command
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- Index script is not optional for logbased articles
                -- Cost of script generation
                select @taskload = @dmoscriptcost + @scriptproccost
                insert #workload_breakdown values (@name, @artid, 13, @taskload)
                -- Cost of adding command for the script
                select @addcommandstotal = @addcommandstotal + @addcommandcost
                -- Increment scripts counter
                select @numscripts = @numscripts + 1

                -- Constraint script?
                if (@schema_option & 0xf00) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 9, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end
    
                -- Trigger script?
                if (@schema_option & 0x100) <> 0x0
                begin
                    -- Cost of script generation
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 2, @taskload)
                    -- Cost of adding command for the script
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end 
        
                -- XProp script?
                if (@schema_option & 0x2000) <> 0x0
                begin
                    -- Cost of script generation 
                    select @taskload = @dmoscriptcost + @scriptproccost
                    insert #workload_breakdown values (@name, @artid, 3, @taskload)
                    -- Cost of adding command
                    select @addcommandstotal = @addcommandstotal + @addcommandcost
                    -- Increment scripts counter
                    select @numscripts = @numscripts + 1
                end
            end        
        
            -- Get fast row count from sysindexes for bcp op estimation
            select @rowcount = 
                    case when isnull(rowcnt,0) > @maxint then @maxint / 10000
                         when isnull(rowcnt,0) > @maxint / 10000 then rowcnt / 10000
                         else isnull(rowcnt,0)
                    end
               from sysindexes 
             where id = @objid 
               and indid in (0,1)

            -- Increment the total row count
            select @totalrowcount = @totalrowcount + @rowcount        

            -- BCP computation            
            -- Bcp file generation
            select @taskload = @bcpoverhead + (@rowcount * @totalbcpcostper100) / 100 
            insert #workload_breakdown values (@name, @artid, 4, @taskload)
        end    

        -- System pre-snapshot script required?
        if @type in (0x40, 0x80) or ((@type & 0x1)<>0 and @pre_creation_command =  3)
        begin
            select @needsysprescript = 1
            -- Incrememt the number of pre-script command counter
            select @numprescriptcommands = @numprescriptcommands + 1
        end

        -- Increment the article count
        select @numarticles = @numarticles + 1

        fetch hCarticles into @artid, @creation_script, @objid, @schema_option, @type, @name, @pre_creation_command
    end
    
    -- System pre-snapshot script processing cost 
    if @needsysprescript = 1
    begin
        select @taskload = @syspreoverhead + 
                (@numprescriptcommands * @syspreper2commands) / 2 +
               @scriptproccost
        insert #workload_breakdown values (N'', -1, 7, @taskload)         
        select @numscripts = @numscripts + 1
    end

    -- Cost of flushing folder for the scripts 
    if @compress_snapshot = 1
    begin
        select @taskload = (@numscripts * @flushper2scripts) / 2
        insert #workload_breakdown values (N'', -1, 8, @taskload) 
    end

    -- Synctran commands cost?
        

    -- Subscription activation cost?


    -- Cost for flushing the cabinet
    if @compress_snapshot = 1
    begin
        select @taskload = (@numscripts * @flushcabper5scripts / 5) +
                           (@totalrowcount * @flushcabper500bcprows / 500)
        insert #workload_breakdown values (N'', -1, 14, @taskload)
    end

    -- Add the total add commands cost
    insert #workload_breakdown values (N'', -1, 6, @addcommandstotal)

    -- Compute the total workload and put that in the 
    -- workload break down
    select @bigtaskload = sum(convert(bigint,taskload)) from #workload_breakdown
    select @taskload =
            case when @bigtaskload > @maxint then @maxint
                 else @bigtaskload
            end
    insert #workload_breakdown values (N'', -1, 0, @taskload) 

    select name, taskid, taskload from #workload_breakdown order by artid, taskid asc
    drop table #workload_breakdown
    return 0

Failure:
    if @table_created = 1
       drop table #workload_breakdown
    return 1

end
go

CREATE FUNCTION system_function_schema.fn_serverid(@servername sysname)
	RETURNS int
AS
BEGIN
	declare @srvid int
	select @srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@servername) collate database_default
	RETURN (@srvid)
END	
go



GRANT EXECUTE ON system_function_schema.fn_serverid TO PUBLIC
go

exec dbo.sp_MS_marksystemobject sp_MSestimatesnapshotworkload
go			

--
-- Name: sp_MSdropfkreferencingarticle
--
-- Description: This procedure is used by the distribution agent to drop 
--              all the foreign key constraints at the subscriber referencing
--              a replicated table before re-applying snapshot. 
--
-- Parameters: @destination_object_name sysname (mandatory) 
--             @destination_owner_name sysname (optional, default = NULL)
--
-- Security: Only members of dbo and sysadmin can execute this procedure
--
print 'Creating procedure sp_MSdropfkreferencingarticle'
print ''
go
create procedure sp_MSdropfkreferencingarticle (
	@destination_object_name sysname,
	@destination_owner_name sysname = null
	)
as
begin
	set nocount on 
	declare @fk_name sysname,
	        @drop_command nvarchar(4000),
            @fkeyid int,
	        @retcode int,
            @robject_name sysname,
            @robject_owner sysname
	select @retcode = 0	

	-- Security check
	exec @retcode = dbo.sp_MSreplcheck_subscribe
	if @@error <> 0 or @retcode <> 0
		return 1	

	select @destination_owner_name = rtrim(ltrim(@destination_owner_name))
	
	declare hForeignKeys cursor local fast_forward
	for 
	    select object_name(sr.constid), sr.fkeyid 
	      from dbo.sysreferences sr
	inner join dbo.sysconstraints sc
		on sr.constid = sc.constid
	inner join dbo.sysobjects so
		on so.id = sr.rkeyid
	     where so.name = @destination_object_name
	       and (@destination_owner_name is null or
		    @destination_owner_name = N'' or
		    so.uid = user_id(@destination_owner_name))		
	open hForeignKeys
	
	fetch hForeignKeys into @fk_name, @fkeyid
	
	while (@@fetch_status <> -1)
	begin
        select @robject_name = name, @robject_owner = user_name(uid)
          from dbo.sysobjects 
         where id = @fkeyid

        select @drop_command = N'alter table ' +
               quotename(@robject_owner) + N'.' +
               quotename(@robject_name) + 
               N' drop constraint ' + quotename(@fk_name)
		exec(@drop_command)
		if @@error <> 0
		begin
			select @retcode = 1
			goto Failure
		end	
		fetch hForeignKeys into @fk_name, @fkeyid 
	end

Failure:
	close hForeignKeys
	deallocate hForeignKeys
	return @retcode
end
go
exec sp_MS_marksystemobject sp_MSdropfkreferencingarticle
go
--
-- sp_addscriptexec 
--
-- Description: this stored procedure can be used to post a SQL script to all 
-- 		subscribers of specified publication.
--
-- Parameters:	@publication	sysname		name of a single publication 
--		@scriptfile	nvarchar(4000)	full path to the SQL script file 
--		@skiperror	bit		stop or continue upon error
--
-- Returns:
-- 		0 if success
--		1 if failure
--
create proc sp_addscriptexec (
	@publication sysname
	,@scriptfile nvarchar (4000) 
	,@skiperror bit = 0
)
as
declare @directory nvarchar(4000)
declare @cmd nvarchar(4000)
declare @filename nvarchar(1024)
declare @subdirectory nvarchar(1024)
declare @artid int
declare @pubid int
declare @repl_freq int
declare @retcode int
declare @category int
declare @merge_pubid uniqueidentifier
declare @schemaversion int
declare @schemaguid uniqueidentifier

set nocount on

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

-- Check to see if the database has been activated for publication.
SELECT @category = category FROM master..sysdatabases WHERE name = DB_NAME() collate database_default
IF (@category & 1) = 0 and (@category & 4) = 0
BEGIN
	RAISERROR (14013, 16, -1)
	RETURN (1)
END

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

-- Make sure the publication is available before any cmdshell work.
if exists (select * from sysobjects where name='syspublications')
begin
	select @pubid = pubid, @repl_freq = repl_freq  from syspublications where name = @publication
	if @pubid is not null
	begin 
		-- Doesn't make sense to post for every article in the publication, 
		-- but artid is required for sp_replpostcmd to work, so just pick one.
		select top 1 @artid = artid from sysarticles where pubid = @pubid
		if(@artid is null)
		begin 
			RAISERROR (21332, 16, -1, @publication)
			return (1)
		end
		if(@repl_freq = 1) -- don't try to post to snapshot publication, it won't work.
		begin 
			RAISERROR (21340, 16, -1, @publication)
			return (1)
		end
	end
end
if exists (select * from sysobjects where name='sysmergepublications')
begin 
	select @merge_pubid = pubid  from sysmergepublications where name = @publication
	if @merge_pubid is not null
	begin 
		select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange
		if @schemaversion is null
			select @schemaversion = 1

		select @schemaguid = newid()
	end
end

if(@pubid is null and @merge_pubid is null)
begin 
	RAISERROR (21332, 16, -1, @publication)
	return (1)
end

exec @retcode = sp_MScopyscriptfile @scriptfile, @cmd=@cmd output
if @retcode <>0 or @@ERROR<>0
	return (1)

select @cmd = convert(nchar(1), @skiperror) + @cmd
if @pubid is not null
	exec @retcode = sp_replpostcmd 0, @pubid, @artid, 46, @cmd
if @merge_pubid is not null
	exec @retcode = sp_MSinsertschemachange @merge_pubid, NULL, @schemaversion, @schemaguid, 46, @cmd 
if @retcode <>0 or @@ERROR<>0
	return (1)
return (0)
go
EXEC dbo.sp_MS_marksystemobject 'sp_addscriptexec'
go

-- 
-- Name: sp_MSmergeupdatelastsyncinfo
-- 
-- Description: This procedure sets the last_sync_status, last_sync_summary and 
-- last updated time for a given merge subscription.
--
-- Parameters: @subid 				uniqueidentifier (mandatory)
--             @last_sync_status 	int (mandatory)
--             @last_sync_summary 	sysname (mandatory)
--
-- Returns: 0 - succeeded
--          1 - failed
--
-- Security: Sysadmin access only
--
print 'Creating procedure sp_MSmergeupdatelastsyncinfo'
print ''
go
create procedure sp_MSmergeupdatelastsyncinfo (
	@subid				uniqueidentifier,
	@last_sync_status 	int,
	@last_sync_summary 	sysname
)
as
    set nocount on
    declare @retcode int
    select @retcode = 0

    -- Security check
    exec @retcode = sp_MSreplcheck_subscribe    
    if @retcode<>0 or @@error<>0
        return 1

    if object_id('sysmergesubscriptions') is null 
    	begin
	        raiserror(14055, 16, -1)        
    	    return 1
    	end
    	
	update sysmergesubscriptions 
		set last_sync_status = @last_sync_status, 
			last_sync_summary = @last_sync_summary, 
			last_sync_date = getdate() 
		where subid = @subid
	if @@rowcount <> 1 or @@ERROR<>0
		begin
			return (1)
		end			
	return (0)
go

EXEC dbo.sp_MS_marksystemobject 'sp_MSmergeupdatelastsyncinfo'
go
grant execute on dbo.sp_MSmergeupdatelastsyncinfo to public
go


raiserror('Creating procedure sp_MSrepl_FixPALRole', 0,1)
go
CREATE PROCEDURE sp_MSrepl_FixPALRole (@pubid uniqueidentifier, @role sysname output)
AS
    declare @retcode int
    declare @quotedrole sysname
    declare @pubidstr nvarchar(36)
    declare @publication sysname
    declare @publisher_db sysname

    exec dbo.sp_MSguidtostr @pubid, @pubidstr output
    set @role = 'MSmerge_' + @pubidstr

    -- Add a database role which represents the users who have access to this publication
    -- do this fix up only if the role does not already exist. Assuming that if the role
    -- exists all is well and nothing needs to be done.
    if exists (select * from dbo.sysusers where issqlrole=1 and name=@role)
        return 0

    -- verify that there is a publication in the current db with this pubid
    select @publisher_db = db_name()
    select @publication = name from dbo.sysmergepublications where pubid = @pubid
    if (@publication is NULL)
    begin    
         RAISERROR (21073, 16, -1)
         return (1)
    end
    
    exec @retcode = dbo.sp_addrole @role
    if (@retcode <> 0 or @@error <> 0)
        return 1

    select @quotedrole = quotename(@role)

    -- grant select on system tables to this role
    exec ('grant select on MSmerge_errorlineage to ' +  @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec ('grant select on MSrepl_identity_range to ' + @quotedrole)
    if (@@error <> 0)
        return 1

	exec('grant select on sysmergearticles to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on sysmergesubscriptions to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on MSmerge_replinfo to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on MSmerge_tombstone to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on MSmerge_contents to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on MSmerge_genhistory to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on MSmerge_delete_conflicts to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on sysmergeschemachange to ' + @quotedrole)
    if (@@error <> 0)
        return 1
        
	exec('grant select on sysmergesubsetfilters to ' + @quotedrole)
    if (@@error <> 0)
        return 1

    -- cursor to browse through all articles in this publication and grant
    -- permissions on conflict_table, before_image_table etc to the role
    declare @bi_table sysname
    declare @bi_objectid int
    declare @owner sysname
    declare @quotedname nvarchar(270)
    
    declare art_cursor cursor LOCAL FAST_FORWARD
    for select before_image_objid from dbo.sysmergearticles where pubid = @pubid 
    open art_cursor
    fetch art_cursor into @bi_objectid
    while (@@fetch_status <> -1)
    begin
        if @bi_objectid is not NULL
        begin
            select @owner = NULL
            select @owner = user_name(uid) from sysobjects where id = @bi_objectid
            if @owner is NULL
                return 1
                
            select @bi_table = OBJECT_NAME(@bi_objectid)
            if (@@error <> 0)
                return 1
                
            select @quotedname = QUOTENAME(@owner)+ '.' + QUOTENAME(@bi_table)
        	exec('grant select (system_delete, generation), update(generation), delete on ' + @quotedname + ' to ' + @quotedrole)
            if (@@error <> 0)
                return 1            
        end
        select @bi_objectid = NULL
        fetch art_cursor into @bi_objectid
    end
    close art_cursor
    deallocate art_cursor


    -- check if there are any users already been granted access to on the
    -- distributor for this publication
    declare @rpcsrvname sysname
    declare @distribdb sysname
    declare @distproc sysname
    declare @login sysname
    declare @user sysname
    
    exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @rpcsrvname OUTPUT, @distribdb = @distribdb OUTPUT
    IF ((@retcode <> 0) or (@@error <> 0) OR (@distribdb IS NULL) OR (@rpcsrvname IS NULL))
    BEGIN
        RAISERROR (14071, 16, -1)
        return(1)
    END

    -- using a temp table because of the following error
    -- EXECUTE cannot be used as a source when inserting into a table variable.
    create table #logins_table (login sysname)
    
    SELECT @distproc = RTRIM(@rpcsrvname) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSenumerate_PAL'

    insert into #logins_table exec @distproc 
            @publisher = @@SERVERNAME, 
            @publisher_db = @publisher_db, 
            @publication = @publication
    if @@error <> 0
        return 1
        
    declare logins_cursor cursor LOCAL FAST_FORWARD
    for select login from #logins_table
    open logins_cursor
    fetch logins_cursor into @login
    while (@@fetch_status <> -1)
    begin
        select @user = NULL
        select @user = name from sysusers where sid = suser_sid(@login) and hasdbaccess = 1 and name <> 'dbo'
        if @user is not NULL
        begin
            exec @retcode = dbo.sp_addrolemember @role, @user
            if (@retcode <> 0 or @@error <> 0)
                goto FAILURE
        end
        fetch logins_cursor into @login
    end
    close logins_cursor
    deallocate logins_cursor

    drop table #logins_table
    return 0
    
FAILURE:
    close logins_cursor
    deallocate logins_cursor

    drop table #logins_table
    return 1
go
EXEC dbo.sp_MS_marksystemobject 'sp_MSrepl_FixPALRole'
go

raiserror('Creating procedure sp_createmergepalrole', 0,1)
go
CREATE PROCEDURE sp_createmergepalrole (@publication sysname)
AS
    declare @role sysname
    declare @retcode int
    declare @pubid uniqueidentifier

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

    select @pubid = pubid from dbo.sysmergepublications 
        where name = @publication and publisher_db = db_name() 
            and UPPER(publisher) collate database_default = UPPER(@@SERVERNAME) collate database_default
    if (@pubid is NULL)
    begin
    	RAISERROR (20026, 16, -1, @publication)
	    return (1)
    end

    exec @retcode = sp_MSrepl_FixPALRole @pubid = @pubid, @role = @role OUTPUT
    if @retcode <> 0 or @@error <> 0
    begin
        RAISERROR (20625, 16, -1, @publication)
        return 1
    end

    return 0
go
EXEC dbo.sp_MS_marksystemobject 'sp_createmergepalrole'
go
grant execute on dbo.sp_createmergepalrole to public
go

create procedure sp_MSsetcontext_replagent @agent_type tinyint
as
begin
	declare @cur_context varbinary(128)
	declare @cur_context_first_byte binary(1)
	declare @bitmask tinyint
	
	-- agent type: snapshot=1, logreader=2, distrib=3, merge=4
	-- bit to set: snapshot=1, logreader=2, distrib=4, merge=8
	select @bitmask =	case 	
							when @agent_type = 1 then 1 
							when @agent_type = 2 then 2
							when @agent_type = 3 then 4
							when @agent_type = 4 then 8
						end

	-- get the current context_info from sysprocesses. remember we only want to modify a bit without changing the rest of the info
	select @cur_context = context_info from master.dbo.sysprocesses where spid = @@spid
	-- get the first byte out. the replication agent flags are set in the first byte.
	select @cur_context_first_byte = substring(@cur_context, 1, 1)
	-- set the appropriate bit in this one byte (leaving other bits unchanged).
	select @cur_context_first_byte = (convert(tinyint,@cur_context_first_byte) | @bitmask)
	-- replace the first byte of the 128 byte binary variable, so that now it has the appropriate bit set.
	select @cur_context = convert(varbinary(128),stuff (@cur_context, 1, 1, @cur_context_first_byte))
	-- set the context_info again with the new binary(128) value.
	set context_info @cur_context
end
go
EXEC dbo.sp_MS_marksystemobject 'sp_MSsetcontext_replagent'
go
grant execute on dbo.sp_MSsetcontext_replagent to public
go
create function dbo.fn_isreplmergeagent() returns bit
as
begin
	declare @cur_context varbinary(128)
	declare @cur_context_first_byte binary(1)
	declare @bitmask tinyint
	declare @ismergeagent bit
	
	select @bitmask = 8		-- 	snapshot=1, logreader=2, distrib=4, merge=8
	
	-- get the current context_info from sysprocesses. 
	select @cur_context = context_info from master.dbo.sysprocesses where spid = @@spid
	-- get the first byte out of the 128 byte array.
	select @cur_context_first_byte = substring(@cur_context, 1, 1)
	-- check whether it has the merge agent bit set.
	select @bitmask = (convert(tinyint,@cur_context_first_byte) & @bitmask)
	-- set the return value appropriately.
	select @ismergeagent = case when @bitmask = 0 then 0 else 1 end

	return @ismergeagent
end
go
grant execute on dbo.fn_isreplmergeagent to public
go
grant execute on dbo.sp_MSestimatesnapshotworkload to public
go

grant execute on dbo.sp_helpreplicationoption to public
go

grant execute on dbo.sp_addpullsubscription to public
go

grant execute on dbo.sp_addpullsubscription_agent to public
go

grant execute on dbo.sp_droppullsubscription to public
go

grant execute on dbo.sp_helppullsubscription to public
go

grant execute on dbo.sp_helpreplicationdboption to public
go

grant exec on dbo.sp_addqueued_artinfo to public
grant exec on dbo.sp_addsynctriggers to public
grant exec on dbo.sp_setreplfailovermode to public
grant exec on dbo.sp_helpreplfailovermode to public
go

grant exec on dbo.sp_MScheck_agent_instance to public
go

grant exec on dbo.sp_get_distributor to public
go

grant exec on dbo.sp_table_validation to public

grant exec on dbo.sp_addmergepullsubscription to public

grant exec on dbo.sp_dropmergepullsubscription to public

grant exec on dbo.sp_changemergepullsubscription to public

grant exec on dbo.sp_helpmergepullsubscription to public

grant exec on dbo.sp_addmergepullsubscription_agent to public
go

grant exec on dbo.sp_helpsubscription_properties to public

grant exec on dbo.sp_change_subscription_properties to public

grant exec on dbo.sp_MSreplcheck_subscribe to public

grant exec on dbo.sp_link_publication to public

grant exec on dbo.sp_MSrepl_linkedservers_rowset to public

grant exec on dbo.sp_MScreate_sub_tables to public
--grant exec on dbo.sp_MSupdate_mqserver_subdb to public

grant exec on dbo.sp_MSget_jobstate to public
go
grant exec on dbo.sp_MSrepl_isdbowner to public
go
grant exec on dbo.sp_MSreplraiserror to public
grant exec on dbo.sp_check_sync_trigger to public
grant exec on dbo.sp_check_for_sync_trigger to public
grant exec on dbo.sp_MSget_publisher_rpc to public
go
--grant execute on dbo.sp_MSscript_where_clause to public
--grant execute on dbo.sp_MSscript_params to public
--grant execute on dbo.sp_MSscript_procbodystart to public
--grant execute on dbo.sp_MSscript_begintrig1 to public
--grant execute on dbo.sp_MSscript_begintrig2 to public
--grant execute on dbo.sp_MSscript_endtrig to public
--grant execute on dbo.sp_MSscript_trigger_variables to public
--grant execute on dbo.sp_MSscript_trigger_assignment to public
--grant execute on dbo.sp_MSscript_trigger_fetch_statement to public
--grant execute on dbo.sp_MSscript_trigger_exec_rpc  to public
--grant execute on dbo.sp_MSscript_trigger_update_checks to public
--grant execute on dbo.sp_MSscript_trigger_updates to public
--grant execute on dbo.sp_MSscript_singlerow_trigger to public 
--grant execute on dbo.sp_MSscript_multirow_trigger to public
grant execute on dbo.sp_MSscript_sync_ins_trig to public
grant execute on dbo.sp_MSscript_sync_upd_trig to public
grant execute on dbo.sp_MSscript_sync_del_trig to public
--grant execute on dbo.sp_MSscript_pkvar_assignment to public
--grant exec on dbo.sp_MSscript_pkvar_assignment to public
--grant execute on dbo.sp_MSreplcheck_pull to public
grant execute on dbo.sp_MSdropfkreferencingarticle to public
go
grant execute on dbo.sp_enableagentoffload to public
grant execute on dbo.sp_disableagentoffload to public
grant execute on dbo.sp_getagentoffloadinfo to public
grant execute on dbo.sp_MSsub_check_identity to public
grant execute on dbo.sp_MSsub_set_identity to public
grant execute on dbo.sp_copysubscription to public
grant execute on dbo.sp_attachsubscription to public
grant execute on dbo.sp_MSadd_compensating_cmd to public
grant execute on dbo.sp_MSsendtosqlqueue to public
grant execute on dbo.sp_MSretrieve_publication_attributes to public
grant execute on dbo.sp_MScleanup_publication_ADinfo to public
go

grant execute on dbo.fn_varbintohexstr to public
grant execute on dbo.fn_varbintohexsubstring to public
grant execute on dbo.fn_MSgensqescstr to public
go

grant execute on dbo.sp_MSgettools_path to public
grant execute on dbo.sp_MSget_shared_agent to public
grant execute on dbo.sp_addscriptexec to public
grant execute on dbo.sp_MSgetlastupdatedtime to public
go

grant execute on system_function_schema.fn_replquotename to public
grant execute on system_function_schema.fn_chariswhitespace to public
grant execute on system_function_schema.fn_generateparameterpattern to public
grant execute on system_function_schema.fn_skipparameterargument to public
grant execute on system_function_schema.fn_removeparameterwithargument to public
grant execute on system_function_schema.fn_updateparameterwithargument to public
grant execute on system_function_schema.fn_repluniquename to public
go

--grant execute on dbo.sp_MSreset_queue to public


dump tran master with no_log
go
sp_configure 'allow updates',0
go
reconfigure with override
go

print ''
print 'Checking objects created by replsys.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 'replsys.sql completed successfully.'
go

dump tran master with no_log
go
checkpoint
go

