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_ i.e the base ** table structure with the following additional columns: ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. origin_datasource (varchar(255)) Indicates the origin of the conflict ** b. conflict_type (int) Code indicating type of conflict ** UpdateConflict = 1 ** UploadError = 2 ** DownloadError = 3 ** UpdateDeleteConflict= 4 ** ColumnUpdateConflict= 5 ** c. reason_code (int) Error code that may be context sensitive ** d. reason_text (varchar(720)) Error description that may be context sensitive ** e. pubid (uniqueidentifier) Publication identifier */ raiserror('Creating procedure sp_helpmergeconflictrows', 0,1) GO CREATE PROCEDURE sp_helpmergeconflictrows( @publication sysname = '%', @conflict_table sysname ) as set nocount on declare @publisher sysname declare @publisher_db sysname declare @pubid uniqueidentifier declare @cmd nvarchar(4000) select @publisher = @@SERVERNAME select @publisher_db = db_name() select @cmd = 'select * from ' select @cmd = @cmd + @conflict_table 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 select @cmd = @cmd + ' where pubid = (select pubid from sysmergepublications where name = ''' + @publication + ''') ' end exec (@cmd) if (@@error <> 0) RETURN (1) return 0 go exec dbo.sp_MS_marksystemobject sp_helpmergeconflictrows go /* ** Name : sp_helpmergedeleteconflictrows ** Description: This sp returns the rows in the MSmerge_delete_conflicts specified. ** Optionally if the publication is specified, all conflicts qualified by the ** publication are returned. For instance if the MSmerge_delete_conflicts 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 only. ** Parameters: 1. Publication Name( default NULL) ** 2. Source Object Name ** Output Result Set has the following structure ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. source_object (nvarchar(386)) Indicates the source object for the delete conflict ** b. rowguid (uniqueidentifier) Row identifier for the delete conflict ** c. origin_datasource (varchar(255)) Indicates the origin of the conflict ** d. conflict_type (int) Code indicating type of conflict ** UpdateConflict = 1 ** UploadError = 2 ** DownloadError = 3 ** UpdateDeleteConflict= 4 ** ColumnUpdateConflict= 5 ** e. reason_code (int) Error code that may be context sensitive ** f. reason_text (varchar(720)) Error description that may be context sensitive ** g. pubid (uniqueidentifier) Publication identifier */ raiserror('Creating procedure sp_helpmergedeleteconflictrows', 0,1) GO CREATE PROCEDURE sp_helpmergedeleteconflictrows( @publication sysname = '%', @source_object nvarchar(386) = NULL ) as declare @publisher sysname declare @publisher_db sysname declare @pubid uniqueidentifier declare @cmd nvarchar(4000) select @publisher = @@SERVERNAME select @publisher_db = db_name() select @cmd = 'select distinct source_object = user_name(sysobjects.uid) + ' select @cmd = @cmd + '''.''' select @cmd = @cmd + ' + sysobjects.name, MSmerge_delete_conflicts.rowguid, MSmerge_delete_conflicts.conflict_type, ' select @cmd = @cmd + ' MSmerge_delete_conflicts.reason_code, MSmerge_delete_conflicts.reason_text, ' select @cmd = @cmd + ' MSmerge_delete_conflicts.origin_datasource, MSmerge_delete_conflicts.pubid from MSmerge_delete_conflicts, sysmergearticles, sysobjects' select @cmd = @cmd + ' where sysmergearticles.nickname = MSmerge_delete_conflicts.tablenick and sysobjects.id = sysmergearticles.objid ' 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 select @cmd = @cmd + ' and MSmerge_delete_conflicts.pubid = (select pubid from sysmergepublications where name = ''' + @publication + ''') ' end if @source_object IS NOT NULL begin declare @object sysname declare @owner sysname declare @tablenick int declare @tablenickstr nvarchar(11) select @object = PARSENAME(@source_object, 1) select @owner = PARSENAME(@source_object, 2) execute dbo.sp_MStablenickname @owner, @object, @tablenick output if @tablenick IS NULL BEGIN raiserror (20003, 11, -1, @object) RETURN (1) END set @tablenickstr = convert(nchar, @tablenick) select @cmd = @cmd + ' and MSmerge_delete_conflicts.tablenick = ' select @cmd = @cmd + @tablenickstr end exec (@cmd) if (@@error <> 0) RETURN (1) return 0 go exec dbo.sp_MS_marksystemobject sp_helpmergedeleteconflictrows go /* ** Name : sp_deletemergeconflictrow ** Description: This sp deletes the row matching rowguid and origin_datasource ** If now rows are left in conflict_table ** --Set the conflict_table property of the article(s) to NULL ** --Drop the conflict table (optionally) ** If the conflict_table is specified as NULL, the conflict is assumed ** to be a delete conflict and the row matching rowguid and origin_datasource ** and source_object is deleted from the MSmerge_delete_conflicts table. The ** MSmerge_delete_conflicts table is a system table and is not deleted ** from the database even if it is empty. ** Parameters: ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. conflict_table (sysname) Indicates the conflict table name. If '%' then delete from MSmerge_delete_conflicts ** b. source_object (nvarchar(386)) Source table ** c. rowguid (uniqueidentifier) Row identifier for the delete conflict ** d. origin_datasource (varchar(255)) Indicates the origin of the conflict ** e. drop_table_if_empty (varchar(10)) Flag indicating if the Conflict_
** is to be dropped if is empty */ raiserror('Creating procedure sp_deletemergeconflictrow', 0,1) GO CREATE PROCEDURE sp_deletemergeconflictrow( @conflict_table sysname = '%', @source_object nvarchar(386) = NULL, @rowguid uniqueidentifier, @origin_datasource varchar(255), @drop_table_if_empty varchar(10) = 'false') as declare @retcode smallint declare @cmd nvarchar(4000) declare @rowguidstr nvarchar(40) declare @object sysname declare @owner sysname declare @tablenick int declare @tablenickstr nvarchar(11) set @rowguidstr = convert(nchar(36), @rowguid) /* Delete conflict from Conflict_
*/ if @conflict_table <> '%' begin select @cmd = 'delete from ' select @cmd = @cmd + @conflict_table select @cmd = @cmd + ' where origin_datasource = ''' select @cmd = @cmd + @origin_datasource select @cmd = @cmd + ''' and rowguid = ''' select @cmd = @cmd + @rowguidstr select @cmd = @cmd + '''' -- DEBUG select 'Delete conflict_table query' = @cmd exec (@cmd) if @@ERROR<>0 return (1) select @cmd = 'if not exists (select 1 from ' select @cmd = @cmd + @conflict_table select @cmd = @cmd + ')' select @cmd = @cmd + ' update sysmergearticles set ins_conflict_proc = NULL, conflict_table = NULL where conflict_table = ''' select @cmd = @cmd + @conflict_table select @cmd = @cmd + '''' -- DEBUG select "Update conflict_table query" = @cmd exec (@cmd) if @@ERROR<>0 return (1) if LOWER(@drop_table_if_empty) = 'true' begin select @cmd = 'if not exists (select 1 from ' select @cmd = @cmd + @conflict_table select @cmd = @cmd + ')' select @cmd = @cmd + ' drop table ' select @cmd = @cmd + @conflict_table select @cmd = @cmd + '' -- DEBUG select "Drop conflict_table query" = @cmd exec (@cmd) if @@ERROR<>0 return (1) end end /* Delete conflict from MSmerge_delete_conflicts */ else begin select @object = PARSENAME(@source_object, 1) select @owner = PARSENAME(@source_object, 2) execute @retcode=sp_MStablenickname @owner, @object, @tablenick output if @tablenick IS NULL or @@ERROR<>0 or @retcode<>0 BEGIN raiserror (20003, 11, -1, @object) RETURN (1) END set @tablenickstr = convert(nchar, @tablenick) select @cmd = 'delete from MSmerge_delete_conflicts' select @cmd = @cmd + ' where origin_datasource = ''' select @cmd = @cmd + @origin_datasource select @cmd = @cmd + ''' and tablenick = ' select @cmd = @cmd + @tablenickstr select @cmd = @cmd + ' and rowguid = ''' select @cmd = @cmd + @rowguidstr select @cmd = @cmd + '''' -- DEBUG select 'MSMerge_Delete conflict_table query' = @cmd exec (@cmd) if @@ERROR<>0 return (1) end go exec dbo.sp_MS_marksystemobject sp_deletemergeconflictrow go /* ** Name : sp_getmergedeletetype ** Description: This sp returns the type of delete ** Parameters: ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. source_object (nvarchar(386)) Indicates the source object ** b. rowguid (uniqueidentifier) Row identifier for the delete conflict ** c. delete_type(OUTPUT) (int) Code indicating delete type ** User Delete - 1 ** Partial Delete - 5 ** System Delete - 6 */ raiserror('Creating procedure sp_getmergedeletetype', 0,1) GO CREATE PROCEDURE sp_getmergedeletetype( @source_object nvarchar (386), @rowguid uniqueidentifier, @delete_type int OUTPUT ) as declare @object sysname declare @owner sysname declare @tablenick int select @object = PARSENAME(@source_object, 1) select @owner = PARSENAME(@source_object, 2) execute dbo.sp_MStablenickname @owner, @object, @tablenick output if @tablenick IS NULL OR @@ERROR<>0 BEGIN raiserror (20003, 11, -1, @object) RETURN (1) END if @rowguid IS NULL begin raiserror (14027, 11, -1, '@rowguid') return (1) end select @delete_type = type from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick go exec dbo.sp_MS_marksystemobject sp_getmergedeletetype go /* ** Name : sp_mergedummyupdate ** Description: This sp does a dummy updates on the given row so that it will be ** resent during the next merge. * Parameters: ** ---------------------------------------------------------------------------------- ** Name Datatype Description ** ---------------------------------------------------------------------------------- ** a. source_object (nvarchar(386)) Indicates the source object ** b. rowguid (uniqueidentifier) Row identifier for the delete conflict */ raiserror('Creating procedure sp_mergedummyupdate', 0,1) GO CREATE PROCEDURE sp_mergedummyupdate( @source_object nvarchar (386), @rowguid uniqueidentifier ) as declare @object sysname declare @owner sysname declare @tablenick int declare @tablenickstr nvarchar(11) select @object = PARSENAME(@source_object, 1) select @owner = PARSENAME(@source_object, 2) execute dbo.sp_MStablenickname @owner, @object, @tablenick output if @tablenick IS NULL or @@ERROR<>0 BEGIN raiserror (20003, 11, -1, @object) RETURN (1) END set @tablenickstr = convert(nchar, @tablenick) declare @rowguidstr nvarchar(40) if @rowguid IS NULL begin raiserror (14043, 11, -1, '@rowguid') return (1) end set @rowguidstr = convert(nchar(36), @rowguid) /* ** If the row does not exist in the base table, call sp_MSdummyupdate with metadata_type = 1 (tombstone) */ exec ('if not exists (select 1 from ' + @source_object + ' where rowguidcol = ''' + @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 1') /* ** If the row exists in the base table and MSmerge_contents , call sp_MSdummyupdate with metadata_type = 2 (contents) */ exec ('if exists (select 1 from ' + @source_object + ' where rowguidcol = ''' + @rowguidstr + ''' ) and exists (select rowguid from MSmerge_contents where rowguid = ''' + @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 2') /* ** If the row exists in the base table, but not in MSmerge_contents , call sp_MSdummyupdate with metadata_type = 3 (contents_deferred) */ exec ('if exists (select 1 from ' + @source_object + ' where rowguidcol = ''' + @rowguidstr + ''' ) and not exists (select rowguid from MSmerge_contents where rowguid = ''' + @rowguidstr + ''' ) exec dbo.sp_MSdummyupdate ''' + @rowguidstr + ''',' + @tablenickstr + ', 3') go exec dbo.sp_MS_marksystemobject sp_mergedummyupdate go raiserror('Creating procedure sp_addtabletocontents', 0,1) GO create procedure sp_addtabletocontents (@table_name sysname, @owner_name sysname = NULL) AS declare @qualified_table_name nvarchar(268) declare @tablenick int declare @tablenickstr nvarchar(12) declare @repl_nick int declare @lineage varbinary(249) declare @colv varbinary(2000) declare @coltrack int declare @objid int declare @maxcolid int declare @retcode int declare @gen int set nocount on create table #temp_cont(rowguid uniqueidentifier) execute @retcode = dbo.sp_MSgetreplnick @nickname = @repl_nick output if (@@error <> 0) or @retcode <> 0 or @repl_nick IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end if @owner_name is NULL begin select @owner_name = user_name(uid) from sysobjects where name = @table_name end set @qualified_table_name = QUOTENAME(@owner_name) + '.' + QUOTENAME(@table_name) set @objid = object_id(@qualified_table_name) if @objid is NULL return (1) select @gen = max(gen_cur), @tablenick = max(nickname), @coltrack = max(column_tracking) from sysmergearticles where objid = @objid if @gen is null set @gen = 0 select @maxcolid = max(colid) from syscolumns where id = @objid if @coltrack = 1 set @colv = { fn INITCOLVS(@maxcolid, @repl_nick) } else set @colv = NULL set @lineage = { fn UPDATELINEAGE(0x0, @repl_nick) } set @tablenickstr = convert(nchar, @tablenick) exec ('insert into #temp_cont(rowguid) select RowGuidCol from ' + @qualified_table_name + ' where RowGuidCol not in (select rowguid from MSmerge_contents where tablenick = ' + @tablenickstr + ')') insert into MSmerge_contents (tablenick, rowguid, generation, joinchangegen, lineage, colv1) select @tablenick, rowguid, @gen, @gen, @lineage, @colv from #temp_cont drop table #temp_cont GO exec dbo.sp_MS_marksystemobject sp_addtabletocontents go grant exec on dbo.sp_addtabletocontents to public go raiserror('Creating procedure sp_MSaddpubtocontents', 0,1) GO create procedure sp_MSaddpubtocontents (@publication sysname) AS declare @pubid uniqueidentifier declare @tablenick int declare @retcode int declare @objid int declare @owner sysname declare @table sysname set nocount on 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 @tablenick = min(nickname) from sysmergearticles where pubid = @pubid while @tablenick is not null begin select @objid = objid from sysmergearticles where pubid = @pubid and nickname = @tablenick select @owner = user_name(uid) from sysobjects where id = @objid set @table = OBJECT_NAME(@objid) exec @retcode = dbo.sp_addtabletocontents @table, @owner IF @@ERROR <> 0 or @retcode <> 0 return (1) select @tablenick = min(nickname) from sysmergearticles where pubid = @pubid and nickname > @tablenick end GO exec dbo.sp_MS_marksystemobject sp_MSaddpubtocontents go grant exec on dbo.sp_MSaddpubtocontents to public go dump tran master with no_log go checkpoint go use master go execute dbo.sp_configure 'update',1 go reconfigure with override go set ANSI_NULLS off 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_rlrecon') begin exec dbo.sp_MSdrop_rlrecon drop procedure sp_MSdrop_rlrecon end /* ** Create stored procedures to drop the stored procedures ** created by this script */ raiserror('Creating procedure sp_MSdrop_rlrecon', 0,1) GO create procedure sp_MSdrop_rlrecon as if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddinitialpublication') drop procedure sp_MSaddinitialpublication -- **************************************************** -- THIS COMMENTED CODE SECTION WILL BE DELETED SOON -- sp_MSgetversion is now part of XPSTAR.DLL and -- will not be installed by REPL code -- If sp_MSgetversion exists as SP drop it -- otherwise drop the extended proc /* if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetversion') drop procedure sp_MSgetversion else if exists (select * from sysobjects where type = 'X' and name = 'sp_MSgetversion') execute dbo.sp_dropextendedproc 'sp_MSgetversion' */ -- **************************************************** if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddinitialsubscription') drop procedure sp_MSaddinitialsubscription if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdropconstraints') drop procedure sp_MSdropconstraints if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeinsertproc') drop procedure sp_MSmakeinsertproc if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeupdateproc') drop procedure sp_MSmakeupdateproc if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeselectproc') drop procedure sp_MSmakeselectproc if exists (select * from sysobjects where type = 'P ' and name = 'sp_MSinsertschemachange') drop procedure sp_MSinsertschemachange if exists (select * from sysobjects where type = 'P' and name = 'sp_MSaddinitialarticle') drop procedure sp_MSaddinitialarticle if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakearticleprocs') drop procedure sp_MSmakearticleprocs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSupdatesysmergearticles') drop procedure sp_MSupdatesysmergearticles if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdroparticletombstones') drop procedure sp_MSdroparticletombstones if exists (select * from sysobjects where type = 'P' and name = 'sp_MSproxiedmetadata') drop procedure sp_MSproxiedmetadata if exists (select * from sysobjects where type = 'P' and name = 'sp_MShelpmergearticles') drop procedure sp_MShelpmergearticles if exists (select * from sysobjects where type = 'P' and name = 'sp_MScreateretry') drop procedure sp_MScreateretry if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdropretry') drop procedure sp_MSdropretry if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumretries') drop procedure sp_MSenumretries if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdeleteretry') drop procedure sp_MSdeleteretry if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetonerow') drop procedure sp_MSgetonerow if exists (select * from sysobjects where type = 'P' and name = 'sp_MSchangearticleresolver') drop procedure sp_MSchangearticleresolver if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetlastrecgen') drop procedure sp_MSgetlastrecgen if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetlastsentgen') drop procedure sp_MSgetlastsentgen if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetlastrecgen') drop procedure sp_MSsetlastrecgen if exists (select * from sysobjects where type = 'P' and name = 'sp_MSbelongs') drop procedure sp_MSbelongs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetupbelongs') drop procedure sp_MSsetupbelongs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSexpandbelongs') drop procedure sp_MSexpandbelongs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSexpandnotbelongs') drop procedure sp_MSexpandnotbelongs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumpartialdeletes') drop procedure sp_MSenumpartialdeletes if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetlastsentgen') drop procedure sp_MSsetlastsentgen if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdummyupdate') drop procedure sp_MSdummyupdate if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdeletepushagent') drop procedure sp_MSdeletepushagent if exists (select * from sysobjects where type = 'P' and name = 'sp_MScleanuptask') drop procedure sp_MScleanuptask if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumgenerations') drop procedure sp_MSenumgenerations if exists (select * from sysobjects where type = 'P' and name = 'sp_MScheckexistsgeneration') drop procedure sp_MScheckexistsgeneration if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumreplicas') drop procedure sp_MSenumreplicas if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumdeletesmetadata') drop procedure sp_MSenumdeletesmetadata if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumchanges') drop procedure sp_MSenumchanges if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumpartialchanges') drop procedure sp_MSenumpartialchanges if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetrowmetadata') drop procedure sp_MSgetrowmetadata if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetrowmetadata') drop procedure sp_MSsetrowmetadata if exists (select * from sysobjects where type = 'P' and name = 'sp_MSinsertgenhistory') drop procedure sp_MSinsertgenhistory if exists (select * from sysobjects where type = 'P' and name = 'sp_MSupdategenhistory') drop procedure sp_MSupdategenhistory if exists (select * from sysobjects where type = 'P' and name = 'sp_MSenumschemachange') drop procedure sp_MSenumschemachange if exists (select * from sysobjects where type = 'P' and name = 'sp_MSupdateschemachange') drop procedure sp_MSupdateschemachange if exists (select * from sysobjects where type = 'P' and name = 'sp_MSadd_mergereplcommand') drop procedure sp_MSadd_mergereplcommand if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetreplicainfo') drop procedure sp_MSsetreplicainfo if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetreplicastatus') drop procedure sp_MSsetreplicastatus if exists (select * from sysobjects where type = 'P' and name = 'sp_MScreateglobalreplica') drop procedure sp_MScreateglobalreplica if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetconflictscript') drop procedure sp_MSsetconflictscript if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetconflicttable') drop procedure sp_MSsetconflicttable go if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeconflictinsertproc') drop procedure sp_MSmakeconflictinsertproc if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmaketempinsertproc') drop procedure sp_MSmaketempinsertproc if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetconflictinsertproc') drop procedure sp_MSgetconflictinsertproc if exists (select * from sysobjects where type = 'P' and name = 'sp_MSinsertdeleteconflict') drop procedure sp_MSinsertdeleteconflict if exists (select * from sysobjects where type = 'P' and name = 'sp_MScheckmetadatamatch') drop procedure sp_MScheckmetadatamatch if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdelrow') drop procedure sp_MSdelrow if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsetartprocs') drop procedure sp_MSsetartprocs if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakesystableviews') drop procedure sp_MSmakesystableviews if exists (select * from sysobjects where type = 'P' and name = 'sp_MSgetchangecount') drop procedure sp_MSgetchangecount if exists (select * from sysobjects where type = 'P' and name = 'sp_MSuplineageversion') drop procedure sp_MSuplineageversion if exists (select * from sysobjects where type = 'P' and name = 'sp_MSvalidatearticle') drop procedure sp_MSvalidatearticle if exists (select * from sysobjects where type = 'P' and name = 'sp_MSsubscriptionvalidated') drop procedure sp_MSsubscriptionvalidated if exists (select * from sysobjects where type = 'P' and name = 'sp_MSdelsubrows') drop procedure sp_MSdelsubrows if exists (select * from sysobjects where type = 'P' and name = 'sp_MScontractsubsnb') drop procedure sp_MScontractsubsnb if exists (select * from sysobjects where type = 'P' and name = 'sp_MSexpandsubsnb') drop procedure sp_MSexpandsubsnb if exists (select * from sysobjects where type = 'P' and name = 'sp_MSmakeviewproc') drop procedure sp_MSmakeviewproc go exec dbo.sp_MS_marksystemobject sp_MSdrop_rlrecon go EXEC dbo.sp_MSdrop_rlrecon go raiserror('Creating procedure sp_MShelpmergearticles', 0,1) GO CREATE PROCEDURE sp_MShelpmergearticles @publication sysname as declare @pubid uniqueidentifier /* ** To public. */ if (@publication is null) begin RAISERROR(14003, 16, -1) return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) 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, 11, -1, @publication) return (1) end select a.name, o.name, user_name(o.uid), a.artid, a.pre_creation_command, a.pubid, a.nickname, a.column_tracking, a.status, a.resolver_clsid, a.conflict_script, a.conflict_table, a.insert_proc, a.update_proc, a.select_proc, a.destination_object, a.missing_col_count, a.missing_cols, c.name, a.article_resolver, a.resolver_info, a.subset_filterclause from sysmergearticles a, sysobjects o left outer join syscolumns c on o.id = c.id and ColumnProperty(o.id, c.name, 'IsRowGuidCol') = 1 where a.pubid = @pubid and o.id = a.objid order by a.nickname return (0) go exec dbo.sp_MS_marksystemobject sp_MShelpmergearticles go grant exec on dbo.sp_MShelpmergearticles to public go raiserror('Creating procedure sp_MScreateretry', 0,1) GO CREATE PROCEDURE sp_MScreateretry as declare @tname sysname declare @pname sysname declare @tempname sysname declare @guid uniqueidentifier declare @guidstr varchar(40) declare @retcode smallint /* ** To public. */ set @guid = newid() exec @retcode=sp_MSguidtostr @guid, @guidstr out if @retcode<>0 or @@ERROR<>0 return (1) set @tempname = '##retry_' + @guidstr exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out if (@@error <> 0) OR @retcode <> 0 begin RAISERROR(15001, 16, -1, 'sp_MSuniquetempname') return (1) end exec ('create table ' + @tempname + ' (tablenick int NOT NULL, rowguid uniqueidentifier ROWGUIDCOL default newid() not null, errcode int NOT NULL, errtext nvarchar(255) NULL, type tinyint NOT NULL)' ) if (@@error <> 0) begin RAISERROR(15001, 16, -1, @tempname) return (1) end set @tname = @tempname set @tempname = '##insert_' + @guidstr exec @retcode = dbo.sp_MSuniquetempname @tempname, @tempname out if (@@error <> 0) begin RAISERROR(15001, 16, -1, 'sp_MSuniquetempname') return (1) end exec @retcode = dbo.sp_MSmaketempinsertproc @tname, @tempname if @@ERROR <>0 or @retcode<>0 return (1) select @pname = @tempname select @tname, @pname return (0) go exec dbo.sp_MS_marksystemobject sp_MScreateretry go grant exec on dbo.sp_MScreateretry to public raiserror('Creating procedure sp_MSdropretry', 0,1) GO CREATE PROCEDURE sp_MSdropretry (@tname sysname, @pname sysname) as declare @retcode int /* ** To public */ exec ('drop table ' + @tname) if @@ERROR <> 0 return(1) exec ('drop procedure ' + @pname) if @@ERROR <> 0 return(1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSdropretry go grant exec on dbo.sp_MSdropretry to public raiserror('Creating procedure sp_MSchangearticleresolver', 0,1) GO CREATE PROCEDURE sp_MSchangearticleresolver ( @article_resolver nvarchar(255), @resolver_clsid nvarchar(40), @artid uniqueidentifier, @resolver_info sysname = NULL ) as if (@resolver_clsid='') select @resolver_clsid = NULL UPDATE sysmergearticles SET article_resolver = @article_resolver, resolver_clsid = @resolver_clsid, resolver_info = @resolver_info WHERE artid = @artid if @@ERROR <> 0 RETURN (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSchangearticleresolver go -- **************************************************** -- THIS COMMENTED CODE SECTION WILL BE DELETED SOON -- sp_MSgetversion is now part of XPSTAR.DLL and -- will not be installed by REPL code --raiserror('Creating sp_MSgetversion', 0,1) --GO if not exists (select * from sysobjects where name = 'sp_MSgetversion') begin exec dbo.sp_addextendedproc 'sp_MSgetversion', 'xpstar.dll' exec dbo.sp_MS_marksystemobject sp_MSgetversion grant exec on dbo.sp_MSgetversion to public end go -- **************************************************** raiserror('Creating procedure sp_MSenumretries', 0,1) GO CREATE PROCEDURE sp_MSenumretries (@tname nvarchar(386), @maxrows int, @tablenick int, @rowguid uniqueidentifier) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) declare @retcode int /* ** Modify temp table, granted to public. */ if (@tablenick < 1) begin set rowcount @maxrows execute ('select tablenick, rowguidcol, errcode, errtext, type from ' + @tname + ' order by tablenick, rowguidcol') IF @@ERROR <>0 RETURN (1) end else begin set rowcount @maxrows set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' execute ('select tablenick, rowguidcol, errcode, errtext, type from ' + @tname + ' where (tablenick = ' + @tnstring + ' and rowguidcol > ' + @rgstring + ') or tablenick > ' + @tnstring + ' order by tablenick, rowguidcol' ) if @@ERROR <> 0 RETURN (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumretries go grant exec on dbo.sp_MSenumretries to public raiserror('Creating procedure sp_MSdeleteretry', 0,1) GO CREATE PROCEDURE sp_MSdeleteretry (@temptable nvarchar(386), @tablenick int, @rowguid uniqueidentifier) as declare @guidstr nvarchar(38) declare @nickstr nvarchar(12) declare @retcode int /* ** Modify temp table, granted to public. */ set @nickstr = convert(nchar, @tablenick) set @guidstr = '''' + convert(nchar(36), @rowguid) + '''' execute ('delete from ' + @temptable + ' where tablenick = ' + @nickstr + ' and rowguidcol = ' + @guidstr) IF @@ERROR <>0 RETURN (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSdeleteretry go grant exec on dbo.sp_MSdeleteretry to public go raiserror('Creating procedure sp_MSdeletepushagent', 0,1) GO /* ** This procedure is obselete for dropping push agent at distribution database. ** If we were to recover, don't use server id as parameter for RPC into distributor. ** Use server name instead. */ CREATE PROCEDURE sp_MSdeletepushagent ( @publisher sysname, @publisher_db sysname, @publication sysname, @subscriber sysname, @subscriber_db sysname ) AS declare @distributor sysname declare @distribdb sysname declare @pubid uniqueidentifier declare @distproc nvarchar(512) declare @pub_srvid smallint declare @sub_srvid smallint declare @retcode smallint EXECUTE @retcode = dbo.sp_helpdistributor @distributor = @distributor OUTPUT, @distribdb = @distribdb OUTPUT IF @@ERROR <> 0 or @retcode <> 0 return (1) select @pub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@publisher) select @sub_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@subscriber) select @pubid=pubid from sysmergepublications where name=@publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db SELECT @distproc = RTRIM(@distributor) + '.' + RTRIM(@distribdb) + '.dbo.sp_MSdrop_agent_entry' EXEC @retcode = @distproc @pub_srvid, @publisher_db, @publication, @sub_srvid, @subscriber_db IF @@ERROR <> 0 OR @retcode <> 0 return (1) return (0) GO exec dbo.sp_MS_marksystemobject sp_MSdeletepushagent go grant exec on dbo.sp_MSdeletepushagent to public go raiserror('Creating procedure sp_MSgetonerow', 0,1) GO CREATE PROCEDURE sp_MSgetonerow (@tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL) as declare @retcode smallint declare @procname sysname /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) select @procname = select_proc from sysmergearticles where nickname = @tablenick and pubid=@pubid exec @retcode = @procname @type =1, @rowguid=@rowguid IF @@ERROR<>0 or @retcode<>0 RETURN (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetonerow go grant exec on dbo.sp_MSgetonerow to public go raiserror('Creating procedure sp_MSuplineageversion', 0,1) GO CREATE PROCEDURE sp_MSuplineageversion (@tablenick int, @rowguid uniqueidentifier, @version int) as declare @replnick int declare @curversion int declare @lineage varbinary(255) declare @retcode int declare @colv varbinary(2048) declare @col_tracking int /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) exec dbo.sp_MSgetreplnick @nickname = @replnick out if (@@error <> 0) or @replnick IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (1) end if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end select @col_tracking = column_tracking from sysmergearticles where nickname = @tablenick begin transaction -- get lineage, locking row in MSmerge_contents select @lineage = lineage, @colv = colv1 from MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and rowguid = @rowguid if (@lineage is null) begin commit RAISERROR(14043, 16, -1, '@rowguid') return (1) end set @curversion = 0 while (@curversion < @version) begin exec master..xp_updatelineage @lineage output, @replnick, @curversion output if (@col_tracking = 0) set @colv = NULL else set @colv = { fn UPDATECOLVBM(@colv, @replnick, 0x01, 0x00) } end update MSmerge_contents set lineage = @lineage, colv1 = @colv where tablenick = @tablenick and rowguid = @rowguid commit return (0) go exec dbo.sp_MS_marksystemobject sp_MSuplineageversion go grant exec on dbo.sp_MSuplineageversion to public raiserror('Creating procedure sp_MSgetlastrecgen', 0,1) GO CREATE PROCEDURE sp_MSgetlastrecgen (@repid uniqueidentifier) as -- To public if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select recgen, recguid from MSmerge_replinfo where repid = @repid return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetlastrecgen go grant exec on dbo.sp_MSgetlastrecgen to public raiserror('Creating procedure sp_MSgetlastsentgen', 0,1) GO CREATE PROCEDURE sp_MSgetlastsentgen (@repid uniqueidentifier) as -- To public if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select sentgen, sentguid from MSmerge_replinfo where repid = @repid return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetlastsentgen go grant exec on dbo.sp_MSgetlastsentgen to public go raiserror('Creating procedure sp_MSdummyupdate', 0,1) GO CREATE PROCEDURE sp_MSdummyupdate (@rowguid uniqueidentifier, @tablenick int, @metatype tinyint, @pubid uniqueidentifier = NULL, @uplineage tinyint = 1) as declare @retcode int declare @lineage varbinary(255) declare @mynickname int declare @objid int declare @col_tracking int declare @ccols int declare @missing_count int declare @colv varbinary(2048) /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) /* Parameter checks */ if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (1) end if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end if (@metatype is null) begin RAISERROR(14043, 16, -1, '@metatype') return (1) end /* Check if we have a merge publication by whether system table is there */ if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end exec dbo.sp_MSgetreplnick @nickname = @mynickname out if (@@error <> 0) or @mynickname IS NULL begin RAISERROR (14055, 11, -1) RETURN(1) end if (@metatype = 0) or @@ERROR<>0 begin declare @reason nvarchar(255) /* We don't have the row. Putting in a system delete tombstone should cause a delete and ** eventual convergence. We are already logging the row as a conflict / error. */ set @lineage = { fn UPDATELINEAGE(0x0, @mynickname) } select @reason = formatmessage(20562) insert into MSmerge_tombstone (rowguid, tablenick, type, lineage, generation, reason) values (@rowguid, @tablenick, 6, @lineage, 0, @reason) end else if (@metatype = 1) begin /* Update systombstone */ select @lineage = lineage from MSmerge_tombstone (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and rowguid = @rowguid if (@uplineage = 1) begin set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname) } end update MSmerge_tombstone set generation = 0, lineage = @lineage where tablenick = @tablenick and rowguid = @rowguid end else if (@metatype = 2) begin /* Update MSmerge_contents */ select @lineage = lineage, @colv = colv1 from MSmerge_contents (UPDLOCK ROWLOCK index = 1) where tablenick = @tablenick and rowguid = @rowguid if (@uplineage = 1) begin set @lineage = { fn UPDATELINEAGE(@lineage, @mynickname) } if @pubid is NULL select @objid = objid, @col_tracking = column_tracking, @missing_count = missing_col_count from sysmergearticles where nickname = @tablenick else select @objid = objid, @col_tracking = column_tracking, @missing_count = missing_col_count from sysmergearticles where nickname = @tablenick and pubid = @pubid if (@col_tracking = 0) set @colv = NULL else set @colv = { fn UPDATECOLVBM(@colv, @mynickname, 0x01, 0x00) } end update MSmerge_contents set generation = 0, lineage = @lineage, colv1 = @colv where tablenick = @tablenick and rowguid = @rowguid end else if (@metatype = 3) begin set @lineage = { fn UPDATELINEAGE(0x0, @mynickname) } if @pubid is NULL select @objid = objid, @col_tracking = column_tracking, @missing_count = missing_col_count from sysmergearticles where nickname = @tablenick else select @objid = objid, @col_tracking = column_tracking, @missing_count = missing_col_count from sysmergearticles where nickname = @tablenick and pubid = @pubid if (@col_tracking = 0) set @colv = NULL else begin select @ccols= count(*) from syscolumns where id = @objid set @ccols = @ccols + @missing_count set @colv = { fn INITCOLVS(@ccols, @mynickname ) } end insert into MSmerge_contents (tablenick, rowguid, lineage, generation, colv1) values (@tablenick, @rowguid, @lineage, 0, @colv) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSdummyupdate go grant exec on dbo.sp_MSdummyupdate to public go raiserror('Creating procedure sp_MSsetlastrecgen', 0,1) GO CREATE PROCEDURE sp_MSsetlastrecgen (@repid uniqueidentifier, @srcgen int, @srcguid uniqueidentifier) as /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @repid = @repid if @retcode<>0 or @@ERROR<>0 return (1) if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end if (@srcgen is null) begin RAISERROR(14043, 16, -1, '@srcgen') return (1) end if (@srcguid is null) begin RAISERROR(14043, 16, -1, '@srcguid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end update MSmerge_replinfo set recgen = @srcgen, recguid = @srcguid where repid = @repid IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetlastrecgen go grant exec on dbo.sp_MSsetlastrecgen to public go dump tran master with no_log go raiserror('Creating procedure sp_MSsetlastsentgen', 0,1) GO CREATE PROCEDURE sp_MSsetlastsentgen (@repid uniqueidentifier, @srcgen int, @srcguid uniqueidentifier) as /* ** Check to see if current publication has permission */ declare @retcode int declare @pubid uniqueidentifier exec @retcode=sp_MSreplcheck_connection @repid = @repid if @retcode<>0 or @@ERROR<>0 return (1) if (@repid is null) begin RAISERROR(14043, 16, -1, '@repid') return (1) end if (@srcgen is null) begin RAISERROR(14043, 16, -1, '@srcgen') return (1) end if (@srcguid is null) begin RAISERROR(14043, 16, -1, '@srcguid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end -- check for setting a sentgen which is obviously too high select @pubid = pubid from sysmergesubscriptions where subid = @repid if (exists (select * from MSmerge_genhistory where generation < @srcgen and guidlocal = '00000000-0000-0000-0000-000000000000' and (art_nick = 0 or art_nick is null or art_nick in (select nickname from sysmergearticles where pubid = @pubid) ))) begin RAISERROR('Setting sentgen too high', 16, -1) return (1) end update MSmerge_replinfo set sentgen= @srcgen, sentguid = @srcguid where repid = @repid IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetlastsentgen go grant exec on dbo.sp_MSsetlastsentgen to public go raiserror('Creating procedure sp_MScleanuptask', 0,1) GO CREATE PROCEDURE sp_MScleanuptask (@pubid uniqueidentifier) as /* ** Check to see if current publication has permission */ declare @retention int declare @retcode int exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) set nocount on if (@pubid is null) begin RAISERROR(14043, 16, -1, '@pubid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end declare @cutoff datetime /* ** Bypass task cleanup if retention value is 0; Null value has been converted to 0 */ select @retention = retention from sysmergepublications where pubid = @pubid if @retention = 0 return (0) select @cutoff = dateadd(dd, -@retention, getdate()) delete from MSmerge_genhistory where coldate < @cutoff declare @mingen int select @mingen = min(generation) from MSmerge_genhistory delete from MSmerge_tombstone where generation > 0 and generation < @mingen IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MScleanuptask go grant exec on dbo.sp_MScleanuptask to public raiserror('Creating procedure sp_MSenumgenerations', 0,1) GO CREATE PROCEDURE sp_MSenumgenerations (@genstart int, @pubid uniqueidentifier) as declare @retcode smallint /* ** To public */ if (@genstart is null) begin RAISERROR(14043, 16, -1, '@genstart') return (1) end if (@pubid is null) begin RAISERROR(14043, 16, -1, '@pubid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end exec @retcode = dbo.sp_MScleanuptask @pubid if @@ERROR<>0 or @retcode<>0 begin return (1) end select DISTINCT generation, guidsrc, art_nick, guidlocal from MSmerge_genhistory where generation >= @genstart and (art_nick = 0 or art_nick is NULL or art_nick in (select nickname from sysmergearticles where pubid = @pubid)) ORDER BY generation ASC IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumgenerations go grant exec on dbo.sp_MSenumgenerations to public raiserror('Creating procedure sp_MScheckexistsgeneration', 0,1) GO CREATE PROCEDURE sp_MScheckexistsgeneration (@genguid uniqueidentifier, @gen int output, @pubid uniqueidentifier) as /* ** Check input parameter */ if (@genguid is null) begin RAISERROR(14043, 16, -1, '@genguid') return (1) end /* delete from MSmerge_genhistory where guidsrc = @genguid and pubid = @pubid and guidlocal = '00000000-0000-0000-0000-000000000000' */ select @gen = max(generation) from MSmerge_genhistory where guidsrc = @genguid and guidlocal <> '00000000-0000-0000-0000-000000000000' and ((pubid = @pubid) or (pubid is null)) IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MScheckexistsgeneration go grant exec on dbo.sp_MScheckexistsgeneration to public raiserror('Creating procedure sp_MSenumreplicas', 0,1) GO CREATE PROCEDURE sp_MSenumreplicas (@pubid uniqueidentifier) as declare @active tinyint declare @deleted tinyint /* ** To public */ select @active = 1 select @deleted = 2 if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select subs.subid, replinfo.replnickname, subs.subscriber_type, subs.subscription_type, subs.priority, replinfo.schemaversion, replinfo.schemaguid, subs.datasource_type, subs.datasource_path, servers.srvname, subs.db_name, subs.status, subs.partnerid, subs.sync_type, subs.description, subs.pubid from sysmergesubscriptions subs, MSmerge_replinfo replinfo, master..sysservers servers where replinfo.repid = subs.subid and subs.srvid = servers.srvid and (subs.status = @active or subs.status=@deleted) and subs.subscriber_type = 1 and (subs.pubid is null or exists (select * from sysmergearticles art1, sysmergearticles art2 where art1.pubid = subs.pubid and art2.pubid = @pubid and art1.artid = art2.artid)) order by convert(binary, subs.subid) IF @@ERROR <>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumreplicas go grant exec on dbo.sp_MSenumreplicas to public raiserror('Creating procedure sp_MSenumdeletesmetadata', 0,1) GO CREATE PROCEDURE sp_MSenumdeletesmetadata (@pubid uniqueidentifier, @maxrows int, @genlist varchar(1000), @tablenick int, @rowguid uniqueidentifier) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) declare @pubidstr nvarchar(38) /* ** To public. */ if (@genlist is null) begin RAISERROR(14043, 16, -1, '@genlist') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end set @pubidstr = '''' + convert(nchar(36), @pubid) + '''' if (@tablenick = 0) begin set rowcount @maxrows execute ('select tablenick, rowguid, generation, lineage, ts.type from MSmerge_tombstone ts, sysmergearticles sm where generation in (' + @genlist + ') and sm.pubid = ' + @pubidstr + ' and ts.tablenick = sm.nickname order by tablenick desc, rowguid asc' ) end else begin set rowcount @maxrows set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' execute ('select tablenick, rowguid, generation, lineage, ts.type from MSmerge_tombstone ts, sysmergearticles sm where generation in (' + @genlist + ') and ((tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') and sm.pubid = ' + @pubidstr + ' and ts.tablenick = sm.nickname order by tablenick desc, rowguid asc' ) end IF @@ERROR <>0 begin return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumdeletesmetadata go grant exec on dbo.sp_MSenumdeletesmetadata to public raiserror('Creating procedure sp_MSenumpartialdeletes', 0,1) GO CREATE PROCEDURE sp_MSenumpartialdeletes (@maxrows int, @tablenick int, @rowguid uniqueidentifier, @tablenotbelongs nvarchar(255)) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) /* ** To public. */ if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end if (@tablenick < 1) begin set rowcount @maxrows execute ('select tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + ' order by tablenick desc, rowguid asc' ) end else begin set rowcount @maxrows set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' execute ('select tablenick, rowguid, COALESCE (generation, 0), lineage, type from ' + @tablenotbelongs + ' where ((tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ') or tablenick < ' + @tnstring + ') order by tablenick desc, rowguid asc' ) end IF @@ERROR <>0 begin return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumpartialdeletes go grant exec on dbo.sp_MSenumpartialdeletes to public go raiserror('Creating procedure sp_MSenumchanges', 0,1) GO CREATE PROCEDURE sp_MSenumchanges (@maxrows int, @genlist varchar(1000), @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL) as declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) declare @tablename sysname declare @retcode smallint declare @ownername sysname declare @procname nvarchar(258) /* ** To public. */ if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename out, @pubid if @@ERROR<>0 or @retcode<>0 begin return (1) end if (@genlist is null) begin RAISERROR(14043, 16, -1, '@genlist') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end create table #cont (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(249) NULL ,colv1 varbinary(2048) NULL) set rowcount @maxrows set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' execute ('insert into #cont select tablenick, rowguid, generation, lineage, colv1 from MSmerge_contents where generation in (' + @genlist + ') and tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ' order by rowguid' ) if @@ERROR <>0 begin return (1) end select @ownername = user_name(uid) from sysobjects where id = object_id(@tablename) select @procname = select_proc from sysmergearticles where nickname=@tablenick and pubid = @pubid exec @retcode = @procname @type=2 IF @@ERROR<>0 or @retcode<>0 RETURN (1) drop table #cont return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumchanges go grant exec on dbo.sp_MSenumchanges to public go raiserror('Creating procedure sp_MSenumpartialchanges', 0,1) GO CREATE PROCEDURE sp_MSenumpartialchanges (@maxrows int, @temp_cont sysname, @tablenick int, @rowguid uniqueidentifier, @pubid uniqueidentifier = NULL) as declare @retcode smallint declare @tnstring nvarchar(12) declare @rgstring nvarchar(38) -- Owner qualified declare @tablename nvarchar(266) declare @procname nvarchar(258) declare @ownername sysname /* ** To public. */ if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename out, @pubid if @@ERROR<>0 or @retcode<>0 begin return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end set rowcount @maxrows set @tnstring = convert(nchar, @tablenick) set @rgstring = '''' + convert(nchar(36), @rowguid) + '''' create table #cont (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(249) NULL ,colv1 varbinary(2048) NULL) execute ('insert into #cont select tablenick, rowguid, generation, lineage, colv from ' + @temp_cont + ' where tablenick = ' + @tnstring + ' and rowguid > ' + @rgstring + ' order by rowguid') if @@ERROR<>0 begin return (1) end /* execute ('select c.tablenick, c.rowguid, c.generation, c.lineage, c.colv, t.* from ' + @tablename + ' t, ' + @temp_cont + ' c where (c.tablenick = ' + @tnstring + ' and c.rowguid > ' + @rgstring + ' and t.rowguidcol = c.rowguid) order by c.rowguid' ) */ select @ownername = user_name(uid) from sysobjects where id = object_id(@tablename) select @procname = select_proc from sysmergearticles where nickname=@tablenick and pubid = @pubid exec @retcode = @procname @type =3 IF @@ERROR<>0 or @retcode<>0 RETURN (1) drop table #cont return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumpartialchanges go grant exec on dbo.sp_MSenumpartialchanges to public raiserror('Creating procedure sp_MSgetrowmetadata', 0,1) GO CREATE PROCEDURE sp_MSgetrowmetadata (@tablenick int, @rowguid uniqueidentifier, @generation int output, @type tinyint output, @lineage varbinary(255) output, @colv varbinary(2048) output, @pubid uniqueidentifier = NULL) as declare @retcode smallint declare @saverr int declare @rc int declare @procname nvarchar(258) declare @ownername sysname /* ** To public. */ if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select @colv = null select @type = type, @generation = generation, @lineage = lineage from MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid if (@lineage is null) begin select @type = 0 select @generation = 0 end if (@type = 0) begin declare @tablename nvarchar(266) exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename out, @pubid if @@ERROR<>0 begin return (1) end select @ownername = user_name(uid) from sysobjects where id = object_id(@tablename) select @procname = select_proc from sysmergearticles where objid = object_id(@tablename) and pubid = @pubid exec @retcode = @procname @type =4, @rowguid=@rowguid select @saverr = @@ERROR, @rc = @@rowcount if @saverr <>0 return (1) if (@rc = 1) begin select @type = 3 select @type = 2, @generation = generation, @lineage = lineage, @colv = colv1 from MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid end end return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetrowmetadata go grant exec on dbo.sp_MSgetrowmetadata to public go raiserror('Creating procedure sp_MSsetrowmetadata', 0,1) GO CREATE PROCEDURE sp_MSsetrowmetadata (@tablenick int, @rowguid uniqueidentifier, @generation int, @lineage varbinary(255), @colv varbinary(2048), @type tinyint) as declare @reason nvarchar(255) declare @cvcurrent varbinary(2048) /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (1) end if (@generation is null) begin RAISERROR(14043, 16, -1, '@generation') return (1) end if (@lineage is null) begin RAISERROR(14043, 16, -1, '@lineage') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end if (@type = 1 or @type = 5 or @type = 6) begin if @type = 5 begin set @reason = formatmessage(20563) -- Out of partial range set @lineage = 0x00 end else if @type = 6 begin set @reason = formatmessage(20564) -- Deleted by system end else begin set @reason = formatmessage(20562) -- Deleted by user end -- update or insert MSmerge_tombstone update MSmerge_tombstone set generation = @generation, lineage = @lineage, type = @type, reason = @reason where tablenick = @tablenick and rowguid = @rowguid if (@@rowcount = 0) insert into MSmerge_tombstone (rowguid, tablenick, type, generation, lineage, reason) values (@rowguid, @tablenick, @type, @generation, @lineage, @reason) end else begin -- update or insert to MSmerge_contents select @cvcurrent = colv1 from MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid if (datalength(@colv) < datalength(@cvcurrent)) set @colv = @cvcurrent /* If filter values have changed, don't change generation */ update MSmerge_contents set generation = @generation, lineage = @lineage, colv1 = @colv where tablenick = @tablenick and rowguid = @rowguid and (partchangegen is null or partchangegen <> generation) and (joinchangegen is null or joinchangegen <> generation) /* If filter values have changed, still update lineage and colv */ if (@@rowcount = 0) update MSmerge_contents set lineage = @lineage, colv1 = @colv where tablenick = @tablenick and rowguid = @rowguid if (@@rowcount = 0) begin if not exists (select * from MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid) insert into MSmerge_contents (rowguid, tablenick, generation, lineage, colv1) values (@rowguid, @tablenick, @generation, @lineage, @colv) delete from MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid end end IF @@ERROR<>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetrowmetadata go grant exec on dbo.sp_MSsetrowmetadata to public go raiserror('Creating procedure sp_MSinsertgenhistory', 0,1) GO CREATE PROCEDURE sp_MSinsertgenhistory (@guidsrc uniqueidentifier, @gen int output, @pubid uniqueidentifier) as declare @dt datetime /* ** Check to see if current publication has permission */ declare @retcode int declare @saverr int exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) if (@guidsrc is null) begin RAISERROR(14043, 16, -1, '@guidsrc') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end /* Check for older in process generation */ if exists (select * from MSmerge_genhistory where guidsrc = @guidsrc) begin select @gen = max(generation) from MSmerge_genhistory where guidsrc = @guidsrc return (0) end select @dt = getdate() begin tran insert into MSmerge_genhistory (guidsrc, pubid, guidlocal, generation, nicknames, coldate) select @guidsrc, @pubid, '00000000-0000-0000-0000-000000000000', COALESCE(1 + max(generation), 1), 0x0, @dt from MSmerge_genhistory (updlock) select @saverr = @@error select @gen = generation from MSmerge_genhistory where guidsrc = @guidsrc if @gen is null begin update MSmerge_genhistory set generation = 1 where guidsrc = @guidsrc set @gen = 1 end if @saverr = 0 begin /* Now put in rows for other publications that share articles with this one */ insert into MSmerge_genhistory (guidsrc, pubid, guidlocal, generation, nicknames, coldate) select distinct @guidsrc, pubid, '00000000-0000-0000-0000-000000000000', @gen, 0x0, @dt from sysmergearticles where pubid <> @pubid and artid in (select artid from sysmergearticles where pubid = @pubid) select @saverr = @@error end commit tran if (@saverr <> 0) begin RAISERROR(15001, 16, -1, 'MSmerge_genhistory') return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSinsertgenhistory go grant exec on dbo.sp_MSinsertgenhistory to public raiserror('Creating procedure sp_MSupdategenhistory', 0,1) GO CREATE PROCEDURE sp_MSupdategenhistory (@guidsrc uniqueidentifier, @pubid uniqueidentifier, @gen int, @art_nick int = NULL) as declare @guidlocal uniqueidentifier declare @dt datetime /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) if (@guidsrc is null) begin RAISERROR(14043, 16, -1, '@guidsrc') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select @dt = getdate() if @art_nick = 0 set @art_nick = NULL set @guidlocal = newid() begin tran if exists (select * from MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen) begin update MSmerge_contents set generation = @gen where generation in (select generation from MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen) if @@ERROR <> 0 goto FAILURE update MSmerge_tombstone set generation = @gen where generation in (select generation from MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen) if @@ERROR <> 0 goto FAILURE delete from MSmerge_genhistory where guidsrc = @guidsrc and generation < @gen if @@ERROR <> 0 goto FAILURE end if exists (select * from MSmerge_genhistory where guidsrc = @guidsrc) update MSmerge_genhistory set guidlocal = @guidlocal, art_nick = @art_nick where guidsrc = @guidsrc else insert into MSmerge_genhistory (guidsrc, guidlocal, generation, art_nick, nicknames, coldate) values (@guidsrc, @guidlocal, @gen, @art_nick, 0x0, @dt) commit IF @@ERROR<>0 return (1) return (0) FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT = 1 ROLLBACK TRANSACTION else COMMIT TRANSACTION RETURN 1 go exec dbo.sp_MS_marksystemobject sp_MSupdategenhistory go grant exec on dbo.sp_MSupdategenhistory to public raiserror('Creating procedure sp_MSenumschemachange', 0,1) GO CREATE PROCEDURE sp_MSenumschemachange( @pubid uniqueidentifier, @schemaversion int ) as /* ** To public */ if (@schemaversion is null) begin RAISERROR(14043, 16, -1, '@schemaversion') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end select pubid, artid, schemaversion, schemaguid, schematype, schematext from sysmergeschemachange where schemaversion > @schemaversion and pubid = @pubid order by schemaversion return (0) go exec dbo.sp_MS_marksystemobject sp_MSenumschemachange go grant exec on dbo.sp_MSenumschemachange to public go raiserror('Creating procedure sp_MSupdateschemachange', 0,1) GO CREATE PROCEDURE sp_MSupdateschemachange( @pubid uniqueidentifier, @artid uniqueidentifier = NULL, /* Can be NULL for directory commands */ @schemaversion int, @schemaguid uniqueidentifier, @schematype int, @schematext nvarchar(2000) ) as /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) /* Parameter validation */ if (@schemaversion is null) begin RAISERROR(14043, 16, -1, '@schemaversion') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end update sysmergeschemachange set schematext = @schematext, schematype = @schematype where pubid = @pubid and artid = @artid and schemaguid = @schemaguid if @@error <> 0 begin RAISERROR(20054 , 16, -1) return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSupdateschemachange go grant exec on dbo.sp_MSupdateschemachange to public go raiserror('Creating procedure sp_MSadd_mergereplcommand', 0,1) GO /* Add the replication command to the database - Used by snapshot */ CREATE PROCEDURE sp_MSadd_mergereplcommand ( @publication sysname, @article sysname = NULL, @schematype int, @schematext nvarchar(2000) ) AS declare @schemaguid uniqueidentifier declare @schemaversion int declare @retcode int declare @pubid uniqueidentifier declare @artid uniqueidentifier /* ** Publish permission check */ exec @retcode=sp_MSreplcheck_publish if @retcode<>0 or @@ERROR<>0 return (1) if @publication IS NULL BEGIN RAISERROR (14003, 16, -1) RETURN (1) END select @pubid = pubid FROM sysmergepublications WHERE name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name() select @artid = artid FROM sysmergearticles WHERE name = @article /* ** For certain system tables that are bcped out such as MSmerge_contents ** and MSmerge_tombstone use the article name as sysobjects.name and get ** sysobjects.id as the artid */ if (@artid IS NULL) AND (@schematype <> 7) begin declare @binguid binary(16) set @binguid = OBJECT_ID(@article) set @artid = convert(uniqueidentifier, @binguid) end if exists (select * from sysmergeschemachange where pubid = @pubid AND artid = @artid AND (schematype = @schematype or @schematype in (3,4) and schematype in (3,4)) ) begin /* Select the existing schema guid */ select @schemaversion = schemaversion, @schemaguid = schemaguid from sysmergeschemachange where pubid = @pubid AND artid = @artid AND (schematype = @schematype or @schematype in (3,4) and schematype in (3,4)) /* For directory commands, delete the previous directory before the update */ if (@schematype = 7) begin declare @dir nvarchar(255) declare @local_path nvarchar(255) declare @delcmd nvarchar(255) declare @distributor sysname declare @distproc nvarchar(255) /* ** Get distribution server information for remote RPC call. */ EXEC @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT IF @@ERROR <> 0 OR @retcode <> 0 BEGIN RAISERROR (14071, 16, -1) RETURN (1) END select @dir = schematext from sysmergeschemachange where schemaversion = @schemaversion /* ** We have to convert UNC to drive, otherwise will get 'Access denied' error in xp_cmdshell */ EXEC @retcode = master.dbo.sp_MSunc_to_drive @unc_path = @dir, @local_server = @distributor, @local_path = @local_path OUTPUT if @retcode<>0 or @@ERROR<>0 return (1) /* ** Delete publication directory in the distributor machine. */ SET @distproc = RTRIM(@distributor) + '.master..xp_cmdshell' SET @delcmd = 'rmdir /S /Q ' + @local_path EXECUTE @distproc @delcmd, NO_OUTPUT if @@ERROR<>0 return (1) end /* ** Update the schema change version */ exec @retcode = dbo.sp_MSupdateschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext if @@error <> 0 or @retcode <> 0 begin RAISERROR(20054 , 16, -1) return (1) end end else begin /* Insert the schema change */ select @schemaversion = schemaversion from sysmergeschemachange if (@schemaversion is NULL) set @schemaversion = 1 else select @schemaversion = 1 + max(schemaversion) from sysmergeschemachange /* generate a new schema guid */ set @schemaguid = newid() exec @retcode = dbo.sp_MSinsertschemachange @pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext if @@error <> 0 or @retcode <> 0 begin RAISERROR(20054 , 16, -1) return (1) end end return (0) go exec dbo.sp_MS_marksystemobject sp_MSadd_mergereplcommand go grant exec on dbo.sp_MSadd_mergereplcommand to public go raiserror('Creating procedure sp_MSsetreplicainfo', 0,1) GO CREATE PROCEDURE sp_MSsetreplicainfo (@publisher sysname, @publisher_db sysname, @publication sysname, @datasource_type int = 0, /* 0 = SQL Server, 1 = DSN, 2 = Jet */ @server_name sysname = NULL, /* Server Name */ @db_name sysname = NULL, /* Database Name */ @datasource_path nvarchar(255) = NULL,/* Datasource path - JET MDB file path etc */ @nickname int = NULL, @schemaversion int = NULL, @subid uniqueidentifier = NULL) as declare @pubid uniqueidentifier declare @repid uniqueidentifier declare @srvid int declare @retcode int /* ** NOTE -- WORKAROUND ODBC PROBLEM */ select @publisher_db = RTRIM(@publisher_db) select @db_name = RTRIM(@db_name) /* ** Subscriber permission check */ if UPPER(@@servername) = UPPER(@publisher) and db_name() = @publisher_db begin exec @retcode=sp_MSreplcheck_connection @publication = @publication if @retcode<>0 or @@ERROR<>0 return (1) end else begin exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 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 if (@server_name is NULL) SET @server_name = @@SERVERNAME if (@db_name is NULL) set @db_name = db_name() SELECT @srvid = srvid FROM master..sysservers WHERE UPPER(srvname) = UPPER(@server_name) IF @@ERROR <> 0 or @srvid IS NULL BEGIN RAISERROR(20021, 16, -1) RETURN (1) END select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db if (@pubid is null) begin RAISERROR (20026, 11, -1, @publication) return (1) end if (@datasource_type = 0) begin SELECT @repid = subid FROM sysmergesubscriptions WHERE srvid = @srvid and db_name = @db_name and pubid = @pubid END ELSE BEGIN SELECT @repid = subid FROM sysmergesubscriptions WHERE datasource_path = @datasource_path and pubid = @pubid END if @repid is NULL begin RAISERROR(20021, 16, -1) return (1) end if @schemaversion is not null begin update MSmerge_replinfo set schemaversion = @schemaversion where repid = @repid if @@error <> 0 begin RAISERROR(20054 , 16, -1) return (1) end end if @subid is not null and @subid <> @repid begin /* Fix the repid for pull subscribers before we copy around global replica rows */ update MSmerge_replinfo set repid = @subid where repid = @repid if @@error <> 0 begin RAISERROR(20054 , 16, -1) return (1) end update sysmergesubscriptions set subid = @subid where subid = @repid if @@error <> 0 begin RAISERROR(20054 , 16, -1) return (1) end end if @nickname IS NOT NULL begin /* If this nickname isn't already assigned, reset it */ if exists (select * from MSmerge_replinfo, sysmergesubscriptions where replnickname = @nickname and repid = subid and (srvid <> @srvid or db_name <> @db_name)) return (0) update MSmerge_replinfo set replnickname = @nickname where repid = @repid if @@error <> 0 begin RAISERROR(20054 , 16, -1) return (1) end end return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetreplicainfo go grant exec on dbo.sp_MSsetreplicainfo to public go raiserror('Creating procedure sp_MSsetreplicastatus', 0,1) GO CREATE PROCEDURE sp_MSsetreplicastatus (@subid uniqueidentifier, @status_value int ) AS /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @repid = @subid if @retcode<>0 or @@ERROR<>0 return (1) IF EXISTS (select subid from sysmergesubscriptions where subid=@subid) update sysmergesubscriptions set status = @status_value WHERE subid=@subid if @@ERROR<>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetreplicastatus go grant exec on dbo.sp_MSsetreplicastatus to public go raiserror('Creating procedure sp_MScreateglobalreplica', 0,1) GO CREATE PROCEDURE sp_MScreateglobalreplica( @pubid uniqueidentifier = NULL, /* Publication ID */ @subid uniqueidentifier, /* Replica ID */ @partnerid uniqueidentifier, /* Partner's Replica ID */ @replica_server sysname, /* Replica server */ @replica_db sysname, /* Replica database */ @replica_priority real, /* Replica priority */ @subscriber_type tinyint = 0, /* Replica's subscriber type - global, hub */ @subscription_type int = 0, /* Replica's subscription type - push or pull */ @datasource_type int = 0, @datasource_path nvarchar(255) = NULL, @nickname int, /* Replica nickname */ @status int, /* Replica status */ @sync_type tinyint = 2 /* Replica sync type 1 = no sync, 2 = automatic */ ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @replica_srvid int DECLARE @pubnickname int declare @retcode int /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) /* ** NOTE */ select @replica_db = RTRIM(@replica_db) /* ** Initializations */ SELECT @replica_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@replica_server) if @replica_srvid is NULL begin EXECUTE @retcode = dbo.sp_addserver @replica_server IF @@error <> 0 OR @retcode <> 0 BEGIN RAISERROR (14042, 16, -1) RETURN (1) END end SELECT @replica_srvid = srvid from master..sysservers where UPPER(srvname) = UPPER(@replica_server) BEGIN TRAN MScreateglobalreplica /* ** Populate the local copy of sysmergesubscriptions */ if exists (select * from sysmergesubscriptions where subid = @subid and pubid = @pubid ) begin update sysmergesubscriptions SET subid = @subid, datasource_type = @datasource_type, datasource_path = @datasource_path, srvid = @replica_srvid, db_name = @replica_db, pubid = @pubid, status = @status, subscriber_type = @subscriber_type, subscription_type = @subscription_type, priority = @replica_priority, sync_type = @sync_type, login_name = suser_sname(suser_sid()) where subid = @subid and pubid = @pubid IF @@ERROR <> 0 goto FAILURE end else begin /* ** If attempting to tell the current replica about another replica whose pubid IS NULL ** ignore the insert because current replica has more current info. */ if exists (select * from sysmergesubscriptions where subid = @subid and @pubid IS NULL) goto SUCCESS IF EXISTS (SELECT * FROM sysmergesubscriptions WHERE srvid = @replica_srvid AND db_name = @replica_db and pubid = @pubid) goto SUCCESS insert sysmergesubscriptions(subid, partnerid, datasource_type, datasource_path, srvid, db_name, pubid, status, subscriber_type, subscription_type, priority, sync_type, login_name) values (@subid, @partnerid, @datasource_type, @datasource_path, @replica_srvid, @replica_db, @pubid, @status, @subscriber_type, @subscription_type, @replica_priority, @sync_type, suser_sname(suser_sid())) IF @@ERROR <> 0 goto FAILURE end if not exists (select * from MSmerge_replinfo where repid = @subid ) begin INSERT INTO MSmerge_replinfo(repid, replnickname) values (@subid, @nickname) IF @@ERROR <> 0 goto FAILURE end SUCCESS: COMMIT TRAN RETURN 0 FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT = 1 ROLLBACK TRANSACTION MScreateglobalreplica else COMMIT TRANSACTION RAISERROR (14057, 16, -1) RETURN 1 go exec dbo.sp_MS_marksystemobject sp_MScreateglobalreplica go grant exec on dbo.sp_MScreateglobalreplica to public go raiserror('Creating procedure sp_MSsetconflictscript', 0,1) GO /* Add the conflict script pointer to sysmergearticles - Used by snapshot */ CREATE PROCEDURE sp_MSsetconflictscript ( @publication sysname, @article sysname, @conflict_script nvarchar(255), @login sysname =NULL, @password sysname =NULL ) AS declare @artid uniqueidentifier declare @pubid uniqueidentifier DECLARE @osql_cmd1 nvarchar (255) DECLARE @osql_cmd_full varchar (255) DECLARE @install_path varchar (255) declare @db_name sysname /* ** Check for publish permission. */ declare @retcode int exec @retcode=sp_MSreplcheck_publish if @retcode<>0 or @@ERROR<>0 return (1) 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 @artid = artid FROM sysmergearticles WHERE name = @article AND pubid = @pubid if @artid IS NULL BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END update sysmergearticles set conflict_script = @conflict_script where artid = @artid if @@ERROR <> 0 return (1) /* if there is already a conflict table, don't run script */ if exists (select * from sysmergearticles where artid = @artid and OBJECT_ID(conflict_table) is null) BEGIN /* Run the script and create the conflict table */ EXECUTE @retcode = master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\MSSQLServer\Setup', 'SQLPath', @param = @install_path OUTPUT IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path='' return (1) IF @login is NULL SELECT @osql_cmd1 = @install_path + '\binn\osql -E ' ELSE -- cannot specify -S w/ -E for local execution, SID does not map due to nofix bug SELECT @osql_cmd1 = @install_path + '\binn\osql -U' + @login + ' -P' + isnull(@password,'') + ' -S' + @@SERVERNAME + ' ' select @osql_cmd1 = @osql_cmd1 + '-l30 -t30 ' set @db_name = db_name() SELECT @osql_cmd_full = @osql_cmd1 + ' -d' + @db_name + ' -b ' + ' -i' + @conflict_script + ' -o' + @install_path + '\install\conflict.out' EXEC @retcode = master..xp_cmdshell @osql_cmd_full IF @@ERROR<> 0 OR @retcode <> 0 return (1) END /* Create the conflict insert proc */ if exists (select * from sysmergearticles where artid = @artid and OBJECT_ID(ins_conflict_proc) is null) BEGIN exec dbo.sp_MSgetconflictinsertproc @artid = @artid, @output = 0 IF @@ERROR<> 0 OR @retcode <> 0 return (1) END return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetconflictscript go grant exec on dbo.sp_MSsetconflictscript to public go raiserror('Creating procedure sp_MSsetconflicttable', 0,1) GO /* Add the conflict table pointer to sysmergearticles - Used by reconciler */ CREATE PROCEDURE sp_MSsetconflicttable ( @article sysname, @conflict_table nvarchar(255) ) AS declare @artid uniqueidentifier select @artid = artid FROM sysmergearticles WHERE name = @article if @artid IS NULL BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @artid = @artid if @retcode<>0 or @@ERROR<>0 return (1) exec @retcode = dbo.sp_MS_marksystemobject @conflict_table if @retcode<>0 or @@ERROR<>0 return (1) update sysmergearticles set conflict_table = @conflict_table where artid = @artid if @@ERROR <> 0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetconflicttable go grant exec on dbo.sp_MSsetconflicttable to public go raiserror('Creating procedure sp_MSmakeconflictinsertproc', 0,1) GO create procedure sp_MSmakeconflictinsertproc (@tablename sysname, @ownername sysname, @procname sysname, @basetableid int) as declare @arglist nvarchar(4000) declare @collist nvarchar(4000) declare @vallist nvarchar(4000) declare @setpc nvarchar(4000) declare @qualname nvarchar(266) declare @argname sysname declare @wherepc nvarchar(255) declare @id int declare @colname sysname declare @typename sysname declare @colid smallint declare @status tinyint declare @len smallint declare @prec smallint declare @scale int declare @retcode smallint if (@ownername is null or @ownername = ' ') set @qualname = QUOTENAME(@tablename) else set @qualname = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename) /* ** To check if specified object exists in current database */ set @id = object_id(@qualname) if @id is NULL return (1) select @colid = min(colid) from syscolumns where id = @id and iscomputed <>1 select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length, @prec = c.prec, @scale = c.scale from syscolumns c, systypes t where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype while (@colname is not null) begin if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes select @len = @len/2 exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale if @@ERROR<>0 or @retcode<>0 return (1) select @argname = '@p' + rtrim(convert(nchar, @colid)) -- based on colid, add text to appropriate pieces if (COLUMNPROPERTY( @basetableid, @colname, 'IsRowGuidCol') = 1) set @wherepc = ' where rowguidcol = ' + @argname else if (@colname = 'origin_datasource') select @wherepc = @wherepc + ' and origin_datasource = ' + @argname set @colname = QUOTENAME(@colname) if @arglist is null begin set @arglist = @argname + ' ' + @typename set @collist = @colname set @vallist = @argname set @setpc = @colname + ' = ' + @argname end else begin set @arglist = @arglist + ', ' + @argname + ' ' + @typename set @collist = @collist + ', ' + @colname set @vallist = @vallist + ', ' + @argname set @setpc = @setpc + ', ' + @colname + ' = ' + @argname end select @colid = min(colid) from syscolumns where id = @id and colid > @colid and iscomputed<>1 set @colname = NULL select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length, @prec = c.prec, @scale = c.scale from syscolumns c, systypes t where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype end -- now create the procedure select @procname = QUOTENAME(@procname) execute ('Create procedure dbo.' + @procname + ' ( ' + @arglist + ') as update ' + @qualname + ' set ' + @setpc + @wherepc + ' if (@@rowcount = 0) insert into ' + @qualname + ' (' + @collist + ') values (' + @vallist + ')') IF @@ERROR <> 0 begin return(1) end execute ('grant execute on ' + @procname + ' to public') exec dbo.sp_MS_marksystemobject @procname go exec dbo.sp_MS_marksystemobject sp_MSmakeconflictinsertproc go dump tran master with no_log go raiserror('Creating procedure sp_MSmaketempinsertproc', 0,1) GO -- Create temp sp, no security check needed create procedure sp_MSmaketempinsertproc (@tablename sysname, @procname sysname) as declare @arglist nvarchar(4000) declare @collist nvarchar(4000) declare @vallist nvarchar(4000) declare @argname sysname declare @setpc nvarchar(4000) declare @wherepc nvarchar(255) declare @qualname nvarchar(266) declare @id int set @qualname = 'tempdb..' + @tablename select @id = id from tempdb..sysobjects where name = @tablename declare @colname sysname declare @typename sysname declare @colid smallint declare @status tinyint declare @len smallint declare @prec smallint declare @scale int declare @retcode smallint set @wherepc = ' where rowguid = @p2 ' select @colid = 1 select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length, @prec = COLUMNPROPERTY(c.id, c.name, 'precision'), @scale = c.scale from tempdb..syscolumns c, systypes t where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype and c.iscomputed<>1 while (@colname is not null) begin if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes select @len = @len/2 exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale if @@error<>0 or @retcode<>0 return (1) set @argname = '@p' + rtrim(convert(nchar, @colid)) if (@colid = 1) begin set @arglist = @argname + ' ' + @typename set @collist = @colname set @vallist = @argname set @setpc = @colname + ' = ' + @argname end else begin set @arglist = @arglist + ', ' + @argname + ' ' + @typename set @collist = @collist + ', ' + @colname set @vallist = @vallist + ', ' + @argname set @setpc = @setpc + ', ' + @colname + ' = ' + @argname end set @colid = @colid + 1 set @colname = NULL select @colname = c.name, @status = c.status, @typename = t.name, @len = c.length, @prec = COLUMNPROPERTY(c.id, c.name, 'precision'), @scale = c.scale from tempdb..syscolumns c, systypes t where c.id = @id and c.colid = @colid and c.xusertype = t.xusertype and c.iscomputed<>1 end select @procname = QUOTENAME(@procname) select @tablename = QUOTENAME(@tablename) -- now create the procedure execute ('Create procedure dbo.' + @procname + ' ( ' + @arglist + ') as update ' + @tablename + ' set ' + @setpc + @wherepc + ' if (@@rowcount = 0) insert into ' + @tablename + ' (' + @collist + ') values (' + @vallist + ')') if @@ERROR<>0 begin return(1) end go exec dbo.sp_MS_marksystemobject sp_MSmaketempinsertproc go grant exec on dbo.sp_MSmaketempinsertproc to public go raiserror('Creating procedure sp_MSgetconflictinsertproc', 0,1) GO /* Add the conflict table pointer to sysmergearticles - Used by reconciler */ CREATE PROCEDURE sp_MSgetconflictinsertproc ( @artid uniqueidentifier, @output int = 1 ) AS declare @conflict_table sysname declare @conflict_proc sysname declare @owner sysname declare @object sysname declare @retcode int declare @basetableid int -- PARSENAME VARS declare @UnqualName nvarchar(258) --rightmost name node declare @QualName1 nvarchar(258) declare @QualName2 nvarchar(258) -- END PARSENAME VARS declare @guidstr varchar(40) exec @retcode=sp_MSguidtostr @artid, @guidstr out if @retcode<>0 or @@ERROR<>0 return (1) /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @artid = @artid if @retcode<>0 or @@ERROR<>0 return (1) select @conflict_table = conflict_table, @conflict_proc = ins_conflict_proc, @basetableid = objid from sysmergearticles where artid = @artid if @@ERROR <> 0 return (1) -- Create an index on the conflict table if it doesn't have one if (OBJECT_ID(@conflict_table) is not null) and not exists (select * from sysindexes where id = OBJECT_ID(@conflict_table) and keys is not null) begin declare @rgcol sysname declare @indname sysname declare @quotedname sysname select @rgcol = QUOTENAME(name) from syscolumns where id = @basetableid and ColumnProperty(id, name, 'isrowguidcol') = 1 select @indname = 'uc_' + @conflict_table set @indname = QUOTENAME(@indname) set @quotedname = QUOTENAME(@conflict_table) exec ('Create unique clustered index ' + @indname + ' on ' + @quotedname + ' (' + @rgcol + ', origin_datasource)' ) if @@error <> 0 return (1) end if ((OBJECT_ID(@conflict_proc) is null) and (OBJECT_ID(@conflict_table) is not null)) begin select @UnqualName = PARSENAME(@conflict_table, 1) select @QualName1 = PARSENAME(@conflict_table, 2) if @UnqualName IS NULL return 1 -- fixup for variable length differences. remove when vars expanded -- to new SQL SERVER 7.0 lengths select @owner = @QualName1 select @object = @UnqualName -- first set up the procedure name variable select @conflict_proc = 'sp_cft_' + @guidstr exec @retcode=sp_MSuniqueobjectname @conflict_proc , @conflict_proc output if @@ERROR <> 0 OR @retcode <> 0 return(1) exec @retcode=sp_MSmakeconflictinsertproc @UnqualName, @owner, @conflict_proc, @basetableid if @@ERROR <> 0 OR @retcode <> 0 begin RAISERROR('Failure when creating conflict insertion procedure', 16, -1) return(1) end update sysmergearticles set ins_conflict_proc = @conflict_proc where artid = @artid end if @output = 1 select @conflict_table, @conflict_proc if @@ERROR <> 0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetconflictinsertproc go grant exec on dbo.sp_MSgetconflictinsertproc to public go raiserror('Creating procedure sp_MSinsertdeleteconflict', 0,1) GO create PROCEDURE sp_MSinsertdeleteconflict( @tablenick int, @rowguid uniqueidentifier, @conflict_type int, @reason_code int, @reason_text nvarchar(720), @origin_datasource nvarchar(255), @pubid uniqueidentifier) as declare @retcode int /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) /* Parameter validation */ if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (1) end if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (1) end /* Don't insert a duplicate row */ if (not exists (select * from MSmerge_delete_conflicts where tablenick = @tablenick and rowguid = @rowguid and origin_datasource = @origin_datasource)) insert into MSmerge_delete_conflicts (tablenick, rowguid, conflict_type, reason_code, reason_text, origin_datasource, pubid) values (@tablenick, @rowguid, @conflict_type, @reason_code, @reason_text, @origin_datasource, @pubid) if @@ERROR <> 0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSinsertdeleteconflict go grant exec on dbo.sp_MSinsertdeleteconflict to public go raiserror('Creating procedure sp_MScheckmetadatamatch', 0,1) GO create procedure sp_MScheckmetadatamatch (@metatype tinyint, @rowguid uniqueidentifier, @tablenick int, @lineage varbinary(255), @match int output) as select @match = 0 if (@metatype = 3 and not exists (select * from MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid)) select @match = 1 else select @match = count(*) from MSmerge_contents (updlock) where tablenick = @tablenick and rowguid = @rowguid and lineage = @lineage return (0) go exec dbo.sp_MS_marksystemobject sp_MScheckmetadatamatch go grant exec on dbo.sp_MScheckmetadatamatch to public raiserror('Creating procedure sp_MSdelrow', 0,1) GO create PROCEDURE sp_MSdelrow (@rowguid uniqueidentifier, @tablenick int, @metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred */ @lineage_old varbinary(255), @generation int, @lineage_new varbinary(255), @pubid uniqueidentifier = NULL) as set nocount on declare @success int declare @tablename nvarchar(266) declare @rowguidstr nvarchar(40) declare @match int declare @new_metatype tinyint declare @retcode smallint declare @reason nvarchar(255) declare @procname nvarchar(266) declare @ownername sysname /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) select @success = 0 /* Parameter validation */ if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (0) end if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (0) end exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename output, @pubid if @@ERROR<>0 return (0) if (@tablename is null) begin RAISERROR(14043, 16, -1, '@tablename') return (0) end if (@lineage_new is null) begin RAISERROR(14043, 16, -1, '@lineage_new') return (0) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (0) end set @rowguidstr = '''' + convert(nchar(36), @rowguid) + '''' -- Are we just changing the type of a tombstone? if (@metadata_type = 5 and exists (select * from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)) begin set @reason = formatmessage (20563) -- Moved out of partial range update MSmerge_tombstone set type = @metadata_type, reason = @reason where rowguid = @rowguid and tablenick = @tablenick set @success = 1 return @success end -- Are we just changing the type of a tombstone? if (@metadata_type = 6 and exists (select * from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)) begin set @reason = formatmessage (20564) -- System deleted update MSmerge_tombstone set type = @metadata_type, reason = @reason where rowguid = @rowguid and tablenick = @tablenick set @success = 1 return @success end -- begin transaction and lock row that we plan to delete begin transaction select @ownername = user_name(uid) from sysobjects where id = object_id(@tablename) select @procname = select_proc from sysmergearticles where objid = object_id(@tablename) and pubid = @pubid exec @retcode = @procname @type =8, @rowguid=@rowguid /* execute ('if not exists (select * from ' + @tablename + '(UPDLOCK) where rowguidcol = ' + @rowguidstr + ') RAISERROR(20031 , 16, -1) ') */ select @success = 2 if @metadata_type = 5 begin set @match = 1 set @new_metatype = 5 end else if @metadata_type = 6 begin set @match = 1 set @new_metatype = 6 end else begin exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output set @new_metatype = 1 end if (@match = 1) begin /* execute ('delete from ' + @tablename + ' where rowguidcol = ' + @rowguidstr) */ /* ** select_proc makes a delete with @type = 5, despite its name. */ exec @retcode = @procname @type =5, @rowguid=@rowguid if (@@error = 0 and @@rowcount = 1) begin exec dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype select @success = 1 end else select @success = 3 end commit return (@success) go exec dbo.sp_MS_marksystemobject sp_MSdelrow go grant exec on dbo.sp_MSdelrow to public go raiserror('Creating procedure sp_MSsetartprocs', 0,1) GO -- Call by snapshot create procedure sp_MSsetartprocs (@publication sysname, @article sysname, @force_flag int = 0) as declare @ownername sysname declare @objectname sysname declare @guidstr nvarchar(40) declare @pubidstr nvarchar(40) declare @ins_procname sysname declare @sel_procname sysname declare @upd_procname sysname declare @view_selprocname sysname declare @viewname sysname declare @artid uniqueidentifier declare @pubid uniqueidentifier declare @objid int declare @rgcol sysname declare @sync_objid int declare @retcode smallint declare @dbname sysname declare @command nvarchar(1000) set nocount on /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_publish if @retcode<>0 or @@ERROR<>0 return (1) -- figure out pubid and artid if @force_flag = 1 begin -- don't qualify that must be publisher when we are forcing remake at subscribers select @pubid = pubid from sysmergepublications where name = @publication end else 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 @artid = artid, @objid = objid, @sync_objid = sync_objid FROM sysmergearticles WHERE name = @article AND pubid = @pubid if @artid IS NULL BEGIN RAISERROR (20027, 16, -1, @article) RETURN (1) END /* Drop the article procs if they preexist */ exec @retcode = dbo.sp_MSdroparticleprocs @pubid, @artid if @@ERROR<>0 OR @retcode<>0 begin return (1) end -- get owner name, and table name select @objectname = name, @ownername = user_name(uid) from sysobjects where id = @objid -- make the insert and update proc names exec @retcode = dbo.sp_MSguidtostr @artid, @guidstr out if @@ERROR <>0 OR @retcode <>0 return (1) exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out if @@ERROR <>0 OR @retcode <>0 return (1) select @ins_procname = 'sp_ins_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec dbo.sp_MSuniqueobjectname @ins_procname, @ins_procname output if @@ERROR <>0 OR @retcode <>0 return (1) select @upd_procname = 'sp_upd_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec dbo.sp_MSuniqueobjectname @upd_procname, @upd_procname output if @@ERROR <>0 OR @retcode <>0 return (1) select @sel_procname = 'sp_sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec dbo.sp_MSuniqueobjectname @sel_procname, @sel_procname output if @@ERROR <>0 OR @retcode <>0 return (1) set @view_selprocname = 'sel_' + substring(@guidstr, 1, 16) + substring(@pubidstr, 1, 16) exec @retcode = dbo.sp_MSuniqueobjectname @view_selprocname , @view_selprocname output if @retcode <> 0 or @@ERROR <> 0 return (1) -- create the procs set @dbname = db_name() set @command = 'sp_MSmakeinsertproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @ins_procname + ', [' + convert(nchar(36), @pubid) + ']' exec @retcode = master..xp_execresultset @command, @dbname if @@ERROR<>0 OR @retcode<>0 begin return (1) end exec @retcode = dbo.sp_MS_marksystemobject @ins_procname if @@ERROR<>0 return (1) exec ('grant exec on ' + @ins_procname + ' to public') set @command = 'sp_MSmakeupdateproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @upd_procname exec @retcode = master..xp_execresultset @command, @dbname if @@ERROR<>0 OR @retcode<>0 begin return (1) end exec @retcode = dbo.sp_MS_marksystemobject @upd_procname if @@ERROR<>0 return (1) exec ('grant exec on ' + @upd_procname + ' to public') set @command = 'sp_MSmakeselectproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername)+ ' , ' + @sel_procname exec (@command) if @@ERROR<>0 begin return (1) end exec @retcode = dbo.sp_MS_marksystemobject @sel_procname if @@ERROR<>0 return (1) exec ('grant exec on ' + @sel_procname + ' to public') if @sync_objid <> 0 begin select @ownername = user_name(uid), @viewname = name from sysobjects where id = @sync_objid select @rgcol = QUOTENAME(name) from syscolumns where id = @objid and ColumnProperty(id, name, 'isrowguidcol') = 1 exec dbo.sp_MSmakeviewproc @viewname, @ownername, @view_selprocname, @rgcol if @@ERROR<>0 begin return (1) end end else set @view_selprocname = '' -- update articles to set the names update sysmergearticles set insert_proc = @ins_procname, update_proc = @upd_procname , select_proc = @sel_procname, view_sel_proc = @view_selprocname where artid = @artid and pubid = @pubid IF @@ERROR<>0 return (1) return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetartprocs go grant exec on dbo.sp_MSsetartprocs to public go raiserror('Creating procedure sp_MSmakesystableviews', 0,1) GO -- Used by snapshot create procedure sp_MSmakesystableviews (@publication sysname) AS declare @guidstr nvarchar(40) declare @pubid uniqueidentifier declare @contentsview sysname declare @tombstoneview sysname declare @genhistoryview sysname declare @filtersview sysname declare @retcode smallint /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_publish if @retcode<>0 or @@ERROR<>0 return (1) 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 exec @retcode = dbo.sp_MSguidtostr @pubid, @guidstr out if @@ERROR<>0 OR @retcode<>0 return (1) select @contentsview = 'cont' + @guidstr select @tombstoneview = 'ts' + @guidstr select @genhistoryview = 'gh' + @guidstr select @filtersview = 'filt' + @guidstr set @guidstr = '''' + convert(nchar(36), @pubid) + '''' exec @retcode = dbo.sp_MSuniqueobjectname @tombstoneview, @tombstoneview out if @@ERROR<>0 OR @retcode<>0 return (1) exec @retcode = dbo.sp_MSuniqueobjectname @contentsview, @contentsview out if @@ERROR<>0 OR @retcode<>0 return (1) exec @retcode = dbo.sp_MSuniqueobjectname @genhistoryview, @genhistoryview out if @@ERROR<>0 OR @retcode<>0 return (1) exec @retcode = dbo.sp_MSuniqueobjectname @filtersview, @filtersview out if @@ERROR<>0 OR @retcode<>0 return (1) /* generate view for MSmerge_contents qualified by the pubid */ exec ('create view ' + @tombstoneview + ' as select * from MSmerge_tombstone where tablenick in (select nickname from sysmergearticles where convert(nchar(36), pubid) = ' + @guidstr + ')') if @@ERROR <>0 begin return (1) end exec ('create view ' + @contentsview + ' as select * from MSmerge_contents where tablenick in (select nickname from sysmergearticles where convert(nchar(36), pubid) = ' + @guidstr + ')' ) if @@ERROR <>0 begin return (1) end exec ('create view ' + @genhistoryview + '(guidsrc, guidlocal, pubid, generation, art_nick, nicknames, coldate) as select DISTINCT guidsrc, guidlocal, CONVERT(uniqueidentifier, ' + @guidstr + '), generation, art_nick, nicknames, coldate from MSmerge_genhistory where guidlocal <> ''00000000-0000-0000-0000-000000000000'' and (art_nick = 0 or art_nick is NULL or art_nick in (select nickname from sysmergearticles where convert(nchar(36), pubid) = ' + @guidstr + ')) ') if @@ERROR <>0 begin return (1) end exec ('create view ' + @filtersview + ' as select * from sysmergesubsetfilters where convert(nchar(36), pubid) = ' + @guidstr) if @@ERROR <>0 begin return (1) end set nocount on select @contentsview, @tombstoneview, @genhistoryview, @filtersview return (0) go exec dbo.sp_MS_marksystemobject sp_MSmakesystableviews go grant exec on dbo.sp_MSmakesystableviews to public go raiserror('Creating procedure sp_MSgetchangecount', 0,1) GO create procedure sp_MSgetchangecount( @startgen int, @changes int output, @updates int output, @deletes int output) as select @deletes = count(*) from MSmerge_tombstone where generation = 0 or generation > @startgen select @updates = count(*) from MSmerge_contents where generation = 0 or generation > @startgen select @changes = @updates + @deletes return (0) go exec dbo.sp_MS_marksystemobject sp_MSgetchangecount go grant exec on dbo.sp_MSgetchangecount to public raiserror('Creating procedure sp_MSbelongs', 0,1) GO -- Modify temp table. No security check needed. create procedure sp_MSbelongs @publisher sysname, @publisher_db sysname, @publication sysname, @tablenick int, @rowguid uniqueidentifier, @retval int output, @nested int = 0 AS declare @artid uniqueidentifier declare @join_guid uniqueidentifier declare @last_joinid int declare @join_id int declare @join_nick int declare @probe_id int declare @last_probe int declare @join_nickstr nvarchar(10) declare @pubid uniqueidentifier declare @guidstring nvarchar(38) declare @subset_filter nvarchar(4000) declare @tablename nvarchar(266) declare @join_table nvarchar(266) declare @boolean nvarchar(4000) declare @retcode smallint select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db /* Check for case of all rows - do I trust subset_type ? */ select @boolean = subset_filterclause, @artid = artid from sysmergearticles where pubid = @pubid and nickname = @tablenick if ((@boolean is null or @boolean = ' ') and not exists (select * from sysmergesubsetfilters where art_nickname = @tablenick)) begin set @retval = 0 return end if @nested = 0 begin create table #found (flag int NOT NULL) insert into #found values (0) create table #probe (probe_id int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier ROWGUIDCOL default newid() not null, tested int NOT NULL) set @last_probe = 0 end else begin select @last_probe = max(probe_id) from #probe end /* pubid is already available */ exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename out, @pubid if @@ERROR<>0 or @retcode<>0 return (1) set @guidstring = '''' + convert(nchar(36), @rowguid) + '''' /* If there is boolean filter, check for it being satisfied */ if @boolean is not null and @boolean <> ' ' begin exec ('if exists (select * from ' + @tablename + ' where rowguidcol = ' + @guidstring + ' and (' + @boolean + ')) update #found set flag = 1') if @@ERROR<>0 return (1) select @retval = flag from #found if @retval = 1 goto EndLabel end /* Loop over join filters, populating #probe */ select @join_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick while @join_id is not null begin select @boolean = join_filterclause, @join_nick = join_nickname from sysmergesubsetfilters where pubid = @pubid and join_filterid = @join_id exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @join_table out, @pubid if @@ERROR<>0 or @retcode<>0 return (1) set @join_nickstr = convert(nchar(10), @join_nick) /* execute a query to put these into the #probe table */ exec ('insert into #probe (tablenick, rowguid, tested) select distinct ' + @join_nickstr + ', ' + @join_table + '.rowguidcol, 0 from ' + @tablename + ', ' + @join_table + ' where ' + @tablename + '.rowguidcol = ' + @guidstring + ' and (' + @boolean + ') and not exists (select * from #probe where tablenick = ' + @join_nickstr + ' and rowguidcol = ' + @join_table + '.rowguidcol) ' ) if @@ERROR<>0 begin return (1) end /* get to next join filter and repeat */ set @last_joinid = @join_id select @join_id = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick and join_filterid > @last_joinid end /* Loop over probe, making recursive call */ select @probe_id = min(probe_id) from #probe where probe_id > @last_probe and tested = 0 while @probe_id is not null begin select @join_nick = tablenick, @join_guid = rowguidcol from #probe where probe_id = @probe_id set @last_probe = @probe_id /* update tested flag on this row so we don't try it again while recursing */ update #probe set tested = 1 where probe_id = @probe_id /* Make recursive call. If it belongs, we are done. */ exec @retcode = dbo.sp_MSbelongs @publisher, @publisher_db, @publication, @join_nick, @join_guid, @retval output, 1 if @@ERROR<>0 OR @retcode<>0 begin return (1) end if @retval = 1 goto EndLabel /* get next probe_id and repeat */ select @probe_id = min(probe_id) from #probe where probe_id > @last_probe and tested = 0 end /* All Done, delete temps if not nested */ EndLabel: if @nested = 0 begin drop table #found drop table #probe end return go exec dbo.sp_MS_marksystemobject sp_MSbelongs go grant exec on dbo.sp_MSbelongs to public go raiserror('Creating procedure sp_MSexpandbelongs', 0,1) GO -- Modify temp table. No security check needed. create procedure sp_MSexpandbelongs @pubid uniqueidentifier AS declare @filterid int declare @retval int declare @expand_proc sysname /* We iterate over the join filters */ select @filterid = min(flag) from #belong select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filterid and exists (select * from #belong where tablenick = join_nickname and flag < join_filterid) while (@filterid is not null) begin select @expand_proc = expand_proc from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid exec @retval = @expand_proc @belong = 1 if @retval <> 0 return (1) select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filterid and exists (select * from #belong where tablenick = join_nickname and flag < join_filterid) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSexpandbelongs go grant exec on dbo.sp_MSexpandbelongs to public go raiserror('Creating procedure sp_MSexpandnotbelongs', 0,1) GO -- Modify temp table. No security check needed. create procedure sp_MSexpandnotbelongs @pubid uniqueidentifier AS declare @filterid int declare @retval int declare @expand_proc sysname /* We iterate over the join filters */ select @filterid = min(flag) from #notbelong select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filterid and exists (select * from #notbelong where tablenick = join_nickname and flag < join_filterid) while (@filterid is not null) begin select @expand_proc = expand_proc from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid exec @retval = @expand_proc @belong = 0 if @retval <> 0 return (1) select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and join_filterid > @filterid and exists (select * from #notbelong where tablenick = join_nickname and flag < join_filterid) end go exec dbo.sp_MS_marksystemobject sp_MSexpandnotbelongs go grant exec on dbo.sp_MSexpandnotbelongs to public go raiserror('Creating procedure sp_MSsetupbelongs', 0,1) GO -- Modify temp table. No security check needed. create procedure sp_MSsetupbelongs @publisher sysname, @publisher_db sysname, @publication sysname, @genlist varchar(1000), @commongen int, @subissql int AS declare @pubid uniqueidentifier declare @temp_id int declare @retval int declare @tablenick int declare @tnstr nvarchar(12) declare @rowguid uniqueidentifier declare @rowguidstr nvarchar(40) declare @belongsname sysname declare @notbelongsname sysname declare @artnick int declare @artnickstr nvarchar(10) declare @artviewobjid int declare @procname sysname declare @artbaseobjid int declare @artviewname sysname declare @artviewowner sysname declare @commongenstr nvarchar(12) declare @partchangegen int declare @joinchangegen int declare @rgcol sysname declare @maxfilterid int declare @view_type int declare @temp_view int declare @retcode smallint /* ** To public */ set @temp_view = 2 select @pubid = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db set @commongenstr = convert(nchar(12), @commongen) /* Set up the ##belong and ##notbelong tables; return names as rowset */ /* step 1 make temptable names, create tables */ set @rowguid = newid() exec @retcode=sp_MSguidtostr @rowguid, @rowguidstr out if @retcode<>0 or @@ERROR<>0 return (1) set @belongsname = '##belong' + @rowguidstr exec @retcode = dbo.sp_MSuniquetempname @belongsname, @belongsname out IF @@ERROR<>0 OR @retcode<>0 return (1) create table #belong (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL, partchangegen int null, joinchangegen int null) create index #indbelong on #belong (rowguid) exec ('create table ' + @belongsname + ' (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(255) NULL, colv varbinary(2048) NULL) ') if @@ERROR <>0 return (1) create table #notbelong (bookmark int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL, partchangegen int null, joinchangegen int null) create index #indnbelong on #notbelong (tablenick, rowguid) set @notbelongsname = '##notbelong' + @rowguidstr exec @retcode = dbo.sp_MSuniquetempname @notbelongsname, @notbelongsname out IF @@ERROR<>0 OR @retcode<>0 return (1) exec ('create table ' + @notbelongsname + ' (tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, generation int NULL, lineage varbinary(255) NULL, type tinyint NOT NULL) ') if @@ERROR <>0 return (1) create table #temp_cont (temp_id int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, partchangegen int null, joinchangegen int null) /* step 2 setup pass through MSmerge_contents */ /* article with permanent views can be handled with bulk inserts */ set @artnick = 0 set rowcount 0 /* Get first article, go into loop */ select @artnick = min(nickname) from sysmergearticles where pubid = @pubid and nickname > @artnick /* Put all relevant changes in #notbelong to start. It simplifies the queries greatly, ** and we can delete out the rows from #belong efficiently at the end. */ exec ('insert into #notbelong (tablenick, rowguid, flag, partchangegen, joinchangegen) select tablenick, c.rowguid, 0, partchangegen, joinchangegen from MSmerge_contents c where generation in (' + @genlist + ')') if @@ERROR <>0 return (1) while (@artnick is not null) begin set @artnickstr = convert(nchar(10), @artnick) select @artviewobjid = sync_objid, @artbaseobjid = objid, @view_type = view_type, @procname = view_sel_proc from sysmergearticles where pubid = @pubid and nickname = @artnick /* Get name of rowguidcol. Aliasing doesn't work through a view. */ select @rgcol = name from syscolumns where id = @artbaseobjid and ColumnProperty(@artbaseobjid, name, 'isrowguidcol') = 1 /* UNDONE get view type from sysmergearticle to see if permanent view to use */ set @artviewname = NULL if @view_type <> @temp_view select @artviewname = name, @artviewowner = user_name(uid) from sysobjects where id = @artviewobjid if (@procname is not null) begin exec @retcode = @procname @artnick if @@ERROR <>0 or @retcode <> 0 return (1) end else begin delete from #temp_cont exec ('insert into #temp_cont (tablenick, rowguid, partchangegen, joinchangegen) select tablenick, rowguid, partchangegen, joinchangegen from MSmerge_contents where tablenick = ' + @artnickstr + ' and generation in (' + @genlist + ') ') if @@ERROR <>0 return (1) set @temp_id = 0 select @temp_id = min(temp_id) from #temp_cont where temp_id > @temp_id while (@temp_id is not null) begin select @tablenick = tablenick, @rowguid = rowguid, @partchangegen = partchangegen, @joinchangegen = joinchangegen from #temp_cont where temp_id = @temp_id set @rowguidstr = '''' + convert(nchar(36), @rowguid) + '''' exec @retcode = dbo.sp_MSbelongs @publisher, @publisher_db, @publication, @tablenick, @rowguid, @retval output, 0 if @@ERROR<>0 OR @retcode <>0 if @retval = 1 begin insert into #belong (tablenick, rowguid, flag, partchangegen, joinchangegen) values (@artnick, @rowguid, 0, @partchangegen, @joinchangegen) if @@ERROR <>0 return (1) end else begin /* Checking partchangegen will tell us if we need to insert this */ if @partchangegen > @commongen insert into #notbelong (tablenick, rowguid, flag) values (@artnick, @rowguid, 0) end select @temp_id = min(temp_id) from #temp_cont where temp_id > @temp_id end end /* Move on to next article, repeat while loop */ select @artnick = min(nickname) from sysmergearticles where pubid = @pubid and nickname > @artnick end drop table #temp_cont /* Clean up #notbelong by using #belong - we inserted with out really checking */ delete from #notbelong where rowguid in (select rowguid from #belong) delete from #notbelong where partchangegen < @commongen /* Optimization: If joinchangegen and partchange are both null or < common gen, ** it is not necessary to expand #belong for that particular row. */ select @maxfilterid = max(join_filterid) from sysmergesubsetfilters if @maxfilterid is not null begin update #belong set flag = @maxfilterid where (joinchangegen <= @commongen and (partchangegen is null or partchangegen <= @commongen)) /* Expand the #belong temptable */ exec @retcode = dbo.sp_MSexpandbelongs @pubid if @@ERROR<>0 OR @retcode<>0 return (1) end /* transfer rows from local temp to global temp */ exec ('insert into ' + @belongsname + ' (tablenick, rowguid, generation, lineage, colv) select b.tablenick, b.rowguid, c.generation, c.lineage, c.colv1 from #belong b left outer join MSmerge_contents c on c.tablenick = b.tablenick and c.rowguid = b.rowguid ') if @@ERROR <>0 return (1) /* If subscriber is sql server, we don't have to expand belongs */ if @subissql = 0 begin /* Expand the #notbelong temptable */ exec dbo.sp_MSexpandnotbelongs @pubid end /* transfer rows from local temp to global temp */ exec ('insert into ' + @notbelongsname + ' (tablenick, rowguid, generation, lineage, type) select b.tablenick, b.rowguid, c.generation, c.lineage, 5 from #notbelong b left outer join MSmerge_contents c on c.tablenick = b.tablenick and c.rowguid = b.rowguid ') if @@ERROR <>0 return (1) drop table #notbelong /* Add tombstones to ##notbelong */ exec ('insert into ' + @notbelongsname + ' (tablenick, rowguid, generation, lineage, type) select tablenick, rowguid, generation, lineage, type from MSmerge_tombstone where generation in (' + @genlist + ')') if @@ERROR <>0 return (1) if not exists (select * from #belong) select @belongsname, @notbelongsname, -1 else select distinct @belongsname, @notbelongsname, tablenick from #belong drop table #belong return (0) go exec dbo.sp_MS_marksystemobject sp_MSsetupbelongs go grant exec on dbo.sp_MSsetupbelongs to public go raiserror('Creating procedure sp_MSaddinitialarticle', 0,1) GO -- Called at the subscriber CREATE PROCEDURE sp_MSaddinitialarticle( @article sysname, /* Name of the article */ @artid uniqueidentifier, /* Article ID */ @pubid uniqueidentifier, /* Publication ID */ @nickname int, /* Article nickname */ @column_tracking int, /* Does the article have column tracking ? */ @status int, /* Status of the article */ @pre_creation_command int = 0, /* Precreate command of the article */ @resolver_clsid nvarchar(255) = NULL,/* Resolver module for the article */ @insert_proc nvarchar(255) = NULL,/* Insert sp for article */ @update_proc nvarchar(255) = NULL,/* Update sp for article */ @select_proc nvarchar(255) = NULL, /* Select SP for this article */ @destination_object sysname, /* Destination object name */ @missing_count int = NULL, @missing_cols varbinary(32) = NULL, @article_resolver nvarchar(255) = NULL, @resolver_info nvarchar(255) = NULL, @filter_clause nvarchar(2000) = NULL ) AS SET NOCOUNT ON declare @objid int declare @retcode int /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) if (@artid is NULL) BEGIN RAISERROR (14057, 16, -1) RETURN (1) END if (@resolver_clsid='') select @resolver_clsid = NULL if (@filter_clause='') set @filter_clause = NULL /* ** Populate the local copy of sysmergearticles */ if exists (select * from sysmergearticles where artid = @artid and pubid = @pubid ) begin update sysmergearticles set name = @article, artid = @artid, pre_creation_command = pre_creation_command, pubid = @pubid, nickname = @nickname, column_tracking = @column_tracking, status = @status, resolver_clsid = @resolver_clsid, insert_proc = @insert_proc, update_proc = @update_proc, select_proc = @select_proc, destination_object = @destination_object, missing_col_count = @missing_count, missing_cols = @missing_cols, article_resolver = @article_resolver, resolver_info = @resolver_info, subset_filterclause = @filter_clause where artid = @artid and pubid = @pubid end else begin select @objid = 0 insert sysmergearticles (name, objid, sync_objid, artid, pre_creation_command, pubid, nickname, column_tracking, status, resolver_clsid, insert_proc, update_proc, select_proc, destination_object, missing_col_count, missing_cols, article_resolver, resolver_info, subset_filterclause) values (@article, @objid, @objid, @artid, @pre_creation_command, @pubid, @nickname, @column_tracking, @status, @resolver_clsid, @insert_proc, @update_proc, @select_proc, @destination_object, @missing_count, @missing_cols, @article_resolver, @resolver_info, @filter_clause) end IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) RETURN (1) END RETURN 0 go exec dbo.sp_MS_marksystemobject sp_MSaddinitialarticle go grant exec on dbo.sp_MSaddinitialarticle to public go raiserror('Creating procedure sp_MSaddinitialpublication', 0,1) GO CREATE PROCEDURE sp_MSaddinitialpublication( @publisher sysname, @publisher_db sysname, @publication sysname, /* Name of the publication */ @description nvarchar(255), /* Description of the publication */ @pubid uniqueidentifier, /* Publication ID */ @retention int, /* Retention period of the publication */ @sync_mode int, /* Sync mode of the publication */ @allow_push int, /* does publication allow push ? */ @allow_pull int, /* does publication allow pull ? */ @allow_anonymous int, /* does publication allow anonymous ? */ @centralized_conflicts int, /* publication does centralized conflicts ? */ @status int, /* publication's status */ @snapshot_ready int, /* publication snapshto_ready flag ? */ @enabled_for_internet int, /* publication enabled_for_internet flag ? */ @publication_type int /* a full publication or a partial one */ ) AS SET NOCOUNT ON declare @retcode int /* ** NOTE -- WORKAROUND ODBC BUG WHICH have not been reproed. */ select @publication = RTRIM(@publication) select @publisher_db = RTRIM(@publisher_db) /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) /* ** Populate the local copy of sysmergepublications */ BEGIN TRAN save TRAN MSaddinitialpublication if exists (select * from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db) begin declare @pubid_local uniqueidentifier select @pubid_local = pubid from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@publisher) and publisher_db=@publisher_db update sysmergesubscriptions SET pubid = @pubid where pubid = @pubid_local IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) goto FAILURE END if @pubid <> @pubid_local delete from sysmergesubscriptions where subid = @pubid update sysmergesubscriptions SET subid = @pubid where subid = @pubid_local IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) goto FAILURE END update sysmergesubscriptions SET partnerid = @pubid where partnerid = @pubid_local IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) goto FAILURE END update sysmergepublications SET pubid = @pubid, name = @publication, description = @description, designmasterid = @pubid, retention = @retention, parentid = pubid, sync_mode = sync_mode, allow_push = @allow_push, allow_pull = @allow_pull, allow_anonymous = @allow_anonymous, centralized_conflicts = @centralized_conflicts, status = @status, snapshot_ready = @snapshot_ready, enabled_for_internet = @enabled_for_internet, publication_type = @publication_type where name = @publication and UPPER(publisher) = UPPER(@publisher) and publisher_db = @publisher_db end else begin insert sysmergepublications(publisher, publisher_db,pubid, name, description, designmasterid, retention, parentid, sync_mode, allow_push, allow_pull, allow_anonymous, centralized_conflicts, status, snapshot_ready, enabled_for_internet, publication_type) values(@publisher, @publisher_db, @pubid, @publication, @description, @pubid, @retention, @pubid, @sync_mode, @allow_push, @allow_pull, @allow_anonymous, @centralized_conflicts, @status, @snapshot_ready, @enabled_for_internet, @publication_type) end IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) goto FAILURE END COMMIT TRAN RETURN (0) FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION MSaddinitialpublication COMMIT TRANSACTION end RETURN (1) go exec dbo.sp_MS_marksystemobject sp_MSaddinitialpublication go grant exec on dbo.sp_MSaddinitialpublication to public go raiserror('Creating procedure sp_MSaddinitialsubscription', 0,1) GO CREATE PROCEDURE sp_MSaddinitialsubscription( @pubid uniqueidentifier, /* Publication ID */ @subid uniqueidentifier, /* Subscription's replica ID */ @partnerid uniqueidentifier, /* Partner's replica ID */ @subscriber sysname, /* Subscriber server */ @subscriber_db sysname, /* Subscriber database */ @subscriber_priority real = 0.0, /* Subscriber priority */ @subscriber_type tinyint = 0, /* Subscriber type - local, global, or anonymous */ @subscription_type int = 0, /* Subscription type - push or pull */ @sync_type tinyint = 2 /* Subscription sync type 1 = no sync, 2 = automatic */ ) AS SET NOCOUNT ON /* ** Declarations. */ DECLARE @local tinyint DECLARE @anonymous tinyint DECLARE @subscriber_srvid int DECLARE @subnickname int DECLARE @active tinyint DECLARE @retcode int DECLARE @subid_old uniqueidentifier /* ** Initializations */ SET @local = 2 SET @anonymous = 3 set @active = 1 /* after this SP is called, the subscription is activated */ select @subscriber_db = RTRIM(@subscriber_db) /* ** Check for subscribing permission ** It is called by merge agent at the publisher side ** subscriber side? */ -- @pubid is not local exec @retcode= dbo.sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) -- this gets executed at both publisher (for pull subscriptions) and at subscriber -- if server is not found use srvid of 0 for local srvid select @subscriber_srvid = srvid from master..sysservers where srvname = @subscriber if @subscriber_srvid is null set @subscriber_srvid = 0 begin tran save TRAN MSaddinitialsubscription /* ** Populate the local copy of sysmergesubscriptions */ if exists (select * from sysmergesubscriptions where subid = @subid) begin update sysmergesubscriptions SET subid = @subid, datasource_type = 0, datasource_path = NULL, srvid = @subscriber_srvid, db_name = @subscriber_db, pubid = @pubid, status = @active, subscriber_type = @subscriber_type, subscription_type = @subscription_type, priority = @subscriber_priority, sync_type = @sync_type where subid = @subid IF @@ERROR <> 0 BEGIN goto FAILURE END end if exists (select * from sysmergesubscriptions where srvid = @subscriber_srvid AND db_name = @subscriber_db AND pubid = @pubid) begin select @subid_old = subid from sysmergesubscriptions where srvid = @subscriber_srvid AND db_name = @subscriber_db AND pubid = @pubid update sysmergesubscriptions SET subid = @subid, datasource_type = 0, datasource_path = NULL, srvid = @subscriber_srvid, db_name = @subscriber_db, pubid = @pubid, status = @active, subscriber_type = @subscriber_type, subscription_type = @subscription_type, priority = @subscriber_priority, sync_type = @sync_type where srvid = @subscriber_srvid AND db_name = @subscriber_db AND pubid = @pubid IF @@ERROR <> 0 BEGIN goto FAILURE END if (@subid_old IS NOT NULL) begin /* ** Delete old row for subscriber from MSmerge_replinfo. */ DELETE from MSmerge_replinfo where repid = @subid_old IF @@ERROR <> 0 BEGIN goto FAILURE END EXECUTE @retcode = dbo.sp_MSgenreplnickname @subid, @subnickname output if @@ERROR<>0 or @retcode<>0 goto FAILURE /* ** Add new row for subscriber to MSmerge_replinfo. */ INSERT INTO MSmerge_replinfo(repid, replnickname) values (@subid, @subnickname) IF @@ERROR <> 0 BEGIN goto FAILURE END end end else begin 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, 0, NULL, @subscriber_srvid, @subscriber_db, @pubid, @active, @subscriber_type, @subscription_type, @subscriber_priority, @sync_type, NULL, suser_sname(suser_sid())) IF @@ERROR <> 0 BEGIN goto FAILURE END /* Look for existing nickname from any other subscription */ select @subnickname = max(replnickname) from MSmerge_replinfo, sysmergesubscriptions where repid = subid and srvid = @subscriber_srvid and db_name = @subscriber_db /* Generate a new replica nickname from the @subid */ if (@subnickname is null) begin EXECUTE @retcode = dbo.sp_MSgenreplnickname @subid, @subnickname output if @@ERROR<>0 or @retcode<>0 goto FAILURE end /* ** Add row for subscriber to MSmerge_replinfo. */ INSERT INTO MSmerge_replinfo(repid, replnickname) values (@subid, @subnickname) IF @@ERROR <> 0 BEGIN goto FAILURE END end COMMIT TRAN RETURN 0 FAILURE: /* UNDONE : This code is specific to 6.X nested transaction semantics */ if @@TRANCOUNT > 0 begin ROLLBACK TRANSACTION MSaddinitialsubscription COMMIT TRANSACTION end RAISERROR (14057, 16, -1) RETURN 1 go exec dbo.sp_MS_marksystemobject sp_MSaddinitialsubscription go grant exec on dbo.sp_MSaddinitialsubscription to public go raiserror('Creating procedure sp_MSmakearticleprocs', 0,1) GO create procedure sp_MSmakearticleprocs (@pubid uniqueidentifier, @artid uniqueidentifier) as declare @ownername sysname declare @objectname sysname declare @ins_procname sysname declare @sel_procname sysname declare @upd_procname sysname declare @guidstr nvarchar(40) declare @ext nvarchar(10) declare @trigname sysname declare @objid int declare @dbname sysname declare @command nvarchar(1000) -- to be called after article is set up in a subscriber declare @retcode smallint /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) select @objid = max(objid) from sysmergearticles where artid = @artid -- get owner name, and table name select @objectname = name, @ownername = user_name(uid) from sysobjects where id = @objid -- get the insert and update proc names from sys articles select @ins_procname = insert_proc, @upd_procname = update_proc, @sel_procname = select_proc from sysmergearticles where pubid = @pubid and artid = @artid -- create the procs set @dbname = db_name() /* If procedure already exists because article in multiple pubs don't bother */ if not exists (select * from sysobjects where name = @ins_procname and type = 'P') begin set @command = 'sp_MSmakeinsertproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @ins_procname + ', [' + convert(nchar(36), @pubid) + ']' exec @retcode = master..xp_execresultset @command, @dbname if @@ERROR<>0 OR @retcode <>0 return (1) exec @retcode = dbo.sp_MS_marksystemobject @ins_procname if @@ERROR<>0 return (1) end exec ('grant exec on ' + @ins_procname + ' to public') if @@ERROR<>0 return (1) /* If procedure already exists because article in multiple pubs don't bother */ if not exists (select * from sysobjects where name = @upd_procname and type = 'P') begin set @command = 'sp_MSmakeupdateproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @upd_procname exec @retcode = master..xp_execresultset @command, @dbname if @@ERROR<>0 OR @retcode <>0 return (1) exec @retcode = dbo.sp_MS_marksystemobject @upd_procname if @@ERROR<>0 return (1) exec ('grant exec on ' + @upd_procname + ' to public') if @@ERROR<>0 return (1) end /* If procedure already exists because article in multiple pubs don't bother */ if not exists (select * from sysobjects where name = @sel_procname and type = 'P') begin set @command = 'sp_MSmakeselectproc ' + QUOTENAME(@objectname) + ' , ' + QUOTENAME(@ownername) + ' , ' + @sel_procname exec (@command) if @@ERROR<>0 return (1) exec @retcode = dbo.sp_MS_marksystemobject @sel_procname if @@ERROR<>0 return (1) exec ('grant exec on ' + @sel_procname + ' to public') if @@ERROR<>0 return (1) end go exec dbo.sp_MS_marksystemobject sp_MSmakearticleprocs go grant exec on dbo.sp_MSmakearticleprocs to public go raiserror('Creating procedure sp_MSupdatesysmergearticles', 0,1) GO CREATE PROCEDURE sp_MSupdatesysmergearticles( @object sysname, /* Name of the table */ @artid uniqueidentifier, /* Article ID */ @owner sysname = NULL ) AS declare @merge_pub_object_bit int declare @id int declare @qualified_name nvarchar(268) SET NOCOUNT ON declare @retcode int if @owner is NULL or @owner = '' begin if exists (select name from sysobjects where id = object_id(@object)) select @owner = user_name(uid) from sysobjects where id = object_id(QUOTENAME(@object)) else begin raiserror(21078, 16, -1, @object) return (1) end end select @qualified_name = QUOTENAME(@owner) + '.' + QUOTENAME(@object) /* ** Check to see if current publication has permission */ /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) select @merge_pub_object_bit = 128 if (@artid is NULL) BEGIN RAISERROR (14057, 16, -1) RETURN (1) END begin tran if exists (select name from sysobjects where id = object_id(@qualified_name)) begin exec dbo.sp_replupdateschema @qualified_name update sysobjects set replinfo = replinfo | @merge_pub_object_bit where id=object_id(@qualified_name) if @@ERROR<>0 goto UNDO /* ** update the local copy of sysmergearticles */ update sysmergearticles set objid = OBJECT_ID(@qualified_name) where artid = @artid IF @@ERROR <> 0 BEGIN RAISERROR (14057, 16, -1) goto UNDO END end else -- THIS IS FINE. This dynimic query is there to provide a good error message. No need to use SP. raiserror(21078, 16, -1, @object) commit tran RETURN 0 UNDO: if @@TRANCOUNT = 1 ROLLBACK TRAN else COMMIT TRAN RETURN 1 go exec dbo.sp_MS_marksystemobject sp_MSupdatesysmergearticles go grant exec on dbo.sp_MSupdatesysmergearticles to public go raiserror('Creating procedure sp_MSmakeinsertproc', 0,1) GO -- This will be called by snapshot at publisher side and -- merge at the subscriber side, check for dbo permission create procedure sp_MSmakeinsertproc (@tablename sysname, @ownername sysname, @procname sysname, @pubid uniqueidentifier) as declare @argname sysname declare @id int declare @qualified_name nvarchar(255) declare @idstr nvarchar(100) if @ownername is NULL or @ownername='' select @qualified_name = QUOTENAME(@tablename) else select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename) select @id = object_id(@qualified_name) if @id is NULL return (1) set @idstr = rtrim(convert(nchar, @id)) declare @retcode smallint declare @colname sysname declare @rgcolname sysname declare @typename sysname declare @colid smallint declare @status tinyint declare @len smallint declare @prec smallint declare @scale int declare @tablenick int declare @tablenickstr nvarchar(12) declare @colordinal smallint declare @cmdpiece nvarchar(4000) set nocount on /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output IF @@ERROR <> 0 or @retcode <>0 return (1) set @tablenickstr = rtrim(convert(nchar, @tablenick)) -- create temp table to select the command text out of create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) NULL) -- insert text pieces that don't repeat for each column -- phase 0 : create procedure and fixed part of argument list set @cmdpiece = 'create procedure dbo.' + QUOTENAME(@procname) + ' (@rowguid uniqueidentifier, @generation int, @lineage varbinary(255), @colv varbinary(2048) ' insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece) -- phase 1 is rest of argument list; goes in during loop over columns -- phase 2 : paren to close argument list, and variable declarations set @cmdpiece = ') as declare @tablenick int declare @success int declare @retcode int exec @retcode = dbo.sp_MSreplcheck_connection @objid = ' + @idstr + ' if @retcode<>0 or @@ERROR<>0 return (3) select @tablenick = ' + @tablenickstr + ' set @success = 0 ' insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece) -- phase 3 is optional set identity insert on, goes in during loop if needed -- phase 4 is beginning a sub transaction, setting save point and starting insert statement set @cmdpiece = ' begin transaction sub save transaction sp1 exec dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage, @colv, 2 insert into ' + @qualified_name + ' (' insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece) -- phase 5 is column list that we are inserting; done in loop -- phase 6 is just the opening and closing parens and VALUES keyword set @cmdpiece = ') values (' insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece) -- phase 7 is all of those arguments as the list of value expressions; done in loop -- phase 8 finish insert, check status, etc. -- if we have a permanent view, check for case where we inserted a row that doesn't -- meet filters of subscriber we are getting the insert from set @cmdpiece = ') if (@@rowcount = 1) begin set @success = 1 end else begin select @success = 3 end ' insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece) if exists (select * from sysmergearticles where pubid = @pubid and objid = @id and view_type = 1) begin /* Get name of rowguidcol. Aliasing doesn't work through a view. */ select @rgcolname = QUOTENAME(name) from syscolumns where id = @id and ColumnProperty(@id, name, 'isrowguidcol') = 1 if @rgcolname is null set @rgcolname = 'rowguid' select @cmdpiece = ' if not exists (select * from ' + QUOTENAME(OBJECT_NAME(sync_objid)) from sysmergearticles where pubid = @pubid and objid = @id set @cmdpiece = @cmdpiece + ' where ' + @rgcolname + ' = @rowguid) begin update MSmerge_contents set generation = 0, partchangegen = 0 where rowguid = @rowguid and tablenick = @tablenick end ' insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece) end set @cmdpiece = ' if (@success = 3) begin rollback transaction sp1 end commit transaction ' insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece) -- phase 9 is setting identity insert off if needed; done in loop -- phase 10 is returning our success / failure status set @cmdpiece = ' return @success' insert into #tempcmd (phase, cmdtext) values (10, @cmdpiece) -- now loop over columns and insert missing command pieces select @colid = min (colid) from syscolumns where id = @id and iscomputed<>1 select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @len = length, @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale from syscolumns where id = @id and colid = @colid if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes select @len = @len/2 set @colordinal = 1 while (@colname is not null) begin exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale if @@error<>0 OR @retcode <>0 return (1) select @argname = '@p' + rtrim(convert(nchar, @colordinal)) -- add to argument list (phase 1) set @cmdpiece = ', ' + @argname + ' ' + @typename insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece) -- add to column list and value list if (@colordinal = 1) begin -- column list is phase 5 set @cmdpiece = @colname insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece) -- argname for values list is phase 7 set @cmdpiece = @argname insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece) end else begin -- column list is phase 5; need preceding comma since not the first one. set @cmdpiece = ', ' + @colname insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece) -- argname for values list is phase 7 need preceding comma since not the first one. set @cmdpiece = ', ' + @argname insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece) end -- is this an identity column? if (@status = 128) begin -- turning identity insert on is phase 3 set @cmdpiece = ' set identity_insert ' + @qualified_name + ' on' insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece) -- turning identity insert on is phase 9 set @cmdpiece = ' set identity_insert ' + @qualified_name + ' off' insert into #tempcmd (phase, cmdtext) values (9, @cmdpiece) end -- now set up to repeat the loop with the next column select @colid = min (colid) from syscolumns where id = @id and colid > @colid and iscomputed<>1 set @colname = NULL if @colid is not null select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @len = length, @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale from syscolumns where id = @id and colid = @colid if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes select @len = @len/2 set @colordinal = @colordinal + 1 end -- Now we select out the command text pieces in proper order so that our caller, -- xp_execresultset will execute the command that creates the stored procedure. select cmdtext from #tempcmd order by phase, step go exec dbo.sp_MS_marksystemobject sp_MSmakeinsertproc go grant exec on dbo.sp_MSmakeinsertproc to public go raiserror('Creating procedure sp_MSmakeupdateproc', 0,1) GO -- This will be called by snapshot at publisher side and -- merge at the subscriber side, check for dbo permission create procedure sp_MSmakeupdateproc (@tablename sysname, @ownername sysname, @procname sysname) as declare @retcode smallint declare @argname nvarchar(10) declare @varname nvarchar(10) declare @cmdpiece nvarchar(4000) declare @qualified_name nvarchar(255) declare @littlecomp nvarchar(300) declare @id int declare @idstr nvarchar(100) set nocount on if @ownername is NULL or @ownername='' select @qualified_name = QUOTENAME(@tablename) else select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename) select @id = object_id(@qualified_name) if @id is NULL return (1) set @idstr = rtrim(convert(nchar, @id)) declare @colname sysname declare @typename sysname declare @colid smallint declare @colordinal smallint declare @colordstr nvarchar(4) declare @status tinyint declare @len smallint declare @blen smallint declare @prec smallint declare @scale int declare @tablenick int declare @tablenickstr nvarchar(12) /* ** Check for dbo permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) execute @retcode = dbo.sp_MStablenickname @ownername, @tablename, @tablenick output if @@ERROR <>0 OR @retcode <>0 return (1) set @tablenickstr = rtrim(convert(nchar, @tablenick)) -- create temp table to select the command text out of create table #tempcmd (phase int NOT NULL, step int identity NOT NULL, cmdtext nvarchar(4000) NULL) -- insert text pieces that don't repeat for each column -- phase 0 : create procedure and fixed part of argument list set @cmdpiece = 'Create procedure dbo.' + @procname + ' (@rowguid uniqueidentifier, @setbm varbinary(125) = NULL, @metadata_type tinyint, @lineage_old varbinary(255), @generation int, @lineage_new varbinary(255), @colv varbinary(2048) ' insert into #tempcmd (phase, cmdtext) values (0, @cmdpiece) -- phase 1 is rest of argument list; goes in during loop over columns -- phase 2 paren to close argument list and fixed variable declarations set @cmdpiece = ') as declare @tablenick int declare @failure int declare @success int declare @fset int declare @match int declare @retcode smallint exec @retcode = dbo.sp_MSreplcheck_connection @objid = ' + @idstr + ' if @retcode<>0 or @@ERROR<>0 return (3) select @tablenick = ' + @tablenickstr + ' set @failure = 0 ' insert into #tempcmd (phase, cmdtext) values (2, @cmdpiece) -- phase 3 is rest of variable declarations; goes in during loop over columns -- phase 4 begin a transaction, set savepoint in case we roll back, begin select to get current values set @cmdpiece = 'begin transaction sub save transaction sp1 select @success = 2' insert into #tempcmd (phase, cmdtext) values (4, @cmdpiece) -- phase 5 is middle part of select assigning column values to local variables -- goes in loop -- phase 6 -- finish the select, check that metadata matches set @cmdpiece = ' from ' + @qualified_name + ' (updlock) where rowguidcol = @rowguid set @match = @@rowcount exec dbo.sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output if (@match = 1) begin select @success = 1 ' insert into #tempcmd (phase, cmdtext) values (6, @cmdpiece) -- phase 7 is a bunch of if's that compare old values with new values ; goes in during loop -- phase 8 finish the stored procedure set @cmdpiece = ' if (@failure = 0) exec dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, @colv, 2 end if (@failure = 1) begin rollback transaction sp1 select @success = 3 end commit transaction return @success' insert into #tempcmd (phase, cmdtext) values (8, @cmdpiece) -- now do the loop over all columns and insert the missing pieces -- don't script out computed columns select @colid = min (colid) from syscolumns where id = @id and iscomputed <> 1 select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @blen = length, @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale from syscolumns where id = @id and colid = @colid if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes set @len = @blen/2 else set @len = @blen set @colordinal = 1 while (@colname is not null) begin if (@status = 128) begin -- just skip past identity columns as they can't be updated select @colid = min (colid) from syscolumns where id = @id and colid > @colid and iscomputed<>1 set @colname = NULL select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @blen = length, @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale from syscolumns where id = @id and colid = @colid if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes set @len = @blen/2 else set @len = @blen set @colordinal = @colordinal + 1 end set @colordstr = convert(nvarchar(4), @colordinal) exec @retcode = dbo.sp_MSmaptype @typename out, @len, @prec, @scale if @@ERROR <>0 OR @retcode <>0 return (1) -- put in argument list element (phase 1) set @argname = '@p' + rtrim(@colordstr) set @cmdpiece = ', ' + @argname + ' ' + @typename + ' = NULL ' insert into #tempcmd (phase, cmdtext) values (1, @cmdpiece) -- put in declaration for variable (phase 3) -- text and image get no variable if (@typename <> 'ntext' and @typename <> 'text' and @typename <> 'image') begin set @varname = '@l' + rtrim(@colordstr) set @cmdpiece = 'declare ' + @varname + ' ' + @typename + ' ' insert into #tempcmd (phase, cmdtext) values (3, @cmdpiece) -- put in set piece to initialize variable to old value in select statement (phase 5) set @cmdpiece = ', ' + @varname + ' = ' + @colname insert into #tempcmd (phase, cmdtext) values (5, @cmdpiece) -- put in if piece that compares old value with new, checks bit if argument is null if (@typename like '%char%') begin -- Compare binaries instead of variables so that case changes are caught as different set @littlecomp = 'convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @argname + ') = convert(varbinary(' + rtrim(convert(nchar, @blen)) + '), ' + @varname + ')' end else begin set @littlecomp = @argname + ' = ' + @varname end set @cmdpiece = ' if ' + @littlecomp + ' set @fset = 0 else if ' + @argname + ' is not null set @fset = 1 else exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + ' if @fset <> 0 begin update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid if (@@rowcount <> 1) set @failure = 1 end ' insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece) end else begin -- for text and image, we just test if argument is null and whether bit is set -- build conditional update (phase 7) set @cmdpiece = ' if ' + @argname + ' is not null set @fset = 1 else exec @fset = dbo.sp_MStestbit @setbm, ' + @colordstr + ' if @fset <> 0 begin update ' + @qualified_name + ' set ' + @colname + ' = ' + @argname + ' where rowguidcol = @rowguid if (@@rowcount <> 1) set @failure = 1 end ' -- Now insert the command to temp table insert into #tempcmd (phase, cmdtext) values (7, @cmdpiece) end -- Advance loop to next column and repeat! select @colid = min (colid) from syscolumns where id = @id and colid > @colid and iscomputed<>1 set @colname = NULL if (@colid is not null) begin select @colname = QUOTENAME(name), @status = status, @typename = type_name(xtype), @blen = length, @prec = COLUMNPROPERTY(id, name, 'precision'), @scale = scale from syscolumns where id = @id and colid = @colid if @typename='nvarchar' or @typename='nchar' -- a unit of nchar takes 2 bytes set @len = @blen/2 else set @len = @blen set @colordinal = @colordinal + 1 end end -- Now we select out the command text pieces in proper order so that our caller, -- xp_execresultset will execute the command that creates the stored procedure. select cmdtext from #tempcmd order by phase, step go exec dbo.sp_MS_marksystemobject sp_MSmakeupdateproc go grant exec on dbo.sp_MSmakeupdateproc to public go raiserror('Creating procedure sp_MSmakeselectproc', 0,1) GO create procedure sp_MSmakeselectproc (@tablename sysname, @ownername sysname, @procname sysname) as declare @retcode smallint declare @argname nvarchar(10) declare @varname nvarchar(10) declare @cmdpiece nvarchar(4000) declare @qualified_name nvarchar(255) declare @column_list nvarchar(4000) declare @littlecomp nvarchar(300) declare @colid int declare @col_name sysname declare @id int set nocount on if @ownername is NULL or @ownername='' select @qualified_name = QUOTENAME(@tablename) else select @qualified_name = QUOTENAME(@ownername) + '.' + QUOTENAME(@tablename) select @id = object_id(@qualified_name) if @id is NULL return (1) /* ** Dynamically generate column list excluding computed columns */ if EXISTS (select name from syscolumns where id=@id and iscomputed=1) BEGIN select @column_list = '' DECLARE column_cursor CURSOR LOCAL FAST_FORWARD FOR select name from syscolumns where id=@id and iscomputed<>1 FOR READ ONLY open column_cursor fetch next from column_cursor into @col_name WHILE (@@fetch_status <> -1) BEGIN if LOWER(@col_name)='rowguid' select @col_name = 'rowguidcol' --Use alias to avoid conflict with #cont table else set @col_name = QUOTENAME(@col_name) if @column_list='' select @column_list = @col_name else select @column_list = @column_list + ', ' + @col_name fetch next from column_cursor into @col_name END close column_cursor deallocate column_cursor if @column_list='' begin RAISERROR(21125, 16, -1) return (1) end END else select @column_list = '*' /* ** Check for dbo permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) set @cmdpiece = 'Create procedure dbo.' + QUOTENAME(@procname) + ' (@type int, @rowguid uniqueidentifier=NULL) AS declare @retcode int declare @objid int select @objid = object_id(''' + @qualified_name + ''') exec @retcode = dbo.sp_MSreplcheck_connection @objid=@objid if @@ERROR<>0 or @retcode<>0 return (1) if @type = 1 select ' + @column_list + ' from ' + @qualified_name + ' where rowguidcol = @rowguid else if @type < 4 select c.tablenick, c.rowguid, c.generation, c.lineage, c.colv1, ' + @column_list + ' from ' + @qualified_name + ' t, #cont c where t.rowguidcol = c.rowguid order by c.rowguid else if @type = 4 select 1 from ' + @qualified_name + ' where rowguidcol = @rowguid else if @type = 5 delete ' + @qualified_name + ' where rowguidcol = @rowguid else if @type = 6 -- sp_MSenumcolumns select ' + @column_list + ' from ' + @qualified_name + ' where 1=2 else if @type = 7 -- sp_MSlocktable select count(*) from ' + @qualified_name + '(tablock holdlock) where 1 = 2 else if @type = 8 -- put update lock if not exists (select * from ' + @qualified_name + '(UPDLOCK) where rowguidcol = @rowguid) RAISERROR(20031 , 16, -1)' exec (@cmdpiece) go exec dbo.sp_MS_marksystemobject sp_MSmakeselectproc go grant exec on dbo.sp_MSmakeselectproc to public go raiserror('Creating procedure sp_MSdropconstraints', 0,1) GO -- This will be called merge at the subscriber side, check for dbo permission create procedure sp_MSdropconstraints @table sysname as declare @const_name sysname declare @objid int declare @retcode int /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) select @table=QUOTENAME(@table) set @objid = object_id(@table) if @objid is null return select @const_name = object_name(constid) from sysreferences where fkeyid = @objid while @const_name is not null begin exec ('alter table ' + @table + ' drop constraint ' + @const_name) if @@ERROR <> 0 return (1) set @const_name = NULL select @const_name = object_name(constid) from sysreferences where fkeyid = @objid end return (0) go exec dbo.sp_MS_marksystemobject sp_MSdropconstraints go grant exec on dbo.sp_MSdropconstraints to public go raiserror('Creating procedure sp_MSinsertschemachange', 0,1) GO CREATE PROCEDURE sp_MSinsertschemachange( @pubid uniqueidentifier, @artid uniqueidentifier = NULL, /* Can be NULL for directory commands */ @schemaversion int, @schemaguid uniqueidentifier, @schematype int, @schematext nvarchar(2000) ) as declare @retcode int /* ** Check for subscribing permission */ exec @retcode=sp_MSreplcheck_subscribe if @retcode<>0 or @@ERROR<>0 return (1) /* Parameter validation */ if (@schemaversion is null) begin RAISERROR(14043, 16, -1, '@schemaversion') return (1) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20001 , 16, -1) return (1) end insert into sysmergeschemachange with (HOLDLOCK TABLOCKX) (pubid, artid, schemaversion, schemaguid, schematype, schematext) values (@pubid, @artid, @schemaversion, @schemaguid, @schematype, @schematext) if @@error <> 0 begin RAISERROR(20001 , 16, -1) return (1) end /* update the schema version and schemaguid in MSmerge_replinfo */ declare @my_nickname int declare @srvid int select @srvid = 0 declare @repid uniqueidentifier select @my_nickname = replnickname, @repid = repid from MSmerge_replinfo where repid in (select subid from sysmergesubscriptions where srvid = @srvid and db_name = DB_NAME() and pubid = @pubid) update MSmerge_replinfo set schemaversion = @schemaversion where repid = @repid if @@error <> 0 begin RAISERROR(20001 , 16, -1) return (1) end update MSmerge_replinfo set schemaguid = @schemaguid where repid = @repid if @@error <> 0 begin RAISERROR(20001 , 16, -1) return (1) end return (0) go exec dbo.sp_MS_marksystemobject sp_MSinsertschemachange go grant exec on dbo.sp_MSinsertschemachange to public go raiserror('Creating procedure sp_MSvalidatearticle', 0, 1) GO create procedure sp_MSvalidatearticle @artid uniqueidentifier, @pubid uniqueidentifier, @expected_rowcount int = NULL OUTPUT, @expected_checksum numeric = NULL OUTPUT, @validation_type int = NULL, @full_or_fast tinyint = 2 as -- get name of sync object and owner declare @objid int declare @syncobjid int declare @owner sysname declare @object sysname declare @view_type tinyint declare @temp_view tinyint declare @retcode int declare @rowcount_only bit /* ** Check to see if current publication has permission */ if @validation_type = 2 set @rowcount_only = 0 else set @rowcount_only = 1 exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) select @syncobjid = sync_objid, @objid = objid, @view_type = view_type from sysmergearticles where pubid = @pubid and artid = @artid if (@syncobjid is not null and @syncobjid <> 0) set @objid = @syncobjid select @object = name, @owner = user_name(uid) from sysobjects where id = @objid -- if sync object is a temp view, we can't do this... set @temp_view = 2 if @view_type = @temp_view begin RAISERROR (20069, 16, -1) return 1 end -- call sp_table_validation exec @retcode = dbo.sp_table_validation @object, @expected_rowcount OUTPUT, @expected_checksum OUTPUT, @rowcount_only, @owner, @full_or_fast return @retcode GO exec dbo.sp_MS_marksystemobject sp_MSvalidatearticle go grant exec on dbo.sp_MSvalidatearticle to public go raiserror('Creating procedure sp_MSsubscriptionvalidated', 0, 1) GO create procedure sp_MSsubscriptionvalidated @subid uniqueidentifier, @pubid uniqueidentifier as /* ** Check to see if current publication has permission */ declare @retcode int exec @retcode=sp_MSreplcheck_connection @pubid = @pubid if @retcode<>0 or @@ERROR<>0 return (1) update sysmergesubscriptions set last_validated = getdate() where subid = @subid and pubid = @pubid if @@rowcount <> 1 or @@error <> 0 begin RAISERROR (20070, 16, -1) return (1) end return (0) GO exec dbo.sp_MS_marksystemobject sp_MSsubscriptionvalidated go grant exec on dbo.sp_MSsubscriptionvalidated to public raiserror('Creating procedure sp_MSdroparticletombstones', 0, 1) GO create procedure sp_MSdroparticletombstones @artid uniqueidentifier as declare @tablenick int select @tablenick = nickname from sysmergearticles where artid = @artid if @tablenick is not null begin delete from MSmerge_tombstone where tablenick = @tablenick delete from MSmerge_contents where tablenick = @tablenick delete from MSmerge_genhistory where art_nick=@tablenick end return (0) GO exec dbo.sp_MS_marksystemobject sp_MSdroparticletombstones go grant exec on dbo.sp_MSdroparticletombstones to public raiserror('Creating procedure sp_MSproxiedmetadata', 0, 1) GO create procedure sp_MSproxiedmetadata @tablenick int, @rowguid uniqueidentifier, @lineage varbinary(256), @colv varbinary(2048) as declare @old_lin varbinary(256) declare @old_colv varbinary(2048) select @old_lin = lineage, @old_colv = colv1 from MSmerge_contents where tablenick = @tablenick and rowguid = @rowguid if (@old_lin IS NOT NULL) begin exec master..xp_proxiedmetadata @lineage out, @colv out, @old_lin, @old_colv update MSmerge_contents set lineage = @lineage, colv1 = @colv where tablenick = @tablenick and rowguid = @rowguid end else begin select @old_lin = lineage from MSmerge_tombstone where tablenick = @tablenick and rowguid = @rowguid if (@old_lin IS NULL) return (0) exec master..xp_proxiedmetadata @lineage out, @colv, @old_lin, NULL update MSmerge_tombstone set lineage = @lineage where tablenick = @tablenick and rowguid = @rowguid end return (0) GO exec dbo.sp_MS_marksystemobject sp_MSproxiedmetadata grant exec on dbo.sp_MSproxiedmetadata to public go raiserror('Creating procedure sp_MScontractsubsnb', 0,1) GO create PROCEDURE sp_MScontractsubsnb (@pubid uniqueidentifier, @tablenick int, @basetable nvarchar(258)) AS declare @filter_clause nvarchar(4000) declare @join_nick int declare @jointable nvarchar(258) declare @filterid int declare @retcode int declare @tablenickstr nvarchar(10) set @tablenickstr = convert(nchar(10), @tablenick) /* First, try to remove rows from notbelong based on the article filter, if there is one */ select @filter_clause = subset_filterclause from sysmergearticles where pubid = @pubid and nickname = @tablenick if len(@filter_clause) > 0 begin exec ('delete from #notbelong where tablenick = ' + @tablenickstr + ' and rowguid in (select RowGuidCol from ' + @basetable + ' where ' + @filter_clause + ')' ) end /* Now loop over any join filters that have this as the base_table */ select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick while @filterid is not null begin /* Get joining table and filter clause */ select @join_nick = join_nickname, @filter_clause = join_filterclause from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @jointable out, @pubid /* Exec query to remove rows from #notbelong that still belong to partial */ exec ('delete from #notbelong where tablenick = ' + @tablenickstr + ' and rowguid in (select ' + @basetable + '.RowGuidCol from ' + @basetable + ', ' + @jointable + ' where (' + @filter_clause + ') and ' + @jointable + '.RowGuidCol not in (select rowguid from #notbelong))') /* Find the next filter that might apply */ select @filterid = min(join_filterid) from sysmergesubsetfilters where pubid = @pubid and art_nickname = @tablenick and join_filterid > @filterid end go exec dbo.sp_MS_marksystemobject sp_MScontractsubsnb go grant exec on dbo.sp_MScontractsubsnb to public go raiserror('Creating procedure sp_MSexpandsubsnb', 0,1) GO create PROCEDURE sp_MSexpandsubsnb (@pubid uniqueidentifier) AS declare @filterid int declare @base_nick int declare @join_nick int declare @basetable nvarchar(258) declare @jointable nvarchar(258) declare @join_clause nvarchar(4000) declare @retcode int declare @base_nickstr nvarchar(10) /* get first filter to expand on */ select @filterid = min(join_filterid) from sysmergesubsetfilters f, #notbelong nb where pubid = @pubid and nb.tablenick = f.join_nickname and f.join_filterid > nb.flag while @filterid is not null begin /* get join clause and tables for this filter */ select @join_nick = join_nickname, @join_clause = join_filterclause, @base_nick = art_nickname from sysmergesubsetfilters where pubid = @pubid and join_filterid = @filterid exec @retcode = dbo.sp_MStablenamefromnick @join_nick, @jointable out, @pubid exec @retcode = dbo.sp_MStablenamefromnick @base_nick, @basetable out, @pubid set @base_nickstr = convert(nchar(10), @base_nick) /* Mark rows so that we know we've expanded those rows for this filter */ update #notbelong set flag = @filterid where flag < @filterid /* exec an insert/select query to expand #notbelong */ exec ('insert into #notbelong (tablenick, rowguid, flag) select ' + @base_nickstr + ', ' + @basetable + '.RowGuidCol, 0 from ' + @basetable + ', ' + @jointable + ' where ( ' + @jointable + '.RowGuidCol in (select rowguid from #notbelong) ) and ' + @join_clause) /* if any rows inserted, try to contract the #notbelong table */ if @@rowcount <> 0 exec @retcode = dbo.sp_MScontractsubsnb @pubid, @base_nick, @basetable /* get next filter to expand with */ select @filterid = min(join_filterid) from sysmergesubsetfilters f, #notbelong nb where pubid = @pubid and nb.tablenick = f.join_nickname and f.join_filterid > nb.flag end go exec dbo.sp_MS_marksystemobject sp_MSexpandsubsnb go grant exec on dbo.sp_MSexpandsubsnb to public go raiserror('Creating procedure sp_MSdelsubrows', 0,1) GO create PROCEDURE sp_MSdelsubrows (@rowguid uniqueidentifier, @tablenick int, @metadata_type tinyint, /* 0 - Missing, 1 - Tombstone, 2 - Contents, 3 - ContentsDeferred */ @lineage_old varbinary(255), @generation int, @lineage_new varbinary(255), @pubid uniqueidentifier = NULL) as set nocount on declare @success int declare @tablename nvarchar(258) declare @rowguidstr nvarchar(40) declare @match int declare @new_metatype tinyint declare @retcode smallint declare @reason nvarchar(255) declare @procname nvarchar(258) declare @ownername sysname /* ** Check to see if current publication has permission */ exec @retcode=sp_MSreplcheck_connection @tablenick = @tablenick if @retcode<>0 or @@ERROR<>0 return (1) select @success = 0 /* Parameter validation */ if (@rowguid is null) begin RAISERROR(14043, 16, -1, '@rowguid') return (0) end if (@tablenick is null) begin RAISERROR(14043, 16, -1, '@tablenick') return (0) end if @pubid is NULL exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename output else exec @retcode = dbo.sp_MStablenamefromnick @tablenick, @tablename output, @pubid if @@ERROR<>0 return (0) if (@tablename is null) begin RAISERROR(14043, 16, -1, '@tablename') return (0) end if (@lineage_new is null) begin RAISERROR(14043, 16, -1, '@lineage_new') return (0) end if (not exists(select * from sysobjects where name = 'MSmerge_contents')) begin RAISERROR(20054 , 16, -1) return (0) end set @rowguidstr = '''' + convert(nchar(36), @rowguid) + '''' -- Are we just changing the type of a tombstone? if (@metadata_type = 5 and exists (select * from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)) begin set @reason = formatmessage (20563) -- Moved out of partial range update MSmerge_tombstone set type = @metadata_type, reason = @reason where rowguid = @rowguid and tablenick = @tablenick set @success = 1 return @success end -- Are we just changing the type of a tombstone? if (@metadata_type = 6 and exists (select * from MSmerge_tombstone where rowguid = @rowguid and tablenick = @tablenick)) begin set @reason = formatmessage (20564) -- System deleted update MSmerge_tombstone set type = @metadata_type, reason = @reason where rowguid = @rowguid and tablenick = @tablenick set @success = 1 return @success end -- begin transaction and lock row that we plan to delete begin transaction select @ownername = user_name(uid) from sysobjects where id = object_id(@tablename) select @procname = select_proc from sysmergearticles where objid = object_id(@tablename) and pubid = @pubid exec @retcode = @procname @type =8, @rowguid=@rowguid select @success = 2 if @metadata_type = 5 begin set @match = 1 set @new_metatype = 5 end else if @metadata_type = 6 begin set @match = 1 set @new_metatype = 6 end else begin exec @retcode=sp_MScheckmetadatamatch @metadata_type, @rowguid, @tablenick, @lineage_old, @match output set @new_metatype = 1 end if (@match = 1) begin /* If there are any joinfilters with this as the join table, try to expand to deleting ** a set of related rows. */ if (exists (select * from sysmergesubsetfilters where pubid = @pubid and join_nickname = @tablenick)) begin declare @tn int declare @table_name sysname set @reason = formatmessage (20563) -- Moved out of partial range /* create temp and put in our tablenick, rowguid */ create table #notbelong (bookmark int identity NOT NULL, tablenick int NOT NULL, rowguid uniqueidentifier NOT NULL, flag int NOT NULL) create index #indnbelong on #notbelong (rowguid) insert into #notbelong (tablenick, rowguid, flag) values (@tablenick, @rowguid, 0) /* call expand proc */ exec @retcode = dbo.sp_MSexpandsubsnb @pubid select @tn = max(tablenick) from #notbelong where flag > -1 while @tn is not null begin exec @retcode = dbo.sp_MStablenamefromnick @tn, @table_name out, @pubid /* delete all rows indicated by the temp table */ exec ('delete from ' + @table_name + ' where RowGuidCol in (select rowguid from #notbelong)' ) /* change tombstone type for those rows */ update MSmerge_tombstone set type = 5, reason = @reason where tablenick = @tn and rowguid in (select rowguid from #notbelong) /* move on to next nickname - decreasing makes delete order correct */ update #notbelong set flag = -1 where tablenick = @tn select @tn = max(tablenick) from #notbelong where flag > -1 end /* drop temp, set success */ drop table #notbelong exec dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype select @success = 1 end else begin /* ** select_proc makes a delete with @type = 5, despite its name. */ exec @retcode = @procname @type =5, @rowguid=@rowguid if (@@error = 0 and @@rowcount = 1) begin exec dbo.sp_MSsetrowmetadata @tablenick, @rowguid, @generation, @lineage_new, NULL, @new_metatype select @success = 1 end else select @success = 3 end end commit return (@success) go exec dbo.sp_MS_marksystemobject sp_MSdelsubrows go grant exec on dbo.sp_MSdelsubrows to public go create procedure sp_MSmakeviewproc (@viewname sysname, @ownername sysname, @procname nvarchar(290), @rgcol sysname) as declare @retcode smallint declare @varname nvarchar(10) declare @cmdpiece nvarchar(4000) set nocount on select @procname=QUOTENAME(@procname) set @cmdpiece = 'create procedure dbo.' + @procname + ' (@tablenick int) AS set nocount on set rowcount 0 insert into #belong (tablenick, rowguid, flag, partchangegen, joinchangegen) select nb.tablenick, nb.rowguid, 0, nb.partchangegen, nb.joinchangegen from #notbelong nb, ' + QUOTENAME(@ownername) + '.' + QUOTENAME(@viewname) + ' v where nb.tablenick = @tablenick and nb.rowguid = v.' + @rgcol + ' if @@ERROR <> 0 begin RAISERROR(''Error selecting from view'' , 16, -1) return (1) end' exec (@cmdpiece) exec dbo.sp_MS_marksystemobject @procname exec ('grant exec on ' + @procname + ' to public') go exec dbo.sp_MS_marksystemobject sp_MSmakeviewproc go grant exec on dbo.sp_MSmakeviewproc to public go exec dbo.sp_configure 'allow updates',0 go dump tran master with no_log go reconfigure with override go