set nocount on go execute dbo.sp_configure 'update',1 go reconfigure with override go set ANSI_NULLS off go use master go dump tran master with no_log go /* ** Drop the stored procedures in this script using the old dropping SP ** and then drop itself */ if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSdrop_rlcore') begin exec dbo.sp_MSdrop_rlcore drop procedure sp_MSdrop_rlcore end /* ** Create stored procedures to drop the stored procedures ** created by this script */ raiserror('Creating procedure sp_MSdrop_rlcore', 0,1) GO create procedure sp_MSdrop_rlcore as if exists (select * from sysobjects where type = 'P' and name = 'sp_MSguidtostr') drop procedure sp_MSguidtostr if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetconflicttablename') drop procedure sp_MSgetconflicttablename if exists (select * from sysobjects where type = 'P' and name = 'sp_MSuniquetempname') drop procedure sp_MSuniquetempname if exists (select * from sysobjects where type = 'P' and name = 'sp_MSuniqueobjectname') drop procedure sp_MSuniqueobjectname if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddguidcolumn') drop procedure sp_MSaddguidcolumn if exists (select * from sysobjects where type = 'P' and name = 'sp_MSuniquecolname') drop procedure sp_MSuniquecolname if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddguidindex') drop procedure sp_MSaddguidindex if exists (select * from sysobjects where type = 'P' and name = 'sp_MSrefcnt') drop procedure sp_MSrefcnt if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgentablenickname') drop procedure sp_MSgentablenickname if exists (select * from sysobjects where type = 'P' and name = 'sp_MStablenickname') drop procedure sp_MStablenickname if exists (select * from sysobjects where type = 'P' and name = 'sp_MStablenamefromnick') drop procedure sp_MStablenamefromnick if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakegeneration') drop procedure sp_MSmakegeneration if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddupdatetrigger') drop procedure sp_MSaddupdatetrigger if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddmergetriggers') drop procedure sp_MSaddmergetriggers if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmaptype') drop procedure sp_MSmaptype go exec dbo.sp_MS_marksystemobject sp_MSdrop_rlcore go exec dbo.sp_MSdrop_rlcore go dump tran master with no_log go raiserror('Creating procedure sp_MSguidtostr', 0, 1) GO create proc sp_MSguidtostr (@guid uniqueidentifier, @mystr nvarchar(32) output) as declare @guidstr nvarchar(36) set @guidstr = convert(nchar(36), @guid) set @mystr = substring(@guidstr, 1, 8) + substring(@guidstr, 10, 4) + substring(@guidstr, 15, 4)+ substring(@guidstr, 20, 4)+ substring(@guidstr, 25, 12) go exec dbo.sp_MS_marksystemobject sp_MSguidtostr go raiserror('Creating procedure sp_MSgetconflicttablename', 0,1) GO CREATE PROCEDURE sp_MSgetconflicttablename @source_object nvarchar(258), @conflict_table sysname = NULL OUTPUT AS declare @objid int declare @retcode int declare @current_conflict sysname declare @object_name sysname declare @name_out sysname select @objid = object_id(@source_object) select @current_conflict = conflict_table from sysmergearticles where objid = @objid and conflict_table is not NULL if @current_conflict is not NULL begin if @conflict_table is NULL select @current_conflict else select @conflict_table = @current_conflict return (0) end select @object_name = object_name(@objid) select @object_name = 'conflict_' + @object_name exec @retcode = dbo.sp_MSuniqueobjectname @object_name, @conflict_table OUTPUT GO exec dbo.sp_MS_marksystemobject sp_MSgetconflicttablename go grant exec on dbo.sp_MSgetconflicttablename to public go raiserror('Creating procedure sp_MSuniqueobjectname', 0,1) GO CREATE PROCEDURE sp_MSuniqueobjectname @name_in sysname, @name_out sysname = NULL output AS declare @name_out_local sysname declare @subschars sysname declare @curchar nchar(1) declare @substidx int declare @pos int select @subschars = 'abcdefghijklmnopqrstuvwxyz' select @name_out_local = @name_in select @substidx = 0 select @pos = 1 while exists (select * from sysobjects where name = @name_out_local) begin if @substidx > 25 begin select @pos = @pos + 1 select @substidx = 1 end else select @substidx = @substidx + 1 select @curchar = substring(@subschars, @substidx, 1) select @name_out_local = stuff(@name_out_local, @pos, 1, @curchar) end if @name_out IS NULL select @name_out_local else select @name_out = @name_out_local return (0) GO exec dbo.sp_MS_marksystemobject sp_MSuniqueobjectname go raiserror('Creating procedure sp_MSuniquetempname', 0,1) GO CREATE PROCEDURE sp_MSuniquetempname @name_in sysname, @name_out sysname output AS declare @subschars nvarchar(26) declare @curchar nchar(1) declare @substidx int declare @pos int declare @saverr int select @subschars = 'abcdefghijklmnopqrstuvwxyz' select @saverr = @@error if (@saverr <> 0) goto EXIT_LABEL select @name_out = @name_in select @saverr = @@error if (@saverr <> 0) goto EXIT_LABEL select @saverr = @@error if (@saverr <> 0) goto EXIT_LABEL select @substidx = 0 select @pos = 3 while exists (select * from tempdb..sysobjects where name = @name_out) begin if @substidx > 25 begin select @pos = @pos + 1 select @substidx = 1 end else select @substidx = @substidx + 1 select @curchar = substring(@subschars, @substidx, 1) select @saverr = @@error if (@saverr <> 0) goto EXIT_LABEL select @name_out = stuff(@name_out, @pos, 1, @curchar) select @saverr = @@error if (@saverr <> 0) goto EXIT_LABEL end return (0) EXIT_LABEL: if (@saverr <> 0) begin RAISERROR(15001, 16, -1, 'sp_MSuniquetempname') return (1) end GO exec dbo.sp_MS_marksystemobject sp_MSuniquetempname go raiserror('Creating procedure sp_MSuniquecolname', 0,1) GO create procedure sp_MSuniquecolname @table_name nvarchar(258), -- this is a qualified_name @base_colname sysname, @unique_colname sysname output as begin set nocount on declare @icol_suffix int select @icol_suffix = ( max(colorder) + 1 ) from syscolumns where id = object_id( @table_name ) select @unique_colname = @base_colname while exists( select * from syscolumns where id = object_id( @table_name ) and name = @unique_colname ) begin select @unique_colname = @base_colname + convert( nvarchar(40), @icol_suffix ) select @icol_suffix = @icol_suffix * ( @@spid + 1 ) end end go exec dbo.sp_MS_marksystemobject sp_MSuniquecolname go raiserror('Creating procedure sp_MSaddguidcolumn', 0,1) GO create procedure sp_MSaddguidcolumn @source_owner sysname, @source_table sysname /* table name */ as declare @rowguidcol sysname declare @qualified_name nvarchar(258) set nocount on select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table) /* Alter the source table to add a rowguid column */ begin tran exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner if @@ERROR <>0 goto UNDO if not exists (select * from syscolumns where ObjectProperty(object_id(@qualified_name), 'tablehasrowguidcol')=1) begin exec dbo.sp_MSuniquecolname @qualified_name, 'rowguid', @rowguidcol output exec ('alter table ' + @qualified_name + ' add ' + @rowguidcol + ' uniqueidentifier ROWGUIDCOL default newid() not null') if @@ERROR<>0 goto UNDO end exec dbo.sp_MSunmarkreplinfo @source_table, @source_owner, 1 if @@ERROR<>0 goto UNDO commit tran return (0) UNDO: if @@TRANCOUNT = 1 ROLLBACK TRANSACTION else COMMIT TRANSACTION return (1) go exec dbo.sp_MS_marksystemobject sp_MSaddguidcolumn go grant exec on dbo.sp_MSaddguidcolumn to public go raiserror('Creating procedure sp_MSaddguidindex', 0,1) GO create procedure sp_MSaddguidindex @source_owner sysname, @source_table sysname as set nocount on declare @indexname nvarchar(270) declare @colname sysname declare @retcode int declare @qualified_name nvarchar(258) select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_table) select @indexname = 'index_' + convert(nvarchar(36), object_id(@qualified_name)) /* Make sure index name is unique */ exec @retcode = dbo.sp_MSuniqueobjectname @indexname, @indexname output if @retcode <>0 return (1) select @colname=name from syscolumns where id=object_id(@qualified_name) and columnproperty(object_id(@qualified_name), name, 'isrowguidcol')=1 if (@colname is null) return (1) /* Alter the source table to add a rowguid column */ if (not exists (select * from sysindexes where id = object_id(@qualified_name) and @colname = index_col(object_name(id), indid, 1) and indexproperty(id, name, 'IsUnique') = 1 and index_col(object_name(id), indid, 2) is null)) exec ('create unique index ' + @indexname + ' on ' + @qualified_name + ' (' + @colname + ')') if @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSaddguidindex go grant exec on dbo.sp_MSaddguidindex to public go raiserror('Creating procedure sp_MSrefcnt', 0,1) GO create procedure sp_MSrefcnt @objid int, @refcnt int output as set @refcnt = 0 create table #temprefs (objid int NOT NULL) insert into #temprefs select distinct rkeyid from sysreferences where fkeyid = @objid while (@@rowcount > 0) insert into #temprefs select distinct rkeyid from sysreferences where fkeyid in (select objid from #temprefs) and rkeyid not in (select objid from #temprefs) select @refcnt = count(*) from #temprefs return (0) GO exec dbo.sp_MS_marksystemobject sp_MSrefcnt go raiserror('Creating procedure sp_MSgentablenickname', 0,1) GO create procedure sp_MSgentablenickname @tablenick int output, @nickname int, @objid int as declare @refcnt int declare @retval int /* Create a tablenickname from the following formula ** 1. Get the refcnt, use it for the high order digits so ** that processing inserts by ascending tablenickname works well ** and processing deletes by descending tablenickname works well. ** 2. Use a couple of digits from the nickname so that it is less likely ** to collide with tablenickname generated at another merge publisher. ** 3. Increment as necessary to make it unique within the publication and database. */ exec @retval = dbo.sp_MSrefcnt @objid, @refcnt output if @retval <> 0 return (1) if @nickname < 0 set @nickname = 0 - @nickname set @tablenick = 1000 * ((@refcnt * 10000) + (@nickname % 10000)) while exists (select * from sysmergearticles where nickname = @tablenick) set @tablenick = @tablenick + 1 return (0) go exec dbo.sp_MS_marksystemobject sp_MSgentablenickname go raiserror('Creating procedure sp_MStablenickname', 0,1) GO create procedure sp_MStablenickname @owner sysname, @tablename sysname, @nick int output as declare @qualified_name nvarchar(255) if @owner is not null select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@tablename) else select @qualified_name = QUOTENAME(@tablename) select @nick = nickname from sysmergearticles a, sysobjects o where a.objid = o.id and o.id = OBJECT_ID(@qualified_name) and (user_name(uid) = @owner or @owner is null) if @nick is NULL return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MStablenickname go raiserror('Creating procedure sp_MStablenamefromnick', 0,1) GO create procedure sp_MStablenamefromnick @nick int, @tablename nvarchar(258) output, @pubid uniqueidentifier = NULL as declare @owner sysname declare @table sysname if (@pubid is null) select @table = name, @owner = user_name(uid) from sysobjects where id in (select objid from sysmergearticles where nickname = @nick) else select @table = name, @owner = user_name(uid) from sysobjects where id in (select objid from sysmergearticles where nickname = @nick and pubid = @pubid) select @tablename = QUOTENAME(@owner) + '.' + QUOTENAME(@table) if (@table is NULL) or (@owner is NULL) begin raiserror(211124, 16, -1, @nick) return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MStablenamefromnick go raiserror('Creating procedure sp_MSmakegeneration', 0,1) GO create procedure sp_MSmakegeneration @rowcount int = 0 as declare @gen int declare @nick int declare @genguid uniqueidentifier declare @dt datetime declare @dt2 datetime declare @art_nick int declare @first_ts int declare @makenewrow int declare @retcode smallint declare @guidnull uniqueidentifier set nocount on set rowcount @rowcount set @guidnull = '00000000-0000-0000-0000-000000000000' /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection if @retcode<>0 or @@ERROR<>0 return (1) set @genguid = newid() exec @retcode=sp_MSgetreplnick @nickname = @nick out if @retcode<>0 or @@error<>0 return (1) set @dt = getdate() -- If someone else is making generations / has just made one, exit so -- that we won't deadlock select @dt2 = max(coldate) from MSmerge_genhistory where guidsrc = guidlocal if datediff(dd, @dt2, @dt) = 0 begin if 500 > datediff(ms, @dt2, @dt) and 0 < datediff(ms, @dt2, @dt) return 0 end -- check for holes select @gen = max(generation) from MSmerge_genhistory if exists (select * from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles)) begin -- before we delete the holes, move contents rows to generation 0 so they don't get forgotten if exists (select * from MSmerge_contents (readpast readcommitted) where generation in (select generation from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles))) begin update MSmerge_contents set generation = 0 where generation in (select generation from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles)) if (@@error <> 0) begin goto FAILURE end end if exists (select * from MSmerge_tombstone (readpast readcommitted) where generation in (select generation from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles))) begin update MSmerge_tombstone set generation = 0 where generation in (select generation from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles)) if (@@error <> 0) begin goto FAILURE end end delete from MSmerge_genhistory where guidlocal = @guidnull and generation < @gen - 100 and generation not in (select gen_cur from sysmergearticles) if (@@error <> 0) begin goto FAILURE end end /* ** If there are no zero generation tombstones or rows, add a dummy row in there. */ if not exists (select * from MSmerge_genhistory where guidlocal <> @guidnull) begin begin tran insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values (@genguid, @genguid, 1, 0, @nick, @dt) if (@@error <> 0) begin goto FAILURE end commit tran end select @art_nick = min(nickname) from sysmergearticles while @art_nick is not null begin begin tran select @gen = max(gen_cur) from sysmergearticles (updlock) where nickname = @art_nick and gen_cur is not null if @gen is null begin insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @art_nick, @nick, @dt from MSmerge_genhistory (updlock) if (@@error <> 0) begin goto FAILURE end select @gen = generation from MSmerge_genhistory where guidsrc = @genguid update sysmergearticles set gen_cur = @gen where nickname = @art_nick if (@@error <> 0) begin goto FAILURE end end -- these updates should be hitting zero rows... if exists (select * from MSmerge_contents (readpast readcommitted) where generation = 0 and tablenick = @art_nick) begin update MSmerge_contents set generation = @gen, partchangegen = @gen, joinchangegen = @gen where generation = 0 and partchangegen = 0 and tablenick = @art_nick if (@@error <> 0) begin goto FAILURE end update MSmerge_contents set generation = @gen, joinchangegen = @gen where generation = 0 and joinchangegen = 0 and tablenick = @art_nick if (@@error <> 0) begin goto FAILURE end update MSmerge_contents set generation = @gen where generation = 0 and tablenick = @art_nick if (@@error <> 0) begin goto FAILURE end end if exists (select * from MSmerge_tombstone (readpast readcommitted) where generation = 0 and tablenick = @art_nick) begin update MSmerge_tombstone set generation = @gen where generation = 0 and tablenick = @art_nick if (@@error <> 0) begin goto FAILURE end end if not exists (select * from MSmerge_contents where tablenick = @art_nick and generation = @gen) and not exists (select * from MSmerge_tombstone where tablenick = @art_nick and generation = @gen) begin select @dt2 = coldate from MSmerge_genhistory where generation = @gen if datediff(dd, @dt2, @dt) = 0 and not exists (select * from MSmerge_genhistory where generation > 100 + @gen) begin set @makenewrow = 0 end else begin set @makenewrow = 1 delete from MSmerge_genhistory where generation = @gen if (@@error <> 0) begin goto FAILURE end end if (@@error <> 0) begin goto FAILURE end end else begin set @makenewrow = 1 set @genguid = newid() update MSmerge_genhistory set guidsrc = @genguid, guidlocal = @genguid, coldate = @dt where generation = @gen if (@@error <> 0) begin goto FAILURE end update MSmerge_replinfo set recgen = @gen, recguid = @genguid, sentgen = @gen, sentguid = @genguid where replnickname = @nick if (@@error <> 0) begin goto FAILURE end end if (@makenewrow = 1) begin /* reset next generation for this article */ set @genguid = newid() insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) select @genguid, @guidnull, COALESCE(1 + max(generation), 1), @art_nick, @nick, @dt from MSmerge_genhistory (updlock) if (@@error <> 0) begin goto FAILURE end select @gen = generation from MSmerge_genhistory where guidsrc = @genguid update sysmergearticles set gen_cur = @gen where nickname = @art_nick if (@@error <> 0) begin goto FAILURE end end commit transaction -- set up for next time through the loop select @art_nick = min(nickname) from sysmergearticles where nickname > @art_nick set @dt = getdate() end return 0 FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT = 1 ROLLBACK TRANSACTION makegeneration else COMMIT TRANSACTION return (1) go exec dbo.sp_MS_marksystemobject sp_MSmakegeneration go grant exec on dbo.sp_MSmakegeneration to public go dump tran master with no_log go raiserror('Creating procedure sp_MSaddupdatetrigger', 0,1) GO CREATE PROCEDURE sp_MSaddupdatetrigger @source_table nvarchar(258), /* source table name */ @owner sysname, /* Owner name of source table */ @object sysname, /* Object name */ @artid uniqueidentifier, /* Article id */ @column_tracking int, @viewname sysname /* name of view on syscontents */ AS declare @command1 nvarchar(4000) declare @command2 nvarchar(4000) declare @tablenick int declare @nickname int declare @trigname sysname declare @ext nvarchar(10) declare @gstr sysname declare @tablenickchar nvarchar(11) declare @ccols int declare @guidstr nvarchar(32) declare @colid smallint declare @colordinal smallint declare @colordstr varchar(4) declare @colname sysname declare @colpat nvarchar(34) declare @colchar nvarchar(5) declare @piece nvarchar(400) declare @retcode int declare @ifcol nvarchar(4000) declare @ccolchar nvarchar(5) declare @partchangecnt int declare @joinchangecnt int declare @partchangecnt2 int declare @cvstr1 nvarchar(500) declare @cvstr2 nvarchar(500) declare @flag smallint declare @missingbm varbinary(500) declare @missingcolid int declare @maxcolid int declare @missingbmstr varchar(1000) declare @objid int declare @partchbm varbinary(500) declare @joinchbm varbinary(500) declare @partchstr varchar(1002) declare @joinchstr varchar(1002) set @ifcol = '' select @flag = 0 set @objid = OBJECT_ID(@source_table) select @ccols = count(*) from syscolumns where id = @objid and iscomputed <> 1 select @ccolchar = convert(nchar, @ccols) set @colordinal = 0 execute @retcode=sp_MStablenickname @owner, @object, @tablenick output if @@ERROR<>0 or @retcode<>0 return (1) set @tablenickchar = convert(nchar, @tablenick) set @joinchbm = 0x0 set @partchbm = 0x0 declare col_cursor CURSOR LOCAL FAST_FORWARD for select name, colid from syscolumns where id = @objid and iscomputed <> 1 order by colid FOR READ ONLY /* Try to set the ifcol pieces of the trigger */ open col_cursor fetch next from col_cursor into @colname, @colid while (@@fetch_status <> -1) begin set @colordinal = @colordinal + 1 set @colpat = '%' + @colname + '%' set @colname = QUOTENAME(@colname) /* Don't let them update the rowguid column */ if columnproperty( @objid, @colname , 'isrowguidcol')=1 set @ifcol = 'if update(' + @colname + ') begin if @@trancount > 0 rollback tran RAISERROR (20062, 16, -1) end ' /* does updating this column change membership in a partial replica? */ select @partchangecnt = count(*) from sysmergearticles where nickname = @tablenick and subset_filterclause like @colpat select @partchangecnt2 = count(*) from sysmergesubsetfilters where art_nickname = @tablenick and join_filterclause like @colpat select @joinchangecnt = count(*) from sysmergesubsetfilters where join_nickname = @tablenick and join_filterclause like @colpat if @partchangecnt > 0 or @partchangecnt2 > 0 exec dbo.sp_MSsetbit @partchbm out, @colid else if @joinchangecnt > 0 exec dbo.sp_MSsetbit @joinchbm out, @colid /* Repeat the loop with next column */ fetch next from col_cursor into @colname, @colid end close col_cursor deallocate col_cursor /* Make strings to initialize variables for partchange, joinchange bitmaps */ exec master..xp_varbintohexstr @partchbm, @partchstr out exec master..xp_varbintohexstr @joinchbm, @joinchstr out /* Figure out if there are any holes in the colid sequence */ select @maxcolid = max(colid) from syscolumns where id = @objid if @maxcolid = @ccols set @missingbmstr = '0x00' else begin set @missingcolid = 1 set @missingbm = 0x00 while (@missingcolid <= @maxcolid) begin if not exists (select * from syscolumns where colid = @missingcolid and id = OBJECT_ID(@source_table) and iscomputed <> 1) exec dbo.sp_MSsetbit @missingbm out, @missingcolid set @missingcolid = @missingcolid + 1 end exec master..xp_varbintohexstr @missingbm, @missingbmstr out end execute @retcode=sp_MSgetreplnick @nickname = @nickname output if @retcode<>0 or @@error<>0 return (1) set @ext = 'upd_' exec @retcode=sp_MSguidtostr @artid, @guidstr out if @retcode<>0 or @@error<>0 return (1) set @trigname = @ext + @guidstr /* Make sure trigger name is unique */ exec @retcode=sp_MSuniqueobjectname @trigname, @trigname output if @retcode<>0 or @@error<>0 return (1) if @column_tracking <> 0 begin /* Set cv pieces appropriately */ set @cvstr1 = ' set @lineage = { fn UPDATELINEAGE(0x0, @nick) } set @lineage = { fn UPDATELINEAGE(@lineage, @nick) } set @cv = { fn INITCOLVS(@ccols, @nick) } if (@@error <> 0) begin goto FAILURE end set @cv = { fn UPDATECOLVBM(@cv, @nick, @bm, @missingbm) } ' set @cvstr2 = ' colv1 = { fn UPDATECOLVBM(colv1, @nick, @bm, @missingbm) } ' end else begin set @cvstr1 = ' set @lineage = { fn UPDATELINEAGE(0x0, @nick) } set @lineage = { fn UPDATELINEAGE(@lineage, @nick) } set @cv = NULL ' set @cvstr2 = ' colv1 = NULL ' end /* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */ select @command1 = 'create trigger ' + @trigname + ' on ' + @source_table + ' FOR UPDATE AS /* Declare variables */ declare @bm varbinary(500) declare @missingbm varbinary(500) declare @tablenick int declare @rowguid uniqueidentifier declare @lineage varbinary(255) declare @cv varbinary(2048) declare @ver int declare @nick int declare @ccols int declare @partchange int declare @joinchange int declare @partgen int declare @joingen int declare @partchangebm varbinary(500) declare @joinchangebm varbinary(500) declare @newgen int set nocount on select @newgen = gen_cur from sysmergearticles where nickname = ' + @tablenickchar + ' if @newgen is null set @newgen = 0 /* Use intrinsic funtion to set bits for updated columns */ set @bm = columns_updated() set @missingbm = ' select @command2 = ' /* See if the partition might have changed */ if @partchangebm = 0x0 set @partchange = 0 else set @partchange= { fn INTERSECTBITMAPS (@bm, @partchangebm) } /* See if a column used in a join filter changed */ if @joinchangebm = 0x0 set @joinchange = 0 else set @joinchange= { fn INTERSECTBITMAPS (@bm, @joinchangebm) } select @tablenick = ' + @tablenickchar + ' exec dbo.sp_MSgetreplnick @nickname = @nick output select @ccols = ' + @ccolchar + ' ' + @cvstr1 + ' if @joinchange = 1 begin update ' + @viewname + ' set lineage = { fn UPDATELINEAGE(lineage, @nick) }, generation = @newgen, joinchangegen = @newgen, ' + @cvstr2 + ' where tablenick = @tablenick and rowguid in (select rowguidcol from inserted) if @@error <> 0 GOTO FAILURE set @joingen = @newgen set @partgen = @newgen end else if @partchange = 1 begin set @partgen = @newgen set @joingen = NULL update ' + @viewname + ' set lineage = { fn UPDATELINEAGE(lineage, @nick) }, generation = @newgen, partchangegen = @newgen, ' + @cvstr2 + ' where tablenick = @tablenick and rowguid in (select rowguidcol from inserted) if @@error <> 0 GOTO FAILURE end else begin set @partgen = NULL set @joingen = NULL update ' + @viewname + ' set lineage = { fn UPDATELINEAGE(lineage, @nick) }, generation = @newgen, ' + @cvstr2 + ' where tablenick = @tablenick and rowguid in (select rowguidcol from inserted) if @@error <> 0 GOTO FAILURE end insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, partchangegen, joinchangegen) select @tablenick, rowguidcol, @lineage, @cv, @newgen, @partgen, @joingen from inserted where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick) if @@error <> 0 GOTO FAILURE return FAILURE: if @@trancount > 0 rollback tran raiserror (20041, 16, -1) return ' execute (@command1 + @missingbmstr + ' set @partchangebm = ' + @partchstr + ' set @joinchangebm = ' + @joinchstr + ' ' + @ifcol + @command2) if @@ERROR <> 0 begin raiserror(20064, 16, -1) return (1) end execute ('sp_MS_marksystemobject ''' + @trigname + '''') GO exec dbo.sp_MS_marksystemobject sp_MSaddupdatetrigger go raiserror('Creating procedure sp_MSaddmergetriggers', 0,1) GO CREATE PROCEDURE sp_MSaddmergetriggers @source_table sysname, /* was type varchar(92), table name */ @column_tracking int = NULL /* Is column tracking on - default is FALSE */ AS set nocount on declare @command nvarchar(4000) declare @ifcoltracking nvarchar(255) declare @tablenick int declare @nickname int declare @artid uniqueidentifier declare @guidstr nvarchar(32) declare @owner sysname declare @site sysname declare @db sysname declare @object sysname declare @updtrigname sysname declare @instrigname sysname declare @deltrigname sysname declare @ext nvarchar(10) declare @ext2 nvarchar(10) declare @tablenickchar nvarchar(11) declare @ccols int declare @ccolchar nvarchar(5) declare @retcode int declare @objid int declare @bitmap varbinary(40) declare @missing_count int declare @viewname sysname declare @tsview sysname set @bitmap = 0x0 set @missing_count = 0 -- PARSENAME VARS declare @UnqualName sysname --rightmost name node declare @QualName1 sysname -- END PARSENAME VARS execute @retcode=sp_MSgetreplnick @nickname = @nickname output if @retcode<>0 or @@ERROR<>0 return (1) select @ext = 'ins_' select @ext2 = 'del_' set @objid = OBJECT_ID(@source_table) select @ccols = count(*) from syscolumns where id = @objid and iscomputed <> 1 select @ccolchar = convert(nchar, @ccols) select @UnqualName = PARSENAME(@source_table, 1) select @QualName1 = PARSENAME(@source_table, 2) if @UnqualName IS NULL return 1 if @QualName1 is NULL select @QualName1 = user_name(uid) from sysobjects where id = object_id(@UnqualName) -- fixup for variable length differences. remove when vars expanded -- to new SQL SERVER 7.0 lengths select @owner = @QualName1 select @object = @UnqualName execute @retcode=sp_MStablenickname @owner, @object, @tablenick output if @retcode<>0 or @@ERROR<>0 return (1) select @artid = artid from sysmergearticles where objid = @objid /* If column tracking wasn't passed in, just figure it out */ if @column_tracking is null select @column_tracking = column_tracking from sysmergearticles where artid = @artid select @tablenickchar = convert(nchar, @tablenick) exec @retcode=sp_MSguidtostr @artid, @guidstr out if @retcode<>0 or @@ERROR<>0 return (1) /* Drop the article's replication triggers if they preexist */ exec dbo.sp_MSdroparticletriggers @source_table if @@ERROR <> 0 return 1 -- owner name removed set @instrigname = @ext + @guidstr set @deltrigname = @ext2 + @guidstr set @updtrigname = 'upd_' + @guidstr set @viewname = 'ctsv_' + @guidstr set @tsview = 'tsvw_' + @guidstr /* Make sure trigger name is unique */ exec @retcode=sp_MSuniqueobjectname @instrigname, @instrigname output if @retcode<>0 or @@ERROR<>0 return (1) exec @retcode=sp_MSuniqueobjectname @deltrigname, @deltrigname output if @retcode<>0 or @@ERROR<>0 return (1) exec @retcode=sp_MSuniqueobjectname @updtrigname, @updtrigname output if @retcode<>0 or @@ERROR<>0 return (1) /* Create the view if it doesn't already exist. */ if not exists (select * from sysobjects where type = 'V' and name = @viewname) begin exec @retcode=sp_MSuniqueobjectname @viewname, @viewname output if @retcode<>0 or @@ERROR<>0 return (1) set @command = 'create view dbo.' + @viewname + ' as select * from MSmerge_contents where trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@instrigname) + ''')) > 0 or trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@updtrigname) + ''')) > 0 or trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@deltrigname) + ''')) > 0 with check option' execute (@command) if @@ERROR<>0 return (1) set @command = 'grant update, insert, select, delete on ' + @viewname + ' to public' execute (@command) if @@ERROR<>0 return (1) execute ('sp_MS_marksystemobject ''' + @viewname + '''') if @@ERROR<>0 return (1) end /* Create the view if it doesn't already exist. */ if not exists (select * from sysobjects where type = 'V' and name = @tsview) begin exec @retcode=sp_MSuniqueobjectname @tsview, @tsview output if @retcode<>0 or @@ERROR<>0 return (1) set @command = 'create view dbo. ' + @tsview + ' as select * from MSmerge_tombstone where trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@instrigname) + ''')) > 0 or trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@updtrigname) + ''')) > 0 or trigger_nestlevel(OBJECT_ID(''' + QUOTENAME(@owner) + '.' + QUOTENAME(@deltrigname) + ''')) > 0 with check option' execute (@command) if @@ERROR<>0 return (1) set @command = 'grant update, insert, select, delete on ' + @tsview + ' to public' execute (@command) if @@ERROR<>0 return (1) execute ('sp_MS_marksystemobject ''' + @tsview + '''') if @@ERROR<>0 return (1) end /* If column tracking is on, construct the string to initialize colv's */ if (@column_tracking <> 0) -- select @ifcoltracking = ' execute master..xp_initcolvs @ccols, @nickname, @colv1 output' select @ifcoltracking = ' set @colv1 = { fn INITCOLVS(@ccols, @nickname) }' else select @ifcoltracking = ' set @colv1 = NULL' /* UNDONE maybe remove null guid checks in SQL SERVER 7.0 */ select @command = 'create trigger ' + @instrigname + ' on ' + @source_table + ' for insert as /* Declare variables */ declare @tablenick int declare @nickname int declare @lineage varbinary(255) declare @colv1 varbinary(2048) declare @ccols int declare @retcode smallint declare @newgen int declare @version int declare @curversion int set nocount on set @tablenick = ' + @tablenickchar + ' select @ccols = ' + @ccolchar + ' set @lineage = 0x0 set @retcode = 0 select @newgen = gen_cur from sysmergearticles where nickname = @tablenick if @newgen is null set @newgen = 0 execute dbo.sp_MSgetreplnick @nickname = @nickname output if (@@error <> 0) begin goto FAILURE end set @lineage = { fn UPDATELINEAGE (0x0, @nickname) } ' + @ifcoltracking + ' if (@@error <> 0) begin goto FAILURE end select @version = max(convert(int, substring(lineage, 5, 1)) + 256 * (convert(int, substring(lineage, 6, 1)) + 256 * (convert(int, substring(lineage, 7, 1)) + 256 * (convert(int, substring(lineage, 8, 1)))))) from ' + @tsview + ' where tablenick = @tablenick and rowguid in (select rowguidcol from inserted) if @version is not null begin -- reset lineage and colv to higher version... set @curversion = 0 while (@curversion <= @version) begin set @lineage = { fn UPDATELINEAGE (@lineage, @nickname) } if (@colv1 IS NOT NULL) set @colv1 = { fn UPDATECOLVBM(@colv1, @nickname, 0x01, 0x00) } set @curversion = @curversion + 1 end delete from ' + @tsview + ' where tablenick = @tablenick and rowguid in (select rowguidcol from inserted) end insert into ' + @viewname + ' (tablenick, rowguid, lineage, colv1, generation, joinchangegen) select @tablenick, rowguidcol, @lineage, @colv1, @newgen, @newgen from inserted where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick) if @@error <> 0 goto FAILURE return FAILURE: if @@trancount > 0 rollback tran raiserror (20041, 16, -1) return ' execute (@command) if @@ERROR <> 0 begin raiserror(20065, 16, -1) return (1) end execute ('sp_MS_marksystemobject ''' + @instrigname + '''') /* Call separate routine to add update trigger */ exec @retcode=sp_MSaddupdatetrigger @source_table, @owner, @object, @artid, @column_tracking, @viewname if @retcode<>0 or @@ERROR<>0 return (1) /* Now make the delete trigger */ -- NOTE: owner name removed /* Make sure trigger name is unique */ exec @retcode = dbo.sp_MSuniqueobjectname @deltrigname, @deltrigname output if @retcode<>0 or @@ERROR<>0 return (1) set @command = 'create trigger ' + @deltrigname + ' on ' + @source_table + ' FOR DELETE AS /* Declare variables */ declare @tablenick int declare @retcode smallint declare @reason nvarchar(255) declare @nickname int declare @lineage varbinary(255) declare @newgen int set nocount on select @tablenick = ' + @tablenickchar + ' select @newgen = gen_cur from sysmergearticles where nickname = @tablenick if @newgen is null set @newgen = 0 select @reason = ''user delete'' execute dbo.sp_MSgetreplnick @nickname = @nickname output if (@@error <> 0) begin goto FAILURE end set @lineage = { fn UPDATELINEAGE(0x0, @nickname) } set @lineage = { fn UPDATELINEAGE(@lineage, @nickname) } insert into ' + @tsview + ' (rowguid, tablenick, type, lineage, generation, reason) select rowguidcol, @tablenick, 1, @lineage, @newgen, @reason from deleted where rowguidcol not in (select rowguid from ' + @viewname + ' where tablenick = @tablenick) if @@error <> 0 GOTO FAILURE /* Now get the ones that are in contents */ insert into ' + @tsview + ' (rowguid, tablenick, type, lineage, generation, reason) select c.rowguid, @tablenick, 1, { fn UPDATELINEAGE(c.lineage, @nickname) }, @newgen, @reason from deleted d, ' + @viewname + ' c where c.tablenick = @tablenick and c.rowguid = d.rowguidcol if @@error <> 0 GOTO FAILURE delete from ' + @viewname + ' where tablenick = @tablenick and rowguid in (select rowguidcol from deleted) if @@error <> 0 GOTO FAILURE return FAILURE: if @@trancount > 0 rollback tran raiserror (20041, 16, -1) return ' execute (@command) if @@ERROR <> 0 begin raiserror(20066, 16, -1) return (1) end execute ('sp_MS_marksystemobject ''' + @deltrigname + '''') update sysmergearticles set missing_col_count = @missing_count, missing_cols = @bitmap where artid = @artid if @@ERROR<>0 return (1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSaddmergetriggers go grant exec on dbo.sp_MSaddmergetriggers to public go raiserror('Creating procedure sp_MSmaptype', 0,1) GO create procedure sp_MSmaptype (@type nvarchar(60) output, @len smallint, @prec smallint, @scale int) as declare @typeout nvarchar(60) select @typeout = case @type when 'binary' then 'varbinary' when 'char' then 'varchar' when 'nchar' then 'nvarchar' when 'datetimn' then 'datetime' when 'decimaln' then 'decimal' when 'floatn' then 'float' when 'intn' then 'int' when 'moneyn' then 'money' when 'numericn' then 'numeric' when 'timestamp' then 'varbinary' when 'bit' then 'tinyint' else @type --for user defined data type which may contain space in between END -- append length or scale and precision if needed if (@typeout = 'varbinary' or @typeout = 'varchar' or @typeout = 'nvarchar') begin select @type = @typeout + '(' + rtrim(convert(nchar, @len)) + ')' return end if (@typeout = 'numeric' or @typeout = 'decimal') begin select @type = @typeout + '(' + rtrim(convert(nchar, @prec)) + ',' + rtrim(convert(nchar, @scale)) + ')' return end select @type = @typeout go exec dbo.sp_MS_marksystemobject sp_MSmaptype go dump tran master with no_log go checkpoint go set nocount on go execute dbo.sp_configure 'update',1 go reconfigure with override go set ANSI_NULLS off go dump tran master with no_log go use master go /* ** Drop the stored procedures in this script using the old dropping SP ** and then drop itself */ if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSdrop_rladmin') begin exec dbo.sp_MSdrop_rladmin drop procedure sp_MSdrop_rladmin end /* ** Create stored procedures to drop the stored procedures ** created by this script */ raiserror('Creating procedure sp_MSdrop_rladmin', 0,1) GO create procedure sp_MSdrop_rladmin as if exists (select * from sysobjects where type in ('P ') and name = 'sp_MSaddmergepub_snapshot') drop procedure sp_MSaddmergepub_snapshot if exists (select * from sysobjects where type in ('P ') and name = 'sp_MScheckatpublisher') drop procedure sp_MScheckatpublisher if exists (select * from sysobjects where type in ('P ') and name = 'sp_MSdropmergepub_snapshot') drop procedure sp_MSdropmergepub_snapshot if exists (select * from sysobjects where type = 'P' and name = 'sp_addmergepublication') drop procedure sp_addmergepublication if exists (select * from sysobjects where type = 'P' and name = 'sp_changemergepublication') drop procedure sp_changemergepublication if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergepublication') drop procedure sp_helpmergepublication if exists (select * from sysobjects where type = 'P' and name = 'sp_MSpublicationview') drop procedure sp_MSpublicationview if exists (select * from sysobjects where type = 'P' and name = 'sp_reinitmergesubscription') drop procedure sp_reinitmergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdrop_expired_mergesubscription') drop procedure sp_MSdrop_expired_mergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_dropmergepublication') drop procedure sp_dropmergepublication if exists (select * from sysobjects where type = 'P' and name = 'sp_addmergearticle') drop procedure sp_addmergearticle if exists (select * from sysobjects where type = 'P' and name = 'sp_changemergearticle') drop procedure sp_changemergearticle if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergearticle') drop procedure sp_helpmergearticle if exists (select * from sysobjects where type = 'P' and name = 'sp_dropmergearticle') drop procedure sp_dropmergearticle if exists (select * from sysobjects where type = 'P' and name = 'sp_addmergesubscription') drop procedure sp_addmergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_changemergesubscription') drop procedure sp_changemergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergesubscription') drop procedure sp_helpmergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_dropmergesubscription') drop procedure sp_dropmergesubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergefilter') drop procedure sp_helpmergefilter if exists (select * from sysobjects where type = 'P' and name = 'sp_changemergefilter') drop procedure sp_changemergefilter if exists (select * from sysobjects where type = 'P' and name = 'sp_addmergefilter') drop procedure sp_addmergefilter if exists (select * from sysobjects where type = 'P' and name = 'sp_dropmergefilter') drop procedure sp_dropmergefilter if exists (select * from sysobjects where type in ('P ') and name = 'sp_MSmergepublishdb') drop procedure sp_MSmergepublishdb if exists (select * from sysobjects where type in ('P ') and name = 'sp_helpallowmerge_publication') drop procedure sp_helpallowmerge_publication if exists (select * from sysobjects where type in ('P ') and name = 'sp_enumcustomresolvers') drop procedure sp_enumcustomresolvers if exists (select * from sysobjects where type in ('P ') and name = 'sp_MSenumpubreferences') drop procedure sp_MSenumpubreferences if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSscript_dri') drop procedure sp_MSscript_dri if exists (select * from sysobjects where type in ('P ') and name = 'sp_MSsubsetpublication') drop procedure sp_MSsubsetpublication if exists (select * from sysobjects where type = 'P' and name = 'sp_generatefilters') drop procedure sp_generatefilters if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakejoinfilter') drop procedure sp_MSmakejoinfilter go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeexpandproc') drop procedure sp_MSmakeexpandproc go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSindexcolfrombin') drop procedure sp_MSindexcolfrombin if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergearticleconflicts') drop procedure sp_helpmergearticleconflicts if exists (select * from sysobjects where type = 'P' and name = 'sp_MShelpmergeconflictcounts') drop procedure sp_MShelpmergeconflictcounts if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergeconflictrows') drop procedure sp_helpmergeconflictrows if exists (select * from sysobjects where type = 'P' and name = 'sp_helpmergedeleteconflictrows') drop procedure sp_helpmergedeleteconflictrows if exists (select * from sysobjects where type = 'P' and name = 'sp_deletemergeconflictrow') drop procedure sp_deletemergeconflictrow if exists (select * from sysobjects where type = 'P' and name = 'sp_getmergedeletetype') drop procedure sp_getmergedeletetype if exists (select * from sysobjects where type = 'P' and name = 'sp_mergedummyupdate') drop procedure sp_mergedummyupdate if exists (select * from sysobjects where type = 'P' and name = 'sp_addtabletocontents') drop procedure sp_addtabletocontents if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddpubtocontents') drop procedure sp_MSaddpubtocontents go exec dbo.sp_MS_marksystemobject sp_MSdrop_rladmin go EXEC dbo.sp_MSdrop_rladmin GO raiserror('Creating procedure sp_MSaddmergepub_snapshot', 0,1) GO CREATE PROCEDURE sp_MSaddmergepub_snapshot ( @publication sysname, @freqtype int = 4 , /* 4== Daily */ @freqinterval int = 1, /* Every day */ @freqsubtype int = 4, /* Sub interval = Minute */ @freqsubinterval int = 5, /* Every five minutes */ @freqrelativeinterval int = 1, @freqrecurrencefactor int = 0, @activestartdate int = 0, /* 12:00 am - 11:59 pm */ @activeenddate int = 99991231 , /* No start date */ @activestarttimeofday int = 0, @activeendtimeofday int = 235959, /* No end time */ @newtaskid int = 0 OUTPUT ) AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @distributor sysname declare @dist_rpcname sysname declare @distribdb sysname declare @distproc nvarchar(255) declare @taskname nvarchar(100) declare @database sysname declare @newid int declare @fFoundPublication int declare @task_args nvarchar(255) declare @command nvarchar(255) declare @pubid uniqueidentifier declare @snapshot_jobid binary(16) /* ** Initializations */ select @fFoundPublication = 0 EXEC @retcode = dbo.sp_helpmergepublication @publication, @fFoundPublication output, @pubid output if @@ERROR <> 0 OR @retcode <> 0 BEGIN RETURN (1) END /* If the publication does not exist return error */ if @fFoundPublication = 0 BEGIN RAISERROR (21040, 11, -1, @publication) RETURN (1) END /* ** Make sure the publication does not already have a task. */ if EXISTS (select * FROM MSmerge_replinfo WHERE repid = @pubid and snapshot_jobid IS NOT NULL) BEGIN RAISERROR (14101, 11, -1, @publication) RETURN(1) END /* ** Get distributor information */ EXEC @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT, @distribdb = @distribdb OUTPUT, @rpcsrvname = @dist_rpcname OUTPUT if @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL BEGIN RAISERROR (14071, 16, -1) RETURN (1) END select @database = DB_NAME() select @task_args = '-Publisher ' + @@SERVERNAME select @task_args = @task_args + ' -PublisherDB ' + QUOTENAME(@database) select @task_args = @task_args + ' -Distributor ' + QUOTENAME(@distributor) select @task_args = @task_args + ' -Publication ' + QUOTENAME(@publication) select @task_args = @task_args + ' -ReplicationType 2' /* ** Create task on distributor */ SELECT @distproc = RTRIM(@dist_rpcname) + '.' + @distribdb + '.dbo.sp_MSadd_snapshot_agent' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @database, @publication = @publication, @publication_type = 2, -- Merge type @local_job = 1, @freqtype = @freqtype, @freqinterval = @freqinterval, @freqsubtype = @freqsubtype, @freqsubinterval = @freqsubinterval, @freqrelativeinterval = @freqrelativeinterval, @freqrecurrencefactor = @freqrecurrencefactor, @activestartdate = @activestartdate, @command = @task_args, @snapshot_jobid = @snapshot_jobid OUTPUT if @@ERROR <> 0 or @retcode <> 0 RETURN(1) SELECT @newtaskid = 1 UPDATE MSmerge_replinfo set snapshot_jobid = @snapshot_jobid WHERE repid = @pubid if @@ERROR <> 0 RETURN(1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSaddmergepub_snapshot go grant execute on dbo.sp_MSaddmergepub_snapshot to public go GO raiserror('Creating procedure sp_MSdropmergepub_snapshot', 0,1) GO CREATE PROCEDURE sp_MSdropmergepub_snapshot ( @publication sysname, @ignore_distributor bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @distributor sysname declare @distproc nvarchar(255) declare @snapshot_jobid binary(16) declare @fFoundPublication int declare @pubid uniqueidentifier declare @distribdb sysname /* ** Initializations */ select @fFoundPublication = 0 /* validate the publication */ /* If the publication is not exist found return error */ EXEC @retcode = dbo.sp_helpmergepublication @publication, @fFoundPublication output, @pubid output if @@ERROR <> 0 OR @fFoundPublication = 0 OR @retcode <> 0 BEGIN RETURN (1) END /* ** Get taskid. Make sure the snapshot_jobid is not NULL only before using MAX ** Otherwise there will be a warnning. */ select @snapshot_jobid = max(snapshot_jobid) FROM MSmerge_replinfo WHERE repid = @pubid if (@snapshot_jobid IS NOT NULL) begin /* ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 0 begin /* ** Get distributor information */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT if @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14071, 16, -1) RETURN (1) END /* ** Delete sync agent of Publication. */ declare @dbname sysname set @dbname = DB_NAME() SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_snapshot_agent' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @dbname, @publication = @publication IF @@ERROR <> 0 or @retcode <> 0 RETURN(1) end /* Update publication's taskid */ UPDATE MSmerge_replinfo set snapshot_jobid = NULL WHERE repid = @pubid IF @@ERROR <> 0 BEGIN RAISERROR (20072, 16, -1) RETURN (1) END end return (0) GO exec dbo.sp_MS_marksystemobject sp_MSdropmergepub_snapshot go grant execute on dbo.sp_MSdropmergepub_snapshot to public go raiserror('Creating procedure sp_MScheckatpublisher', 0,1) GO create procedure sp_MScheckatpublisher @pubid uniqueidentifier AS -- this routine will be called by sp_addmergearticle, sp_changemergearticle declare @db_name sysname select @db_name =db_name from sysmergesubscriptions where (pubid=@pubid) and (subid=@pubid) IF @db_name <> db_name() RETURN 1 ELSE RETURN 0 go exec dbo.sp_MS_marksystemobject sp_MScheckatpublisher go grant execute on dbo.sp_MScheckatpublisher to public go raiserror('Creating procedure sp_addmergearticle', 0,1) GO create procedure sp_addmergearticle @publication sysname, /* publication name */ @article sysname, /* article name */ @source_object sysname, /* source object name */ @type sysname = 'table', /* article type */ @description nvarchar(255)= NULL, /* article description */ @column_tracking nvarchar(10) = 'false', /* column level tracking */ @status nvarchar(10) = 'unsynced', /* unsynced, active */ @pre_creation_cmd nvarchar(10) = 'drop', /* 'none', 'drop', 'delete', 'truncate' */ @creation_script nvarchar(255)= NULL, /* article schema script */ @schema_option binary(8) = 0x00000000000000f1, /* article schema creation options */ @subset_filterclause nvarchar(2000) = '', /* filter clause */ @article_resolver nvarchar(255)= NULL, /* custom resolver for article */ @resolver_info nvarchar(255) = NULL, /* custom resolver info */ @source_owner sysname = NULL AS set nocount on /* ** Declarations. */ declare @resolver_info_len int declare @sp_resolver sysname declare @num_columns smallint declare @pubid uniqueidentifier /* Publication id */ declare @db sysname declare @object sysname declare @owner sysname declare @destination_object sysname declare @retcode int declare @objid int declare @sync_objid int declare @typeid smallint declare @nickname int declare @merge_pub_object_bit int declare @column_tracking_id int declare @cmd nvarchar(255) declare @statusid tinyint declare @precmdid int declare @resolver_clsid nvarchar(50) declare @resolver_clsid_old nvarchar(50) declare @tablenick int declare @artid uniqueidentifier declare @distributor sysname declare @distribdb sysname declare @distproc nvarchar(255) declare @dbname sysname declare @replinfo int declare @db_name sysname declare @subset int declare @row_size int declare @sp_name sysname declare @sp_owner sysname declare @qualified_name nvarchar(257) -- PARSENAME VARS declare @UnqualName nvarchar(258) --rightmost name node ,@QualName1 nvarchar(258) ,@QualName2 nvarchar(258) -- END PARSENAME VARS /* ** Initializations */ select @statusid = 0 select @resolver_clsid = NULL select @subset = 1 /* Const: publication type 'subset' */ select @merge_pub_object_bit = 128 select @sp_resolver = 'Microsoft SQLServer Stored Procedure Resolver' if @source_owner is NULL begin select @source_owner = user_name(uid) from sysobjects where id = object_id(@source_object) if @source_owner is NULL begin raiserror (14027, 11, -1, @source_object) return (1) end end select @qualified_name = QUOTENAME(@source_owner) + '.' + QUOTENAME(@source_object) /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14043, 16, -1, '@publication') return (1) end select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (14027, 11, -1, @publication) return (1) end /* ** Only publisher can call sp_addmergearticle */ EXEC @retcode = dbo.sp_MScheckatpublisher @pubid IF @@ERROR <> 0 or @retcode <> 0 BEGIN RAISERROR (20073, 16, -1) RETURN (1) END select @sync_objid = id from sysobjects where id = OBJECT_ID(@qualified_name) if @sync_objid is NULL begin raiserror (14027, 11, -1, @qualified_name) return (1) end select @row_size=sum(length) from syscolumns where id=OBJECT_ID(@qualified_name) if @row_size>6000 begin RAISERROR (21062, 16, -1, @qualified_name) -- RETURN (1) end select @num_columns=count(*) from syscolumns where id = object_id(@qualified_name) if @num_columns > 246 begin RAISERROR (20068, 16, -1, @qualified_name, 246) RETURN (1) end /* ** Parameter Check: @article. ** Check to see that the @article is local, that it conforms ** to the rules for identifiers, and that it is a table, and not ** a view or another database object. */ if @article is NULL begin raiserror (20045, 16, -1) return (1) end exec @retcode = dbo.sp_MSreplcheck_name @article if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** Merge does not really support destination object. It has the same value as source */ select @destination_object = @source_object /* ** Get the id of the @qualified_name */ select @objid = id, @replinfo = replinfo from sysobjects where id = OBJECT_ID(@qualified_name) if @objid is NULL begin raiserror (14027, 11, -1, @qualified_name) return (1) end /* ** If current publication contains a non-sync subscription, all articles to be added in it ** has to contain a rowguidcol. */ if exists (select * from sysmergesubscriptions where pubid = @pubid and sync_type = 2) begin if not exists (select * from syscolumns c where c.id=@objid and ColumnProperty(c.id, c.name, 'isrowguidcol') = 1) begin raiserror(20085 , 16, -1, @article, @publication) return (1) end end /* ** Make sure that the table name specified is a table and not a view. */ if NOT exists (select * from sysobjects where id = (select OBJECT_ID(@qualified_name)) AND type = 'U') begin raiserror (20074, 16, -1) return (1) end /* ** Check that the underlying table has no timestamp columns. If it does, ** return an appropriate error. */ if EXISTS (SELECT * FROM syscolumns c WHERE c.id = @sync_objid AND type_name(c.xtype) = 'timestamp') BEGIN RAISERROR (20055, 16, -1, @qualified_name) RETURN (1) END /* ** Parameter Check: @creation_script and @schema_option ** @schema_option cannot be null ** If @schema_option is 0, there have to be @creation_script defined. */ IF @schema_option IS NULL BEGIN select @schema_option = 0x00000000000000f1 END /* ** Set the typeid. The default type is table. Anything else is ** currently undefined (reserved for future use). ** ** @typeid type ** ======= ======== ** 1 table ** UNDONE - message */ IF LOWER(@type) NOT IN ('table') BEGIN RAISERROR (20074, 16, -1) RETURN (1) END IF LOWER(@type) = 'table' SET @typeid = 0x0a /* ** Validate the column tracking */ if @column_tracking IS NULL OR LOWER(@column_tracking) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@column_tracking') RETURN (1) END if LOWER(@column_tracking) = 'true' SET @column_tracking_id = 1 else SET @column_tracking_id = 0 /* ** Get the pubid. */ SELECT @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (14027, 11, -1, @publication) return (1) end /* ** Parameter Check: @article, @publication. ** Check if the article already exists in this publication. */ IF EXISTS (SELECT * FROM sysmergearticles WHERE pubid = @pubid AND name = @article) BEGIN RAISERROR (14030, 16, -1, @article, @publication) RETURN (1) END execute @retcode = dbo.sp_MSgetreplnick @pubid = @pubid, @nickname = @nickname output if (@@error <> 0) or @retcode <> 0 or @nickname IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end /* ** Set the precmdid. The default type is 'drop'. ** ** @precmdid pre_creation_cmd ** ========= ================ ** 0 none ** 1 drop ** 2 delete ** 3 truncate */ IF LOWER(@pre_creation_cmd) NOT IN ('none', 'drop', 'delete', 'truncate') BEGIN RAISERROR (14061, 16, -1) RETURN (1) END /* ** Determine the integer value for the pre_creation_cmd. */ IF LOWER(@pre_creation_cmd) = 'none' select @precmdid = 0 ELSE IF LOWER(@pre_creation_cmd) = 'drop' select @precmdid = 1 ELSE IF LOWER(@pre_creation_cmd) = 'delete' select @precmdid = 2 ELSE IF LOWER(@pre_creation_cmd) = 'truncate' select @precmdid = 3 /* ** Validate the article resolver */ if @article_resolver IS NOT NULL begin if @article_resolver = 'default' OR @article_resolver = '' begin select @article_resolver = NULL select @resolver_clsid = NULL end else begin /* ** Get the distributor info */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT IF @@error <> 0 OR @retcode <> 0 OR @distributor IS NULL BEGIN RAISERROR (20036, 16, -1) RETURN (1) END select @distproc = RTRIM(@distributor) + '.master.dbo.xp_regread' EXECUTE @retcode = @distproc 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\MSSQLServer\Replication\ArticleResolver', @article_resolver, @param = @resolver_clsid OUTPUT IF @retcode <> 0 or @resolver_clsid IS NULL BEGIN RAISERROR (20020, 16, -1) RETURN (1) END end end /* ** If article resolver is 'SP resolver', make sure that resolver_info refers to an SP or XP; ** Also make sure it is stored with owner qualification */ if @article_resolver = @sp_resolver begin if not exists (select * from sysobjects where id = object_id(@resolver_info) and ( type = 'P' or type = 'X')) begin select @resolver_info_len = datalength(@resolver_info) raiserror(2812, 16, -1, @resolver_info_len, @resolver_info) return (1) end select @sp_name = name, @sp_owner=user_name(uid) from sysobjects where id = object_id(@resolver_info) select @resolver_info = QUOTENAME(@sp_owner) + '.' + QUOTENAME(@sp_name) end /* ** Validate the resolver procedure for the article - should be either a stored proc or an extended procedure. */ if @resolver_info IS NOT NULL begin /* ** Get the distributor info */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT IF @@error <> 0 OR @retcode <> 0 OR @distributor IS NULL BEGIN RAISERROR (20036, 16, -1) RETURN (1) END select @distproc = RTRIM(@distributor) + '.master.dbo.xp_regread' /* Don't force different resolver than one that was passed in. */ end /* ** Add article to sysmergearticles and update sysobjects category bit. */ begin tran save TRAN sp_addmergearticle select @artid = artid from sysmergearticles where objid = OBJECT_ID(@qualified_name) select @statusid = 1 /*default status is inactive */ if @artid is NULL begin set @artid = newid() if @@ERROR <> 0 goto FAILURE execute @retcode = dbo.sp_MSgentablenickname @tablenick output, @nickname, @objid if @@ERROR <> 0 OR @retcode <> 0 goto FAILURE end /* Clone the article properties if article has already been published (in a different pub) */ else begin /* ** Parameter Check: @article, @publication. ** Check if the table already exists in this publication. */ if exists (select * from sysmergearticles where pubid = @pubid AND artid = @artid) begin raiserror (14030, 16, -1, @article, @publication) goto FAILURE end /* Make sure that coltracking option matches */ if exists (select * from sysmergearticles where artid = @artid and column_tracking <> @column_tracking_id) begin raiserror (20030, 16, -1, @article) goto FAILURE end /* Reuse the article nickname if article has already been published (in a different pub)*/ select @tablenick = nickname from sysmergearticles where artid = @artid if @tablenick IS NULL goto FAILURE /* Make sure that @resolver_clsid matches the existing resolver_clsid */ select @resolver_clsid_old = resolver_clsid from sysmergearticles where artid = @artid if ((@resolver_clsid IS NULL AND @resolver_clsid_old IS NOT NULL) OR (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NULL) OR (@resolver_clsid IS NOT NULL AND @resolver_clsid_old IS NOT NULL AND @resolver_clsid_old <> @resolver_clsid)) begin raiserror (20037, 16, -1, @article) goto FAILURE end /* Insert to articles, copying some stuff from other article row */ set rowcount 1 insert into sysmergearticles (name, type, objid, sync_objid, artid, description, pre_creation_command, pubid, nickname, column_tracking, status, conflict_table, creation_script, conflict_script, article_resolver, resolver_clsid, ins_conflict_proc, schema_option, destination_object, subset_filterclause, view_type, resolver_info, gen_cur) -- use top 1, distinct could return more than one matching row if status different on partitioned articles select top 1 @article, type, objid, @sync_objid, @artid, @description, @precmdid, @pubid, nickname, column_tracking, 1, conflict_table, @creation_script, conflict_script, article_resolver, resolver_clsid, ins_conflict_proc, @schema_option, @destination_object, @subset_filterclause, 0, resolver_info, gen_cur from sysmergearticles where artid = @artid set rowcount 0 /* Jump to end of transaction */ goto DONE_TRAN end /* Add the specific GUID based replication columns to sys articles */ insert sysmergearticles (name, objid, sync_objid, artid, type, description, pubid, nickname, column_tracking, status, schema_option, pre_creation_command, destination_object, article_resolver, resolver_clsid, subset_filterclause, view_type, resolver_info) values (@article, @objid, @sync_objid, @artid, @typeid, @description, @pubid, @tablenick, @column_tracking_id, @statusid, @schema_option, @precmdid, @destination_object, @article_resolver, @resolver_clsid, @subset_filterclause, 0, @resolver_info) if @@ERROR <> 0 goto FAILURE exec @retcode = dbo.sp_replupdateschema @qualified_name if @@ERROR <> 0 or @retcode <> 0 goto FAILURE update sysobjects set replinfo = (replinfo | @merge_pub_object_bit) where id = @objid if @@ERROR <> 0 goto FAILURE /* Make a generation */ execute @retcode = dbo.sp_MSmakegeneration if @@ERROR <> 0 goto FAILURE /* If the article status is active then publish the user tables */ if @status = 'active' begin /* Get a holdlock on the underlying table */ select @cmd = 'select * into #tab1 from ' select @cmd = @cmd + @qualified_name select @cmd = @cmd + '(TABLOCK HOLDLOCK) where 1 = 2 ' execute(@cmd) /* Add the guid column to the user table */ execute @retcode = dbo.sp_MSaddguidcolumn @source_owner, @source_object if @@ERROR <> 0 OR @retcode <> 0 -- NOTE: new change goto FAILURE /* Create an index on the rowguid column in the user table */ execute @retcode = dbo.sp_MSaddguidindex @source_owner, @source_object if @@ERROR <> 0 OR @retcode <> 0 goto FAILURE /* Create the merge triggers on the base table */ execute @retcode = dbo.sp_MSaddmergetriggers @qualified_name, @column_tracking_id if @@ERROR <> 0 OR @retcode <> 0 goto FAILURE /* Create the merge insert/update stored procedures for the base table */ execute @retcode = dbo.sp_MSsetartprocs @publication, @article if @@ERROR <> 0 OR @retcode <> 0 goto FAILURE /* Set the article status to be active so that Snapshot does not do this again */ select @statusid = 2 /* Active article */ update sysmergearticles set status = @statusid where artid = @artid if @@ERROR <> 0 goto FAILURE end DONE_TRAN: /* ** For articles with subset filter clause - set the pub type to subset */ if len(@subset_filterclause) > 0 begin execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode<>0 goto FAILURE end /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN goto FAILURE END SELECT @dbname = DB_NAME() SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSadd_article' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @dbname, @publication = @publication, @article = @article, @destination_object = @destination_object, @source_owner = @source_owner, @source_object = @source_object, @description = @description -- @article_id = NULL IF @@ERROR <> 0 or @retcode <> 0 BEGIN goto FAILURE END COMMIT TRAN /* If the article status is active adding the merge triggers to the base table */ return (0) FAILURE: RAISERROR (20009, 16, -1, @article, @publication) if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION sp_addmergearticle COMMIT TRANSACTION end return (1) go exec dbo.sp_MS_marksystemobject sp_addmergearticle go grant execute on dbo.sp_addmergearticle to public go raiserror('Creating procedure sp_changemergearticle', 0,1) GO CREATE PROCEDURE sp_changemergearticle ( @publication sysname, /* Publication name */ @article sysname, /* Article name */ @property sysname = NULL, /* The property to change */ @value nvarchar(2000) = NULL /* The new property value */ ) AS SET NOCOUNT ON /* ** Declarations. */ declare @resolver_info_len int declare @sp_resolver sysname declare @db_name sysname declare @artid uniqueidentifier declare @pubid uniqueidentifier declare @artidstr nvarchar(38) declare @pubidstr nvarchar(38) declare @object sysname declare @owner sysname declare @resolver_clsid nvarchar(50) declare @article_resolver nvarchar(255) declare @retcode int declare @statusid int declare @precmdid tinyint declare @regkey nvarchar(255) declare @distributor sysname declare @distproc nvarchar(255) declare @schemaversion int declare @schemaguid uniqueidentifier declare @schematype int declare @schematext nvarchar(2000) /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Check to see if the database has been activated for publication. */ if (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME()) = 0 BEGIN RAISERROR (14013, 16, -1) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (14027, 11, -1, @publication) return (1) end select @db_name = db_name from sysmergesubscriptions where (pubid=@pubid) and (subid=@pubid) IF @db_name <> db_name() BEGIN RAISERROR (20047, 16, -1) RETURN (1) END /* ** Parameter Check: @property. ** If the @property parameter is NULL, print the options. */ if @property IS NULL BEGIN CREATE TABLE #tab1 (properties sysname) INSERT INTO #tab1 VALUES ('description') INSERT INTO #tab1 VALUES ('pre_creation_command') INSERT INTO #tab1 VALUES ('creation_script') INSERT INTO #tab1 VALUES ('column_tracking') INSERT INTO #tab1 VALUES ('article_resolver') INSERT INTO #tab1 VALUES ('resolver_info') INSERT INTO #tab1 VALUES ('status') INSERT INTO #tab1 VALUES ('subset_filterclause') INSERT INTO #tab1 VALUES ('schema_option') select * FROM #tab1 RETURN (0) END /* ** Parameter Check: @property. ** Check to make sure that @property is a valid property in ** sysmergearticles. */ if @property IS NULL OR LOWER(@property) NOT IN ('name', 'description', 'pre_creation_command', 'creation_script', 'column_tracking', 'article_resolver', 'resolver_info', 'status', 'subset_filterclause', 'schema_option') BEGIN RAISERROR (20019, 16, -1) RETURN (1) END /* ** Parameter Check: @publication. ** Make sure that the publication exists. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid IS NULL BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END /* ** Check to see that the article exists in sysmergearticles. ** Fetch the article identification number. */ if @article IS NULL BEGIN RAISERROR (14043, 16, -1, '@article') RETURN (1) END select @artid = artid FROM sysmergearticles WHERE name = @article AND pubid = @pubid if @artid IS NULL BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END set @artidstr = '''' + convert(nchar(36), @artid) + '''' set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' select @sp_resolver = 'Microsoft SQLServer Stored Procedure Resolver' /* ** Change the property. */ if LOWER(@property) = 'column_tracking' BEGIN /* ** This property can be modified for articles belonging to publications that are not active. */ if EXISTS (select status FROM sysmergearticles WHERE artid = @artid AND status = 2) BEGIN RAISERROR (20043, 16, -1, @article) RETURN (1) END /* ** Check to make sure that we have a valid type. */ if LOWER(@value) NOT IN ('true', 'false') BEGIN RAISERROR (14137, 16, -1) RETURN (1) END /* ** Update the syssubsetdefintions table with the new column tracking. */ if LOWER(@value) = 'true' update sysmergearticles set column_tracking = 1 where artid=@artid else update sysmergearticles set column_tracking = 0 where artid=@artid if @@ERROR <> 0 RETURN (1) END if LOWER(@property)='description' BEGIN UPDATE sysmergearticles SET description = @value WHERE artid = @artid and pubid = @pubid AND pubid = @pubid if @@ERROR <> 0 RETURN (1) END if LOWER(@property) ='creation_script' BEGIN update sysmergearticles set creation_script=@value where artid=@artid and pubid=@pubid if @@ERROR <> 0 RETURN (1) END if LOWER(@property) = 'subset_filterclause' BEGIN /* ** This property can be modified for articles belonging to publications that are not active. */ if EXISTS (select status FROM sysmergearticles WHERE artid = @artid AND pubid = @pubid AND status = 2) BEGIN RAISERROR (20043, 16, -1, @article) RETURN (1) END update sysmergearticles set subset_filterclause = @value where artid=@artid and pubid=@pubid if @@ERROR<>0 return (1) /* ** set the pub type to subset or full as appropriate */ execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 OR @retcode <> 0 RETURN (1) END if LOWER(@property) ='article_resolver' BEGIN if @value IS NULL OR @value = 'default' OR @value = '' begin set @article_resolver = NULL set @resolver_clsid = NULL end else begin EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\MSSQLServer\Replication\ArticleResolver', @value, @param = @resolver_clsid OUTPUT IF @@ERROR <> 0 or @retcode <> 0 or @resolver_clsid IS NULL BEGIN RAISERROR (20020, 16, -1) RETURN (1) END end /* ** Update the appropriate column in sysmergearticles with the new article resolver name. ** Note this could affect multiple publication if the same table spans publications */ /* NOTE: new change */ begin tran save TRANSACTION change_article exec @retcode = dbo.sp_MSchangearticleresolver @value, @resolver_clsid, @artid if @@ERROR <> 0 OR @retcode <> 0 begin if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION change_article COMMIT TRANSACTION end RETURN (1) end declare one_pub CURSOR LOCAL FAST_FORWARD FOR select DISTINCT pubid from sysmergearticles where artid=@artid FOR READ ONLY open one_pub fetch next from one_pub into @pubid while (@@fetch_status <> -1) begin select @schemaversion = schemaversion from sysmergeschemachange if (@schemaversion is NULL) set @schemaversion = 1 else select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange set @schemaguid = newid() set @schematype = 8 if @value is not NULL and @value <> '' select @schematext = 'exec dbo.sp_MSchangearticleresolver ' + '''' + @value + '''' + ',' + '''' + @resolver_clsid + '''' + ',' + '''' + convert(nchar(36), @artid) + '''' else select @schematext = 'exec dbo.sp_MSchangearticleresolver NULL, NULL,' + '''' + convert(nchar(36), @artid) + '''' exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext if @@ERROR <> 0 OR @retcode <> 0 begin if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION change_article COMMIT TRANSACTION end RETURN (1) end fetch next from one_pub into @pubid end close one_pub deallocate one_pub COMMIT TRANSACTION END /* for property = 'article_resolver' */ if LOWER(@property) ='resolver_info' BEGIN /* allow non-sp's as resolver info; don't change the resolver class */ select @article_resolver = article_resolver, @resolver_clsid = resolver_clsid from sysmergearticles where artid = @artid -- Use empty string for nulls so that schema text won't be null if @article_resolver is null set @article_resolver = '' if @resolver_clsid is null set @resolver_clsid = '' if @value is null set @value = '' if @article_resolver = @sp_resolver begin if not exists (select * from sysobjects where id = object_id(@value) and ( type = 'P' or type = 'X')) begin select @resolver_info_len = datalength(@value) raiserror(2812, 16, -1, @resolver_info_len, @value) return (1) end end /* ** Update the appropriate column in sysmergearticles with the new resolver info. ** Note this could affect multiple publication if the same table spans publications */ BEGIN TRANSACTION exec @retcode = dbo.sp_MSchangearticleresolver @article_resolver, @resolver_clsid, @artid, @value if @@ERROR <> 0 OR @retcode <> 0 begin if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION change_article COMMIT TRANSACTION end RETURN (1) end declare one_pub CURSOR LOCAL FAST_FORWARD FOR select DISTINCT pubid from sysmergearticles where artid=@artid FOR READ ONLY open one_pub fetch next from one_pub into @pubid while (@@fetch_status <> -1) begin select @schemaversion = schemaversion from sysmergeschemachange if (@schemaversion is NULL) set @schemaversion = 1 else select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange set @schemaguid = newid() set @schematype = 8 select @schematext = 'exec dbo.sp_MSchangearticleresolver ' + '''' + @article_resolver + '''' + ',' + '''' + @resolver_clsid + '''' + ',' + '''' + convert(nchar(36), @artid) + '''' + ',' + '''' + @value + '''' exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext if @@ERROR <> 0 OR @retcode <> 0 begin if @@TRANCOUNT = 1 ROLLBACK TRANSACTION else COMMIT TRANSACTION RETURN (1) end fetch next from one_pub into @pubid end close one_pub deallocate one_pub COMMIT TRANSACTION END /* for property = 'resolver_info' */ if LOWER(@property) = 'pre_creation_command' BEGIN /* ** Check to make sure that we have a valid pre_creation_cmd. */ if LOWER(@value) NOT IN ('none', 'drop', 'delete', 'truncate') BEGIN RAISERROR (14061, 16, -1) RETURN (1) END /* ** Determine the integer value for the pre_creation_cmd. */ if LOWER(@value) = 'none' select @precmdid = 0 else if LOWER(@value) = 'drop' select @precmdid = 1 else if LOWER(@value) = 'delete' select @precmdid = 2 else if LOWER(@value) = 'truncate' select @precmdid = 3 /* ** Update the article with the new pre_creation_cmd. */ UPDATE sysmergearticles SET pre_creation_command = @precmdid WHERE artid = @artid AND pubid = @pubid if @@ERROR <> 0 RETURN (1) END if LOWER(@property) = 'status' BEGIN /* ** Check to make sure that we have a valid status */ if LOWER(@value) NOT IN ('active', 'unsynced') BEGIN RAISERROR (20075, 16, -1) RETURN (1) END /* ** Determine the integer value for the type. */ if LOWER(@value) = 'unsynced' select @statusid = 1 else if LOWER(@value) = 'active' select @statusid = 2 /* ** Update the article with the new type. The same base table might be ** in multiple publications - so qualify with pubid. */ UPDATE sysmergearticles SET status = @statusid WHERE artid = @artid and pubid = @pubid if @@ERROR <> 0 RETURN (1) END IF LOWER(@property) = 'schema_option' BEGIN IF @value IS NULL BEGIN RAISERROR(14146, 16,1) RETURN (1) END CREATE TABLE #tab_changearticle (value binary(8) NULL) IF @@ERROR <> 0 BEGIN RETURN (1) END EXEC ('insert #tab_changearticle values (' + @value +')' ) IF @@ERROR <> 0 BEGIN RETURN (1) END UPDATE sysmergearticles SET schema_option = tab.value from #tab_changearticle tab WHERE artid = @artid AND pubid = @pubid if @@ERROR <> 0 BEGIN DROP TABLE #tab_changearticle RETURN (1) END DROP TABLE #tab_changearticle IF @@ERROR <> 0 BEGIN RETURN (1) END END /* ** Return succeed. */ RETURN (0) go exec dbo.sp_MS_marksystemobject sp_changemergearticle go grant execute on dbo.sp_changemergearticle to public go /* ** This SP is called to see if merge publication is still allowed for current database. ** Merge publishing is disallowed if current DB subscribes as local/anonymous subscriber ** 1 means OK, 0 for publication not allowed. */ raiserror('Creating procedure sp_helpallowmerge_publication', 0,1) GO CREATE PROCEDURE sp_helpallowmerge_publication AS declare @srvid int declare @db_name sysname /* Select srvid = 0 for the local server name */ select @srvid = 0 select @db_name = db_name() if exists (select name from sysobjects where name='sysmergesubscriptions') if exists (select priority from sysmergesubscriptions where db_name=@db_name and srvid = @srvid and priority=0) begin select 0 RETURN (0) end select 1 GO exec dbo.sp_MS_marksystemobject sp_helpallowmerge_publication go raiserror('Creating procedure sp_helpmergearticle', 0,1) GO CREATE PROCEDURE sp_helpmergearticle ( @publication sysname = '%', /* The publication name */ @article sysname = '%' /* The article name */ ) AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int /* ** Running sp_help is OK from everywhere, whether enabled for publishing or not */ IF not exists (select * from sysobjects where name= 'sysmergesubscriptions') RETURN (0) /* ** Security Check. To public. */ /* ** Parameter Check: @publication. ** Check to make sure that the publication exists, that it conforms ** to the rules for identifiers, and that it isn't NULL. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END /* ** Create a temporary table to hold all information. */ create table #helpmergearticle ( id int identity NOT NULL, name sysname NOT NULL, source_owner sysname NOT NULL, source_object sysname NOT NULL, /* converted from objid */ sync_object_owner sysname NOT NULL, sync_object sysname NOT NULL, /* converted from sync_objid */ description nvarchar(255) NULL, status tinyint NULL, creation_script nvarchar(127) NULL, conflict_table nvarchar(258) NULL, article_resolver nvarchar(255) NULL, subset_filterclause nvarchar(2000) NULL, pre_creation_command tinyint NULL, schema_option binary(8) NULL, type tinyint NULL, column_tracking int NOT NULL, resolver_info nvarchar(255) NULL ) if @publication <> '%' BEGIN if NOT EXISTS (select pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END END /* ** Parameter Check: @article. ** Check to make sure that the article exists, that it conforms ** to the rules for identifiers, and that it isn't NULL. */ if @article IS NULL BEGIN RAISERROR (14043, 16, -1, '@article') RETURN (1) END if @article <> '%' BEGIN if NOT EXISTS (select * FROM sysmergearticles WHERE name = @article AND pubid IN (select pubid FROM sysmergepublications WHERE name like @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())) BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END END INSERT INTO #helpmergearticle (name, source_owner, source_object, sync_object_owner, sync_object, description, status, creation_script, conflict_table, pre_creation_command, schema_option, type, column_tracking, article_resolver, subset_filterclause, resolver_info)( select art.name, users.name, objects.name, users.name, syncobjects.name, art.description, art.status, art.creation_script, art.conflict_table, art.pre_creation_command, art.schema_option, art.type, art.column_tracking, art.article_resolver, art.subset_filterclause, art.resolver_info FROM sysmergearticles art, sysmergepublications pubs, sysobjects objects, sysobjects syncobjects, sysusers users WHERE art.name LIKE @article AND art.pubid = pubs.pubid AND pubs.name LIKE @publication AND UPPER(pubs.publisher) = UPPER(@@servername) AND pubs.publisher_db = db_name() AND objects.id = art.objid AND objects.uid = users.uid AND syncobjects.id = art.sync_objid AND syncobjects.uid = users.uid) order by art.nickname desc select * from #helpmergearticle RETURN (0) go exec dbo.sp_MS_marksystemobject sp_helpmergearticle go grant execute on dbo.sp_helpmergearticle to public go raiserror('Creating procedure sp_dropmergearticle', 0,1) GO CREATE PROCEDURE sp_dropmergearticle( @publication sysname, /* The publication name */ @article sysname, /* The article name */ @ignore_distributor bit = 0, @reserved bit = 0 ) AS set nocount on /* ** Declarations. */ declare @db_name sysname declare @cmd nvarchar(255) declare @artid uniqueidentifier declare @objid int declare @pubid uniqueidentifier declare @pubidstr nvarchar(38) declare @merge_pub_object_bit int declare @unpublish_bit int declare @retcode int declare @replinfo int declare @dbname sysname declare @distributor sysname declare @distribdb sysname declare @distproc nvarchar(255) declare @object_name sysname declare @uid smallint declare @owner sysname declare @qualified_name nvarchar(255) declare @filterid int declare @proc_name sysname declare @implicit_transaction int declare @close_cursor_at_commit int declare @sync_objid int declare @view_type int select @close_cursor_at_commit = 0 select @implicit_transaction = 0 /* ** Save setting values first before changing them */ IF (@reserved = 0) BEGIN SELECT @implicit_transaction = @@options & 2 SELECT @close_cursor_at_commit = @@options & 4 SET IMPLICIT_TRANSACTIONS OFF SET CURSOR_CLOSE_ON_COMMIT OFF END /* ** Initializations. */ -- merge uses bit 8 in replinfo select @merge_pub_object_bit = 128 select @unpublish_bit = ~@merge_pub_object_bit /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Check to make sure that this database is enabled for publishing */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END /* ** Get the @pubid. */ if NOT EXISTS (select * FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() 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 set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' /* ** Parameter Check: @article. ** If the @article is 'all', drop all articles for the specified ** publication (@publication). */ if LOWER(@article) = 'all' BEGIN declare hC CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergearticles WHERE pubid=@pubid FOR READ ONLY OPEN hC FETCH hC INTO @article WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergearticle @publication, @article, @ignore_distributor = @ignore_distributor, @reserved = 1 FETCH hC INTO @article END CLOSE hC DEALLOCATE hC RETURN (0) END /* ** Parameter Check: @article. ** The @article name must conform to the rules for identifiers. */ if @article IS NULL BEGIN RAISERROR (14043, 16, -1, '@article') RETURN (1) END /* ** Parameter Check: @publication. ** The @publication name must conform to the rules for identifiers. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END /* ** Ascertain the existence of the article. */ if NOT EXISTS (select * FROM sysmergearticles WHERE name = @article AND pubid = @pubid) BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END /* ** Delete article from sysmergearticles and clear publish bit in ** sysobjects. */ begin tran save TRAN dropmergearticle /* ** Retrieve the object id of the underlying table. */ select @sync_objid = sync_objid, @view_type = view_type, @artid = artid, @objid = objid from sysmergearticles where name = @article AND pubid = @pubid select @replinfo = replinfo, @object_name=name, @owner= user_name(uid) from sysobjects where id = @objid /* ** Remove the corresponding rows from sysmergeschemachange */ DELETE FROM sysmergeschemachange WHERE artid = @artid AND pubid = @pubid if @@ERROR <> 0 goto FAILURE /* ** If this is the last article that refers to the base table, drop the ** triggers and stored procs */ if NOT exists (select * from sysmergearticles WHERE artid = @artid AND pubid <> @pubid) begin /* ** Cleanup the triggers and stored procs */ EXECUTE @retcode = dbo.sp_MSarticlecleanup @artid = @artid, @pubid = @pubid if @@ERROR <> 0 OR @retcode <> 0 BEGIN GOTO FAILURE END /* ** Clear the replication bit in sysobjects. Now merge and transactional level ** uses different replication bit, checking transactional level is not needed. */ select @qualified_name = (QUOTENAME(@owner) + '.' + QUOTENAME(@object_name)) exec @retcode = dbo.sp_replupdateschema @qualified_name if @@ERROR <> 0 OR @retcode <> 0 BEGIN GOTO FAILURE END update sysobjects set replinfo = (replinfo & @unpublish_bit) where id = @objid IF @@ERROR <> 0 goto FAILURE end else begin /* Always drop the article proc's they are not shared among publications */ EXECUTE @retcode = dbo.sp_MSdroparticleprocs @artid = @artid, @pubid = @pubid if @@ERROR <> 0 OR @retcode <> 0 BEGIN GOTO FAILURE END /* If the article's has a temporary ( view type = 2) or a permanent view (view_type = 1 ) drop the sync object */ if (@view_type = 1 OR @view_type = 2) begin declare @viewname sysname select @viewname = sysobjects.name from sysobjects where ObjectProperty (sysobjects.id, 'IsView') = 1 and ObjectProperty (sysobjects.id, 'IsMSShipped') = 1 and sysobjects.id = @sync_objid if @viewname IS NOT NULL begin set @viewname = QUOTENAME(@viewname) exec ('drop view ' + @viewname) if @@ERROR<>0 GOTO FAILURE end end end /* ** Remove the row from sysmergearticles. */ DELETE FROM sysmergearticles WHERE artid = @artid AND pubid = @pubid if @@ERROR <> 0 BEGIN GOTO FAILURE END /* delete all the filter components that are defined upon the designated article */ select @filterid = min(join_filterid) from sysmergesubsetfilters where artid = @artid AND pubid = @pubid while (@filterid is not null) begin select @proc_name = expand_proc from sysmergesubsetfilters where artid = @artid AND pubid = @pubid and join_filterid = @filterid if (@proc_name IS NOT NULL) and exists (select * from sysobjects where name = @proc_name and type = 'P') begin exec ('drop proc ' + @proc_name) IF @@ERROR <> 0 goto FAILURE end delete from sysmergesubsetfilters where artid = @artid AND pubid = @pubid and join_filterid = @filterid IF @@ERROR <> 0 goto FAILURE select @filterid = min(join_filterid) from sysmergesubsetfilters where artid = @artid AND pubid = @pubid end /* ** set the pub type to subset or full as appropriate */ execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode <> 0 RETURN (1) /* ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 0 begin /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN goto FAILURE END SELECT @dbname = DB_NAME() SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_article' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @dbname, @publication = @publication, @article = @article IF @@ERROR <> 0 or @retcode <> 0 BEGIN goto FAILURE END end COMMIT TRAN /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN (0) FAILURE: RAISERROR (14047, 16, -1, @article) if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION dropmergearticle COMMIT TRANSACTION end /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN (1) go exec dbo.sp_MS_marksystemobject sp_dropmergearticle go grant execute on dbo.sp_dropmergearticle to public go raiserror('Creating procedure sp_addmergepublication', 0,1) GO create procedure sp_addmergepublication ( @publication sysname, /* Publication name */ @description nvarchar(255)= NULL, /* Publication description */ @retention int = 60, /* Retention period of 60 days */ @sync_mode nvarchar(10) = 'native', /* (bcp)native, (bcp)character */ @allow_push nvarchar(5) = 'true', /* Pulication allows push subscriptions */ @allow_pull nvarchar(5) = 'true', /* Pulication allows pull subscriptions*/ @allow_anonymous nvarchar(5) = 'false', /* Pulication allows anonymous subscriptions */ @enabled_for_internet nvarchar(5) = 'false', /* Pulication is enabled for internet */ @centralized_conflicts nvarchar(5) = 'true', /* Conflict records stored at publisher : true or false */ @dynamic_filters nvarchar(5) = 'false' /* Will publication be filtered on dynamic clause? */ ) as set nocount on /* ** Declarations. */ declare @retcode int /* return code value for procedure execution */ declare @push tinyint /* subscription type is push */ declare @statid tinyint /* status id based on @status */ declare @sync_modeid tinyint /* sync mode id based on @sync_mode */ declare @global tinyint /* subscriber type of loop-back subscription */ declare @db_name sysname /* database name */ declare @srvid int /* Server ID */ declare @nickname int /* replica nickname */ declare @tranpublish_bit smallint /* online publish bit (flag) in sysdatabases */ declare @mergepublish_bit smallint /* merge publish bit (flag) in sysdatabases */ declare @found int /* flag indicating if publication is found */ declare @pubid uniqueidentifier /* Publication identifier */ declare @allow_push_id bit declare @allow_pull_id bit declare @allow_anonymous_id bit declare @dynamic_filters_id bit DECLARE @enabled_for_internet_id bit declare @centralized_conflicts_id bit declare @priority real declare @automatic tinyint declare @false bit declare @true bit declare @distributor sysname declare @distproc nvarchar(255) declare @distribdb sysname declare @distpubid int declare @full int /* ** Initializations */ select @mergepublish_bit = 4 select @tranpublish_bit = 1 select @priority = 100.0 select @automatic = 1 /* Const: synchronization type 'automatic' */ select @true = 1 select @false = 0 select @full = 0 /* Const: publication type 'full' */ /* ** Set the status to unsynced (1) */ select @statid = 1 select @global = 1 select @push = 0 select @db_name = DB_NAME() /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Only publisher can call sp_addmergepublication to add its own publications */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END /* ** Parameter Check: @publication. ** The @publication name must conform to the rules for identifiers, ** and must not be the keyword 'all'. */ if @publication is NULL begin raiserror (14043, 16, -1, '@publication') return (1) end exec @retcode = dbo.sp_MSreplcheck_name @publication if @@ERROR <> 0 or @retcode <> 0 return(1) if LOWER (@publication) = 'all' begin raiserror (14034, 16, -1) return (1) end /* ** Parameter Check: @retention. ** Make sure that the maximum retention period is 60 days */ if @retention is not NULL and @retention<0 begin raiserror(20050, 16, -1, 0) return(1) end if @retention is NULL select @retention = 0 /* ** Parameter Check: @sync_mode. ** Make sure that the sync_mode is one of the following: ** ** id sync_mode ** == ========== ** 0 (bcp)native ** 1 (bcp)character */ if LOWER(@sync_mode)='portable' select @sync_mode='character' if LOWER(@sync_mode) is NULL OR LOWER(@sync_mode) NOT IN ('bcp native', 'bcp character', 'native', 'character') begin raiserror (20076, 16, -1) return (1) end if LOWER(@sync_mode) = 'native' or LOWER(@sync_mode)='bcp native' select @sync_modeid = 0 else select @sync_modeid = 1 /* ** Parameter Check: @allow_push. */ if @allow_push IS NULL OR LOWER(@allow_push) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@allow_push') RETURN (1) END if LOWER(@allow_push) = 'true' select @allow_push_id = 1 else select @allow_push_id = 0 /* ** Parameter Check: @allow_pull. */ if @allow_pull IS NULL OR LOWER(@allow_pull) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@allow_pull') RETURN (1) END if LOWER(@allow_pull) = 'true' select @allow_pull_id = 1 else select @allow_pull_id = 0 /* ** Parameter Check: @allow_anonymous. */ if @allow_anonymous IS NULL OR LOWER(@allow_anonymous) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@allow_anonymous') RETURN (1) END if LOWER(@allow_anonymous) = 'true' select @allow_anonymous_id = 1 else select @allow_anonymous_id = 0 /* ** Parameter Check: @enabled_for_internet. */ IF @enabled_for_internet IS NULL OR LOWER(@enabled_for_internet) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@enabled_for_internet') RETURN (1) END IF LOWER(@enabled_for_internet) = 'true' SELECT @enabled_for_internet_id = 1 ELSE SELECT @enabled_for_internet_id = 0 /* ** Parameter Check: @centralized_conflicts. */ if @centralized_conflicts IS NULL OR LOWER(@centralized_conflicts) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@centralized_conflicts') RETURN (1) END if LOWER(@centralized_conflicts) = 'true' select @centralized_conflicts_id = 1 else select @centralized_conflicts_id = 0 /* ** Parameter Check: @dynamic_filter. */ IF @dynamic_filters IS NULL OR LOWER(@dynamic_filters) NOT IN ('true', 'false') BEGIN RAISERROR (14148, 16, -1, '@dynamic_filters') RETURN (1) END IF LOWER(@dynamic_filters) = 'true' SELECT @dynamic_filters_id = 1 ELSE SELECT @dynamic_filters_id = 0 /* ** Check to see if the publication name is already used. ** 1. check merge pubs ** 2. check online publications */ if exists (select * from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) begin RAISERROR (20025, 16, -1, @publication) RETURN (1) end if (select category & @tranpublish_bit from master..sysdatabases where name = @db_name) <> 0 begin EXEC @retcode = dbo.sp_helppublication @publication, @found output if @@ERROR <> 0 OR @retcode <> 0 BEGIN RETURN (1) END if @found <> 0 BEGIN RAISERROR (20025, 16, -1, @publication) RETURN (1) END end /* ** Add the publication as the designmaster of the replica set. */ /* Generate a guid for the publication ID */ set @pubid = newid() /* Select the server's ID as 0 since this is the LOCAL server */ select @srvid = 0 /* Look for existing nickname from any other subscription */ exec @retcode=sp_MSgetreplnick NULL, NULL , NULL, @nickname out if (@@error <> 0) or @retcode <> 0 begin RETURN(1) end /* Generate a new replica nickname from the @pubid */ if (@nickname is null) begin execute @retcode = dbo.sp_MSgenreplnickname @pubid, @nickname output IF @@ERROR <>0 OR @retcode <> 0 BEGIN RAISERROR (20077, 16, -1) RETURN (1) END end else select @priority=max(priority) from sysmergesubscriptions where db_name=@db_name and srvid = @srvid /* ** A change in design. */ if @priority = 0 begin RAISERROR(21087, 16, -1) return (1) end /* ** Get distributor information */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT if @@error <> 0 OR @retcode <> 0 or @distributor IS NULL OR @distribdb IS NULL BEGIN RAISERROR (14071, 16, -1) RETURN (1) END /* ** add an entry into sysmergepublications */ begin tran save tran sp_addmergepublication /* Add row in the publications table */ insert sysmergepublications (pubid, name, description, designmasterid, retention, parentid, sync_mode, allow_push, allow_pull, allow_anonymous, centralized_conflicts, status, snapshot_ready, enabled_for_internet, publication_type, dynamic_filters) values (@pubid, @publication, @description, @pubid, @retention, @pubid, @sync_modeid, @allow_push_id, @allow_pull_id, @allow_anonymous_id, @centralized_conflicts_id, @statid, @false, @enabled_for_internet_id, @full, @dynamic_filters_id) if @@ERROR <> 0 begin goto FAILURE end /* Add row to represent reciprocal subscription */ insert sysmergesubscriptions(subid, partnerid, datasource_type, srvid, db_name, status, priority, pubid, subscriber_type, subscription_type, sync_type, login_name) values (@pubid, @pubid, 0, @srvid, @db_name, @statid, @priority, @pubid, @global, @push, @automatic, suser_sname(suser_sid())) if @@ERROR <> 0 begin goto FAILURE end /* ** Add row for merge publication to MSmerge_replinfo. */ insert MSmerge_replinfo(repid, replnickname) values (@pubid, @nickname) if @@ERROR <> 0 begin goto FAILURE end /* ** Add the publication to the distributor side */ SELECT @distpubid = @nickname select @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSadd_publication' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @db_name, @publication = @publication, --@publication_id = NULL, @publication_type = 2, -- 0 = Trans, 1 = Snapshot, 2 = Merge @independent_agent = @true, @immediate_sync = @true, @allow_push = @allow_push_id, @allow_pull = @allow_pull_id, @allow_anonymous = @allow_anonymous_id, --@snapshot_agent = NULL, --@logreader_agent = NULL, @description = @description, @retention = @retention IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO FAILURE END -- Populate the initial list. exec @retcode = dbo.sp_grant_publication_access @publication = @publication, @login = null, @reserved = 'init' IF @@error <> 0 OR @retcode <> 0 GOTO FAILURE commit tran return (0) FAILURE: RAISERROR (14018, 16, -1) /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION sp_addmergepublication COMMIT TRANSACTION end return (1) go exec dbo.sp_MS_marksystemobject sp_addmergepublication go grant execute on dbo.sp_addmergepublication to public go raiserror('Creating procedure sp_changemergepublication', 0,1) GO CREATE PROCEDURE sp_changemergepublication ( @publication sysname, /* Publication name */ @property sysname = NULL, /* The property to change */ @value nvarchar(255) = NULL /* The new property value */ ) AS SET NOCOUNT ON /* ** Declarations. */ declare @cmd nvarchar(255) declare @pubid uniqueidentifier declare @pubidstr nvarchar(38) declare @retcode int declare @retention int declare @statusid tinyint declare @sync_modeid tinyint declare @distributor sysname declare @distproc nvarchar(255) declare @value_bit bit declare @subscribed int declare @dbname sysname declare @distribdb sysname /* ** Initializations */ select @subscribed = 1 /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Check if current DB is enabled for publication/subscription */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 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) INSERT INTO #tab1 VALUES ('description') INSERT INTO #tab1 VALUES ('status') INSERT INTO #tab1 VALUES ('retention') INSERT INTO #tab1 VALUES ('sync_mode') INSERT INTO #tab1 VALUES ('allow_push') INSERT INTO #tab1 VALUES ('allow_pull') INSERT INTO #tab1 VALUES ('allow_anonymous') INSERT INTO #tab1 VALUES ('enabled_for_internet') INSERT INTO #tab1 VALUES ('centralized_conflicts') INSERT INTO #tab1 VALUES ('snapshot_ready') select * FROM #tab1 RETURN (0) END if @value is NULL and LOWER(@property) not in ('description', 'retention') begin RAISERROR (20081, 16, -1, @property) RETURN (1) end /* ** Parameter Check: @publication. ** Make sure that the publication exists. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' if @pubid IS NULL BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END else /* ** Parameter Check: @property. ** Check to make sure that @property is a valid property in ** sysmergepublications. */ if LOWER(@property) NOT IN ('description', 'status', 'retention', 'sync_mode', 'allow_push', 'allow_pull', 'allow_anonymous', 'enabled_for_internet', 'centralized_conflicts', 'snapshot_ready') BEGIN RAISERROR (21053, 16, -1) RETURN (1) END BEGIN TRAN sp_changemergepublication /* ** Change the property. */ if LOWER(@property) IN ('description') BEGIN UPDATE sysmergepublications SET description = @value WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO END if LOWER(@property) = 'status' BEGIN /* ** Check to make sure that we have a valid status. */ if LOWER(@value) NOT IN ('active', 'inactive') BEGIN RAISERROR (14012, 16, -1) GOTO UNDO END /* ** Determine the integer value for the status. */ if LOWER(@value) = 'active' select @statusid = 1 else select @statusid = 0 /* ** Update the publication with the new status. */ UPDATE sysmergepublications SET status = @statusid WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO /* ** If setting to inactive, allow articles / join filters to be altered, and ** clear the snapshot ready bit as well. */ if @statusid = 0 begin UPDATE sysmergepublications SET snapshot_ready = 0 WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO UPDATE sysmergearticles SET status = 1 WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO end END if LOWER(@property) = 'retention' BEGIN /* ** Update the publication with the new replication frequency. */ select @retention = CONVERT(int, @value) if @retention is NULL select @retention = 0 if @retention < 0 begin raiserror(20050, 16, -1, 0) GOTO UNDO end UPDATE sysmergepublications SET retention = @retention WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO END if LOWER(@property) = 'sync_mode' BEGIN /* ** Check for a valid synchronization method. */ if LOWER(@value) NOT IN ('native', 'character', 'bcp native', 'bcp character') begin raiserror (20076, 16, -1) GOTO UNDO end /* ** Determine the integer value for the sync_mode. */ if LOWER(@value) IN ('native', 'bcp native') select @sync_modeid = 0 else if LOWER(@value) IN ('character', 'bcp character') select @sync_modeid = 1 /* ** Update the publication with the new synchronization method. */ UPDATE sysmergepublications SET sync_mode = @sync_modeid WHERE pubid = @pubid if @@ERROR <> 0 GOTO UNDO END if LOWER(@property) IN ('allow_push', 'allow_pull', 'allow_anonymous', 'enabled_for_internet', 'centralized_conflicts', 'snapshot_ready') BEGIN /* ** Check for a valid value. */ if LOWER(@value) NOT IN ('true', 'false') BEGIN RAISERROR (14137, 16, -1) GOTO UNDO END /* ** set value bit */ if LOWER(@value) = 'true' select @value_bit = 1 else select @value_bit = 0 if LOWER(@property) = 'allow_anonymous' BEGIN /* Update the allow_anonymous column */ UPDATE sysmergepublications SET allow_anonymous = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END if LOWER(@property) = 'allow_push' BEGIN /* Update the allow_push column */ UPDATE sysmergepublications SET allow_push = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END if LOWER(@property) = 'allow_pull' BEGIN /* Update the allow_pull column */ UPDATE sysmergepublications SET allow_pull = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END if LOWER(@property) = 'centralized_conflicts' BEGIN /* Update the centralized_conflicts column */ UPDATE sysmergepublications SET centralized_conflicts = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END if LOWER(@property) = 'enabled_for_internet' BEGIN /* Update the enabled_for_internet column */ UPDATE sysmergepublications SET enabled_for_internet = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END if LOWER(@property) = 'snapshot_ready' BEGIN /* Update the allow_anonymous column */ UPDATE sysmergepublications SET snapshot_ready = @value_bit WHERE pubid = @pubid if @@error <> 0 BEGIN GOTO UNDO END END END /* ** Update merge publication property at distributor side if necessaray */ IF LOWER(@property) IN ('description','allow_push', 'allow_pull', 'allow_anonymous','retention') BEGIN IF LOWER(@property) IN ('allow_push', 'allow_pull', 'allow_anonymous') /* Translate values */ BEGIN IF LOWER(@value) = 'true' SELECT @value = '1' ELSE IF LOWER(@value) = 'false' SELECT @value = '0' END /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO UNDO END SELECT @dbname = DB_NAME() SELECT @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSchange_publication' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @dbname, @publication = @publication, @property = @property, @value = @value IF @@ERROR <> 0 OR @retcode <> 0 BEGIN GOTO UNDO END END COMMIT TRAN /* ** Return succeed. */ RAISERROR (14077, 10, -1) RETURN (0) UNDO: IF @@TRANCOUNT = 1 ROLLBACK TRAN ELSE COMMIT TRAN GO go exec dbo.sp_MS_marksystemobject sp_changemergepublication go grant execute on dbo.sp_changemergepublication to public go raiserror('Creating procedure sp_helpmergepublication', 0,1) GO CREATE PROCEDURE sp_helpmergepublication ( @publication sysname = '%', /* The publication name */ @found int = NULL OUTPUT, @publication_id uniqueidentifier = NULL OUTPUT, @reserved nvarchar(20) = NULL ) AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @no_row bit declare @our_srvid int declare @has_subscription bit /* ** Initializations. */ select @has_subscription = 0 if @found is NULL BEGIN select @no_row=0 END else BEGIN select @no_row=1 END select @found = 0 select @our_srvid = max(srvid) from master..sysservers where UPPER(srvname) = UPPER(@@SERVERNAME) /* ** Running sp_help is OK from everywhere, whether enabled for publishing or not */ IF not exists (select * from sysobjects where name='sysmergesubscriptions') RETURN (0) /* ** Parameter Check: @publication. ** Check to make sure that there are some publications ** to display. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END IF LOWER(@reserved) = 'internal' GOTO SelectPubs if NOT EXISTS (select * FROM sysmergepublications pub, sysmergesubscriptions sub WHERE pub.name like @publication and UPPER(pub.publisher)=UPPER(@@servername) and pub.publisher_db=db_name() and sub.pubid = pub.pubid and sub.srvid = @our_srvid and sub.db_name = db_name()) BEGIN select @found = 0 RETURN (0) END else BEGIN select @found = 1 select @publication_id = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if exists (select * from sysmergesubscriptions where pubid<>subid and pubid in (select pubid from sysmergepublications where name like @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name())) select @has_subscription = 1 if @no_row <> 0 RETURN(0) END SelectPubs: CREATE TABLE #tab1 ( id int identity NOT NULL, name sysname NOT NULL, description nvarchar(255) NULL, status tinyint NOT NULL, retention int NULL, sync_mode tinyint NULL, allow_push int NOT NULL, allow_pull int NOT NULL, allow_anonymous int NOT NULL, centralized_conflicts int NOT NULL, priority float(8) NOT NULL, snapshot_ready tinyint NOT NULL, publication_type int NULL, pubid uniqueidentifier NOT NULL, snapshot_jobid binary(16) NULL, enabled_for_internet int NULL, dynamic_filters int NULL, has_subscription bit NULL ) /* This is valid at all sites - used for decentralized conflicts */ IF LOWER(@reserved) = 'internal' begin INSERT into #tab1(name, description, status, retention, sync_mode, allow_push, allow_pull, allow_anonymous, centralized_conflicts, priority, snapshot_ready, publication_type, pubid, snapshot_jobid, enabled_for_internet, dynamic_filters) select pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid, pubs.enabled_for_internet, pubs.dynamic_filters FROM sysmergesubscriptions subs, sysmergepublications pubs, MSmerge_replinfo replinfo WHERE pubs.name LIKE @publication AND UPPER(pubs.publisher)=UPPER(@@servername) AND pubs.publisher_db=db_name() AND subs.subid = pubs.pubid AND replinfo.repid = pubs.pubid AND subs.subscriber_type = 1 ORDER BY name end /* This is valid only at publishers and republishers */ else begin INSERT into #tab1(name, description, status, retention, sync_mode, allow_push, allow_pull, allow_anonymous, centralized_conflicts, priority, snapshot_ready, publication_type, pubid, snapshot_jobid, enabled_for_internet, dynamic_filters, has_subscription) select pubs.name, pubs.description, pubs.status, pubs.retention, pubs.sync_mode, pubs.allow_push, pubs.allow_pull, pubs.allow_anonymous, pubs.centralized_conflicts, subs.priority, pubs.snapshot_ready, pubs.publication_type, pubs.pubid, replinfo.snapshot_jobid, pubs.enabled_for_internet, pubs.dynamic_filters, case when exists (select * from sysmergesubscriptions where pubid<>subid and pubid in (select in_pubs.pubid from sysmergepublications in_pubs where in_pubs.name = pubs.name and UPPER(in_pubs.publisher)=UPPER(@@servername) and in_pubs.publisher_db=db_name())) then 1 else 0 end FROM sysmergesubscriptions subs, sysmergepublications pubs, MSmerge_replinfo replinfo WHERE pubs.name LIKE @publication and UPPER(pubs.publisher)=UPPER(@@servername) and pubs.publisher_db=db_name() AND subs.subid = pubs.pubid AND replinfo.repid = pubs.pubid AND subs.subscriber_type = 1 AND subs.srvid = @our_srvid AND subs.db_name = db_name() ORDER BY name end if @@ERROR <> 0 RETURN (1) select * FROM #tab1 RETURN (0) go exec dbo.sp_MS_marksystemobject sp_helpmergepublication go grant execute on dbo.sp_helpmergepublication to public go raiserror('Creating procedure sp_dropmergepublication', 0,1) GO CREATE PROCEDURE sp_dropmergepublication( @publication sysname, /* The publication name */ @ignore_distributor bit = 0, @reserved bit = 0 ) AS set nocount on /* ** Declarations. */ declare @pubid uniqueidentifier declare @article sysname declare @cmd nvarchar(255) declare @retcode int declare @distproc nvarchar(255) declare @distributor sysname declare @distribdb sysname declare @working_dir varchar(255) declare @working_dir_drive varchar(255) declare @pub_dir nvarchar(255) declare @db_name sysname declare @implicit_transaction int declare @close_cursor_at_commit int select @close_cursor_at_commit = 0 select @implicit_transaction = 0 /* ** Save setting values first before changing them */ IF (@reserved = 0) BEGIN SELECT @implicit_transaction = @@options & 2 SELECT @close_cursor_at_commit = @@options & 4 SET IMPLICIT_TRANSACTIONS OFF SET CURSOR_CLOSE_ON_COMMIT OFF END /* ** Initializations. */ select @db_name = db_name() /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END if LOWER(@publication) = 'all' BEGIN declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() FOR READ ONLY OPEN hC1 FETCH hC1 INTO @publication WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergepublication @publication=@publication, @ignore_distributor = @ignore_distributor, @reserved = 1 FETCH hC1 INTO @publication END CLOSE hC1 DEALLOCATE hC1 RETURN (0) END if @publication IS NULL BEGIN RAISERROR (14003, 16, -1) RETURN (1) END /* ** Get the @pubid. */ if NOT EXISTS (select * FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() /* ** Ignore external publications */ if exists (select * from sysmergesubscriptions where subid=@pubid and pubid=@pubid and db_name<>db_name()) RETURN (0) /* ** Check to make sure that there are push or pull subscriptions on the publication. */ if EXISTS (select * FROM sysmergesubscriptions subs, sysmergepublications pubs, MSmerge_replinfo repinfo WHERE pubs.name = @publication AND UPPER(pubs.publisher)=UPPER(@@servername) AND pubs.publisher_db=db_name() AND subs.pubid = pubs.pubid AND subs.status <> 2 -- Having a deleted subscription row is fine AND repinfo.repid <> @pubid AND subs.subid <> subs.partnerid) BEGIN RAISERROR (14005, 16, -1) RETURN (1) END begin tran save TRANSACTION dropmergepublication /* ** Delete all articles from the publication. */ EXECUTE @retcode = dbo.sp_dropmergearticle @publication = @publication, @article = 'all', @ignore_distributor = @ignore_distributor if @@ERROR <> 0 OR @retcode <> 0 begin RAISERROR (20040, 16, -1, @publication) goto FAILURE end /* ** Delete sync task of Publication. */ execute @retcode = dbo.sp_MSdropmergepub_snapshot @publication = @publication, @ignore_distributor = @ignore_distributor if @@ERROR <> 0 OR @retcode <> 0 begin RAISERROR (20010, 16, -1, @publication) goto FAILURE end /* ** Remove my own subscription from sysmergesubscriptions. */ if exists (select * from sysmergesubscriptions where subid = @pubid) begin DELETE from sysmergesubscriptions WHERE subid = @pubid if @@ERROR <> 0 goto FAILURE end if exists (select * from MSmerge_replinfo where repid = @pubid) begin DELETE from MSmerge_replinfo WHERE repid = @pubid if @@ERROR <> 0 goto FAILURE end /* ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 0 begin /* ** Get distribution server information for remote RPC call. */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT, @directory = @working_dir OUTPUT IF @@ERROR <> 0 OR @retcode <> 0 BEGIN RAISERROR (14071, 16, -1) goto FAILURE END /* ** Drop the publication info from the distributor */ select @distproc = RTRIM(@distributor) + '.' + @distribdb + '.dbo.sp_MSdrop_publication' EXECUTE @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @db_name, @publication = @publication if @@ERROR <> 0 OR @retcode <> 0 begin goto FAILURE end end /* ** Remove the corresponding rows from sysmergeschemachange */ DELETE FROM sysmergeschemachange WHERE pubid = @pubid if @@ERROR <> 0 goto FAILURE /* ** Delete publication from sysmergepublications. */ DELETE FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @@ERROR <> 0 goto FAILURE COMMIT TRANSACTION /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END return (0) FAILURE: RAISERROR (14006, 16, -1) /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION dropmergepublication COMMIT TRANSACTION end /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN (1) go exec dbo.sp_MS_marksystemobject sp_dropmergepublication go grant execute on dbo.sp_dropmergepublication to public go raiserror('Creating procedure sp_reinitmergesubscription', 0, 1) GO create procedure sp_reinitmergesubscription @publication sysname = 'all', @subscriber sysname = 'all', @subscriber_db sysname = 'all' AS declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @subscription_type int declare @reinit_bit int declare @publisher sysname declare @publisher_db sysname declare @distribdb sysname declare @distributor sysname declare @distproc nvarchar(255) declare @retcode int /* ** Replace 'all' with '%' */ if LOWER(@publication) = 'all' SELECT @publication = '%' if LOWER(@subscriber) = 'all' SELECT @subscriber = '%' if LOWER(@subscriber_db) = 'all' SELECT @subscriber_db = '%' /* ** At publisher side, publication name is unique */ IF NOT EXISTS (SELECT * FROM sysmergepublications WHERE name LIKE @publication) BEGIN IF @publication = '%' RAISERROR (14008, 11, -1) ELSE RAISERROR (20026, 11, -1, @publication) RETURN (1) END EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 return (1) SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSmarkreinit ' BEGIN TRAN Declare SYN_CUR CURSOR LOCAL FAST_FORWARD FOR select subs.subid, subs.subscription_type, pubs.publisher, pubs.publisher_db from sysmergepublications pubs, sysmergesubscriptions subs where pubs.name LIKE @publication and UPPER(pubs.publisher)=UPPER(@@servername) and pubs.publisher_db=db_name() AND pubs.pubid=subs.pubid AND subs.pubid<>subs.subid AND db_name like @subscriber_db AND srvid in (select srvid from master..sysservers where ((@subscriber = N'%') or (UPPER(srvname) = UPPER(@subscriber)))) FOR READ ONLY open SYN_CUR fetch SYN_CUR into @subid, @subscription_type, @publisher, @publisher_db while (@@fetch_status<>-1) BEGIN if @subscription_type = 0 update MSmerge_replinfo set schemaversion=0, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL where repid=@subid and schemaversion is NOT NULL else update MSmerge_replinfo set schemaversion= -1, recgen = NULL, recguid=NULL, sentgen=NULL, sentguid = NULL where repid=@subid and schemaversion is NOT NULL -- 0 for push and -1 for pull exec @distproc @publisher, @publisher_db, @publication, @subscriber, @subscriber_db, 1 if @@ERROR<>0 BEGIN goto Failure END fetch next from SYN_CUR into @subid, @subscription_type, @publisher, @publisher_db END close SYN_CUR deallocate SYN_CUR commit TRAN return (0) Failure: close SYN_CUR deallocate SYN_CUR if @@TRANCOUNT = 1 ROLLBACK TRAN else COMMIT TRAN return (1) GO exec dbo.sp_MS_marksystemobject sp_reinitmergesubscription go raiserror('Creating procedure sp_MSpublicationview', 0,1) GO CREATE PROCEDURE sp_MSpublicationview( @publication sysname, @force_flag int = 0 ) AS declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @join_articlename nvarchar(270) declare @join_viewname nvarchar(270) declare @article sysname declare @art_nick int declare @join_nick int declare @join_filterclause nvarchar(2000) declare @bool_filterclause nvarchar(2000) declare @view_rule nvarchar(2000) declare @article_level int declare @progress int declare @art int declare @viewname nvarchar(270) declare @procname nvarchar(290) declare @source_objid int declare @source_object nvarchar(258) declare @sync_objid int declare @permanent int declare @temporary int declare @filter_id int declare @filter_id_str nvarchar(10) declare @guidstr nvarchar(40) declare @pubidstr nvarchar(40) declare @rgcol sysname declare @view_type int declare @belongsname sysname declare @join_nickstr nvarchar(10) declare @unqual_jointable sysname declare @retcode smallint declare @hasguid int declare @join_unique_key int declare @simple_join_view int declare @join_filterid int declare @allhaveguids int declare @command nvarchar(4000) declare @objid int declare @owner sysname declare @table sysname declare @quoted_view nvarchar(290) declare @quoted_pub nvarchar(290) declare @quoted_proc nvarchar(290) declare @snapshot_ready int set @progress = 1 set @article_level = 0 set @permanent = 1 set @temporary = 2 set @allhaveguids = 1 /* ** Only legal publisher can run this stored procedure */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END select @pubid = pubid, @snapshot_ready = snapshot_ready FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() IF @pubid IS NULL BEGIN RAISERROR (20026, 11, -1, @publication) RETURN (1) END -- If snapshot is already ready, views are good. Don't drop and recreate as someone -- might be using them. if @snapshot_ready = 1 and @force_flag = 0 return (0) exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out if @@ERROR <>0 OR @retcode <>0 return (1) create table #art(indexcol int identity NOT NULL, art_nick int NOT NULL, article_level int NOT NULL) if @@ERROR <> 0 begin goto FAILURE end while @progress > 0 BEGIN /* ** Select articles that have either a boolean_filter or atleast one join filter ** into a temp table in an optimized order. */ insert into #art(art_nick, article_level) select nickname, @article_level from sysmergearticles where pubid=@pubid and nickname not in (select art_nick from #art) and nickname not in (select art_nickname from sysmergesubsetfilters where pubid=@pubid and join_nickname not in (select art_nick from #art)) /* ** NOTENOTE: add error checking here. */ set @progress = @@rowcount select @article_level = @article_level + 1 END /* Drop the old views and reset sync_objid */ select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and sync_objid <> objid while @art_nick is not null begin /* Drop the old view */ select @viewname = OBJECT_NAME (sync_objid) from sysmergearticles where pubid = @pubid and nickname = @art_nick if @viewname IS NOT NULL begin select @quoted_view = QUOTENAME(@viewname) exec ('drop view ' + @quoted_view) end /* Update the row in sysmergearticles */ update sysmergearticles set view_type = 0, sync_objid = objid where pubid = @pubid and nickname = @art_nick if @@ERROR <> 0 goto FAILURE /* Find the next one */ select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and sync_objid <> objid end set @art = 0 select @art=min(indexcol) from #art where indexcol>@art while (@art is not null) begin select @art_nick=art_nick, @article_level = article_level from #art where indexcol = @art select @article = name, @artid = artid, @source_objid = objid, @sync_objid = sync_objid, @procname = view_sel_proc from sysmergearticles where nickname=@art_nick and pubid = @pubid select @quoted_proc = QUOTENAME(@procname) exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out if @@ERROR <>0 OR @retcode <>0 return (1) select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects where id = @source_objid select @bool_filterclause=subset_filterclause from sysmergearticles where name = @article and pubid = @pubid set @rgcol = NULL select @rgcol = QUOTENAME(name) from syscolumns where id = @source_objid and ColumnProperty(id, name, 'isrowguidcol') = 1 if @rgcol is not NULL set @hasguid = 1 else begin set @hasguid = 0 set @allhaveguids = 0 end /* ** Process non looping articles that have either a boolean or a join_filter. */ if ( @article_level > 0 OR (len(@bool_filterclause) > 0) ) begin /* ** If the article has a previously generated view, then drop the view before ** creating the new one. */ set @viewname = NULL select @viewname = name from sysobjects where id = @sync_objid and ObjectProperty (id, 'IsView') = 1 and ObjectProperty (id, 'IsMSShipped') = 1 if @viewname IS NOT NULL begin select @quoted_view = QUOTENAME(@viewname) exec ('drop view ' + @quoted_view) if @@ERROR<>0 return (1) end /* ** Any join filter(s)? If any, process join filter(s) */ if (@article_level > 0) begin declare pub1 CURSOR LOCAL FAST_FORWARD FOR select join_filterclause, join_nickname, join_articlename, join_unique_key, join_filterid from sysmergesubsetfilters where pubid=@pubid and artid=@artid FOR READ ONLY open pub1 fetch pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid select @unqual_jointable = QUOTENAME(name) from sysobjects where id = (select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) select @join_viewname = object_name(sync_objid) from sysmergearticles where nickname = @join_nick and pubid = @pubid select @join_viewname = QUOTENAME(@join_viewname) if (@join_unique_key = 1 and (@bool_filterclause is null or len(@bool_filterclause) = 0) and not exists (select * from sysmergesubsetfilters where pubid=@pubid and artid=@artid and join_filterid <> @join_filterid)) begin set @simple_join_view = 1 set @view_rule = 'select ' + @source_object + '.* from ' + @source_object + ', ' + @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause end else begin set @simple_join_view = 0 set @view_rule = 'select ' + @source_object + '.rowguidcol from ' + @source_object + ', ' + @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause end fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid WHILE (@@fetch_status <> -1) begin select @unqual_jointable = name from sysobjects where id = ( select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) select @join_viewname = object_name(sync_objid) from sysmergearticles where nickname = @join_nick and pubid = @pubid select @join_viewname = QUOTENAME(@join_viewname) set @view_rule = @view_rule + ' union select ' + @source_object + '.rowguidcol from ' + @source_object + ', ' + @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid end close pub1 deallocate pub1 if len(@bool_filterclause) > 0 set @view_rule = @view_rule + ' union select ' + @source_object + '.rowguidcol from '+ @source_object + ' where '+ @bool_filterclause -- Now do the actual view rule as a semi-join, if not a simple join on unique key if (@simple_join_view = 0) set @view_rule = 'select * from ' + @source_object + ' where rowguidcol in (' + @view_rule + ')' end else /* boolean filter only */ select @view_rule = ' select * from '+ @source_object + ' where '+ @bool_filterclause select @viewname = @publication + '_' + @article + '_VIEW' exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output select @quoted_view = QUOTENAME(@viewname) if @retcode <> 0 or @@ERROR <> 0 return (1) /* If we havent generated rowguidcol yet, use dummy rule that doesnt refer to it */ if @hasguid = 0 set @view_rule = ' select * from '+ @source_object exec ('create view '+ @quoted_view + ' as '+ @view_rule) /* Mark view as system object */ execute ('sp_MS_marksystemobject ' + @quoted_view) if @hasguid = 1 begin if @procname is not null begin exec ('drop procedure ' + @quoted_proc) end else begin set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output if @retcode <> 0 or @@ERROR <> 0 return (1) end select @owner = user_name(uid) from sysobjects where name = @viewname exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol end update sysmergearticles set sync_objid = OBJECT_ID (@viewname), view_type = @permanent, view_sel_proc = @procname where artid = @artid and pubid = @pubid end /* end of view creation for this article */ else if @procname is null and @hasguid = 1 begin /* still make the select proc, although it selects directly from table */ set @procname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec @retcode = dbo.sp_MSuniqueobjectname @procname , @procname output if @retcode <> 0 or @@ERROR <> 0 return (1) select @owner = user_name(uid), @viewname = name from sysobjects where id = @source_objid exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol update sysmergearticles set view_sel_proc = @procname where artid = @artid and pubid = @pubid end select @art=min(indexcol) from #art where indexcol>@art end /* If there are looping articles, we must use a dynamic publication since no views on temp tables */ update sysmergearticles set view_type = @temporary where pubid=@pubid and nickname not in (select art_nick from #art) if @@rowcount > 0 begin if not exists (select * from sysmergepublications where dynamic_filters = 1 and pubid = @pubid) begin declare @repl_nick int /* treat these articles as if the publication were dynamic */ execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and view_type = @temporary while @art_nick is not null begin /* Loop over articles with circular filters. Create dummy view and add rows to contents */ select @article = name, @artid = artid, @source_objid = objid, @sync_objid = sync_objid, @procname = view_sel_proc from sysmergearticles where nickname=@art_nick and pubid = @pubid select @source_object = QUOTENAME(user_name(uid)) + '.' + QUOTENAME(name) from sysobjects where id = @source_objid set @viewname = NULL select @viewname = name from sysobjects where id = @sync_objid and ObjectProperty (id, 'IsView') = 1 and ObjectProperty (id, 'IsMSShipped') = 1 if @viewname IS NOT NULL begin select @quoted_view = QUOTENAME(@viewname) exec ('drop view ' + @quoted_view) if @@ERROR<>0 return (1) end select @viewname = 'SYNC_' + @publication + '_' + @article exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output if @retcode <> 0 or @@ERROR <> 0 return (1) select @quoted_view = QUOTENAME(@viewname) exec ('create view ' + @quoted_view + ' as select * from ' + @source_object + ' where 1 = 0 ') if @@ERROR<>0 return (1) update sysmergearticles set sync_objid = OBJECT_ID (@viewname), view_sel_proc = NULL where artid = @artid and pubid = @pubid if @@ERROR<>0 return (1) select @owner = user_name(uid) from sysobjects where id = @source_objid set @table = OBJECT_NAME(@source_objid) exec @retcode = dbo.sp_addtabletocontents @table, @owner IF @@ERROR <> 0 or @retcode <> 0 return (1) select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and view_type = @temporary and nickname > @art_nick end end end drop table #art if @allhaveguids = 1 begin declare @dbname sysname set @dbname = db_name() /* create the filter expand procs now */ set @filter_id = 0 select @filter_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filter_id while @filter_id is not null begin set @filter_id_str = convert(nvarchar(10), @filter_id) select @procname = expand_proc from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filter_id /* drop old proc, or generate a new procname */ select @quoted_proc = QUOTENAME(@procname) if @procname is not null exec ('drop procedure ' + @quoted_proc) else begin set @procname = 'expand_' + @filter_id_str exec @retcode = dbo.sp_MSuniqueobjectname @procname, @procname output if @retcode <>0 return (1) update sysmergesubsetfilters set expand_proc = @procname where pubid = @pubid and join_filterid = @filter_id end select @quoted_proc = QUOTENAME(@procname) select @quoted_pub = QUOTENAME(@publication) set @command = 'exec dbo.sp_MSmakeexpandproc ' + @quoted_pub + ' , ' + @filter_id_str + ', ' + @quoted_proc exec @retcode = master..xp_execresultset @command, @dbname if @retcode <> 0 return (1) exec dbo.sp_MS_marksystemobject @quoted_proc exec ('grant execute on ' + @quoted_proc + ' to public ') select @filter_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filter_id end end return (0) FAILURE: return (1) go exec dbo.sp_MS_marksystemobject sp_MSpublicationview go grant execute on dbo.sp_MSpublicationview to public go dump tran master with no_log go raiserror('Creating procedure sp_addmergesubscription', 0,1) GO CREATE PROCEDURE sp_addmergesubscription ( @publication sysname, /* Publication name */ @subscriber sysname = NULL, /* Subscriber server */ @subscriber_db sysname = NULL, /* Subscription database */ @subscription_type nvarchar(15) = 'push', /* Subscription type - push, pull */ @subscriber_type nvarchar(15) = 'local', /* Subscriber type */ @subscription_priority real = NULL, /* Subscription priority */ @sync_type nvarchar(15) = 'automatic', /* subscription sync type */ @frequency_type int = NULL, @frequency_interval int = NULL, @frequency_relative_interval int = NULL, @frequency_recurrence_factor int = NULL, @frequency_subday int = NULL, @frequency_subday_interval int = NULL, @active_start_time_of_day int = NULL, @active_end_time_of_day int = NULL, @active_start_date int = NULL, @active_end_date int = NULL, @optional_command_line nvarchar(4000) = NULL, @description nvarchar(255) = NULL, @enabled_for_syncmgr nvarchar(5) = 'false' /* Enabled for SYNCMGR: true or false */ ) AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @subnickname int declare @subscriber_srvid int declare @publisher_srvid int declare @priority real declare @subid uniqueidentifier declare @pubid uniqueidentifier /* Publication id */ declare @subscriber_typeid smallint declare @merge_jobid binary(16) /* Scheduler jobid for the merge agent */ declare @subscription_type_id int declare @distproc nvarchar(255) declare @command nvarchar(255) declare @inactive tinyint declare @subscriber_bit smallint declare @global tinyint /* subscriber type is global */ declare @push tinyint /* subscription type is push */ declare @partnerid uniqueidentifier /* Partner replica identifier */ declare @sync_typeid tinyint declare @nosync tinyint declare @automatic tinyint declare @distributor sysname declare @distribdb sysname declare @active tinyint declare @publisher sysname declare @publisher_db sysname declare @found int declare @datasource_type int declare @datasource_path sysname DECLARE @platform_nt binary declare @is_jet int declare @Jet_datasource_path sysname /* ** Initializations. */ set @datasource_type = 0 /* Default SQL Server */ set @datasource_path = NULL set @platform_nt = 0x1 SET @nosync = 2 /* Const: synchronization type 'nosync' */ SET @automatic = 1 /* Const: synchronization type 'automatic' */ set @inactive = 0 SET @subscriber_bit = 4 set @global = 1 set @push = 0 set @pubid = NULL set @active = 1 /* Const: subscription status 'active', 0 for pull subscriptions at publisher side */ set @publisher = @@SERVERNAME set @publisher_db = DB_NAME() select @found = 1 /* Any non-NULL value is fine */ /* ** Parameter Check: @subscription_type. ** Set subscriber_typeid based on the @subscription_type specified. ** ** subscription_type subscription_type ** ================= =============== ** 0 push ** 1 pull */ if LOWER(@subscription_type) NOT IN ('push', 'pull') BEGIN RAISERROR (14128, 16, -1) RETURN (1) END IF LOWER(@subscription_type) = 'push' set @subscription_type_id = 0 else set @subscription_type_id = 1 /* ** Security Check. */ IF @subscription_type_id = 0 BEGIN exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) END ELSE BEGIN exec @retcode = dbo.sp_MSreplcheck_pull @publication if @@ERROR <> 0 or @retcode <> 0 return(1) END /* This SP is called through UI with a subscription_type = pull; in this scenario ** the status of the subscription is inactive before merge agent is run */ if @subscription_type_id = 1 select @active = 0 /* ** Validate that the publisher is a valid server */ select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) IF @publisher_srvid IS NULL BEGIN RAISERROR (14010, 16, -1) RETURN (1) END /* ** Parameter Check: @subscriber ** Check to make sure that the subscriber is defined */ IF @subscriber IS NULL BEGIN RAISERROR (14043, 16, -1, '@subscriber') RETURN (1) END IF NOT EXISTS (SELECT * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) AND (srvstatus & @subscriber_bit) <> 0) BEGIN RAISERROR (14010, 16, -1) RETURN (1) END IF @subscriber = 'all' BEGIN RAISERROR (14136, 16, -1) RETURN (1) END /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO FAILURE END SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MShelp_subscriber_info ' exec @distproc @publisher, @subscriber, @found output if (@found <> 1) BEGIN RAISERROR (14085, 16, -1) RETURN (1) END select @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MScheck_Jet_Subscriber ' exec @retcode = @distproc @subscriber, @is_jet OUTPUT, @Jet_datasource_path OUTPUT if @retcode<>0 return (1) IF @is_jet = 1 BEGIN select @datasource_type = 2 select @datasource_path = @Jet_datasource_path END EXECUTE @retcode = dbo.sp_validname @subscriber IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) /* ** Parameter Check: @subscriber_db */ IF @subscriber_db IS NULL BEGIN RAISERROR (14043, 16, -1, '@subscriber_db') RETURN (1) END IF @subscriber_db = 'all' BEGIN RAISERROR (14136, 16, -1) RETURN (1) END /* ** Check to see if system tables exist. If not create them. Since under current ** design every database is qualified for subscribing. */ IF not exists (select name from sysobjects where name='sysmergesubscriptions') BEGIN execute @retcode = dbo.sp_MScreate_mergesystables if @@ERROR <> 0 or @retcode <> 0 begin return (1) end END /* ** Parameter Check: @publication. ** Check to make sure that the publication exists and that it conforms ** to the rules for identifiers. */ if NOT EXISTS (select * FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END if @pubid IS NULL select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @partnerid IS NULL begin select @partnerid = subid FROM sysmergesubscriptions WHERE srvid = @publisher_srvid and db_name = @publisher_db and pubid = @pubid end /* ** Parameter Check: @subscriber_type. ** Set subscriber_typeid based on the @subscriber_type specified. ** ** subscriber_type subscriber_type ** ================= =============== ** 1 global ** 2 local ** 3 anonymous ** Type 'republisher' is taken out for B3. We may want to add this back later. */ if LOWER(@subscriber_type) NOT IN ('local', 'global', 'anonymous') BEGIN RAISERROR (20023, 16, -1) RETURN (1) END if LOWER(@subscriber_type) IN ('global') set @subscriber_typeid = 1 else if LOWER(@subscriber_type) IN ('local') set @subscriber_typeid = 2 else if LOWER(@subscriber_type) IN ('anonymous') set @subscriber_typeid = 3 /* Do not allow anonymous for a PUSH subscription */ if @subscriber_typeid = 3 and @subscription_type_id = 0 BEGIN RAISERROR (20087, 16, -1) RETURN (1) 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) BEGIN RAISERROR (20088, 16, -1) RETURN (1) END if (@subscription_priority IS NULL) begin select @priority = 0.99 * min(priority) from sysmergesubscriptions where subscriber_type = 1 if (@priority IS NOT NULL) select @subscription_priority = @priority if (@subscription_priority IS NULL) select @subscription_priority = 0.0 end /* ** For local and anonymous subscriptions the priority is 0.0 */ if LOWER(@subscriber_type) IN ('local', 'anonymous') select @subscription_priority = 0.0 /* ** Validate that the subscriber is a valid server */ select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) IF @subscriber_srvid IS NULL BEGIN RAISERROR (14010, 16, -1) RETURN (1) END IF exists (select * from sysobjects where name= 'syssubscriptions') begin if exists (select name from sysmergearticles where pubid=@pubid and objid in (select objid from sysarticles where artid in (select artid from syssubscriptions where dest_db=@subscriber_db and srvid=@subscriber_srvid))) begin RAISERROR(20084, 16, -1, @publication, @subscriber_db) RETURN (1) end end /* ** Making it possible for a deleted subscription to come back. ** UNDONE : This disallows second pull subscription from being added unless the previous ** subscription was initial synced. */ if EXISTS (select db_name, srvid FROM sysmergesubscriptions WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid AND status <>2) --We can definitely add back subscriptions that were deleted. BEGIN RAISERROR (14058, 16, -1) RETURN (1) END IF EXISTS (select db_name, srvid FROM sysmergesubscriptions WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid AND status = 2) BEGIN select @subid = subid from sysmergesubscriptions WHERE db_name = @subscriber_db AND srvid = @subscriber_srvid AND pubid = @pubid delete from sysmergesubscriptions where subid = @subid delete from MSmerge_replinfo where repid = @subid END select @subid = newid() /* ** Parameter Check: @sync_type. ** Set sync_typeid based on the @sync_type specified. ** ** sync_typeid sync_type ** =========== ========= ** 1 automatic ** 2 nosync */ IF LOWER(@sync_type) NOT IN ('automatic', 'none') BEGIN RAISERROR (14052, 16, -1) RETURN (1) END /* ** If current publication contains an article without rowguidcol, do not allow no-sync subscription */ IF LOWER(@sync_type) = 'automatic' BEGIN SET @sync_typeid = @automatic END ELSE BEGIN if exists (select * from sysmergearticles a where pubid=@pubid and not exists (select * from syscolumns c where c.id = a.objid and ColumnProperty(c.id, c.name, 'IsRowGuidCol') = 1)) BEGIN Raiserror(20086, 16, -1, @publication) RETURN (1) END else SET @sync_typeid = @nosync END /* ** UNDONE: Validate that the publisher is of type "republisher" */ begin tran save TRAN addmergesubscription /* Generate a guid for the Subscriber ID */ /* Look for existing nickname from any other subscription */ exec @retcode = dbo.sp_MSgetreplnick @subscriber, @subscriber_db , NULL, @subnickname out if (@@error <> 0) or @retcode <> 0 GOTO FAILURE /* Generate a new replica nickname from the @subid */ if (@subnickname is null) begin EXECUTE dbo.sp_MSgenreplnickname @subid, @subnickname output if @@ERROR<>0 GOTO FAILURE end /* ** The subscription doesn't exist, so let's add it to sysmergesubscriptions */ INSERT sysmergesubscriptions (subid, partnerid, datasource_type, datasource_path, srvid, db_name, pubid, status, subscriber_type, subscription_type, priority, sync_type, description, login_name) VALUES (@subid, @partnerid, @datasource_type, @datasource_path, @subscriber_srvid, @subscriber_db, @pubid, @active, @subscriber_typeid, @subscription_type_id, @subscription_priority, @sync_typeid, @description, suser_sname(suser_sid())) if @@ERROR <> 0 BEGIN GOTO FAILURE END /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO FAILURE END SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSadd_merge_subscription' EXEC @retcode = @distproc @publisher = @@SERVERNAME, @publisher_db = @publisher_db, @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = @subscription_type_id, @sync_type = @sync_typeid, @status = @active, @frequency_type = @frequency_type, @frequency_interval = @frequency_interval, @frequency_relative_interval = @frequency_relative_interval, @frequency_recurrence_factor = @frequency_recurrence_factor, @frequency_subday = @frequency_subday, @frequency_subday_interval = @frequency_subday_interval, @active_start_time_of_day = @active_start_time_of_day, @active_end_time_of_day = @active_end_time_of_day, @active_start_date = @active_start_date, @active_end_date = @active_end_date, @optional_command_line = @optional_command_line, @merge_jobid = @merge_jobid OUTPUT IF @@ERROR <> 0 OR @retcode <> 0 begin goto FAILURE end /* ** Add row for subscription in MSmerge_replinfo. */ insert MSmerge_replinfo(repid, replnickname, merge_jobid) values (@subid, @subnickname, @merge_jobid) if @@ERROR <> 0 BEGIN GOTO FAILURE END /* Conditional support for MobileSync */ if LOWER(@enabled_for_syncmgr) = 'true' BEGIN /* MobileSync Support */ declare @distributor_server sysname declare @distributor_security_mode int declare @distributor_login sysname declare @distributor_password sysname /* ** The registry entry needs to be created only for push subscriptions - ** i.e - need not be called when a pull subscription is created at the ** subscriber and sp_addmergesubscription is being called then. */ IF @subscription_type_id = 0 BEGIN EXECUTE @retcode = dbo.sp_helpdistributor @distributor = @distributor_server OUTPUT /* Distributor RPC server name */ IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO FAILURE END -- Always use integrated security on winNT if (@platform_nt = platform() & @platform_nt ) begin set @distributor_security_mode = 1 end -- For Win9x the dist publisher and distributor are the same machine else begin select @distributor_security_mode = 0, @distributor_login = login, @distributor_password = password from msdb..MSdistpublishers where UPPER(name) = UPPER(@@servername) end /* Call sp_MSregistersubscription so that the subscription can be synchronized via Onestop etc. */ exec @retcode = dbo.sp_MSregistersubscription @replication_type = 2, @publisher = @@SERVERNAME, @publisher_db = @publisher_db, @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @distributor = @distributor, @distributor_security_mode = @distributor_security_mode, @distributor_login = @distributor_login, @distributor_password = @distributor_password, @subscription_id = @subid, @subscription_type = @subscription_type_id IF @@error <> 0 OR @retcode <> 0 BEGIN GOTO FAILURE END END END COMMIT TRAN return (0) FAILURE: RAISERROR (14057, 16, -1) /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION addmergesubscription COMMIT TRANSACTION end RETURN (1) go exec dbo.sp_MS_marksystemobject sp_addmergesubscription go grant execute on dbo.sp_addmergesubscription to public go raiserror('Creating procedure sp_changemergesubscription', 0,1) GO CREATE PROCEDURE sp_changemergesubscription ( @publication sysname = NULL, /* Publication name */ @subscriber sysname = NULL, /* Subscriber server */ @subscriber_db sysname = NULL, /* Subscription database */ @property sysname = NULL, /* The property to change */ @value nvarchar(255) = NULL /* The new property value */ ) AS SET NOCOUNT ON /* ** Declarations. */ declare @subscriber_bit smallint declare @subscriber_srvid int declare @publisher_srvid int declare @retcode int declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @partnerid uniqueidentifier declare @sync_typeid tinyint declare @nosync tinyint declare @automatic tinyint declare @artid uniqueidentifier declare @schematype int declare @schemaversion int declare @schemaguid uniqueidentifier declare @db_name sysname declare @subscriber_type int declare @schematext nvarchar(2000) declare @publisher sysname declare @publisher_db sysname /* ** Initializations. */ SET @nosync = 2 /* Const: synchronization type 'none' */ SET @automatic = 1 /* Const: synchronization type 'automatic' */ set @publisher = @@SERVERNAME set @publisher_db = DB_NAME() /* ** Security Check. */ BEGIN exec @retcode = dbo.sp_MSreplcheck_subscribe if @@ERROR <> 0 or @retcode <> 0 return(1) END /* ** Check to see if current database is doing publishing/subscribing */ IF not exists (select name from sysobjects where name='sysmergesubscriptions') BEGIN RAISERROR (14055, 16, -1) RETURN (1) END /* ** Parameter Check: @property. ** If the @property parameter is NULL, print the options. */ IF @property IS NULL BEGIN CREATE TABLE #tab1 (properties sysname) INSERT INTO #tab1 VALUES ('sync_type') INSERT INTO #tab1 VALUES ('priority') INSERT INTO #tab1 VALUES ('description') select * FROM #tab1 RETURN (0) END /* ** Parameter Check: @publication. ** Make sure that the publication exists. */ IF @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() IF @pubid IS NULL BEGIN RAISERROR (20026, 11, -1, @publication) RETURN (1) END /* ** Validate that the publisher is a valid server */ select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) IF @publisher_srvid IS NULL BEGIN RAISERROR (14010, 16, -1) RETURN (1) END /* ** Parameter Check: @subscriber. ** Check to make sure we have a valid subscriber. */ IF @subscriber IS NULL BEGIN RAISERROR (14043, 16, -1, '@subscriber') RETURN (1) END /* ** Validate that the subscriber is a valid server */ select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) IF @subscriber_srvid IS NULL BEGIN RAISERROR (14010, 16, -1) RETURN (1) END /* ** Check to see if you have a local / global subscription on this publication */ set @subid = NULL select @subid = subs1.subid, @pubid = pubs.pubid, /* identified from publication name */ @subscriber_type=subs1.subscriber_type, @partnerid = subs2.subid from sysmergesubscriptions subs1, sysmergesubscriptions subs2, sysmergepublications pubs where subs1.srvid = @subscriber_srvid and subs1.db_name = @subscriber_db and subs2.srvid = @publisher_srvid and subs2.db_name = @publisher_db and subs1.pubid = subs2.subid and subs2.pubid = pubs.pubid and pubs.name = @publication and UPPER(pubs.publisher)=UPPER(@@servername) and pubs.publisher_db=db_name() if @subid IS NULL begin RAISERROR (14050, 11, -1) RETURN(1) end /* ** Parameter Check: @property. ** Check to make sure that @property is a valid property in ** sysarticles. */ IF LOWER(@property) NOT IN ('sync_type', 'priority', 'description') BEGIN RAISERROR (20078, 16, -1) RETURN (1) END /* ** Change the property. */ IF LOWER(@property) = 'sync_type' BEGIN /* ** Check to make sure that we have a valid sync_type. */ IF LOWER(@value) NOT IN ('automatic', 'none') BEGIN RAISERROR (14052, 16, -1) RETURN (1) END /* ** Determine the integer value for the sync_type. */ IF LOWER(@value) = 'automatic' SET @sync_typeid = @automatic ELSE BEGIN /* ** If current publication contains an article without rowguidcol, do not allow no-sync subscription */ if exists (select * from sysmergearticles a where pubid = @pubid and not exists (select * from syscolumns c where c.id=a.objid and columnproperty (c.id, c.name, 'isrowguidcol')=1)) begin Raiserror(20086, 16, -1, @publication) RETURN (1) end else SET @sync_typeid = @nosync END /* ** Update the subscription with the new sync_type. */ UPDATE sysmergesubscriptions SET sync_type = @sync_typeid WHERE subid = @subid IF @@ERROR <> 0 BEGIN RAISERROR (14053, 16, -1) RETURN (1) END END IF LOWER(@property) = '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) = '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 IF convert(real, @value)>100.0 BEGIN RAISERROR (20049, 16, -1) /* Don't accept priority greater than 100 */ RETURN (1) END select @schemaversion = schemaversion from sysmergeschemachange if (@schemaversion is NULL) set @schemaversion = 1 else select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange set @schemaguid = newid() set @artid = newid() set @schematype = 8 /* change priority */ select @schematext = 'exec dbo.sp_MSchange_priority '+ '''' + convert(nchar(36),@subid) + '''' + ',' + '''' + @value + '''' BEGIN TRANSACTION change_priority exec dbo.sp_MSchange_priority @subid, @value if @@ERROR<>0 goto UNDO exec @retcode=sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext if @@ERROR<>0 or @retcode<>0 goto UNDO COMMIT TRANSACTION END /* ** Return succeed. It is not an error message. */ RAISERROR (14054, 10, -1) RETURN (0) UNDO: if @@TRANCOUNT = 1 ROLLBACK TRANSACTION else COMMIT TRANSACTION return (1) go exec dbo.sp_MS_marksystemobject sp_changemergesubscription go grant execute on dbo.sp_changemergesubscription to public go raiserror('Creating procedure sp_helpmergesubscription', 0,1) GO CREATE PROCEDURE sp_helpmergesubscription( @publication sysname = '%', /* Publication name */ @subscriber sysname = '%', /* Subscriber server */ @subscriber_db sysname = '%', /* Subscription database */ @publisher sysname = '%', /* Publisher server */ @publisher_db sysname = '%', /* Publisher database */ @subscription_type nvarchar(15) = 'both', /* Subscription type - push or pull */ @found int = NULL OUTPUT )AS SET NOCOUNT ON /* ** Declarations. */ declare @db sysname declare @retcode int declare @subscriber_bit smallint declare @srvid int declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @partnerid uniqueidentifier declare @cursor_open int declare @no_row bit declare @subscription_type_id int /* ** Initializations. */ set @subscriber_bit = 4 set @cursor_open = 0 /* ** Initializations of @now_row. */ IF @found is NULL BEGIN SELECT @no_row=0 END ELSE BEGIN SELECT @no_row=1 END select @db=db_name() -- so that it can appear in dynamic query /* ** Calling sp_help* is all right whether current database is enabled for pub/sub or not */ IF not exists (select * from sysobjects where name='sysmergesubscriptions') RETURN (0) /* Security check */ EXEC @retcode = dbo.sp_MSreplcheck_pull @publication = @publication, @raise_fatal_error = 0 if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** Parameter Check: @subscription_type. ** Set subscription_typeid based on the @subscription_type specified. ** ** subscription_type subscription_type ** ================= =============== ** 0 push ** 1 pull ** 2 both */ if LOWER(@subscription_type) NOT IN ('push', 'pull', 'both') BEGIN RAISERROR (20079, 16, -1) RETURN (1) END IF LOWER(@subscription_type) = 'both' set @subscription_type_id = 2 else IF LOWER(@subscription_type) = 'push' set @subscription_type_id = 0 else set @subscription_type_id = 1 /* ** Parameter Check: @publisher ** Check to make sure that the publisher is defined */ IF @publisher <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @publisher IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) END /* ** Parameter Check: @subscriber. ** If remote server, limit the view to the remote server's subscriptions. ** Make sure that the name isn't NULL. */ if @subscriber IS NULL BEGIN RAISERROR (14043, 16, -1, '@subscriber') RETURN (1) END /* ** Parameter Check: @subscriber. ** Check if remote server is defined as a subscription server, and ** that the name conforms to the rules for identifiers. */ if @subscriber <> '%' BEGIN EXECUTE @retcode = dbo.sp_validname @subscriber if @retcode <> 0 OR @@ERROR <> 0 RETURN (1) if NOT EXISTS (select * FROM master..sysservers WHERE UPPER(srvname) = UPPER(@subscriber) AND (srvstatus & @subscriber_bit) <> 0) BEGIN --RAISERROR (14010, 16, -1) RETURN (1) END END /* ** Parameter Check: @publication. ** If the publication name is specified, check to make sure that it ** conforms to the rules for identifiers and that the publication ** actually exists. Disallow NULL. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END /* ** Get subscriptions */ if @publication <>'%' begin execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode<>0 Return (1) end create table #helpsubscription ( publication sysname NOT NULL, publisher sysname NOT NULL, publisher_db sysname NOT NULL, subscriber sysname NOT NULL, subscriber_db sysname 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) NULL, merge_jobid binary(16) NULL, full_publication tinyint NULL ) /* ** Performance Optimization: Eliminate the 'LIKE' clause for publication name. ** Empirical evidence shows almost 50% speed improvement when ** opening the cursor if publication name is provided. */ IF (@publication <> '%') insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type FROM sysmergesubscriptions subs1, sysmergesubscriptions subs2, MSmerge_replinfo replinfo, master..sysservers servers1, master..sysservers servers2, sysmergepublications pubs where subs1.subid <> subs2.subid and subs1.status <> 2 and subs2.subid = subs1.partnerid and pubs.pubid = subs1.pubid and pubs.pubid = subs2.pubid and servers1.srvid = subs1.srvid and servers2.srvid = subs2.srvid and pubs.name = @publication and replinfo.repid = subs1.subid and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1) and subs1.db_name like @subscriber_db and subs2.db_name like @publisher_db and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber))) and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher))) and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2) ELSE insert into #helpsubscription select distinct pubs.name, servers2.srvname, subs2.db_name, servers1.srvname, subs1.db_name, subs1.status, subs1.subscriber_type, subs1.subscription_type, subs1.priority, subs1.sync_type, subs1.description, replinfo.merge_jobid, pubs.publication_type FROM sysmergesubscriptions subs1, sysmergesubscriptions subs2, MSmerge_replinfo replinfo, master..sysservers servers1, master..sysservers servers2, sysmergepublications pubs where subs1.subid <> subs2.subid and subs1.status <> 2 and subs2.subid = subs1.partnerid and pubs.pubid = subs1.pubid and pubs.pubid = subs2.pubid and servers1.srvid = subs1.srvid and servers2.srvid = subs2.srvid and replinfo.repid = subs1.subid and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1) and subs1.db_name like @subscriber_db and subs2.db_name like @publisher_db and ((@subscriber = N'%') or (UPPER(servers1.srvname) = UPPER(@subscriber))) and ((@publisher = N'%') or (UPPER(servers2.srvname) = UPPER(@publisher))) and (subs1.subscription_type = @subscription_type_id or @subscription_type_id = 2) if exists (select * from #helpsubscription) select @found = 1 else select @found = 0 if @no_row = 1 goto DONE IF LOWER(@subscription_type) = 'push' or LOWER(@subscription_type) = 'both' begin select 'subscription_name' = subscriber + ':' + subscriber_db, * from #helpsubscription order by publisher, publisher_db, publication, subscriber, subscriber_db end else begin select 'subscription_name' = publisher + ':' + publisher_db + ':' + publication, * from #helpsubscription order by publisher, publisher_db, publication, subscriber, subscriber_db end select @retcode = 0 DONE: if (@cursor_open = 1) begin close #cursor deallocate #cursor end drop table #helpsubscription return @retcode go exec dbo.sp_MS_marksystemobject sp_helpmergesubscription go grant execute on dbo.sp_helpmergesubscription to public go raiserror('Creating procedure sp_dropmergesubscription', 0,1) GO CREATE PROCEDURE sp_dropmergesubscription( @publication sysname = NULL, /* Publication name */ @subscriber sysname = NULL, /* Subscriber server */ @subscriber_db sysname = NULL, /* Subscription database */ @subscription_type nvarchar(15) = 'push', /* Subscription type - push, pull, both */ @ignore_distributor bit = 0, @reserved bit = 0 )AS SET NOCOUNT ON /* ** Declarations. */ declare @retcode int declare @subscriber_bit smallint declare @subscriber_type smallint declare @subscriber_srvid int declare @publisher_srvid int declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @partnerid uniqueidentifier declare @subscription_type_id int declare @found_subscription int declare @local_server sysname declare @local_db sysname declare @cmd nvarchar(290) declare @distributor sysname declare @distribdb sysname declare @distproc nvarchar(512) declare @pubidstr nvarchar(38) declare @publisher sysname declare @publisher_db sysname declare @implicit_transaction int declare @close_cursor_at_commit int select @close_cursor_at_commit = 0 select @implicit_transaction = 0 /* ** Save setting values first before changing them */ IF (@reserved = 0) BEGIN SELECT @implicit_transaction = @@options & 2 SELECT @close_cursor_at_commit = @@options & 4 SET IMPLICIT_TRANSACTIONS OFF SET CURSOR_CLOSE_ON_COMMIT OFF END /* ** Initializations. */ set @subscriber_bit = 4 set @subscription_type_id = -1 set @found_subscription = 0 set @local_db = DB_NAME() set @local_server = @@SERVERNAME set @publisher = @@SERVERNAME set @publisher_db = DB_NAME() /* ** Check to see if current database is enabled for publishing/subscribing */ IF not exists (select name from sysobjects where name='sysmergesubscriptions') BEGIN RAISERROR (14055, 16, -1) RETURN (1) END /* ** Parameter Check: @subscription_type. ** Set subscription_typeid based on the @subscription_type specified. ** ** subscription_type subscription_type ** ================= =============== ** 0 push ** 1 pull */ if LOWER(@subscription_type) NOT IN ('both', 'push', 'pull') BEGIN RAISERROR (14128, 16, -1) RETURN (1) END IF LOWER(@subscription_type) = 'both' begin EXECUTE dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = 'push', @ignore_distributor = @ignore_distributor, @reserved = 1 EXECUTE dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = 'pull', @ignore_distributor = @ignore_distributor, @reserved = 1 RETURN (0) end IF LOWER(@subscription_type) = 'push' set @subscription_type_id = 0 else set @subscription_type_id = 1 /* ** Parameter validation (different for push and pull modes) */ IF LOWER(@subscription_type) = 'push' begin /* ** Assign parameter values appropriately */ if @publisher IS NULL set @publisher = @@SERVERNAME if (@publisher_db IS NULL) set @publisher_db = DB_NAME() /* ** Parameter Check: @subscriber ** Check to make sure that the subscriber is defined */ IF @subscriber IS NULL BEGIN RAISERROR (14043, 16, -1, '@subscriber') RETURN (1) END /* ** Parameter Check: @subscriber_db */ IF @subscriber_db IS NULL BEGIN select @subscriber_db = 'all' END end else begin /* ** Assign parameter values appropriately */ if @subscriber IS NULL set @subscriber = @@SERVERNAME if @subscriber_db IS NULL set @subscriber_db = DB_NAME() /* ** Parameter Check: @publisher ** Check to make sure that the publisher is defined */ IF @publisher IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher') RETURN (1) END EXECUTE @retcode = dbo.sp_validname @publisher IF @@ERROR <> 0 OR @retcode <> 0 RETURN (1) /* ** Parameter Check: @publisher_db */ IF @publisher_db IS NULL BEGIN RAISERROR (14043, 16, -1, '@publisher_db') RETURN (1) END end /* ** Parameter Check: @publication. ** If the publication name is specified, check to make sure that it ** conforms to the rules for identifiers and that the publication ** actually exists. Disallow NULL. */ if @publication IS NULL BEGIN RAISERROR (14043, 16, -1, '@publication') RETURN (1) END IF LOWER(@publication) = 'all' BEGIN declare hC1 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT name FROM sysmergepublications where UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() FOR READ ONLY OPEN hC1 FETCH hC1 INTO @publication WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = @subscription_type, @ignore_distributor = @ignore_distributor, @reserved = 1 FETCH hC1 INTO @publication END CLOSE hC1 DEALLOCATE hC1 RETURN (0) END if NOT EXISTS (select * FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name()) BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' if @pubid is null BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END IF LOWER(@subscriber) = 'all' BEGIN declare hC2 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT srvname FROM master..sysservers WHERE (srvstatus & 4 <> 0) FOR READ ONLY OPEN hC2 FETCH hC2 INTO @subscriber WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = @subscription_type, @ignore_distributor = @ignore_distributor, @reserved = 1 FETCH hC2 INTO @subscriber END CLOSE hC2 DEALLOCATE hC2 RETURN (0) END /* ** Validate that the subscriber is a valid server */ select @subscriber_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) IF @subscriber_srvid IS NULL BEGIN --RAISERROR (14010, 16, -1) RETURN (1) END /* ** NOTE: remove this batch */ IF LOWER(@subscriber_db) = 'all' BEGIN declare hC3 CURSOR LOCAL FAST_FORWARD FOR select DISTINCT db_name FROM sysmergesubscriptions WHERE srvid = @subscriber_srvid AND subid <> pubid AND sysmergesubscriptions.pubid = @pubid AND sysmergesubscriptions.subscription_type = @subscription_type_id FOR READ ONLY OPEN hC3 FETCH hC3 INTO @subscriber_db WHILE (@@fetch_status <> -1) BEGIN EXECUTE dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = @subscription_type, @ignore_distributor = @ignore_distributor, @reserved = 1 FETCH hC3 INTO @subscriber_db END CLOSE hC3 DEALLOCATE hC3 RETURN (0) END /* ** Validate that the publisher is a valid server */ select @publisher_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) IF @publisher_srvid IS NULL BEGIN --RAISERROR (14010, 16, -1) RETURN (1) END select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL return (0) if exists (select * from sysmergesubscriptions where subid=@pubid and pubid=@pubid and db_name<>db_name()) RETURN (0) /* ** Get subscriptions from either local replicas or global replicas */ select @subid = subs1.subid, @partnerid = subs2.subid, @subscriber_type = subs1.subscriber_type from sysmergesubscriptions subs1, sysmergesubscriptions subs2, sysmergepublications pubs where subs1.srvid = @subscriber_srvid and subs1.db_name = @subscriber_db and subs2.srvid = @publisher_srvid and subs2.db_name = @publisher_db and subs1.pubid = subs2.subid and subs2.pubid = pubs.pubid and pubs.name = @publication and UPPER(pubs.publisher)=UPPER(@@servername) and pubs.publisher_db=db_name() and subs1.subscription_type = @subscription_type_id and (suser_sname(suser_sid()) = subs1.login_name OR is_member('db_owner')=1 OR is_srvrolemember('sysadmin') = 1) if @subid IS NULL begin -- raiserror (14050, 16, -1) RETURN (0) end begin tran save TRAN dropmergesubscription /* ** Do not drop the subscription corresponding to the loopback subscription */ if (@subid <> @partnerid) begin /* ** global/republisher subscriptions have to stay for a while even after being ** dropped so that they won't regain lives for themselves. They would be cleanup eventually. */ if (@subscriber_type<>1) begin delete from sysmergesubscriptions where subid = @subid IF @@ERROR <> 0 GOTO FAILURE delete MSmerge_replinfo WHERE repid = @subid IF @@ERROR <> 0 GOTO FAILURE end else begin update sysmergesubscriptions set status=2 where subid=@subid IF @@ERROR<>0 GOTO FAILURE end /* ** The MobileSync registry entry needs to be dropped only for push subscriptions - ** i.e - need not be called when a pull subscription is created at the ** subscriber and sp_addmergesubscription is being called then. */ IF LOWER(@subscription_type) = 'push' begin /* Call sp_MSunregistersubscription so that the reg entries get deleted */ exec @retcode = dbo.sp_MSunregistersubscription @publisher = @@SERVERNAME, @publisher_db = @publisher_db, @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db IF @retcode<>0 or @@ERROR<>0 GOTO FAILURE END end /* ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 0 begin /* ** Get distribution server information for remote RPC call. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 BEGIN GOTO FAILURE END SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_merge_subscription' EXEC @retcode = @distproc @@SERVERNAME, @publisher_db, @publication, @subscriber, @subscriber_db, @subscription_type IF @@ERROR <> 0 OR @retcode <> 0 begin goto FAILURE end end /* ** If last subscription is dropped and the DB is not enabled for publishing, ** then remove the merge system tables */ IF (not exists (select * from sysmergesubscriptions )) AND (select category & 4 FROM master..sysdatabases WHERE name = DB_NAME())=0 BEGIN execute @retcode = dbo.sp_MSdrop_mergesystables if @@ERROR <> 0 or @retcode <> 0 begin return (1) end END COMMIT TRAN /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END RETURN(0) FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ RAISERROR (14056, 16, -1) if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION dropmergesubscription COMMIT TRANSACTION end /* ** Set back original settings */ IF @reserved = 0 BEGIN IF @implicit_transaction <>0 SET IMPLICIT_TRANSACTIONS ON IF @close_cursor_at_commit <>0 SET CURSOR_CLOSE_ON_COMMIT ON END return (1) go exec dbo.sp_MS_marksystemobject sp_dropmergesubscription go grant execute on dbo.sp_dropmergesubscription to public go raiserror('Creating procedure sp_MSmergepublishdb', 0,1) GO CREATE PROCEDURE sp_MSmergepublishdb( @value sysname, @ignore_distributor bit = 0 ) AS SET NOCOUNT ON /* ** Declarations. */ declare @command nvarchar(255) declare @description nvarchar(500) declare @cmptlevel tinyint declare @db_name sysname declare @retcode int declare @distributor sysname declare @distribdb sysname declare @distproc nvarchar (255) declare @category_name sysname declare @agentname sysname /* ** Initialization */ select @db_name = DB_NAME() /* ** Parameter check ** @value */ IF LOWER(@value) NOT IN ('true','false') BEGIN RAISERROR(14137,16,-1) RETURN(1) END /* ** if @ignore_distributor = 1, we are in bruteforce cleanup mode, don't do RPC. */ if @ignore_distributor = 0 begin /* ** Test to see if the distributor is installed and online. */ EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 or @distributor IS NULL or @distribdb IS NULL BEGIN IF LOWER(@value) = 'true' RAISERROR (20028, 16, -1) ELSE RAISERROR (20029, 16, -1) RETURN (1) END end /* ** Enable the database for publishing. */ IF LOWER(@value) = 'true' BEGIN select @cmptlevel = cmptlevel from master..sysdatabases where name=db_name() if @cmptlevel<70 OR @cmptlevel is NULL begin RAISERROR(20061, 16, -1) goto FAILURE end execute @retcode = dbo.sp_MScreate_mergesystables if @@ERROR <> 0 or @retcode <> 0 begin goto FAILURE end END ELSE /* Disable the database for publishing. */ BEGIN /* ** Remove all the registration entries for subscriptions */ if not exists(select * from sysobjects where name = 'sysmergesubscriptions') goto FAILURE exec @retcode = dbo.sp_dropmergesubscription @publication = 'all', @subscriber = 'all', @subscriber_db = 'all', @subscription_type = 'both', @ignore_distributor = @ignore_distributor IF @@ERROR <> 0 or @retcode <> 0 begin goto FAILURE end /* ** Remove all publications and articles in the database. */ EXEC @retcode = dbo.sp_dropmergepublication @publication = 'all', @ignore_distributor = @ignore_distributor IF @@ERROR <> 0 or @retcode <> 0 begin -- sp_dropmergepublication will raiserror goto FAILURE end If NOT EXISTS (select * from sysmergepublications) BEGIN execute @retcode = dbo.sp_MSdrop_mergesystables if @@ERROR <> 0 or @retcode <> 0 begin goto FAILURE end END END return 0 FAILURE: return (1) GO exec dbo.sp_MS_marksystemobject sp_MSmergepublishdb go raiserror('Creating procedure sp_enumcustomresolvers', 0,1) GO CREATE PROCEDURE sp_enumcustomresolvers -- @distributor parameter will be removed in the next version. @distributor sysname = NULL AS SET NOCOUNT ON declare @distributor_rpc sysname declare @return_status int declare @distproc nvarchar(100) declare @retcode int select @return_status = 0 /* ** Get the distributor ** Use local RPC if @distributor == @servername. This is used by UI ** before installing a distributor. */ if @distributor = @@servername select @distributor_rpc = @@servername else begin EXEC @return_status = dbo.sp_helpdistributor @rpcsrvname = @distributor_rpc OUTPUT IF @@error <> 0 OR @return_status <> 0 OR @distributor_rpc IS NULL BEGIN RAISERROR (20036, 16, -1) RETURN (1) END end declare @key_exists int select @key_exists = 0 create table #keyexists (keyexists int) select @distproc = RTRIM(@distributor_rpc) + '.master..xp_regread' insert into #keyexists exec @distproc 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\MSSQLServer\Replication\ArticleResolver' select @key_exists = keyexists from #keyexists if (@key_exists = 1) begin select @distproc = RTRIM(@distributor_rpc) + '.master..xp_regenumvalues' exec @distproc 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\MSSQLServer\Replication\ArticleResolver' if @@ERROR<>0 return (1) end drop table #keyexists RETURN (0) GO exec dbo.sp_MS_marksystemobject sp_enumcustomresolvers go grant execute on dbo.sp_enumcustomresolvers to public go raiserror('Creating procedure sp_changemergefilter', 0,1) GO create procedure sp_changemergefilter( @publication sysname, @article sysname, @filtername sysname, @property sysname, @value nvarchar(2000) )AS set nocount on declare @db_name sysname declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @retcode int declare @join_filterid int declare @join_objid int declare @join_nickname int /* ** Security Check. ** Only the System Administrator (SA) or the Database Owner (dbo) can ** call this procedure */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** Parameter Check: @join_articlename. ** The join_articlename cannot be NULL */ if @filtername is NULL begin raiserror (14043, 11, -1, '@filtername') return (1) end if @value is NULL or @value = '' begin raiserror (14043, 11, -1, '@value') return (1) end /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14043, 11, -1, '@publication') return (1) end /* ** Get the pubid and make sure the publication exists */ select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (20026, 16, -1, @publication) return (1) end /* This can only be done at the publisher */ exec @retcode = dbo.sp_MScheckatpublisher @pubid if @retcode <> 0 or @@ERROR <> 0 return (1) /* ** This can be done for articles that are not active. */ if EXISTS (select status FROM sysmergearticles WHERE pubid = @pubid AND status = 2) BEGIN RAISERROR (20043, 16, -1, @article) RETURN (1) END select @db_name = db_name from sysmergesubscriptions where (pubid=@pubid) and (subid=@pubid) IF @db_name <> db_name() BEGIN RAISERROR (20047, 16, -1) RETURN (1) END /* ** Parameter Check: @article. ** Check to see that the @article is valid and does exist */ if @article is NULL begin raiserror (20045, 16, -1) return (1) end select @artid = artid from sysmergearticles where name = @article and pubid = @pubid if @artid is NULL begin raiserror (20046, 16, -1) return (1) end select @join_filterid=join_filterid from sysmergesubsetfilters where pubid=@pubid and artid=@artid and filtername=@filtername if @join_filterid is null begin raiserror (14028, 16, -1) return (1) end IF @property IS NULL BEGIN CREATE TABLE #temp (properties sysname) INSERT INTO #temp VALUES ('filtername') INSERT INTO #temp VALUES ('join_filterclause') INSERT INTO #temp VALUES ('join_articlename') select * FROM #tab1 RETURN (0) END if @value is null begin raiserror (14028, 16, -1) return (1) end IF LOWER(@property)='join_filterclause' BEGIN update sysmergesubsetfilters set join_filterclause=@value where join_filterid=@join_filterid execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode<>0 goto FAILURE END IF LOWER(@property)='filtername' BEGIN update sysmergesubsetfilters set filtername=@value where join_filterid=@join_filterid END IF LOWER(@property)='join_articlename' BEGIN select @join_objid = objid from sysmergearticles where name = @value and pubid = @pubid IF @join_objid is NULL BEGIN raiserror (14027, 11, -1, @value) return (1) END select @join_nickname = nickname from sysmergearticles where pubid = @pubid AND objid = @join_objid if @join_nickname is NULL begin raiserror (20001, 11, -1, @article, @publication) return (1) end update sysmergesubsetfilters set join_articlename=@value, join_nickname=@join_nickname where join_filterid=@join_filterid END return(0) FAILURE: RAISERROR (20038, 16, -1, @article, @publication) return(1) go exec dbo.sp_MS_marksystemobject sp_changemergefilter go grant execute on dbo.sp_changemergefilter to public go raiserror('Creating procedure sp_addmergefilter', 0,1) GO create procedure sp_addmergefilter( @publication sysname, /* publication name */ @article sysname, /* article name */ @filtername sysname, /* join filter name */ @join_articlename sysname, /* Name of the table being joined to the base table */ @join_filterclause nvarchar(2000), /* filter clause qualifying the join */ @join_unique_key int = 0 )AS set nocount on /* ** Declarations. */ declare @db_name sysname declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @art_nickname int declare @join_nickname int declare @db sysname declare @object sysname declare @owner sysname declare @retcode int declare @join_objid int declare @status int /* ** Only publisher can run this stored procedure */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END /* ** Security Check. ** Only the System Administrator (SA) or the Database Owner (dbo) can ** add an article to a publication. */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** Parameter Check: @filtername. ** The join_filter_name cannot be NULL */ if @filtername is NULL begin raiserror (14043, 11, -1, @filtername) return (1) end if @join_filterclause is NULL or @join_filterclause = '' begin raiserror (14043, 11, -1, '@join_filterclause') return (1) end /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14003, 16, -1) return (1) end /* ** Get the pubid and make sure the publication exists */ select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (14027, 16, -1, @publication) return (1) end /* This can only be done at the publisher */ exec @retcode = dbo.sp_MScheckatpublisher @pubid if @retcode <> 0 or @@ERROR <> 0 return (1) 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 /* ** This can be done for articles belonging to publications that are not active. */ if EXISTS (select status FROM sysmergepublications WHERE pubid = @pubid AND status = 2) BEGIN RAISERROR (20043, 16, -1, @article) RETURN (1) END /* ** Parameter Check: @article. ** Check to see that the @article is valid and does exist */ if @article is NULL begin raiserror (20045, 16, -1) return (1) end select @artid = artid, @art_nickname = nickname from sysmergearticles where name = @article and pubid = @pubid if @artid is NULL begin raiserror (20046, 16, -1) return (1) end /* ** Get the id of the @join_articlename */ select @join_objid = objid from sysmergearticles where name=@join_articlename and pubid = @pubid IF @join_objid is NULL BEGIN raiserror (14027, 11, -1, @join_articlename) return (1) END select @join_nickname = nickname from sysmergearticles where pubid = @pubid AND objid = @join_objid if @join_nickname is NULL begin raiserror (20001, 11, -1, @article, @publication) return (1) end IF NOT EXISTS (select * from sysmergearticles where pubid=@pubid AND nickname = @join_nickname) BEGIN RAISERROR (20046, 16, -1) /* Only the original publisher can do so */ RETURN (1) END /* ** Make sure that the table name specified is a table and not a view. */ if NOT exists (select * from sysobjects where id = @join_objid AND type = 'U') begin raiserror (14028, 16, -1) return (1) end /* ** Add the join filter to sysmergesubsetfilters if it is not already there */ IF exists (select * from sysmergesubsetfilters where filtername=@filtername and pubid=@pubid and artid=@artid) begin raiserror (20002, 16, -1, @filtername, @article, @publication) return (1) end insert INTO sysmergesubsetfilters(filtername, pubid, artid, art_nickname, join_articlename, join_nickname, join_unique_key, join_filterclause) values(@filtername, @pubid, @artid, @art_nickname, @join_articlename, @join_nickname, @join_unique_key, @join_filterclause) if @@error <> 0 begin goto FAILURE end execute @retcode = dbo.sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode <>0 goto FAILURE return (0) FAILURE: RAISERROR (20038, 16, -1, @article, @publication) return (1) go exec dbo.sp_MS_marksystemobject sp_addmergefilter go grant execute on dbo.sp_addmergefilter to public go raiserror('Creating procedure sp_dropmergefilter', 0,1) GO create procedure sp_dropmergefilter @publication sysname, /* publication name */ @article sysname, /* article name */ @filtername sysname /* Name of the table being joined to the base table */ AS set nocount on /* ** Declarations. */ declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @join_objid int declare @retcode int declare @join_filterid int declare @db_name sysname /* ** Only publisher can run this stored procedure */ if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END /* ** Security Check. */ exec @retcode=sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14003, 16, -1) return (1) end /* ** Get the pubid, and check if this publication exists. */ select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (20026, 16, -1, @publication ) return (1) end select @db_name = db_name from sysmergesubscriptions where (pubid=@pubid) and (subid=@pubid) IF @db_name <> db_name() BEGIN RAISERROR (20047, 16, -1) RETURN (1) END /* ** Parameter Check: @article. ** Check to see that the @article is valid, and if it exists */ if @article is NULL begin raiserror (20045, 16, -1) return (1) end /* ** This can be done for articles belonging to publications that are not active. */ if EXISTS (select status FROM sysmergepublications WHERE pubid = @pubid AND status = 2) BEGIN RAISERROR (20043, 16, -1, @article) RETURN (1) END select @artid = artid from sysmergearticles where name = @article and pubid = @pubid if @artid is NULL begin raiserror (20046, 16, -1) return (1) end select @join_filterid = join_filterid from sysmergesubsetfilters where pubid = @pubid AND artid= @artid AND filtername=@filtername /* ** Remove the join filter from sysmergesubsetfilters */ delete from sysmergesubsetfilters where join_filterid = @join_filterid if @@error <> 0 begin goto FAILURE end /* ** set the pub type to subset or full as appropriate */ exec @retcode=sp_MSsubsetpublication @publication if @@ERROR <> 0 or @retcode<>0 begin goto FAILURE end return(0) FAILURE: RAISERROR (20039, 16, -1, @article, @publication) return (1) go exec dbo.sp_MS_marksystemobject sp_dropmergefilter go raiserror('Creating procedure sp_helpmergefilter', 0,1) GO create procedure sp_helpmergefilter @publication sysname, /* publication name */ @article sysname = '%', /* article name */ @filtername sysname = '%' AS set nocount on /* ** Declarations. */ declare @pubid uniqueidentifier declare @artid uniqueidentifier declare @retcode int /* ** Security Check. */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) /* ** 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) /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14003, 16, -1) return (1) end /* ** Get the pubid and check if the publication does exist */ select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (20026, 16, -1, @publication) return (1) end /* ** Parameter Check: @article. ** If an @article is specified, make sure it exists */ select @artid = artid from sysmergearticles where name = @article and pubid = @pubid if @artid is NULL and (@article <> '%' or @filtername <> '%') begin raiserror (20046, 16, -1) return (1) end /* ** Return the join filters from sysmergesubsetfilters */ IF @filtername <> '%' select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key, 'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name, 'article name' = b_a.name from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u, sysusers b_u, sysmergearticles j_a, sysmergearticles b_a where f.pubid = @pubid AND b_a.pubid = @pubid AND f.filtername = @filtername AND f.artid = @artid AND f.artid = b_a.artid AND b_o.id = b_a.objid AND b_u.uid = b_o.uid AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid AND j_u.uid = j_o.uid ORDER BY j_o.name, b_o.name ELSE begin if @artid is not null select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key, 'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name, 'article name' = b_a.name from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u, sysusers b_u, sysmergearticles j_a, sysmergearticles b_a where f.pubid = @pubid AND b_a.pubid = @pubid AND f.artid = @artid AND f.artid = b_a.artid AND b_o.id = b_a.objid AND b_u.uid = b_o.uid AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid AND j_u.uid = j_o.uid ORDER BY j_o.name, b_o.name else select distinct join_filterid, filtername, 'join article name' = j_a.name, join_filterclause, f.join_unique_key, 'base table owner' = b_u.name, 'base table name' = b_o.name, 'join table owner' = j_u.name, 'join table name' = j_o.name, 'article name' = b_a.name from sysmergesubsetfilters f, sysobjects j_o, sysobjects b_o, sysusers j_u, sysusers b_u, sysmergearticles j_a, sysmergearticles b_a where f.pubid = @pubid AND b_a.pubid = @pubid AND f.artid = b_a.artid AND b_o.id = b_a.objid AND b_u.uid = b_o.uid AND f.join_nickname = j_a.nickname AND j_o.id = j_a.objid and j_a.pubid = @pubid AND j_u.uid = j_o.uid ORDER BY j_o.name, b_o.name end return(0) go exec dbo.sp_MS_marksystemobject sp_helpmergefilter go grant execute on dbo.sp_helpmergefilter to public go raiserror('Creating procedure sp_MSscript_dri', 0,1) go create procedure sp_MSscript_dri (@publication sysname, @article sysname) AS declare @pubid uniqueidentifier select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() select rkeyid, fkeyid from sysreferences where fkeyid in (select objid from sysmergearticles where pubid = @pubid and name = @article) and rkeyid not in (select objid from sysmergearticles where pubid = @pubid) go exec dbo.sp_MS_marksystemobject sp_MSscript_dri go grant execute on dbo.sp_MSscript_dri to public go raiserror('Creating procedure sp_MSenumpubreferences', 0,1) GO create procedure sp_MSenumpubreferences (@publication sysname) as declare @pubid uniqueidentifier declare @retcode int /* ** Security Check. */ exec @retcode = dbo.sp_MSreplcheck_publish if @@ERROR <> 0 or @retcode <> 0 return(1) if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is null BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END select distinct ReferencingObject = object_name(rkeyid), ArticleObject = object_name(fkeyid) from sysreferences r, sysmergearticles where r.fkeyid in (select objid from sysmergearticles where pubid = @pubid) and r.rkeyid not in (select objid from sysmergearticles where pubid = @pubid) select distinct ReferencedObject = object_name(fkeyid), ArticleObject = object_name(rkeyid) from sysreferences r where r.rkeyid in (select objid from sysmergearticles where pubid = @pubid) and r.fkeyid not in (select objid from sysmergearticles where pubid = @pubid) return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumpubreferences go grant execute on dbo.sp_MSenumpubreferences to public go raiserror('Creating procedure sp_MSsubsetpublication', 0,1) GO create procedure sp_MSsubsetpublication (@publication sysname) as declare @pubid uniqueidentifier declare @false bit declare @true bit declare @boolean_filter bit declare @join_filter bit declare @full int declare @subset int declare @unsynced int /* ** Initializations */ select @true = 1 select @false = 0 select @full = 0 /* Const: publication type 'full' */ select @subset = 1 /* Const: publication type 'subset' */ select @unsynced = 1 if not exists (select * from sysobjects where name = 'sysmergepublications') BEGIN RAISERROR (20054, 16, -1) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is null BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END /* ** Set the publication_type to subset if the publication has either a boolean or a join filter */ if exists (select * from sysmergearticles where pubid = @pubid and len(subset_filterclause) > 0) set @boolean_filter = @true if exists (select * from sysmergesubsetfilters where pubid = @pubid) set @join_filter = @true /* ** For subset publications set the article status to be unsynced so that the triggers can be regenerated. */ if (@boolean_filter = 1 OR @join_filter = 1) begin update sysmergepublications set publication_type = @subset where pubid = @pubid if @@ERROR <> 0 return (1) update sysmergearticles set status = @unsynced where pubid = @pubid if @@ERROR <> 0 return (1) end else update sysmergepublications set publication_type = @full where pubid = @pubid if @@ERROR <> 0 return (1) return(0) go exec dbo.sp_MS_marksystemobject sp_MSsubsetpublication go raiserror('Creating procedure sp_MSindexcolfrombin', 0,1) GO create procedure sp_MSindexcolfrombin @object_id int, @col_index int, @colids_bin varbinary(256), @colname sysname output AS /* Declare variables */ declare @start_byte int declare @colid int set @colid = unicode( substring( convert( nvarchar(128),@colids_bin ), @col_index, 1 ) ) /* Use object id and colid to look up the column name in syscolumns */ select @colname = name from syscolumns where id = @object_id and colid = @colid return (0) GO exec dbo.sp_MS_marksystemobject sp_MSindexcolfrombin go raiserror('Creating procedure sp_MSmakejoinfilter', 0,1) GO create procedure sp_MSmakejoinfilter @publication sysname, @article sysname, @base_objid int, @join_objid int, @join_unique int AS /* Declare additional variables */ declare @table_name sysname declare @join_table sysname declare @join_article sysname declare @filt_name sysname declare @basecol sysname declare @joincol sysname declare @keycnt int declare @basekeys varbinary(32) declare @joinkeys varbinary(32) declare @keyindex int declare @filtclause nvarchar(3000) declare @filtpiece nvarchar(500) declare @qual_jointable nvarchar(258) declare @retcode smallint declare @pubid uniqueidentifier select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() /* Are we adding join filter on referencing table (@join_unique = 1) or on unique key table ? */ if @join_unique = 1 /* Select the keycnt, fkeys, rkeys, and filter name from sysreferences */ select @keycnt = keycnt, @basekeys = forkeys, @joinkeys = refkeys, @filt_name = object_name(constid) from sysreferences where fkeyid = @base_objid and rkeyid = @join_objid else select @keycnt = keycnt, @basekeys = refkeys, @joinkeys = forkeys, @filt_name = object_name(constid) from sysreferences where rkeyid = @base_objid and fkeyid = @join_objid /* Set up object names - we use them as correlation values */ set @table_name = QUOTENAME(object_name(@base_objid)) set @join_table = QUOTENAME(object_name(@join_objid)) select @join_article = name from sysmergearticles where objid = @join_objid and pubid=@pubid -- set @qual_jointable = @join_owner + '.' + @join_table /* Loop over keys, building up our join filter clause */ set @keyindex = 1 while @keyindex <= @keycnt begin /* Get the column names */ exec dbo.sp_MSindexcolfrombin @base_objid, @keyindex, @basekeys, @basecol output if @@ERROR<>0 return (1) exec dbo.sp_MSindexcolfrombin @join_objid, @keyindex, @joinkeys, @joincol output if @@ERROR<>0 return (1) /* Make the piece of predicate pertaining to this key column */ set @filtpiece = @table_name + '.' + @basecol + ' = ' + @join_table + '.' + @joincol /* If first time through, initialize clause, else add to it */ if @keyindex = 1 set @filtclause = @filtpiece else set @filtclause = @filtclause + ' and ' + @filtpiece /* move on to the next key */ set @keyindex = @keyindex + 1 end /* Add the join filter */ exec @retcode = dbo.sp_addmergefilter @publication, @article, @filt_name, @join_article, @filtclause, @join_unique if @@ERROR<>0 or @retcode<>0 return (1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSmakejoinfilter go raiserror('Creating procedure sp_MSmakeexpandproc', 0,1) GO create procedure sp_MSmakeexpandproc @pubname sysname, @filterid int, @procname sysname AS /* Declare additional variables */ declare @pubid uniqueidentifier declare @base_nick int declare @join_nick int declare @base_nickstr nvarchar(10) declare @join_nickstr nvarchar(10) declare @filterid_str nvarchar(10) declare @base_objid int declare @join_objid int declare @base_table sysname declare @join_table sysname declare @base_owner sysname declare @join_owner sysname declare @join_clause nvarchar(4000) declare @retcode int declare @must_check int declare @view_type int declare @guidcolname sysname declare @view_objid int declare @view_name sysname declare @cmd_piece nvarchar(4000) select @pubid = pubid from sysmergepublications where name = @pubname and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() -- this procedure is to be called by xp_execresultset, so -- we create a temp table, put command pieces into it, and select them out -- create temp table to select the command text out of create table #tempcmd (step int identity NOT NULL, cmdtext nvarchar(4000) NULL) /* Figure out base table, join table for this join filter */ select @base_nick = art_nickname, @join_nick = join_nickname, @join_clause = join_filterclause from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid select @base_objid = objid, @view_type = view_type, @view_objid = sync_objid from sysmergearticles where pubid = @pubid and nickname = @base_nick select @join_objid = objid from sysmergearticles where pubid = @pubid and nickname = @join_nick select @base_table = QUOTENAME(name), @base_owner = QUOTENAME(user_name(uid)) from sysobjects where id = @base_objid select @join_table = QUOTENAME(name), @join_owner = QUOTENAME(user_name(uid)) from sysobjects where id = @join_objid select @guidcolname = name from syscolumns where id = @base_objid and columnproperty (id, name, 'isrowguidcol')=1 select @view_name = object_name(@view_objid) -- Quote the viewname. It is made from pub name which may have odd characters. set @view_name = QUOTENAME(@view_name) set @base_nickstr = convert(nchar(10), @base_nick) set @join_nickstr = convert(nchar(10), @join_nick) set @filterid_str = convert(nchar(10), @filterid) set @cmd_piece = 'create procedure ' + @procname + ' @belong int AS ' insert into #tempcmd(cmdtext) values (@cmd_piece) set @cmd_piece = 'if @belong = 1 begin /* Do a bulk insert to expand #belong */ update #belong set flag = ' + @filterid_str + ' where flag < ' + @filterid_str + ' insert into #belong (tablenick, rowguid, flag) select ' + @base_nickstr + ', ' + @base_table + '.rowguidcol, 0 from ' + @base_owner + '.' + @base_table + ', ' + @join_owner + '.' + @join_table + ', #belong b where (' + @join_clause + ') and ' + @join_table + '.rowguidcol = b.rowguid and b.tablenick = ' + @join_nickstr insert into #tempcmd(cmdtext) values (@cmd_piece) set @cmd_piece = ' if @@ERROR <>0 return (1) /* Delete duplicates */ delete from #belong where flag = 0 and rowguid in (select rowguid from #belong where flag <> 0) end ' insert into #tempcmd(cmdtext) values (@cmd_piece) /* Will we have to check rows that we add to #notbelong? */ if exists (select * from sysmergearticles where pubid = @pubid and nickname = @join_nick and len(subset_filterclause) > 0) set @must_check = 1 else if exists (select * from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid and join_unique_key <> 1) set @must_check = 1 else if not exists (select * from sysmergesubsetfilters where pubid = @pubid and art_nickname = @base_nick and join_filterid <> @filterid) set @must_check = 0 set @cmd_piece = ' else begin /* Do a bulk insert to expand #notbelong */ insert into #notbelong (tablenick, rowguid, flag) select ' + @base_nickstr + ', ' + @base_table + '.rowguidcol, -1 from ' + @base_owner + '.' + @base_table + ', ' + @join_owner + '.' + @join_table + ', #notbelong nb where (' + @join_clause + ') and ' + @join_table + '.rowguidcol = nb.rowguid /* Remove duplicates */ delete from #notbelong where flag = -1 and rowguid in (select rowguid from #notbelong where flag <> -1) ' if @must_check = 0 begin insert into #tempcmd(cmdtext) values (@cmd_piece) set @cmd_piece = ' update #notbelong set flag = 0 where flag = -1 end ' insert into #tempcmd(cmdtext) values (@cmd_piece) end else if @view_type = 1 begin insert into #tempcmd(cmdtext) values (@cmd_piece) set @cmd_piece = ' -- We can do our check with a bulk delete, bulk update delete from #notbelong where flag = -1 and rowguid in (select ' + @guidcolname + ' from ' + @view_name + ') update #notbelong set flag = 0 where flag = -1 end ' insert into #tempcmd(cmdtext) values (@cmd_piece) end -- else we don't bother expanding #notbelong for this filter since there are cyclic -- join filters and this is not a unique key join. The cursored calls to sp_belongs -- are unacceptably slow, and there would still be cases where orphaned rows could occur. -- Now we select out the command text pieces in proper order so that our caller, -- xp_execresultset will execute the command that creates the stored procedure. select cmdtext from #tempcmd order by step GO exec dbo.sp_MS_marksystemobject sp_MSmakeexpandproc go raiserror('Creating procedure sp_MSdrop_expired_mergesubscription', 0,1) GO create procedure sp_MSdrop_expired_mergesubscription AS /* ** This stored procedure is to periodically check the status of all the subscriptions ** of every merge publication. If any of them is out-of-date, i.e., has lost contact ** with publisher for a certain length of time, we can declare the death of that replica ** and cleanup their traces at the publisher side */ declare @subscription_type int declare @sub_type nvarchar(5) declare @publication sysname declare @pubid uniqueidentifier declare @subid uniqueidentifier declare @status tinyint declare @publisher_id int declare @subscriber sysname declare @subscriber_id int declare @subscriber_db sysname declare @publisher_db sysname declare @distributor sysname declare @distribdb sysname declare @retention int -- in days declare @retcode smallint declare @distproc nvarchar(255) declare @localproc nvarchar(255) declare @msg nvarchar(255) declare @recgen int declare @sentgen int declare @max_distretention int declare @recent_merge datetime declare @minus_retention2 datetime declare @minus_retention datetime declare @send_ts datetime declare @receive_ts datetime /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) 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 select @minus_retention2 = dateadd(day, -@retention * 2, getdate()) select @minus_retention = dateadd(day, -@retention, getdate()) WHILE (@@fetch_status <> -1) BEGIN if @retention is not NULL and @retention > 0 begin declare SC CURSOR LOCAL FAST_FORWARD for select srvid, db_name, subid, status, subscription_type from sysmergesubscriptions where pubid = @pubid and pubid<>subid for read only open SC fetch SC into @subscriber_id, @subscriber_db, @subid, @status, @subscription_type WHILE (@@fetch_status <> -1) BEGIN select @subscriber=srvname from master..sysservers where srvid=@subscriber_id if @subscription_type = 0 select @sub_type = 'push' else select @sub_type = 'pull' select @receive_ts = coldate from MSmerge_genhistory where guidsrc = (select recguid from MSmerge_replinfo where repid = @subid) select @sentgen=sentgen from MSmerge_replinfo where repid=@subid select @send_ts = coldate from MSmerge_genhistory where generation=@sentgen if @receive_ts>@send_ts select @recent_merge = @receive_ts else select @recent_merge = @send_ts if @status <> 2 and @recent_merge<@minus_retention begin exec @retcode = dbo.sp_dropmergesubscription @publication = @publication, @subscriber = @subscriber, @subscriber_db = @subscriber_db, @subscription_type = @sub_type if @retcode <>0 or @@ERROR<>0 goto FAILURE end if @recent_merge<@minus_retention2 begin delete from sysmergesubscriptions where subid = @subid --delete the row in sysmergesubscription if @@ERROR<>0 goto FAILURE delete from MSmerge_replinfo where repid = @subid if @@ERROR<>0 goto FAILURE end fetch SC into @subscriber_id, @subscriber_db, @subid, @status, @subscription_type END CLOSE SC DEALLOCATE SC end fetch PC into @publication, @pubid, @retention END CLOSE PC DEALLOCATE PC return (0) FAILURE: close SC deallocate SC close PC deallocate PC return (1) GO exec dbo.sp_MS_marksystemobject sp_MSdrop_expired_mergesubscription go raiserror('Creating procedure sp_generatefilters', 0,1) GO create procedure sp_generatefilters @publication sysname AS /* Declare a few variables */ declare @pubid uniqueidentifier declare @art_name sysname declare @object_id int declare @join_objid int declare @retcode int declare @join_unique int declare @distance int /* ** Security Check */ EXEC @retcode = dbo.sp_MSreplcheck_publish IF @@ERROR <> 0 or @retcode <> 0 return (1) /* ** Parameter Check: @publication. ** The @publication id cannot be NULL and must conform to the rules ** for identifiers. */ if @publication is NULL begin raiserror (14043, 16, -1, '@publication') return (1) end /* ** Get the pubid and make sure the publication exists */ select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@servername) and publisher_db=db_name() if @pubid is NULL begin raiserror (14027, 16, -1, @publication) return (1) end /* Set up some temp tables to help keep track of what to process */ create table #filtered (object_id int NOT NULL, distance int NOT NULL) create table #unfiltered (object_id int NOT NULL, art_name sysname NOT NULL) /* Do initial population of temp tables */ insert into #filtered (object_id, distance) select objid, 0 from sysmergearticles where pubid = @pubid and len(subset_filterclause) > 0 insert into #unfiltered (object_id, art_name) select objid, name from sysmergearticles where pubid = @pubid and objid not in (select object_id from #filtered) /* remove self-referencing tables from #unfiltered as we should not try to filter them */ delete from #unfiltered where object_id in (select rkeyid from sysreferences where rkeyid = fkeyid) select @distance = min(distance) from #filtered f, sysreferences r, #unfiltered u where (f.object_id = r.rkeyid and r.fkeyid = u.object_id) or (u.object_id = r.rkeyid and r.fkeyid = f.object_id) /* Look for something in sysreferences to add a join filter for */ select @join_unique = 1, @object_id = fkeyid, @join_objid = rkeyid, @art_name = art_name from sysreferences r, #unfiltered u where r.fkeyid = u.object_id and r.rkeyid in (select object_id from #filtered where distance = @distance) if @art_name is null select @join_unique = 0, @object_id = rkeyid, @join_objid = fkeyid, @art_name = art_name from sysreferences r, #unfiltered u where r.rkeyid = u.object_id and r.fkeyid in (select object_id from #filtered where distance = @distance) while @art_name is not null begin /* Make the join filter corresponding to this relationship */ exec @retcode=sp_MSmakejoinfilter @publication, @art_name, @object_id, @join_objid, @join_unique if @@ERROR<>0 or @retcode<>0 return (1) /* Move row from #unfiltered to #filtered */ insert into #filtered (object_id, distance) values (@object_id, @distance + 1) delete from #unfiltered where object_id = @object_id /* See if any more that can be added */ select @distance = min(distance) from #filtered f, sysreferences r, #unfiltered u where (f.object_id = r.rkeyid and r.fkeyid = u.object_id) or (u.object_id = r.rkeyid and r.fkeyid = f.object_id) set @art_name = NULL select @join_unique = 1, @object_id = fkeyid, @join_objid = rkeyid, @art_name = art_name from sysreferences r, #unfiltered u where r.fkeyid = u.object_id and r.rkeyid in (select object_id from #filtered where distance = @distance) if @art_name is null select @join_unique = 0, @object_id = rkeyid, @join_objid = fkeyid, @art_name = art_name from sysreferences r, #unfiltered u where r.rkeyid = u.object_id and r.fkeyid in (select object_id from #filtered where distance = @distance) end return (0) go exec dbo.sp_MS_marksystemobject sp_generatefilters go grant execute on dbo.sp_generatefilters to public go /* ** Name : sp_MShelpmergeconflictcounts ** Description: This sp returns the count of conflicts (from MSmerge_delete_conflicts and ** each conflict table) in each publication. Results can optionally be filtered ** to include only a single publication. Results are always ordered by article ** name. Only articles with non-zero conflict counts are returned. ** Parameters: 1. Publication Name( sysname; default '%'==ALL PUBLICATIONS) ** Output Result Set has the following structure ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. article (sysname) Article name ** b. conflict_table (sysname) Associated conflict table ** c. guidcolname (sysname) Article's rowguidcol name ** d. centralized_conflicts(integer) Centralized (1) or Decentralized (0) ** conflicts specified by the article ** e. conflict_ucount (integer) Count of (update) conflicts in the ** conflict table for this article ** f. conflicts_dcount (integer) Count of (delete) conflicts in the ** MSmerge_delete_conflicts table for this article */ raiserror('Creating procedure sp_MShelpmergeconflictcounts', 0,1) GO create procedure sp_MShelpmergeconflictcounts ( @publication_name sysname = '%' ) as begin set nocount on declare @pname sysname, @aname sysname, @cmd nvarchar(2000), @dbname sysname, @conflict_table sysname, @count integer, @db_mergepublish integer select @dbname = db_name(), @db_mergepublish = 4 -- make sure current db has merge publishing tables (true on both pub and sub) if not exists ( select * from sysobjects where name = 'sysmergearticles') begin raiserror( 18757, 16, -1 ) return(1) end -- allow null conflict table name to handle case where there are delete conflicts but no update conflicts create table #result_list ( article sysname, source_object sysname, conflict_table sysname null, guidcolname sysname, centralized_conflicts integer, conflicts_ucount integer, conflicts_dcount integer ) create table #conflict_list ( article_name sysname, conflicts_ucount integer, conflicts_dcount integer ) create table #update_list ( article_name sysname, conflicts_ucount integer ) -- get delete counts if ( @publication_name = '%' ) declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for select distinct a.name from MSmerge_delete_conflicts d inner join sysmergepublications p on p.pubid = d.pubid inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick else declare hCdcount CURSOR LOCAL FAST_FORWARD fast_forward for select distinct a.name from MSmerge_delete_conflicts d inner join sysmergepublications p on p.pubid = d.pubid inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick where p.name = @publication_name open hCdcount fetch hCdcount into @aname while ( @@fetch_status <> -1 ) begin select @cmd = 'select ''' + @aname + ''', 0, count(*) from MSmerge_delete_conflicts d inner join sysmergepublications p on p.pubid = d.pubid inner join sysmergearticles a on a.pubid = p.pubid and a.nickname = d.tablenick where a.name = N''' + @aname + ''' ' if ( @publication_name <> '%' ) select @cmd = @cmd + ' and p.name = N''' + @publication_name + '''' insert #conflict_list ( article_name, conflicts_ucount, conflicts_dcount ) exec ( @cmd ) fetch hCdcount into @aname end close hCdcount deallocate hCdcount -- get update counts if ( @publication_name = '%' ) declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for select distinct a.name, a.conflict_table from sysmergepublications p inner join sysmergearticles a on a.pubid = p.pubid where a.conflict_table is not null else declare hCucount CURSOR LOCAL FAST_FORWARD fast_forward for select distinct a.name, a.conflict_table from sysmergepublications p inner join sysmergearticles a on a.pubid = p.pubid where a.conflict_table is not null and p.name = @publication_name open hCucount fetch hCucount into @aname, @conflict_table while ( @@fetch_status <> -1 ) begin select @cmd = 'select ''' + @aname + ''', count(*) from ' + QUOTENAME( @conflict_table ) + ' ct inner join sysmergepublications p on p.pubid = ct.pubid ' if ( @publication_name <> '%' ) select @cmd = @cmd + ' where p.name = N''' + @publication_name + '''' insert #update_list ( article_name, conflicts_ucount ) exec( @cmd ) fetch hCucount into @aname, @conflict_table end close hCucount deallocate hCucount update #conflict_list set conflicts_ucount = isnull( ul.conflicts_ucount, 0 ) from #conflict_list cl inner join #update_list ul on ul.article_name = cl.article_name delete #update_list from #update_list ul inner join #conflict_list cl on ul.article_name = cl.article_name insert #conflict_list select *, 0 from #update_list where conflicts_ucount > 0 drop table #update_list select @cmd = 'select distinct t.article_name, '''' + quotename(user_name( o.uid )) + ''.'' + quotename(o.name) + '''',' + ' a.conflict_table, c.name, p.centralized_conflicts, t.conflicts_ucount, t.conflicts_dcount from #conflict_list t inner join sysmergearticles a on a.name = t.article_name inner join sysmergepublications p on p.pubid = a.pubid inner join sysobjects o on o.id = a.objid inner join syscolumns c on c.id = o.id and ColumnProperty (o.id, c.name, ''IsRowGuidCol'') = 1 where t.conflicts_ucount > 0 or t.conflicts_dcount > 0' insert #result_list exec ( @cmd ) if ( @@error <> 0 ) return (1) drop table #conflict_list select * from #result_list drop table #result_list return (0) end go exec dbo.sp_MS_marksystemobject sp_MShelpmergeconflictcounts go grant execute on dbo.sp_MShelpmergeconflictcounts to public go /* ** Name : sp_helpmergearticleconflicts ** Description: This sp returns the articles in the publication that have conflicts. ** Optionally if the publication is not specified, all articles in the ** database that have conflicts is returned. ** Parameters: Publication Name( default NULL) ** Output Result Set has the following columns ** publication, article, source_object, conflict_table, guidcolname */ raiserror('Creating procedure sp_helpmergearticleconflicts', 0,1) GO CREATE PROCEDURE sp_helpmergearticleconflicts( @publication sysname = '%' ) as set nocount on declare @publisher sysname declare @publisher_db sysname declare @pubid uniqueidentifier declare @cmd nvarchar(4000) declare @retcode int declare @nickname int declare @retcode2 int declare @name sysname declare @source_owner sysname declare @source_object sysname declare @conflict_table sysname declare @guidcolname sysname declare @centralized_conflicts int declare @objid int declare @command nvarchar(200) select @publisher = @@SERVERNAME select @publisher_db =db_name() if @publication <> '%' begin /* ** Parameter Check: @publication. ** Make sure that the publication exists. */ select @pubid = pubid from sysmergepublications where name = @publication if @pubid IS NULL BEGIN RAISERROR (20026, 16, -1, @publication) RETURN (1) END end create table #temp_conflict(article sysname, source_owner sysname, source_object sysname, conflict_table sysname, guidcolname sysname, centralized_conflicts int) declare #cur_conflict cursor local for select name, objid, conflict_table, pubid, nickname from sysmergearticles where conflict_table is not NULL and pubid in (select pubid from sysmergepublications where name like @publication) for read only open #cur_conflict fetch #cur_conflict into @name, @objid, @conflict_table, @pubid, @nickname while (@@fetch_status <> -1) begin select @command = 'if exists (select * from ' + QUOTENAME(@conflict_table) + ') select @retcode2 = 1 else select @retcode2 = 0' EXEC @retcode = dbo.sp_executesql @command, N'@retcode2 int output', @retcode2 output if @retcode <>0 return (1) if @retcode2 = 1 begin select @source_owner = user_name(uid) from sysobjects where id = @objid select @source_object = object_name (@objid) select @guidcolname = name from syscolumns where id = @objid and ColumnProperty(@objid, name, 'IsRowGuidCol') = 1 select @centralized_conflicts = centralized_conflicts from sysmergepublications where pubid = @pubid insert into #temp_conflict values (@name, @source_owner, @source_object, @conflict_table, @guidcolname, @centralized_conflicts) end if EXISTS (select * from MSmerge_delete_conflicts where tablenick = @nickname) begin insert into #temp_conflict values (@name, @source_owner, @source_object, 'MSmerge_delete_conflicts', @guidcolname, @centralized_conflicts) end fetch #cur_conflict into @name, @objid, @conflict_table, @pubid, @nickname end select * from #temp_conflict order by article drop table #temp_conflict close #cur_conflict deallocate #cur_conflict return(0) go exec dbo.sp_MS_marksystemobject sp_helpmergearticleconflicts go /* ** Name : sp_helpmergeconflictrows ** Description: This sp returns the rows in the conflict_table specified. ** Optionally if the publication is specified, all conflicts qualified by the ** publication are returned. For instance if the Conflict_Customers table ** has conflict rows for the 'WA' and the 'CA' publication, passing in ** a publication name say 'CA' retrieves conflicts pertaining to the ** 'CA' publication. ** Parameters: 1. Publication Name( default NULL) ** 2. Conflict Table Name ** Output Result Set has the same structure as the Conflict_