declare @before_name nvarchar(270) declare @before_viewname nvarchar(270) declare @unqual_sourcename nvarchar(270) declare @article nvarchar(270) declare @art_nick int declare @join_nick int declare @join_filterclause nvarchar(4000) declare @bool_filterclause nvarchar(4000) declare @view_rule nvarchar(4000) declare @before_view_rule nvarchar(4000) declare @before_objid int declare @article_level int declare @progress int declare @art int declare @viewname nvarchar(270) declare @procname nvarchar(300) declare @source_objid int declare @source_object nvarchar(270) declare @sync_objid int declare @bitset 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 nvarchar(270) declare @view_type int declare @belongsname nvarchar(270) declare @join_nickstr nvarchar(10) declare @unqual_jointable nvarchar(270) declare @hasguid int declare @vertical_partition 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 nvarchar(270) declare @table nvarchar(270) declare @quoted_obj nvarchar(290) declare @quoted_rowguid nvarchar(290) declare @before_rowguidname sysname declare @snapshot_ready int declare @columns varbinary(128) declare @column_list_1_to_15 nvarchar(4000), @column_list_16_to_30 nvarchar(4000), @column_list_31_to_45 nvarchar(4000), @column_list_46_to_60 nvarchar(4000), @column_list_61_to_75 nvarchar(4000), @column_list_76_to_90 nvarchar(4000), @column_list_91_to_105 nvarchar(4000), @column_list_106_to_120 nvarchar(4000), @column_list_121_to_135 nvarchar(4000), @column_list_136_to_150 nvarchar(4000), @column_list_151_to_165 nvarchar(4000), @column_list_166_to_180 nvarchar(4000), @column_list_181_to_195 nvarchar(4000), @column_list_196_to_210 nvarchar(4000), @column_list_211_to_225 nvarchar(4000), @column_list_226_to_240 nvarchar(4000), @column_list_241_to_255 nvarchar(4000), @column_list_256_to_270 nvarchar(4000) declare @colname nvarchar(270) declare @colid int declare @dynamic_filters bit declare @alias_for_sourceobject sysname declare @retcode int declare @dbname sysname declare @allcolsreturned bit declare @tempcollistphase int declare @viewexeccmd nvarchar(200) declare @beforeviewexeccmd nvarchar(200) declare @related_articles table (nickname int) -- Security check exec @retcode= dbo.sp_MSreplcheck_publish if @@error <> 0 or @retcode <> 0 return (1) set @tempcollistphase= 100 set @viewexeccmd= 'select cmdtext from #viewcmd where phase<>' + cast(@tempcollistphase as nvarchar(5)) + ' order by phase,step' set @beforeviewexeccmd= 'select cmdtext from #beforeviewcmd order by phase,step' set @progress = 1 set @article_level = 0 set @permanent = 1 set @temporary = 2 set @allhaveguids = 1 set @before_rowguidname = NULL /* ** Only legal publisher can run this stored procedure */ set nocount on /* make sure current database is enabled for merge replication */ exec @retcode=dbo.sp_MSCheckmergereplication if @@ERROR<>0 or @retcode<>0 return (1) set @dbname= db_name() select @pubid = pubid, @snapshot_ready = snapshot_ready, @dynamic_filters = dynamic_filters 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 @table=object_name(objid) from sysmergearticles where pubid=@pubid and (columns is NULL or columns = 0x00) if @table is not NULL begin raiserror(21318, 16, -1, @table) 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 #viewcmd (phase int, step int identity(1,1), cmdtext nvarchar(4000)) if @@error<>0 goto FAILURE create table #beforeviewcmd (phase int, step int identity(1,1), cmdtext nvarchar(4000)) if @@error<>0 goto FAILURE 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 at least 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 /* ** When the force_flag is 2, sp_MSpublicationview is being invoked from code paths such as sp_repladdcolumn/sp_repldropcolumn - ** In that case - prune the #art table by removing nicknames that are not related ** to the article name that is passed int */ if (@force_flag = 2) begin select @art_nick = nickname from dbo.sysmergearticles where pubid=@pubid and name = @articlename declare @progress_table table (nickname int, parent_nickname int null) declare @top_level_articles table (nickname int) -- First find the ones that are top-level parents. -- Top-level parents are considered to have themselves as their parents. -- Save off such articles in @top_level_articles insert into @top_level_articles (nickname) values(@art_nick) insert into @progress_table (nickname) select distinct nickname from @top_level_articles -- For each nickname in @progress_table which still has parent_nickname = NULL in @progress_table, -- find the top-level parent. while exists (select * from @progress_table where parent_nickname is NULL) begin declare @keep_traversing_upwards bit -- get one article - start with the one with min nickname insert into @related_articles (nickname) select min(nickname) from @progress_table where parent_nickname is NULL set @keep_traversing_upwards = 1 while @keep_traversing_upwards = 1 begin -- work your way up until you find the top-level parent. insert into @related_articles(nickname) select join_nickname from dbo.sysmergesubsetfilters where art_nickname in (select nickname from @related_articles) and join_nickname not in (select nickname from @related_articles) if @@rowcount <> 0 set @keep_traversing_upwards = 1 else set @keep_traversing_upwards = 0 end update @progress_table set parent_nickname = (select top 1 nickname from @top_level_articles where nickname in (select nickname from @related_articles)) where nickname in (select nickname from @related_articles) end delete from @progress_table insert into @progress_table (nickname) select distinct nickname from @top_level_articles while exists (select * from @progress_table where parent_nickname is NULL) begin declare @keep_traversing_downwards bit -- get one article - start with the one with min nickname insert into @related_articles (nickname) select min(nickname) from @progress_table where parent_nickname is NULL set @keep_traversing_downwards = 1 while @keep_traversing_downwards = 1 begin -- work your way up until you find the top-level parent. insert into @related_articles(nickname) select art_nickname from dbo.sysmergesubsetfilters where join_nickname in (select nickname from @related_articles) and art_nickname not in (select nickname from @related_articles) if @@rowcount <> 0 set @keep_traversing_downwards = 1 else set @keep_traversing_downwards = 0 end update @progress_table set parent_nickname = (select top 1 nickname from @top_level_articles where nickname in (select nickname from @related_articles)) where nickname in (select nickname from @related_articles) end delete from #art where art_nick not in (select distinct nickname from @related_articles) end -- Views for a particular article are being recreated only. if (@force_flag = 2) begin select @art_nick = nickname, @artid = artid from dbo.sysmergearticles where pubid=@pubid and name = @articlename if (@art_nick is NOT NULL) begin /* Drop the old view */ select @viewname = OBJECT_NAME (sync_objid), @before_viewname = OBJECT_NAME(before_view_objid) from sysmergearticles where pubid = @pubid and nickname = @art_nick if @viewname IS NOT NULL and ObjectProperty (object_id(@viewname), 'IsView') = 1 begin select @quoted_obj = QUOTENAME(@viewname) exec ('drop view ' + @quoted_obj) end if @before_viewname IS NOT NULL and ObjectProperty (object_id(@before_viewname), 'IsView') = 1 begin select @quoted_obj = QUOTENAME(@before_viewname) exec ('drop view ' + @quoted_obj) end /* Update the row in sysmergearticles */ update sysmergearticles set view_type = 0, sync_objid = objid, before_view_objid = NULL where pubid = @pubid and nickname = @art_nick if @@ERROR <> 0 goto FAILURE end end else begin /* Drop the old views and reset sync_objid */ select @art_nick = min(nickname) from sysmergearticles where pubid = @pubid and objid<>sync_objid while @art_nick is not null begin /* Drop the old view */ select @viewname = OBJECT_NAME (sync_objid), @before_viewname = OBJECT_NAME(before_view_objid) from sysmergearticles where pubid = @pubid and nickname = @art_nick if @viewname IS NOT NULL and ObjectProperty (object_id(@viewname), 'IsView') = 1 begin select @quoted_obj = QUOTENAME(@viewname) exec ('drop view ' + @quoted_obj) end if @before_viewname IS NOT NULL and ObjectProperty (object_id(@before_viewname), 'IsView') = 1 begin select @quoted_obj = QUOTENAME(@before_viewname) exec ('drop view ' + @quoted_obj) 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 objid<>sync_objid end end set @art = 0 select @art=min(indexcol) from #art where indexcol>@art while (@art is not null) begin delete from #viewcmd delete from #beforeviewcmd select @art_nick=art_nick, @article_level = article_level from #art where indexcol = @art select @article = name, @artid = artid, @columns = columns, @source_objid = objid, @sync_objid = sync_objid, @procname = view_sel_proc, @before_objid = before_image_objid from sysmergearticles where nickname=@art_nick and pubid = @pubid -- Need to run sp_MSgetcolumnlist already, to initialize @allcolsreturned. -- Just use an otherwise unused @phase value, which will be updated later on. insert into #viewcmd(phase, cmdtext) exec dbo.sp_MSgetcolumnlist @pubid=@pubid, @column_list_1_to_15 = @column_list_1_to_15 output, @column_list_16_to_30 = @column_list_16_to_30 output, @column_list_31_to_45 = @column_list_31_to_45 output, @column_list_46_to_60 = @column_list_46_to_60 output, @column_list_61_to_75 = @column_list_61_to_75 output, @column_list_76_to_90 = @column_list_76_to_90 output, @column_list_91_to_105 = @column_list_91_to_105 output, @column_list_106_to_120 = @column_list_106_to_120 output, @column_list_121_to_135 = @column_list_121_to_135 output, @column_list_136_to_150 = @column_list_136_to_150 output, @column_list_151_to_165 = @column_list_151_to_165 output, @column_list_166_to_180 = @column_list_166_to_180 output, @column_list_181_to_195 = @column_list_181_to_195 output, @column_list_196_to_210 = @column_list_196_to_210 output, @column_list_211_to_225 = @column_list_211_to_225 output, @column_list_226_to_240 = @column_list_226_to_240 output, @column_list_241_to_255 = @column_list_241_to_255 output, @column_list_256_to_270 = @column_list_256_to_270 output, @source_objid=@source_objid, @phase=@tempcollistphase, @allcolsreturned=@allcolsreturned output set @before_name = OBJECT_NAME(@before_objid) if @before_name is not null begin select @before_rowguidname=name from syscolumns where id=@source_objid and columnproperty(@source_objid, name , 'isrowguidcol')=1 exec @retcode = dbo.sp_MSguidtostr @pubid, @guidstr out set @before_viewname = @before_name + '_v_' + @guidstr end else set @before_viewname = NULL 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 @unqual_sourcename = QUOTENAME(OBJECT_NAME(@source_objid)) select @bool_filterclause=subset_filterclause, @vertical_partition=vertical_partition from sysmergearticles where name = @article and pubid = @pubid -- verify the syntax of boolean filter, if added with vertical-partition to true -- in this case, the filter clause can contain columns that do not exist in the partition. if len(@bool_filterclause) > 0 begin /* -- let server return appropriate error message exec ('select ' + @column_list_1_to_15 + @column_list_16_to_30 + @column_list_31_to_45 + @column_list_46_to_60 + @column_list_61_to_75 + @column_list_76_to_90 + @column_list_91_to_105 + @column_list_106_to_120 + @column_list_121_to_135 + @column_list_136_to_150 + @column_list_151_to_165 + @column_list_166_to_180 + @column_list_181_to_195 + @column_list_196_to_210 + @column_list_211_to_225 + @column_list_226_to_240 + @column_list_241_to_255 + @column_list_256_to_270 + ' into #temptable_publicationview from ' + @source_object + 'declare @test int select @test=1 from #temptable_publicationview ' + @unqual_sourcename + ' where ' + @bool_filterclause) if @@ERROR<>0 begin raiserror(21256, 16, -1, @bool_filterclause, @source_object) return (1) end */ select @bool_filterclause = ' (' + @bool_filterclause + ') ' end 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_obj = QUOTENAME(@viewname) exec ('drop view ' + @quoted_obj) 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 @join_filterclause=' ( ' + @join_filterclause + ') ' select @unqual_jointable = QUOTENAME(name) from sysobjects where id = (select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) if @max_network_optimization = 0 select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid) from sysmergearticles where nickname = @join_nick and pubid = @pubid else select @join_viewname = object_name(sync_objid), @join_before_view = object_name(case when before_view_objid is not null then before_view_objid else before_image_objid end) from sysmergearticles where nickname = @join_nick and pubid = @pubid select @join_viewname = QUOTENAME(@join_viewname) if 1=@hasguid begin 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 ' insert into #viewcmd(phase,cmdtext) values (3, @view_rule) -- sp_MSgetcolumnlist was called at the beginning of the article loop. -- Thus, we now just set the right phase. update #viewcmd set phase= 4 where phase=@tempcollistphase set @view_rule= ' from ' + @source_object + ' ' + @unqual_sourcename + ' , ' + @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase,cmdtext) values (5, @view_rule) end else begin set @simple_join_view = 0 /* Alias the source object with the unqualified name and use that to select the rowguidcol */ set @view_rule = 'select ' + @unqual_sourcename + '.rowguidcol from ' + @source_object + ' ' + @unqual_sourcename + ' , ' + @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values(3, @view_rule) end end if @before_name is not null begin set @before_view_rule = 'select * from ' + @before_name + ' ' + @unqual_sourcename + ' where (exists (select * from ' + @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from ' + @join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') ' insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule) end fetch next from pub1 into @join_filterclause, @join_nick, @join_articlename, @join_unique_key, @join_filterid WHILE (@@fetch_status <> -1) begin select @join_filterclause=' ( ' + @join_filterclause + ') ' select @unqual_jointable = quotename(name) from sysobjects where id = ( select objid from sysmergearticles where name=@join_articlename and pubid=@pubid) if @max_network_optimization = 0 select @join_viewname = object_name(sync_objid), @join_before_view = object_name(before_image_objid) from sysmergearticles where nickname = @join_nick and pubid = @pubid else select @join_viewname = object_name(sync_objid), @join_before_view = object_name(case when before_view_objid is not null then before_view_objid else before_image_objid end) from sysmergearticles where nickname = @join_nick and pubid = @pubid select @join_viewname = QUOTENAME(@join_viewname) if 1=@hasguid begin set @view_rule = ' union select ' + @unqual_sourcename + '.rowguidcol from ' + @source_object + ' ' + @unqual_sourcename + ', ' + @join_viewname + ' ' + @unqual_jointable + ' where (' + @join_filterclause + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values(5, @view_rule) end if @before_name is not null begin set @before_view_rule = ' or exists (select * from ' + @join_viewname + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') or exists (select * from ' + @join_before_view + ' ' + @unqual_jointable + ' where ' + @join_filterclause + ') ' insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule) end 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 begin if 1=@hasguid begin set @view_rule = ' union select ' + @unqual_sourcename + '.rowguidcol from ' + @source_object + ' ' + @unqual_sourcename + ' where ('+ @bool_filterclause + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values(5, @view_rule) end if @before_name is not null begin set @before_view_rule = ' or ' + @bool_filterclause insert into #beforeviewcmd(phase,cmdtext) values(3,@before_view_rule) end end if 1=@hasguid begin -- Now do the actual view rule as a semi-join, if not a simple join on unique key if (@simple_join_view = 0) begin /* ** Generate a unique alias for the outer select to make sure that it does not generate an ** ambiguous reference with table names used in the join_filter clause */ set @alias_for_sourceobject = 'alias_' + @guidstr set @view_rule= 'select ' insert into #viewcmd(phase, cmdtext) values (2, @view_rule) -- Here we cannot reuse the original call to sp_MSgetcolumnlist, because -- it was done with default value for @guid_alias. insert into #viewcmd(phase, cmdtext) exec dbo.sp_MSgetcolumnlist @pubid=@pubid, @column_list_1_to_15 = @column_list_1_to_15 output, @column_list_16_to_30 = @column_list_16_to_30 output, @column_list_31_to_45 = @column_list_31_to_45 output, @column_list_46_to_60 = @column_list_46_to_60 output, @column_list_61_to_75 = @column_list_61_to_75 output, @column_list_76_to_90 = @column_list_76_to_90 output, @column_list_91_to_105 = @column_list_91_to_105 output, @column_list_106_to_120 = @column_list_106_to_120 output, @column_list_121_to_135 = @column_list_121_to_135 output, @column_list_136_to_150 = @column_list_136_to_150 output, @column_list_151_to_165 = @column_list_151_to_165 output, @column_list_166_to_180 = @column_list_166_to_180 output, @column_list_181_to_195 = @column_list_181_to_195 output, @column_list_196_to_210 = @column_list_196_to_210 output, @column_list_211_to_225 = @column_list_211_to_225 output, @column_list_226_to_240 = @column_list_226_to_240 output, @column_list_241_to_255 = @column_list_241_to_255 output, @column_list_256_to_270 = @column_list_256_to_270 output, @source_objid=@source_objid, @guid_alias=@alias_for_sourceobject, @phase=2 set @view_rule= ' from ' + @source_object + ' ' + @alias_for_sourceobject + ' where rowguidcol in (' insert into #viewcmd(phase,cmdtext) values(2,@view_rule) set @view_rule= ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values(6, @view_rule) end end end else /* boolean filter only */ begin if 1=@hasguid begin delete from #viewcmd where phase<>@tempcollistphase delete from #beforeviewcmd set @view_rule= 'select ' insert into #viewcmd(phase,cmdtext) values (2, @view_rule) -- sp_MSgetcolumnlist was called at the beginning of the article loop. -- Thus, we now just set the right phase. update #viewcmd set phase= 3 where phase=@tempcollistphase select @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename + ' where ('+ @bool_filterclause + ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values (3, @view_rule) end if @before_name is not null begin set @before_view_rule = ' select * from ' + @before_name + ' ' + @unqual_sourcename + ' where (' + @bool_filterclause insert into #beforeviewcmd(phase, cmdtext) values(3, @before_view_rule) end end select @viewname = @publication + '_' + @article + '_VIEW' exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output if @retcode <> 0 or @@ERROR <> 0 return (1) select @quoted_obj = QUOTENAME(@viewname) /* If we havent generated rowguidcol yet, use dummy rule that doesnt refer to it */ if @hasguid = 0 begin delete from #viewcmd where phase<>@tempcollistphase set @view_rule= 'select ' insert into #viewcmd(phase, cmdtext) values (2, @view_rule) -- sp_MSgetcolumnlist was called at the beginning of the article loop. -- Thus, we now just set the right phase. update #viewcmd set phase= 3 where phase=@tempcollistphase set @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values (3, @view_rule) end set @view_rule= 'create view [dbo].'+ @quoted_obj + ' as ' insert into #viewcmd(phase,cmdtext) values(1,@view_rule) exec @retcode= master.dbo.xp_execresultset @cmd= @viewexeccmd, @dbname= @dbname if @@error<>0 or @retcode<>0 return 1 /* grant select permission on sync view to public - security check is performed inside the view */ exec ('grant select on ' + @quoted_obj + ' to public') if @@ERROR<>0 return (1) /* Mark view as system object */ execute sp_MS_marksystemobject @quoted_obj if @@ERROR<>0 return (1) if @hasguid = 1 begin select @procname=view_sel_proc from sysmergearticles where pubid=@pubid and artid=@artid if object_id(@procname) is not NULL begin set @quoted_obj= quotename(@procname) exec ('drop procedure ' + @quoted_obj) update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid 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, @source_objid if @retcode<>0 or @@ERROR<>0 return (1) update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid end select @quoted_obj = QUOTENAME(@viewname) update sysmergearticles set sync_objid = OBJECT_ID (@quoted_obj), view_type = @permanent where artid = @artid and pubid = @pubid if @before_name is not null and @before_view_rule is not null begin set @quoted_obj= quotename(@before_viewname) exec @retcode = sp_MScreatebeforetable @source_objid if @@ERROR <>0 OR @retcode <>0 return (1) if object_id(@before_viewname) is not NULL and ObjectProperty (object_id(@quoted_obj), 'IsView') = 1 begin exec ('drop view ' + @quoted_obj) end set @before_view_rule= ') and ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #beforeviewcmd(phase,cmdtext) values(5,@before_view_rule) set @before_view_rule= 'create view [dbo].' + @quoted_obj + ' as ' insert into #beforeviewcmd(phase,cmdtext) values(2,@before_view_rule) exec @retcode= master.dbo.xp_execresultset @cmd= @beforeviewexeccmd, @dbname= @dbname if @@error<>0 or @retcode<>0 return 1 if @before_rowguidname is not NULL begin set @quoted_rowguid= quotename(@before_rowguidname) exec ('grant select (' + @quoted_rowguid + ') on '+ @quoted_obj + ' to public') if @@ERROR<>0 return (1) end exec ('grant select (generation) on '+ @quoted_obj + ' to public') if @@ERROR<>0 return (1) execute sp_MS_marksystemobject @before_viewname if @@ERROR<>0 return (1) update sysmergearticles set before_view_objid = OBJECT_ID (@before_viewname) where artid = @artid and pubid = @pubid end end else begin select @sync_objid = @source_objid if @vertical_partition=1 and 0=@allcolsreturned begin select @viewname = @publication + '_' + @article + '_VIEW' exec @retcode = dbo.sp_MSuniqueobjectname @viewname , @viewname output select @quoted_obj = QUOTENAME(@viewname) set @view_rule= 'create view [dbo].'+ @quoted_obj + ' as '+ ' select ' insert into #viewcmd(phase, cmdtext) values (1, @view_rule) -- sp_MSgetcolumnlist was called at the beginning of the article loop. -- Thus, we now just set the right phase. update #viewcmd set phase= 2 where phase=@tempcollistphase set @view_rule= ' from '+ @source_object + ' ' + @unqual_sourcename + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' insert into #viewcmd(phase, cmdtext) values (2, @view_rule) exec @retcode= master.dbo.xp_execresultset @cmd= @viewexeccmd, @dbname= @dbname if @@error<>0 or @retcode<>0 return 1 execute sp_MS_marksystemobject @quoted_obj if @@ERROR<>0 return (1) /* grant select permission on sync view to public - security check is performed inside the view */ exec ('grant select on ' + @quoted_obj + ' to public') if @@ERROR<>0 return (1) select @sync_objid=object_id(@viewname) update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid where artid = @artid and pubid = @pubid end else if @dynamic_filters = 1 begin /* This article doesn't have any vertical or horizontal filters but if the publication is enabled for dynamic filtering, we still want to generate a dummy view so that logins in the publication access list can generate a dynamic snapshot. */ select @viewname = @publication + '_' + @article + '_VIEW' exec @retcode = dbo.sp_MSuniqueobjectname @viewname, @viewname output select @quoted_obj = QUOTENAME(@viewname) set @view_rule = ' select * from ' + @source_object + ' where ({ fn ISPALUSER(''' + convert(nvarchar(36), @pubid) + ''') } = 1)' exec ('create view [dbo].'+ @quoted_obj + ' as '+ @view_rule) if @@ERROR<>0 return (1) execute sp_MS_marksystemobject @quoted_obj if @@ERROR<>0 return (1) exec ('grant select on ' + @quoted_obj + ' to public') if @@ERROR<>0 return (1) select @sync_objid=object_id(@viewname) update sysmergearticles set view_sel_proc = @procname, sync_objid=@sync_objid, view_type = @permanent where artid = @artid and pubid = @pubid end if @hasguid = 1 begin /* still make the select proc, although it selects directly from table */ if object_id(@procname) is not NULL begin set @quoted_obj= quotename(@procname) exec ('drop proc ' + @quoted_obj) update sysmergearticles set view_sel_proc = NULL where artid = @artid and pubid = @pubid end 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 = @sync_objid exec dbo.sp_MSmakeviewproc @viewname, @owner, @procname, @rgcol, @source_objid update sysmergearticles set view_sel_proc = @procname where pubid=@pubid and artid=@artid end end select @art=min(indexcol) from #art where indexcol>@art end -- Do the following only if executing in non-article mode if (@force_flag <> 2) begin /* 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_obj = QUOTENAME(@viewname) exec ('drop view ' + @quoted_obj) 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_obj = QUOTENAME(@viewname) exec ('create view [dbo].' + @quoted_obj + ' as select * from '